From 40ee551715c3a784ea6132dbf604b0e665ca2def Mon Sep 17 00:00:00 2001 From: temporal Date: Thu, 10 Jul 2008 02:12:20 +0000 Subject: Initial checkin. --- src/google/protobuf/reflection_ops.cc | 241 ++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 src/google/protobuf/reflection_ops.cc (limited to 'src/google/protobuf/reflection_ops.cc') diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc new file mode 100644 index 00000000..2b263298 --- /dev/null +++ b/src/google/protobuf/reflection_ops.cc @@ -0,0 +1,241 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. +// http://code.google.com/p/protobuf/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +void ReflectionOps::Copy(const Descriptor* descriptor, + const Message::Reflection& from, + Message::Reflection* to) { + if (&from == to) return; + Clear(descriptor, to); + Merge(descriptor, from, to); +} + +void ReflectionOps::Merge(const Descriptor* descriptor, + const Message::Reflection& from, + Message::Reflection* to) { + GOOGLE_CHECK_NE(&from, to); + vector fields; + from.ListFields(&fields); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + + if (field->is_repeated()) { + int count = from.FieldSize(field); + for (int j = 0; j < count; j++) { + switch (field->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, METHOD) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + to->Add##METHOD(field, \ + from.GetRepeated##METHOD(field, j)); \ + break; + + HANDLE_TYPE(INT32 , Int32 ); + HANDLE_TYPE(INT64 , Int64 ); + HANDLE_TYPE(UINT32, UInt32); + HANDLE_TYPE(UINT64, UInt64); + HANDLE_TYPE(FLOAT , Float ); + HANDLE_TYPE(DOUBLE, Double); + HANDLE_TYPE(BOOL , Bool ); + HANDLE_TYPE(STRING, String); + HANDLE_TYPE(ENUM , Enum ); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_MESSAGE: + to->AddMessage(field)->MergeFrom( + from.GetRepeatedMessage(field, j)); + break; + } + } + } else if (from.HasField(field)) { + switch (field->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, METHOD) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + to->Set##METHOD(field, from.Get##METHOD(field)); \ + break; + + HANDLE_TYPE(INT32 , Int32 ); + HANDLE_TYPE(INT64 , Int64 ); + HANDLE_TYPE(UINT32, UInt32); + HANDLE_TYPE(UINT64, UInt64); + HANDLE_TYPE(FLOAT , Float ); + HANDLE_TYPE(DOUBLE, Double); + HANDLE_TYPE(BOOL , Bool ); + HANDLE_TYPE(STRING, String); + HANDLE_TYPE(ENUM , Enum ); +#undef HANDLE_TYPE + + case FieldDescriptor::CPPTYPE_MESSAGE: + to->MutableMessage(field)->MergeFrom( + from.GetMessage(field)); + break; + } + } + } + + to->MutableUnknownFields()->MergeFrom(from.GetUnknownFields()); +} + +void ReflectionOps::Clear(const Descriptor* descriptor, + Message::Reflection* reflection) { + vector fields; + reflection->ListFields(&fields); + for (int i = 0; i < fields.size(); i++) { + reflection->ClearField(fields[i]); + } + + reflection->MutableUnknownFields()->Clear(); +} + +bool ReflectionOps::IsInitialized(const Descriptor* descriptor, + const Message::Reflection& reflection) { + // Check required fields of this message. + for (int i = 0; i < descriptor->field_count(); i++) { + if (descriptor->field(i)->is_required()) { + if (!reflection.HasField(descriptor->field(i))) { + return false; + } + } + } + + // Check that sub-messages are initialized. + vector fields; + reflection.ListFields(&fields); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (field->is_repeated()) { + int size = reflection.FieldSize(field); + + for (int i = 0; i < size; i++) { + if (!reflection.GetRepeatedMessage(field, i).IsInitialized()) { + return false; + } + } + } else { + if (reflection.HasField(field) && + !reflection.GetMessage(field).IsInitialized()) { + return false; + } + } + } + } + + return true; +} + +void ReflectionOps::DiscardUnknownFields( + const Descriptor* descriptor, + Message::Reflection* reflection) { + reflection->MutableUnknownFields()->Clear(); + + vector fields; + reflection->ListFields(&fields); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (field->is_repeated()) { + int size = reflection->FieldSize(field); + for (int i = 0; i < size; i++) { + reflection->MutableRepeatedMessage(field, i)->DiscardUnknownFields(); + } + } else { + if (reflection->HasField(field)) { + reflection->MutableMessage(field)->DiscardUnknownFields(); + } + } + } + } +} + +static string SubMessagePrefix(const string& prefix, + const FieldDescriptor* field, + int index) { + string result(prefix); + if (field->is_extension()) { + result.append("("); + result.append(field->full_name()); + result.append(")"); + } else { + result.append(field->name()); + } + if (index != -1) { + result.append("["); + result.append(SimpleItoa(index)); + result.append("]"); + } + result.append("."); + return result; +} + +void ReflectionOps::FindInitializationErrors( + const Descriptor* descriptor, + const Message::Reflection& reflection, + const string& prefix, + vector* errors) { + // Check required fields of this message. + for (int i = 0; i < descriptor->field_count(); i++) { + if (descriptor->field(i)->is_required()) { + if (!reflection.HasField(descriptor->field(i))) { + errors->push_back(prefix + descriptor->field(i)->name()); + } + } + } + + // Check sub-messages. + vector fields; + reflection.ListFields(&fields); + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + + if (field->is_repeated()) { + int size = reflection.FieldSize(field); + + for (int i = 0; i < size; i++) { + const Message& sub_message = reflection.GetRepeatedMessage(field, i); + FindInitializationErrors(field->message_type(), + *sub_message.GetReflection(), + SubMessagePrefix(prefix, field, i), + errors); + } + } else { + if (reflection.HasField(field)) { + const Message& sub_message = reflection.GetMessage(field); + FindInitializationErrors(field->message_type(), + *sub_message.GetReflection(), + SubMessagePrefix(prefix, field, -1), + errors); + } + } + } + } +} + +} // namespace internal +} // namespace protobuf +} // namespace google -- cgit v1.2.3