// 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 #include #include #include #include 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::iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { iter->second.Free(); } } void ExtensionSet::AppendToList(vector* output) const { for (map::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::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::const_iterator iter = extensions_.find(number); if (iter == extensions_.end()) return false; return iter->second.GetSize(); } void ExtensionSet::ClearExtension(int number) { map::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::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::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::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(); \ 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::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::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::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(); 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::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::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::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(); 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::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::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::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(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::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 void MergeRepeatedFields(const RepeatedField& source, RepeatedField* destination) { destination->Reserve(destination->size() + source.size()); for (int i = 0; i < source.size(); i++) { destination->Add(source.Get(i)); } } void MergeRepeatedFields(const RepeatedPtrField& source, RepeatedPtrField* 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& source, RepeatedPtrField* 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::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( 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::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::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::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