aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/extension_set.cc
diff options
context:
space:
mode:
authorGravatar temporal <temporal@630680e5-0e50-0410-840e-4b1c322b438d>2008-07-10 02:12:20 +0000
committerGravatar temporal <temporal@630680e5-0e50-0410-840e-4b1c322b438d>2008-07-10 02:12:20 +0000
commit40ee551715c3a784ea6132dbf604b0e665ca2def (patch)
tree6e3ea9674be5b0f59106f88f3afa1313854beebf /src/google/protobuf/extension_set.cc
Initial checkin.
Diffstat (limited to 'src/google/protobuf/extension_set.cc')
-rw-r--r--src/google/protobuf/extension_set.cc735
1 files changed, 735 insertions, 0 deletions
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
new file mode 100644
index 00000000..154f06f8
--- /dev/null
+++ b/src/google/protobuf/extension_set.cc
@@ -0,0 +1,735 @@
+// 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 <google/protobuf/stubs/hash.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/repeated_field.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// -------------------------------------------------------------------
+// Lookup functions
+
+const FieldDescriptor*
+ExtensionSet::FindKnownExtensionByName(const string& name) const {
+ const FieldDescriptor* result = descriptor_pool_->FindExtensionByName(name);
+ if (result != NULL && result->containing_type() == extendee_) {
+ return result;
+ }
+
+ if (extendee_->options().message_set_wire_format()) {
+ // MessageSet extensions may be identified by type name.
+ const Descriptor* type = descriptor_pool_->FindMessageTypeByName(name);
+ if (type != NULL) {
+ // Look for a matching extension in the foreign type's scope.
+ for (int i = 0; i < type->extension_count(); i++) {
+ const FieldDescriptor* extension = type->extension(i);
+ if (extension->containing_type() == extendee_ &&
+ extension->type() == FieldDescriptor::TYPE_MESSAGE &&
+ extension->is_optional() &&
+ extension->message_type() == type) {
+ // Found it.
+ return extension;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+const FieldDescriptor*
+ExtensionSet::FindKnownExtensionByNumber(int number) const {
+ return descriptor_pool_->FindExtensionByNumber(extendee_, number);
+}
+
+const FieldDescriptor*
+ExtensionSet::FindKnownExtensionOrDie(int number) const {
+ const FieldDescriptor* descriptor = FindKnownExtensionByNumber(number);
+ if (descriptor == NULL) {
+ // This extension doesn't exist, so we have to crash. However, let's
+ // try to provide an informative error message.
+ if (descriptor_pool_ == DescriptorPool::generated_pool() &&
+ message_factory_ == MessageFactory::generated_factory()) {
+ // This is probably the ExtensionSet for a generated class.
+ GOOGLE_LOG(FATAL) << ": No extension is registered for \""
+ << extendee_->full_name() << "\" with number "
+ << number << ". Perhaps you were trying to access it via "
+ "the Reflection interface, but you provided a "
+ "FieldDescriptor which did not come from a linked-in "
+ "message type? This is not permitted; linkin-in message "
+ "types cannot use non-linked-in extensions. Try "
+ "converting to a DynamicMessage first.";
+ } else {
+ // This is probably a DynamicMessage.
+ GOOGLE_LOG(FATAL) << ": No extension is registered for \""
+ << extendee_->full_name() << "\" with number "
+ << number << ". If you were using a DynamicMessage, "
+ "remember that you are only allowed to access extensions "
+ "which are defined in the DescriptorPool which you passed "
+ "to DynamicMessageFactory's constructor.";
+ }
+ }
+ return descriptor;
+}
+
+const Message*
+ExtensionSet::GetPrototype(const Descriptor* message_type) const {
+ return message_factory_->GetPrototype(message_type);
+}
+
+// ===================================================================
+// Constructors and basic methods.
+
+ExtensionSet::ExtensionSet(const Descriptor* extendee,
+ const DescriptorPool* pool,
+ MessageFactory* factory)
+ : extendee_(extendee),
+ descriptor_pool_(pool),
+ message_factory_(factory) {
+}
+
+ExtensionSet::~ExtensionSet() {
+ for (map<int, Extension>::iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ iter->second.Free();
+ }
+}
+
+void ExtensionSet::AppendToList(vector<const FieldDescriptor*>* output) const {
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ bool has = false;
+ if (iter->second.descriptor->is_repeated()) {
+ has = iter->second.GetSize() > 0;
+ } else {
+ has = !iter->second.is_cleared;
+ }
+
+ if (has) {
+ output->push_back(iter->second.descriptor);
+ }
+ }
+}
+
+bool ExtensionSet::Has(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) return false;
+ GOOGLE_DCHECK(!iter->second.descriptor->is_repeated());
+ return !iter->second.is_cleared;
+}
+
+int ExtensionSet::ExtensionSize(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) return false;
+ return iter->second.GetSize();
+}
+
+void ExtensionSet::ClearExtension(int number) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) return;
+ iter->second.Clear();
+}
+
+// ===================================================================
+// Field accessors
+
+#define GOOGLE_DCHECK_TYPE(DESCRIPTOR, LABEL, CPPTYPE) \
+ GOOGLE_DCHECK_EQ(DESCRIPTOR->label(), FieldDescriptor::LABEL_##LABEL); \
+ GOOGLE_DCHECK_EQ(DESCRIPTOR->cpp_type(), FieldDescriptor::CPPTYPE_##CPPTYPE)
+
+// -------------------------------------------------------------------
+// Primitives
+
+#define PRIMITIVE_ACCESSORS(UPPERCASE, LOWERCASE, CAMELCASE) \
+ \
+LOWERCASE ExtensionSet::Get##CAMELCASE(int number) const { \
+ map<int, Extension>::const_iterator iter = extensions_.find(number); \
+ if (iter == extensions_.end()) { \
+ /* Not present. Return the default value. */ \
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, UPPERCASE); \
+ return descriptor->default_value_##LOWERCASE(); \
+ } else { \
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, UPPERCASE); \
+ return iter->second.LOWERCASE##_value; \
+ } \
+} \
+ \
+void ExtensionSet::Set##CAMELCASE(int number, LOWERCASE value) { \
+ Extension* extension = &extensions_[number]; \
+ if (extension->descriptor == NULL) { \
+ /* Not previoulsy present. Initialize it. */ \
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, UPPERCASE); \
+ extension->descriptor = descriptor; \
+ extension->LOWERCASE##_value = descriptor->default_value_##LOWERCASE(); \
+ } else { \
+ GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, UPPERCASE); \
+ extension->is_cleared = false; \
+ } \
+ extension->LOWERCASE##_value = value; \
+} \
+ \
+LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) const { \
+ map<int, Extension>::const_iterator iter = extensions_.find(number); \
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, UPPERCASE); \
+ return iter->second.repeated_##LOWERCASE##_value->Get(index); \
+} \
+ \
+void ExtensionSet::SetRepeated##CAMELCASE( \
+ int number, int index, LOWERCASE value) { \
+ map<int, Extension>::iterator iter = extensions_.find(number); \
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, UPPERCASE); \
+ iter->second.repeated_##LOWERCASE##_value->Set(index, value); \
+} \
+ \
+void ExtensionSet::Add##CAMELCASE(int number, LOWERCASE value) { \
+ Extension* extension = &extensions_[number]; \
+ if (extension->descriptor == NULL) { \
+ /* Not previoulsy present. Initialize it. */ \
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \
+ GOOGLE_DCHECK_TYPE(descriptor, REPEATED, UPPERCASE); \
+ extension->repeated_##LOWERCASE##_value = new RepeatedField<LOWERCASE>(); \
+ extension->descriptor = descriptor; \
+ } else { \
+ GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, UPPERCASE); \
+ } \
+ extension->repeated_##LOWERCASE##_value->Add(value); \
+}
+
+PRIMITIVE_ACCESSORS( INT32, int32, Int32)
+PRIMITIVE_ACCESSORS( INT64, int64, Int64)
+PRIMITIVE_ACCESSORS(UINT32, uint32, UInt32)
+PRIMITIVE_ACCESSORS(UINT64, uint64, UInt64)
+PRIMITIVE_ACCESSORS( FLOAT, float, Float)
+PRIMITIVE_ACCESSORS(DOUBLE, double, Double)
+PRIMITIVE_ACCESSORS( BOOL, bool, Bool)
+
+#undef PRIMITIVE_ACCESSORS
+
+// -------------------------------------------------------------------
+// Enums
+
+int ExtensionSet::GetEnum(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) {
+ // Not present. Return the default value.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, ENUM);
+ return descriptor->default_value_enum()->number();
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, ENUM);
+ return iter->second.enum_value;
+ }
+}
+
+void ExtensionSet::SetEnum(int number, int value) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, ENUM);
+ extension->descriptor = descriptor;
+ extension->enum_value = descriptor->default_value_enum()->number();
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, ENUM);
+ extension->is_cleared = false;
+ }
+ GOOGLE_DCHECK(extension->descriptor->enum_type()->FindValueByNumber(value) != NULL);
+ extension->enum_value = value;
+}
+
+int ExtensionSet::GetRepeatedEnum(int number, int index) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, ENUM);
+ return iter->second.repeated_enum_value->Get(index);
+}
+
+void ExtensionSet::SetRepeatedEnum(int number, int index, int value) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, ENUM);
+ GOOGLE_DCHECK(iter->second.descriptor->enum_type()
+ ->FindValueByNumber(value) != NULL);
+ iter->second.repeated_enum_value->Set(index, value);
+}
+
+void ExtensionSet::AddEnum(int number, int value) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, REPEATED, ENUM);
+ extension->repeated_enum_value = new RepeatedField<int>();
+ extension->descriptor = descriptor;
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, ENUM);
+ }
+ GOOGLE_DCHECK(extension->descriptor->enum_type()->FindValueByNumber(value) != NULL);
+ extension->repeated_enum_value->Add(value);
+}
+
+// -------------------------------------------------------------------
+// Strings
+
+const string& ExtensionSet::GetString(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) {
+ // Not present. Return the default value.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, STRING);
+ return descriptor->default_value_string();
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, STRING);
+ return *iter->second.string_value;
+ }
+}
+
+string* ExtensionSet::MutableString(int number) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, STRING);
+ extension->descriptor = descriptor;
+ extension->string_value = new string;
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, STRING);
+ extension->is_cleared = false;
+ }
+ return extension->string_value;
+}
+
+const string& ExtensionSet::GetRepeatedString(int number, int index) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, STRING);
+ return iter->second.repeated_string_value->Get(index);
+}
+
+string* ExtensionSet::MutableRepeatedString(int number, int index) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, STRING);
+ return iter->second.repeated_string_value->Mutable(index);
+}
+
+string* ExtensionSet::AddString(int number) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, REPEATED, STRING);
+ extension->repeated_string_value = new RepeatedPtrField<string>();
+ extension->descriptor = descriptor;
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, STRING);
+ }
+ return extension->repeated_string_value->Add();
+}
+
+// -------------------------------------------------------------------
+// Messages
+
+const Message& ExtensionSet::GetMessage(int number) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ if (iter == extensions_.end()) {
+ // Not present. Return the default value.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, MESSAGE);
+ return *GetPrototype(descriptor->message_type());
+ } else {
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, MESSAGE);
+ return *iter->second.message_value;
+ }
+}
+
+Message* ExtensionSet::MutableMessage(int number) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, MESSAGE);
+ extension->descriptor = descriptor;
+ extension->message_value = GetPrototype(descriptor->message_type())->New();
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, MESSAGE);
+ extension->is_cleared = false;
+ }
+ return extension->message_value;
+}
+
+const Message& ExtensionSet::GetRepeatedMessage(int number, int index) const {
+ map<int, Extension>::const_iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, MESSAGE);
+ return iter->second.repeated_message_value->Get(index);
+}
+
+Message* ExtensionSet::MutableRepeatedMessage(int number, int index) {
+ map<int, Extension>::iterator iter = extensions_.find(number);
+ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
+ GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, MESSAGE);
+ return iter->second.repeated_message_value->Mutable(index);
+}
+
+Message* ExtensionSet::AddMessage(int number) {
+ Extension* extension = &extensions_[number];
+ if (extension->descriptor == NULL) {
+ // Not previoulsy present. Initialize it.
+ const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number);
+ GOOGLE_DCHECK_TYPE(descriptor, REPEATED, MESSAGE);
+ extension->repeated_message_value =
+ new RepeatedPtrField<Message>(GetPrototype(descriptor->message_type()));
+ extension->descriptor = descriptor;
+ } else {
+ GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, MESSAGE);
+ }
+ return extension->repeated_message_value->Add();
+}
+
+#undef GOOGLE_DCHECK_TYPE
+
+// ===================================================================
+
+void ExtensionSet::Clear() {
+ for (map<int, Extension>::iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ iter->second.Clear();
+ }
+}
+
+namespace {
+
+// A helper function for merging RepeatedFields...
+// TODO(kenton): Implement this as a method of RepeatedField? Make generated
+// MergeFrom methods use it?
+
+template <typename Type>
+void MergeRepeatedFields(const RepeatedField<Type>& source,
+ RepeatedField<Type>* destination) {
+ destination->Reserve(destination->size() + source.size());
+ for (int i = 0; i < source.size(); i++) {
+ destination->Add(source.Get(i));
+ }
+}
+
+void MergeRepeatedFields(const RepeatedPtrField<string>& source,
+ RepeatedPtrField<string>* destination) {
+ destination->Reserve(destination->size() + source.size());
+ for (int i = 0; i < source.size(); i++) {
+ destination->Add()->assign(source.Get(i));
+ }
+}
+
+void MergeRepeatedFields(const RepeatedPtrField<Message>& source,
+ RepeatedPtrField<Message>* destination) {
+ destination->Reserve(destination->size() + source.size());
+ for (int i = 0; i < source.size(); i++) {
+ destination->Add()->MergeFrom(source.Get(i));
+ }
+}
+
+} // namespace
+
+void ExtensionSet::MergeFrom(const ExtensionSet& other) {
+ GOOGLE_DCHECK_EQ(extendee_, other.extendee_);
+
+ for (map<int, Extension>::const_iterator iter = other.extensions_.begin();
+ iter != other.extensions_.end(); ++iter) {
+ const FieldDescriptor* field = iter->second.descriptor;
+ if (field->is_repeated()) {
+ const Extension& other_extension = iter->second;
+ Extension* extension = &extensions_[iter->first];
+ switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ if (extension->descriptor == NULL) { \
+ extension->descriptor = field; \
+ extension->repeated_##LOWERCASE##_value = \
+ new REPEATED_TYPE; \
+ } \
+ MergeRepeatedFields( \
+ *other_extension.repeated_##LOWERCASE##_value, \
+ extension->repeated_##LOWERCASE##_value); \
+ break;
+
+ HANDLE_TYPE( INT32, int32, RepeatedField < int32>);
+ HANDLE_TYPE( INT64, int64, RepeatedField < int64>);
+ HANDLE_TYPE( UINT32, uint32, RepeatedField < uint32>);
+ HANDLE_TYPE( UINT64, uint64, RepeatedField < uint64>);
+ HANDLE_TYPE( FLOAT, float, RepeatedField < float>);
+ HANDLE_TYPE( DOUBLE, double, RepeatedField < double>);
+ HANDLE_TYPE( BOOL, bool, RepeatedField < bool>);
+ HANDLE_TYPE( ENUM, enum, RepeatedField < int>);
+ HANDLE_TYPE( STRING, string, RepeatedPtrField< string>);
+#undef HANDLE_TYPE
+
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ if (extension->descriptor == NULL) {
+ extension->descriptor = field;
+ extension->repeated_message_value = new RepeatedPtrField<Message>(
+ other_extension.repeated_message_value->prototype());
+ }
+ MergeRepeatedFields(
+ *other_extension.repeated_message_value,
+ extension->repeated_message_value);
+ break;
+ }
+ } else {
+ if (!iter->second.is_cleared) {
+ switch (field->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ Set##CAMELCASE(iter->first, iter->second.LOWERCASE##_value); \
+ break;
+
+ HANDLE_TYPE( INT32, int32, Int32);
+ HANDLE_TYPE( INT64, int64, Int64);
+ HANDLE_TYPE(UINT32, uint32, UInt32);
+ HANDLE_TYPE(UINT64, uint64, UInt64);
+ HANDLE_TYPE( FLOAT, float, Float);
+ HANDLE_TYPE(DOUBLE, double, Double);
+ HANDLE_TYPE( BOOL, bool, Bool);
+ HANDLE_TYPE( ENUM, enum, Enum);
+#undef HANDLE_TYPE
+ case FieldDescriptor::CPPTYPE_STRING:
+ SetString(iter->first, *iter->second.string_value);
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ MutableMessage(iter->first)->MergeFrom(*iter->second.message_value);
+ break;
+ }
+ }
+ }
+ }
+}
+
+bool ExtensionSet::IsInitialized() const {
+ // Extensions are never requried. However, we need to check that all
+ // embedded messages are initialized.
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ const Extension& extension = iter->second;
+ if (extension.descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (extension.descriptor->is_repeated()) {
+ for (int i = 0; i < extension.repeated_message_value->size(); i++) {
+ if (!extension.repeated_message_value->Get(i).IsInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (!extension.is_cleared) {
+ if (!extension.message_value->IsInitialized()) return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
+ Message::Reflection* reflection) {
+ const FieldDescriptor* field =
+ FindKnownExtensionByNumber(WireFormat::GetTagFieldNumber(tag));
+
+ return WireFormat::ParseAndMergeField(tag, field, reflection, input);
+}
+
+bool ExtensionSet::SerializeWithCachedSizes(
+ int start_field_number, int end_field_number,
+ const Message::Reflection* reflection,
+ io::CodedOutputStream* output) const {
+ map<int, Extension>::const_iterator iter;
+ for (iter = extensions_.lower_bound(start_field_number);
+ iter != extensions_.end() && iter->first < end_field_number;
+ ++iter) {
+ if (!iter->second.SerializeFieldWithCachedSizes(reflection, output)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int ExtensionSet::ByteSize(const Message::Reflection* reflection) const {
+ int total_size = 0;
+
+ for (map<int, Extension>::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ total_size += iter->second.ByteSize(reflection);
+ }
+
+ return total_size;
+}
+
+// ===================================================================
+// Methods of ExtensionSet::Extension
+
+void ExtensionSet::Extension::Clear() {
+ if (descriptor->is_repeated()) {
+ switch (descriptor->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ repeated_##LOWERCASE##_value->Clear(); \
+ 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( ENUM, enum);
+ HANDLE_TYPE( STRING, string);
+ HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+ }
+ } else {
+ if (!is_cleared) {
+ switch (descriptor->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ LOWERCASE##_value = descriptor->default_value_##LOWERCASE(); \
+ 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);
+#undef HANDLE_TYPE
+ case FieldDescriptor::CPPTYPE_ENUM:
+ enum_value = descriptor->default_value_enum()->number();
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (descriptor->has_default_value()) {
+ string_value->assign(descriptor->default_value_string());
+ } else {
+ string_value->clear();
+ }
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ message_value->Clear();
+ break;
+ }
+
+ is_cleared = true;
+ }
+ }
+}
+
+bool ExtensionSet::Extension::SerializeFieldWithCachedSizes(
+ const Message::Reflection* reflection,
+ io::CodedOutputStream* output) const {
+ if (descriptor->is_repeated() || !is_cleared) {
+ return WireFormat::SerializeFieldWithCachedSizes(
+ descriptor, reflection, output);
+ } else {
+ return true;
+ }
+}
+
+int64 ExtensionSet::Extension::ByteSize(
+ const Message::Reflection* reflection) const {
+ if (descriptor->is_repeated() || !is_cleared) {
+ return WireFormat::FieldByteSize(descriptor, reflection);
+ } else {
+ // Cleared, non-repeated field.
+ return 0;
+ }
+}
+
+int ExtensionSet::Extension::GetSize() const {
+ GOOGLE_DCHECK(descriptor->is_repeated());
+ switch (descriptor->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ return repeated_##LOWERCASE##_value->size()
+
+ 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( ENUM, enum);
+ HANDLE_TYPE( STRING, string);
+ HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return 0;
+}
+
+void ExtensionSet::Extension::Free() {
+ if (descriptor->is_repeated()) {
+ switch (descriptor->cpp_type()) {
+#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
+ case FieldDescriptor::CPPTYPE_##UPPERCASE: \
+ delete repeated_##LOWERCASE##_value; \
+ 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( ENUM, enum);
+ HANDLE_TYPE( STRING, string);
+ HANDLE_TYPE(MESSAGE, message);
+#undef HANDLE_TYPE
+ }
+ } else {
+ switch (descriptor->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_STRING:
+ delete string_value;
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ delete message_value;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google