From d37d46dfbcedadeb439ad0367f8afcf8867dca43 Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Sat, 25 Apr 2009 02:53:47 +0000 Subject: Integrate recent changes from Google-internal code tree. See CHANGES.txt for details. --- src/google/protobuf/extension_set.cc | 988 +++++++++++++++++++++++++---------- 1 file changed, 710 insertions(+), 278 deletions(-) (limited to 'src/google/protobuf/extension_set.cc') diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index f431cedc..0e618902 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -33,68 +33,108 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include +#include +#include #include #include #include #include #include -#include +#include +#include #include #include +#include namespace google { namespace protobuf { namespace internal { -// ------------------------------------------------------------------- -// Lookup functions - -const FieldDescriptor* -ExtensionSet::FindKnownExtensionOrDie(int number) const { - const FieldDescriptor* descriptor = - descriptor_pool_->FindExtensionByNumber(*extendee_, 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."; - } +namespace { + +inline FieldDescriptor::Type real_type(FieldType type) { + GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE); + return static_cast(type); +} + +inline FieldDescriptor::CppType cpp_type(FieldType type) { + return FieldDescriptor::TypeToCppType(real_type(type)); +} + +// Registry stuff. +struct ExtensionInfo { + inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed) + : type(type), is_repeated(is_repeated), is_packed(is_packed) {} + + FieldType type; + bool is_repeated; + bool is_packed; + + union { + ExtensionSet::EnumValidityFunc* enum_is_valid; + const Message* message_prototype; + }; +}; + +typedef hash_map, ExtensionInfo> ExtensionRegistry; +ExtensionRegistry* registry_ = NULL; + +// This function is only called at startup, so there is no need for thread- +// safety. +void Register(const Message* containing_type, int number, ExtensionInfo info) { + if (registry_ == NULL) registry_ = new ExtensionRegistry; + + if (!InsertIfNotPresent(registry_, make_pair(containing_type, number), + info)) { + GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \"" + << containing_type->GetDescriptor()->full_name() + << "\", field number " << number << "."; } - return descriptor; } -const Message* -ExtensionSet::GetPrototype(const Descriptor* message_type) const { - return message_factory_->GetPrototype(message_type); +const ExtensionInfo* FindRegisteredExtension( + const Message* containing_type, int number) { + return (registry_ == NULL) ? NULL : + FindOrNull(*registry_, make_pair(containing_type, number)); +} + +} // namespace + +void ExtensionSet::RegisterExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed) { + GOOGLE_CHECK_NE(type, FieldDescriptor::TYPE_ENUM); + GOOGLE_CHECK_NE(type, FieldDescriptor::TYPE_MESSAGE); + GOOGLE_CHECK_NE(type, FieldDescriptor::TYPE_GROUP); + ExtensionInfo info(type, is_repeated, is_packed); + Register(containing_type, number, info); +} + +void ExtensionSet::RegisterEnumExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + EnumValidityFunc* is_valid) { + GOOGLE_CHECK_EQ(type, FieldDescriptor::TYPE_ENUM); + ExtensionInfo info(type, is_repeated, is_packed); + info.enum_is_valid = is_valid; + Register(containing_type, number, info); +} + +void ExtensionSet::RegisterMessageExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + const Message* prototype) { + GOOGLE_CHECK(type == FieldDescriptor::TYPE_MESSAGE || + type == FieldDescriptor::TYPE_GROUP); + ExtensionInfo info(type, is_repeated, is_packed); + info.message_prototype = prototype; + Register(containing_type, number, info); } // =================================================================== // Constructors and basic methods. -ExtensionSet::ExtensionSet(const Descriptor* const* extendee, - const DescriptorPool* pool, - MessageFactory* factory) - : extendee_(extendee), - descriptor_pool_(pool), - message_factory_(factory) { -} +ExtensionSet::ExtensionSet() {} ExtensionSet::~ExtensionSet() { for (map::iterator iter = extensions_.begin(); @@ -103,18 +143,21 @@ ExtensionSet::~ExtensionSet() { } } -void ExtensionSet::AppendToList(vector* output) const { +void ExtensionSet::AppendToList(const Descriptor* containing_type, + const DescriptorPool* pool, + vector* output) const { for (map::const_iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { bool has = false; - if (iter->second.descriptor->is_repeated()) { + if (iter->second.is_repeated) { has = iter->second.GetSize() > 0; } else { has = !iter->second.is_cleared; } if (has) { - output->push_back(iter->second.descriptor); + output->push_back( + pool->FindExtensionByNumber(containing_type, iter->first)); } } } @@ -122,7 +165,7 @@ void ExtensionSet::AppendToList(vector* output) const { 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()); + GOOGLE_DCHECK(!iter->second.is_repeated); return !iter->second.is_cleared; } @@ -141,47 +184,46 @@ void ExtensionSet::ClearExtension(int number) { // =================================================================== // 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) +#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ + GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \ + : FieldDescriptor::LABEL_OPTIONAL, \ + FieldDescriptor::LABEL_##LABEL); \ + GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE) // ------------------------------------------------------------------- // Primitives #define PRIMITIVE_ACCESSORS(UPPERCASE, LOWERCASE, CAMELCASE) \ \ -LOWERCASE ExtensionSet::Get##CAMELCASE(int number) const { \ +LOWERCASE ExtensionSet::Get##CAMELCASE(int number, \ + LOWERCASE default_value) 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(); \ + if (iter == extensions_.end() || iter->second.is_cleared) { \ + return default_value; \ } else { \ - GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, UPPERCASE); \ + GOOGLE_DCHECK_TYPE(iter->second, 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(); \ +void ExtensionSet::Set##CAMELCASE(int number, FieldType type, \ + LOWERCASE value) { \ + Extension* extension; \ + if (MaybeNewExtension(number, &extension)) { \ + extension->type = type; \ + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_##UPPERCASE);\ + extension->is_repeated = false; \ } else { \ - GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, UPPERCASE); \ - extension->is_cleared = false; \ + GOOGLE_DCHECK_TYPE(*extension, 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); \ + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE); \ return iter->second.repeated_##LOWERCASE##_value->Get(index); \ } \ \ @@ -189,20 +231,22 @@ 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); \ + GOOGLE_DCHECK_TYPE(iter->second, 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); \ +void ExtensionSet::Add##CAMELCASE(int number, FieldType type, \ + bool packed, LOWERCASE value) { \ + Extension* extension; \ + if (MaybeNewExtension(number, &extension)) { \ + extension->type = type; \ + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_##UPPERCASE);\ + extension->is_repeated = true; \ + extension->is_packed = packed; \ extension->repeated_##LOWERCASE##_value = new RepeatedField(); \ - extension->descriptor = descriptor; \ } else { \ - GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, UPPERCASE); \ + GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE); \ + GOOGLE_DCHECK_EQ(extension->is_packed, packed); \ } \ extension->repeated_##LOWERCASE##_value->Add(value); \ } @@ -220,121 +264,113 @@ PRIMITIVE_ACCESSORS( BOOL, bool, Bool) // ------------------------------------------------------------------- // Enums -int ExtensionSet::GetEnum(int number) const { +int ExtensionSet::GetEnum(int number, int default_value) const { map::const_iterator iter = extensions_.find(number); - if (iter == extensions_.end()) { + if (iter == extensions_.end() || iter->second.is_cleared) { // Not present. Return the default value. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, ENUM); - return descriptor->default_value_enum()->number(); + return default_value; } else { - GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, ENUM); + GOOGLE_DCHECK_TYPE(iter->second, 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(); +void ExtensionSet::SetEnum(int number, FieldType type, int value) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_ENUM); + extension->is_repeated = false; } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, ENUM); - extension->is_cleared = false; + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, ENUM); } - GOOGLE_DCHECK(extension->descriptor->enum_type()->FindValueByNumber(value) != NULL); + extension->is_cleared = false; 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); + GOOGLE_DCHECK_TYPE(iter->second, 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); + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM); 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); +void ExtensionSet::AddEnum(int number, FieldType type, + bool packed, int value) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_ENUM); + extension->is_repeated = true; + extension->is_packed = packed; extension->repeated_enum_value = new RepeatedField(); - extension->descriptor = descriptor; } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, ENUM); + GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM); + GOOGLE_DCHECK_EQ(extension->is_packed, packed); } - GOOGLE_DCHECK(extension->descriptor->enum_type()->FindValueByNumber(value) != NULL); extension->repeated_enum_value->Add(value); } // ------------------------------------------------------------------- // Strings -const string& ExtensionSet::GetString(int number) const { +const string& ExtensionSet::GetString(int number, + const string& default_value) const { map::const_iterator iter = extensions_.find(number); - if (iter == extensions_.end()) { + if (iter == extensions_.end() || iter->second.is_cleared) { // Not present. Return the default value. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, STRING); - return descriptor->default_value_string(); + return default_value; } else { - GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, STRING); + GOOGLE_DCHECK_TYPE(iter->second, 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; +string* ExtensionSet::MutableString(int number, FieldType type) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_STRING); + extension->is_repeated = false; extension->string_value = new string; } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, STRING); - extension->is_cleared = false; + GOOGLE_DCHECK_TYPE(*extension, 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); + GOOGLE_DCHECK_TYPE(iter->second, 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); + GOOGLE_DCHECK_TYPE(iter->second, 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); +string* ExtensionSet::AddString(int number, FieldType type) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_STRING); + extension->is_repeated = true; + extension->is_packed = false; extension->repeated_string_value = new RepeatedPtrField(); - extension->descriptor = descriptor; } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, STRING); + GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING); } return extension->repeated_string_value->Add(); } @@ -342,59 +378,108 @@ string* ExtensionSet::AddString(int number) { // ------------------------------------------------------------------- // Messages -const Message& ExtensionSet::GetMessage(int number) const { +const Message& ExtensionSet::GetMessage(int number, + const Message& default_value) 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()); + return default_value; + } else { + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); + return *iter->second.message_value; + } +} + +const Message& ExtensionSet::GetMessage(int number, + const Descriptor* message_type, + MessageFactory* factory) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end() || iter->second.is_cleared) { + // Not present. Return the default value. + return *factory->GetPrototype(message_type); } else { - GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, MESSAGE); + GOOGLE_DCHECK_TYPE(iter->second, 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(); +Message* ExtensionSet::MutableMessage(int number, FieldType type, + const Message& prototype) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->message_value = prototype.New(); } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, MESSAGE); - extension->is_cleared = false; + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); } + extension->is_cleared = false; + return extension->message_value; +} + +Message* ExtensionSet::MutableMessage(int number, FieldType type, + const Descriptor* message_type, + MessageFactory* factory) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->is_packed = false; + const Message* prototype = factory->GetPrototype(message_type); + GOOGLE_CHECK(prototype != NULL); + extension->message_value = prototype->New(); + } else { + GOOGLE_DCHECK_TYPE(*extension, 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); + GOOGLE_DCHECK_TYPE(iter->second, 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); + GOOGLE_DCHECK_TYPE(iter->second, 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); +Message* ExtensionSet::AddMessage(int number, FieldType type, + const Message& prototype) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = true; + extension->repeated_message_value = + new RepeatedPtrField(&prototype); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); + } + return extension->repeated_message_value->Add(); +} + +Message* ExtensionSet::AddMessage(int number, FieldType type, + const Descriptor* message_type, + MessageFactory* factory) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = true; + const Message* prototype = factory->GetPrototype(message_type); + GOOGLE_CHECK(prototype != NULL); extension->repeated_message_value = - new RepeatedPtrField(GetPrototype(descriptor->message_type())); - extension->descriptor = descriptor; + new RepeatedPtrField(prototype); } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, MESSAGE); + GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } return extension->repeated_message_value->Add(); } @@ -410,59 +495,32 @@ void ExtensionSet::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()) { + const Extension& other_extension = iter->second; + + if (other_extension.is_repeated) { + Extension* extension; + bool is_new = MaybeNewExtension(iter->first, &extension); + if (is_new) { + // Extension did not already exist in set. + extension->type = other_extension.type; + extension->is_repeated = true; + } else { + GOOGLE_DCHECK_EQ(extension->type, other_extension.type); + GOOGLE_DCHECK(extension->is_repeated); + } + + switch (cpp_type(other_extension.type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ - if (extension->descriptor == NULL) { \ - extension->descriptor = field; \ + if (is_new) { \ extension->repeated_##LOWERCASE##_value = \ new REPEATED_TYPE; \ } \ - MergeRepeatedFields( \ - *other_extension.repeated_##LOWERCASE##_value, \ - extension->repeated_##LOWERCASE##_value); \ + extension->repeated_##LOWERCASE##_value->MergeFrom( \ + *other_extension.repeated_##LOWERCASE##_value); \ break; HANDLE_TYPE( INT32, int32, RepeatedField < int32>); @@ -477,22 +535,21 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_MESSAGE: - if (extension->descriptor == NULL) { - extension->descriptor = field; + if (is_new) { extension->repeated_message_value = new RepeatedPtrField( other_extension.repeated_message_value->prototype()); } - MergeRepeatedFields( - *other_extension.repeated_message_value, - extension->repeated_message_value); + extension->repeated_message_value->MergeFrom( + *other_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); \ + if (!other_extension.is_cleared) { + switch (cpp_type(other_extension.type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE: \ + Set##CAMELCASE(iter->first, other_extension.type, \ + other_extension.LOWERCASE##_value); \ break; HANDLE_TYPE( INT32, int32, Int32); @@ -505,10 +562,13 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { HANDLE_TYPE( ENUM, enum, Enum); #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - SetString(iter->first, *iter->second.string_value); + SetString(iter->first, other_extension.type, + *other_extension.string_value); break; case FieldDescriptor::CPPTYPE_MESSAGE: - MutableMessage(iter->first)->MergeFrom(*iter->second.message_value); + MutableMessage(iter->first, other_extension.type, + *other_extension.message_value) + ->MergeFrom(*other_extension.message_value); break; } } @@ -518,19 +578,16 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { void ExtensionSet::Swap(ExtensionSet* x) { extensions_.swap(x->extensions_); - std::swap(extendee_, x->extendee_); - std::swap(descriptor_pool_, x->descriptor_pool_); - std::swap(message_factory_, x->message_factory_); } bool ExtensionSet::IsInitialized() const { - // Extensions are never requried. However, we need to check that all + // Extensions are never required. 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()) { + if (cpp_type(extension.type) == FieldDescriptor::CPPTYPE_MESSAGE) { + if (extension.is_repeated) { for (int i = 0; i < extension.repeated_message_value->size(); i++) { if (!extension.repeated_message_value->Get(i).IsInitialized()) { return false; @@ -548,36 +605,201 @@ bool ExtensionSet::IsInitialized() const { } bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, - Message* message) { - const FieldDescriptor* field = - message->GetReflection() - ->FindKnownExtensionByNumber(WireFormat::GetTagFieldNumber(tag)); + const Message* containing_type, + UnknownFieldSet* unknown_fields) { + int number = WireFormat::GetTagFieldNumber(tag); + WireFormat::WireType wire_type = WireFormat::GetTagWireType(tag); + + const ExtensionInfo* extension = + FindRegisteredExtension(containing_type, number); + + bool is_unknown; + if (extension == NULL) { + is_unknown = true; + } else if (extension->is_packed) { + is_unknown = (wire_type != WireFormat::WIRETYPE_LENGTH_DELIMITED); + } else { + WireFormat::WireType expected_wire_type = + WireFormat::WireTypeForFieldType(real_type(extension->type)); + is_unknown = (wire_type != expected_wire_type); + } + + if (is_unknown) { + WireFormat::SkipField(input, tag, unknown_fields); + } else if (extension->is_packed) { + uint32 size; + if (!input->ReadVarint32(&size)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(size); + + switch (extension->type) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + while (input->BytesUntilLimit() > 0) { \ + CPP_LOWERCASE value; \ + if (!WireFormat::Read##CAMELCASE(input, &value)) return false; \ + Add##CPP_CAMELCASE(number, FieldDescriptor::TYPE_##UPPERCASE, \ + true, value); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, Int32, int32); + HANDLE_TYPE( INT64, Int64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, Int32, int32); + HANDLE_TYPE( SINT64, SInt64, Int64, int64); + HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, Float, float); + HANDLE_TYPE( DOUBLE, Double, Double, double); + HANDLE_TYPE( BOOL, Bool, Bool, bool); +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: + while (input->BytesUntilLimit() > 0) { + int value; + if (!WireFormat::ReadEnum(input, &value)) return false; + if (extension->enum_is_valid(value)) { + AddEnum(number, FieldDescriptor::TYPE_ENUM, true, value); + } + } + break; + + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + + input->PopLimit(limit); + } else { + switch (extension->type) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: { \ + CPP_LOWERCASE value; \ + if (!WireFormat::Read##CAMELCASE(input, &value)) return false; \ + if (extension->is_repeated) { \ + Add##CPP_CAMELCASE(number, FieldDescriptor::TYPE_##UPPERCASE, \ + false, value); \ + } else { \ + Set##CPP_CAMELCASE(number, FieldDescriptor::TYPE_##UPPERCASE, value);\ + } \ + } break + + HANDLE_TYPE( INT32, Int32, Int32, int32); + HANDLE_TYPE( INT64, Int64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, Int32, int32); + HANDLE_TYPE( SINT64, SInt64, Int64, int64); + HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, Float, float); + HANDLE_TYPE( DOUBLE, Double, Double, double); + HANDLE_TYPE( BOOL, Bool, Bool, bool); +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: { + int value; + if (!WireFormat::ReadEnum(input, &value)) return false; + + if (!extension->enum_is_valid(value)) { + // Invalid value. Treat as unknown. + if (unknown_fields != NULL) { + unknown_fields->AddVarint(number, value); + } + } else if (extension->is_repeated) { + AddEnum(number, FieldDescriptor::TYPE_ENUM, false, value); + } else { + SetEnum(number, FieldDescriptor::TYPE_ENUM, value); + } + break; + } + + case FieldDescriptor::TYPE_STRING: { + string* value = extension->is_repeated ? + AddString(number, FieldDescriptor::TYPE_STRING) : + MutableString(number, FieldDescriptor::TYPE_STRING); + if (!WireFormat::ReadString(input, value)) return false; + break; + } - return WireFormat::ParseAndMergeField(tag, field, message, input); + case FieldDescriptor::TYPE_BYTES: { + string* value = extension->is_repeated ? + AddString(number, FieldDescriptor::TYPE_STRING) : + MutableString(number, FieldDescriptor::TYPE_STRING); + if (!WireFormat::ReadBytes(input, value)) return false; + break; + } + + case FieldDescriptor::TYPE_GROUP: { + Message* value = extension->is_repeated ? + AddMessage(number, FieldDescriptor::TYPE_GROUP, + *extension->message_prototype) : + MutableMessage(number, FieldDescriptor::TYPE_GROUP, + *extension->message_prototype); + if (!WireFormat::ReadGroup(number, input, value)) return false; + break; + } + + case FieldDescriptor::TYPE_MESSAGE: { + Message* value = extension->is_repeated ? + AddMessage(number, FieldDescriptor::TYPE_MESSAGE, + *extension->message_prototype) : + MutableMessage(number, FieldDescriptor::TYPE_MESSAGE, + *extension->message_prototype); + if (!WireFormat::ReadMessage(input, value)) return false; + break; + } + } + } + + return true; } -bool ExtensionSet::SerializeWithCachedSizes( +void ExtensionSet::SerializeWithCachedSizes( int start_field_number, int end_field_number, - const Message& message, 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(message, output)) { - return false; - } + iter->second.SerializeFieldWithCachedSizes(iter->first, output); } +} - return true; +uint8* ExtensionSet::SerializeWithCachedSizesToArray( + int start_field_number, int end_field_number, + uint8* target) const { + // For now, just create an array output stream around the target and dispatch + // to SerializeWithCachedSizes(). Give the array output stream kint32max + // bytes; we will certainly write less than that. It is up to the caller to + // ensure that the buffer has sufficient space. + int written_bytes; + { + io::ArrayOutputStream array_stream(target, kint32max); + io::CodedOutputStream output_stream(&array_stream); + SerializeWithCachedSizes(start_field_number, + end_field_number, + &output_stream); + written_bytes = output_stream.ByteCount(); + GOOGLE_DCHECK(!output_stream.HadError()); + } + return target + written_bytes; } -int ExtensionSet::ByteSize(const Message& message) const { +int ExtensionSet::ByteSize() const { int total_size = 0; for (map::const_iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { - total_size += iter->second.ByteSize(message); + total_size += iter->second.ByteSize(iter->first); } return total_size; @@ -595,12 +817,19 @@ int ExtensionSet::SpaceUsedExcludingSelf() const { return total_size; } +bool ExtensionSet::MaybeNewExtension(int number, Extension** result) { + pair::iterator, bool> insert_result = + extensions_.insert(make_pair(number, Extension())); + *result = &insert_result.first->second; + return insert_result.second; +} + // =================================================================== // Methods of ExtensionSet::Extension void ExtensionSet::Extension::Clear() { - if (descriptor->is_repeated()) { - switch (descriptor->cpp_type()) { + if (is_repeated) { + switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ repeated_##LOWERCASE##_value->Clear(); \ @@ -620,33 +849,18 @@ void ExtensionSet::Extension::Clear() { } } 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; + switch (cpp_type(type)) { case FieldDescriptor::CPPTYPE_STRING: - if (descriptor->has_default_value()) { - string_value->assign(descriptor->default_value_string()); - } else { - string_value->clear(); - } + string_value->clear(); break; case FieldDescriptor::CPPTYPE_MESSAGE: message_value->Clear(); break; + default: + // No need to do anything. Get*() will return the default value + // as long as is_cleared is true and Set*() will overwrite the + // previous value. + break; } is_cleared = true; @@ -654,29 +868,247 @@ void ExtensionSet::Extension::Clear() { } } -bool ExtensionSet::Extension::SerializeFieldWithCachedSizes( - const Message& message, +void ExtensionSet::Extension::SerializeFieldWithCachedSizes( + int number, io::CodedOutputStream* output) const { - if (descriptor->is_repeated() || !is_cleared) { - return WireFormat::SerializeFieldWithCachedSizes( - descriptor, message, output); - } else { - return true; + if (is_repeated) { + if (is_packed) { + if (cached_size == 0) return; + + WireFormat::WriteTag(number, WireFormat::WIRETYPE_LENGTH_DELIMITED, + output); + output->WriteVarint32(cached_size); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + WireFormat::Write##CAMELCASE##NoTag( \ + repeated_##LOWERCASE##_value->Get(i), output); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + 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::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + } else { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + WireFormat::Write##CAMELCASE(number, \ + repeated_##LOWERCASE##_value->Get(i), output); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + WireFormat::Write##CAMELCASE(number, VALUE, output); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( FIXED32, Fixed32, uint32_value); + HANDLE_TYPE( FIXED64, Fixed64, uint64_value); + HANDLE_TYPE(SFIXED32, SFixed32, int32_value); + HANDLE_TYPE(SFIXED64, SFixed64, int64_value); + HANDLE_TYPE( FLOAT, Float, float_value); + HANDLE_TYPE( DOUBLE, Double, double_value); + HANDLE_TYPE( BOOL, Bool, bool_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + } } } -int64 ExtensionSet::Extension::ByteSize(const Message& message) const { - if (descriptor->is_repeated() || !is_cleared) { - return WireFormat::FieldByteSize(descriptor, message); - } else { - // Cleared, non-repeated field. - return 0; +int ExtensionSet::Extension::ByteSize(int number) const { + int result = 0; + + if (is_repeated) { + if (is_packed) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + result += WireFormat::CAMELCASE##Size( \ + repeated_##LOWERCASE##_value->Get(i)); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( ENUM, Enum, enum); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += WireFormat::k##CAMELCASE##Size * \ + repeated_##LOWERCASE##_value->size(); \ + break + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + + cached_size = result; + if (result > 0) { + result += io::CodedOutputStream::VarintSize32(result); + result += io::CodedOutputStream::VarintSize32( + WireFormat::MakeTag(number, WireFormat::WIRETYPE_LENGTH_DELIMITED)); + } + } else { + int tag_size = WireFormat::TagSize(number, real_type(type)); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += tag_size * repeated_##LOWERCASE##_value->size(); \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + result += WireFormat::CAMELCASE##Size( \ + repeated_##LOWERCASE##_value->Get(i)); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += (tag_size + WireFormat::k##CAMELCASE##Size) * \ + repeated_##LOWERCASE##_value->size(); \ + break + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + result += WireFormat::TagSize(number, real_type(type)); + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += WireFormat::CAMELCASE##Size(LOWERCASE); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += WireFormat::k##CAMELCASE##Size; \ + break + HANDLE_TYPE( FIXED32, Fixed32); + HANDLE_TYPE( FIXED64, Fixed64); + HANDLE_TYPE(SFIXED32, SFixed32); + HANDLE_TYPE(SFIXED64, SFixed64); + HANDLE_TYPE( FLOAT, Float); + HANDLE_TYPE( DOUBLE, Double); + HANDLE_TYPE( BOOL, Bool); +#undef HANDLE_TYPE + } } + + return result; } int ExtensionSet::Extension::GetSize() const { - GOOGLE_DCHECK(descriptor->is_repeated()); - switch (descriptor->cpp_type()) { + GOOGLE_DCHECK(is_repeated); + switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ return repeated_##LOWERCASE##_value->size() @@ -699,8 +1131,8 @@ int ExtensionSet::Extension::GetSize() const { } void ExtensionSet::Extension::Free() { - if (descriptor->is_repeated()) { - switch (descriptor->cpp_type()) { + if (is_repeated) { + switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ delete repeated_##LOWERCASE##_value; \ @@ -719,7 +1151,7 @@ void ExtensionSet::Extension::Free() { #undef HANDLE_TYPE } } else { - switch (descriptor->cpp_type()) { + switch (cpp_type(type)) { case FieldDescriptor::CPPTYPE_STRING: delete string_value; break; @@ -734,8 +1166,8 @@ void ExtensionSet::Extension::Free() { int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { int total_size = 0; - if (descriptor->is_repeated()) { - switch (descriptor->cpp_type()) { + if (is_repeated) { + switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ total_size += sizeof(*repeated_##LOWERCASE##_value) + \ @@ -754,7 +1186,7 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { HANDLE_TYPE(MESSAGE, message); } } else { - switch (descriptor->cpp_type()) { + switch (cpp_type(type)) { case FieldDescriptor::CPPTYPE_STRING: total_size += sizeof(*string_value) + StringSpaceUsedExcludingSelf(*string_value); -- cgit v1.2.3