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.h | 441 +++++++++++++++++++++++++----------- 1 file changed, 314 insertions(+), 127 deletions(-) (limited to 'src/google/protobuf/extension_set.h') diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index 9ad241f2..8e64b9bd 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -44,6 +44,7 @@ #include #include +#include #include namespace google { @@ -53,6 +54,7 @@ namespace protobuf { class DescriptorPool; // descriptor.h class Message; // message.h class MessageFactory; // message.h + class UnknownFieldSet; // unknown_field_set.h namespace io { class CodedInputStream; // coded_stream.h class CodedOutputStream; // coded_stream.h @@ -64,6 +66,12 @@ namespace protobuf { namespace protobuf { namespace internal { +// Used to store values of type FieldDescriptor::Type without having to +// #include descriptor.h. Also, ensures that we use only one byte to store +// these values, which is important to keep the layout of +// ExtensionSet::Extension small. +typedef uint8 FieldType; + // This is an internal helper class intended for use within the protocol buffer // library and generated classes. Clients should not use it directly. Instead, // use the generated accessors such as GetExtension() of the class being @@ -77,30 +85,42 @@ namespace internal { // off to the ExtensionSet for parsing. Etc. class LIBPROTOBUF_EXPORT ExtensionSet { public: - // Construct an ExtensionSet. - // extendee: Descriptor for the type being extended. We pass in a pointer - // to a pointer to the extendee to get around an initialization - // problem: when we create the ExtensionSet for a message type, - // its descriptor may not exist yet. But we know where that - // descriptor pointer will be placed, and by the time it's used - // by this ExtensionSet it will be fully initialized, so passing - // a pointer to that location works. Note that this problem - // will only occur for messages defined in descriptor.proto. - // pool: DescriptorPool to search for extension definitions. - // factory: MessageFactory used to construct implementations of messages - // for extensions with message type. This factory must be able - // to construct any message type found in "pool". - // All three objects remain property of the caller and must outlive the - // ExtensionSet. - ExtensionSet(const Descriptor* const* extendee, - const DescriptorPool* pool, - MessageFactory* factory); - + ExtensionSet(); ~ExtensionSet(); + // A function which, given an integer value, returns true if the number + // matches one of the defined values for the corresponding enum type. This + // is used with RegisterEnumExtension, below. + typedef bool EnumValidityFunc(int number); + + // These are called at startup by protocol-compiler-generated code to + // register known extensions. The registrations are used by ParseField() + // to look up extensions for parsed field numbers. Note that dynamic parsing + // does not use ParseField(); only protocol-compiler-generated parsing + // methods do. + static void RegisterExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed); + static void RegisterEnumExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + EnumValidityFunc* is_valid); + static void RegisterMessageExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + const Message* prototype); + + // ================================================================= + // Add all fields which are currently present to the given vector. This - // is useful to implement Reflection::ListFields(). - void AppendToList(vector* output) const; + // is useful to implement Reflection::ListFields(). The FieldDescriptors + // are looked up by number from the given pool. + // + // TODO(kenton): Looking up each field by number is somewhat unfortunate. + // Is there a better way? + void AppendToList(const Descriptor* containing_type, + const DescriptorPool* pool, + vector* output) const; // ================================================================= // Accessors @@ -138,28 +158,34 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // singular fields ------------------------------------------------- - int32 GetInt32 (int number) const; - int64 GetInt64 (int number) const; - uint32 GetUInt32(int number) const; - uint64 GetUInt64(int number) const; - float GetFloat (int number) const; - double GetDouble(int number) const; - bool GetBool (int number) const; - int GetEnum (int number) const; - const string & GetString (int number) const; - const Message& GetMessage(int number) const; - - void SetInt32 (int number, int32 value); - void SetInt64 (int number, int64 value); - void SetUInt32(int number, uint32 value); - void SetUInt64(int number, uint64 value); - void SetFloat (int number, float value); - void SetDouble(int number, double value); - void SetBool (int number, bool value); - void SetEnum (int number, int value); - void SetString(int number, const string& value); - string * MutableString (int number); - Message* MutableMessage(int number); + int32 GetInt32 (int number, int32 default_value) const; + int64 GetInt64 (int number, int64 default_value) const; + uint32 GetUInt32(int number, uint32 default_value) const; + uint64 GetUInt64(int number, uint64 default_value) const; + float GetFloat (int number, float default_value) const; + double GetDouble(int number, double default_value) const; + bool GetBool (int number, bool default_value) const; + int GetEnum (int number, int default_value) const; + const string & GetString (int number, const string& default_value) const; + const Message& GetMessage(int number, const Message& default_value) const; + const Message& GetMessage(int number, const Descriptor* message_type, + MessageFactory* factory) const; + + void SetInt32 (int number, FieldType type, int32 value); + void SetInt64 (int number, FieldType type, int64 value); + void SetUInt32(int number, FieldType type, uint32 value); + void SetUInt64(int number, FieldType type, uint64 value); + void SetFloat (int number, FieldType type, float value); + void SetDouble(int number, FieldType type, double value); + void SetBool (int number, FieldType type, bool value); + void SetEnum (int number, FieldType type, int value); + void SetString(int number, FieldType type, const string& value); + string * MutableString (int number, FieldType type); + Message* MutableMessage(int number, FieldType type, + const Message& prototype); + Message* MutableMessage(int number, FieldType type, + const Descriptor* message_type, + MessageFactory* factory); // repeated fields ------------------------------------------------- @@ -186,17 +212,21 @@ class LIBPROTOBUF_EXPORT ExtensionSet { string * MutableRepeatedString (int number, int index); Message* MutableRepeatedMessage(int number, int index); - void AddInt32 (int number, int32 value); - void AddInt64 (int number, int64 value); - void AddUInt32(int number, uint32 value); - void AddUInt64(int number, uint64 value); - void AddFloat (int number, float value); - void AddDouble(int number, double value); - void AddBool (int number, bool value); - void AddEnum (int number, int value); - void AddString(int number, const string& value); - string * AddString (int number); - Message* AddMessage(int number); + void AddInt32 (int number, FieldType type, bool packed, int32 value); + void AddInt64 (int number, FieldType type, bool packed, int64 value); + void AddUInt32(int number, FieldType type, bool packed, uint32 value); + void AddUInt64(int number, FieldType type, bool packed, uint64 value); + void AddFloat (int number, FieldType type, bool packed, float value); + void AddDouble(int number, FieldType type, bool packed, double value); + void AddBool (int number, FieldType type, bool packed, bool value); + void AddEnum (int number, FieldType type, bool packed, int value); + void AddString(int number, FieldType type, const string& value); + string * AddString (int number, FieldType type); + Message* AddMessage(int number, FieldType type, + const Message& prototype); + Message* AddMessage(int number, FieldType type, + const Descriptor* message_type, + MessageFactory* factory); // ----------------------------------------------------------------- // TODO(kenton): Hardcore memory management accessors @@ -212,40 +242,41 @@ class LIBPROTOBUF_EXPORT ExtensionSet { void Swap(ExtensionSet* other); bool IsInitialized() const; - // These parsing and serialization functions all want a pointer to the - // message object because they hand off the actual work to WireFormat, - // which works in terms of a reflection interface. Yes, this means there - // are some redundant virtual function calls that end up being made, but - // it probably doesn't matter much in practice, and the alternative would - // involve reproducing a lot of WireFormat's functionality. - // Parses a single extension from the input. The input should start out - // positioned immediately after the tag. - bool ParseField(uint32 tag, io::CodedInputStream* input, Message* message); + // positioned immediately after the tag. |containing_type| is the default + // instance for the containing message; it is used only to look up the + // extension by number. See RegisterExtension(), above. Unlike the other + // methods of ExtensionSet, this only works for generated message types -- + // it looks up extensions registered using RegisterExtension(). + bool ParseField(uint32 tag, io::CodedInputStream* input, + const Message* containing_type, + UnknownFieldSet* unknown_fields); // Write all extension fields with field numbers in the range // [start_field_number, end_field_number) // to the output stream, using the cached sizes computed when ByteSize() was // last called. Note that the range bounds are inclusive-exclusive. - bool SerializeWithCachedSizes(int start_field_number, + void SerializeWithCachedSizes(int start_field_number, int end_field_number, - const Message& message, io::CodedOutputStream* output) const; + // Same as SerializeWithCachedSizes, but without any bounds checking. + // The caller must ensure that target has sufficient capacity for the + // serialized extensions. + // + // Returns a pointer past the last written byte. + uint8* SerializeWithCachedSizesToArray(int start_field_number, + int end_field_number, + uint8* target) const; + // Returns the total serialized size of all the extensions. - int ByteSize(const Message& message) const; + int ByteSize() const; // Returns (an estimate of) the total number of bytes used for storing the // extensions in memory, excluding sizeof(*this). int SpaceUsedExcludingSelf() const; private: - // Like FindKnownExtension(), but GOOGLE_CHECK-fail if not found. - const FieldDescriptor* FindKnownExtensionOrDie(int number) const; - - // Get the prototype for the message. - const Message* GetPrototype(const Descriptor* message_type) const; - struct Extension { union { int32 int32_value; @@ -271,7 +302,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet { RepeatedPtrField* repeated_message_value; }; - const FieldDescriptor* descriptor; + FieldType type; + bool is_repeated; // For singular types, indicates if the extension is "cleared". This // happens when an extension is set and then later cleared by the caller. @@ -281,19 +313,29 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // simply becomes zero when cleared. bool is_cleared; - Extension(): descriptor(NULL), is_cleared(false) {} + // For repeated types, this indicates if the [packed=true] option is set. + bool is_packed; + + // For packed fields, the size of the packed data is recorded here when + // ByteSize() is called then used during serialization. + // TODO(kenton): Use atomic when C++ supports it. + mutable int cached_size; // Some helper methods for operations on a single Extension. - bool SerializeFieldWithCachedSizes( - const Message& message, + void SerializeFieldWithCachedSizes( + int number, io::CodedOutputStream* output) const; - int64 ByteSize(const Message& message) const; + int ByteSize(int number) const; void Clear(); int GetSize() const; void Free(); int SpaceUsedExcludingSelf() const; }; + // Gets the extension with the given number, creating it if it does not + // already exist. Returns true if the extension did not already exist. + bool MaybeNewExtension(int number, Extension** result); + // The Extension struct is small enough to be passed by value, so we use it // directly as the value type in the map rather than use pointers. We use // a map rather than hash_map here because we expect most ExtensionSets will @@ -301,30 +343,26 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // for 100 elements or more. Also, we want AppendToList() to order fields // by field number. map extensions_; - const Descriptor* const* extendee_; - const DescriptorPool* descriptor_pool_; - MessageFactory* message_factory_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet); }; // These are just for convenience... -inline void ExtensionSet::SetString(int number, const string& value) { - MutableString(number)->assign(value); +inline void ExtensionSet::SetString(int number, FieldType type, + const string& value) { + MutableString(number, type)->assign(value); } inline void ExtensionSet::SetRepeatedString(int number, int index, const string& value) { MutableRepeatedString(number, index)->assign(value); } -inline void ExtensionSet::AddString(int number, const string& value) { - AddString(number)->assign(value); +inline void ExtensionSet::AddString(int number, FieldType type, + const string& value) { + AddString(number, type)->assign(value); } // =================================================================== -// Implementation details -// -// DO NOT DEPEND ON ANYTHING BELOW THIS POINT. This is for use from -// generated code only. +// Glue for generated extension accessors // ------------------------------------------------------------------- // Template magic @@ -377,8 +415,10 @@ class PrimitiveTypeTraits { public: typedef Type ConstType; - static inline ConstType Get(int number, const ExtensionSet& set); - static inline void Set(int number, ConstType value, ExtensionSet* set); + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value); + static inline void Set(int number, FieldType field_type, + ConstType value, ExtensionSet* set); }; template @@ -388,17 +428,18 @@ class RepeatedPrimitiveTypeTraits { static inline Type Get(int number, const ExtensionSet& set, int index); static inline void Set(int number, int index, Type value, ExtensionSet* set); - static inline void Add(int number, Type value, ExtensionSet* set); + static inline void Add(int number, FieldType field_type, + bool is_packed, Type value, ExtensionSet* set); }; #define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \ template<> inline TYPE PrimitiveTypeTraits::Get( \ - int number, const ExtensionSet& set) { \ - return set.Get##METHOD(number); \ + int number, const ExtensionSet& set, TYPE default_value) { \ + return set.Get##METHOD(number, default_value); \ } \ template<> inline void PrimitiveTypeTraits::Set( \ - int number, ConstType value, ExtensionSet* set) { \ - set->Set##METHOD(number, value); \ + int number, FieldType field_type, TYPE value, ExtensionSet* set) { \ + set->Set##METHOD(number, field_type, value); \ } \ \ template<> inline TYPE RepeatedPrimitiveTypeTraits::Get( \ @@ -406,12 +447,13 @@ template<> inline TYPE RepeatedPrimitiveTypeTraits::Get( \ return set.GetRepeated##METHOD(number, index); \ } \ template<> inline void RepeatedPrimitiveTypeTraits::Set( \ - int number, int index, ConstType value, ExtensionSet* set) { \ + int number, int index, TYPE value, ExtensionSet* set) { \ set->SetRepeated##METHOD(number, index, value); \ } \ template<> inline void RepeatedPrimitiveTypeTraits::Add( \ - int number, ConstType value, ExtensionSet* set) { \ - set->Add##METHOD(number, value); \ + int number, FieldType field_type, bool is_packed, \ + TYPE value, ExtensionSet* set) { \ + set->Add##METHOD(number, field_type, is_packed, value); \ } PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32) @@ -433,14 +475,17 @@ class LIBPROTOBUF_EXPORT StringTypeTraits { typedef const string& ConstType; typedef string* MutableType; - static inline const string& Get(int number, const ExtensionSet& set) { - return set.GetString(number); + static inline const string& Get(int number, const ExtensionSet& set, + ConstType default_value) { + return set.GetString(number, default_value); } - static inline void Set(int number, const string& value, ExtensionSet* set) { - set->SetString(number, value); + static inline void Set(int number, FieldType field_type, + const string& value, ExtensionSet* set) { + set->SetString(number, field_type, value); } - static inline string* Mutable(int number, ExtensionSet* set) { - return set->MutableString(number); + static inline string* Mutable(int number, FieldType field_type, + ExtensionSet* set) { + return set->MutableString(number, field_type); } }; @@ -460,11 +505,14 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { static inline string* Mutable(int number, int index, ExtensionSet* set) { return set->MutableRepeatedString(number, index); } - static inline void Add(int number, const string& value, ExtensionSet* set) { - set->AddString(number, value); + static inline void Add(int number, FieldType field_type, + bool is_packed, const string& value, + ExtensionSet* set) { + set->AddString(number, field_type, value); } - static inline string* Add(int number, ExtensionSet* set) { - return set->AddString(number); + static inline string* Add(int number, FieldType field_type, + ExtensionSet* set) { + return set->AddString(number, field_type); } }; @@ -473,20 +521,23 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { // ExtensionSet represents enums using integers internally, so we have to // static_cast around. -template +template class EnumTypeTraits { public: typedef Type ConstType; - static inline ConstType Get(int number, const ExtensionSet& set) { - return static_cast(set.GetEnum(number)); + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value) { + return static_cast(set.GetEnum(number, default_value)); } - static inline void Set(int number, ConstType value, ExtensionSet* set) { - set->SetEnum(number, value); + static inline void Set(int number, FieldType field_type, + ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->SetEnum(number, field_type, value); } }; -template +template class RepeatedEnumTypeTraits { public: typedef Type ConstType; @@ -496,10 +547,13 @@ class RepeatedEnumTypeTraits { } static inline void Set(int number, int index, ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); set->SetRepeatedEnum(number, index, value); } - static inline void Add(int number, ConstType value, ExtensionSet* set) { - set->AddEnum(number, value); + static inline void Add(int number, FieldType field_type, + bool is_packed, ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->AddEnum(number, field_type, is_packed, value); } }; @@ -513,13 +567,17 @@ template class MessageTypeTraits { public: typedef const Type& ConstType; - typedef Type* MutableType; + typedef Type* MutableType; - static inline ConstType Get(int number, const ExtensionSet& set) { - return static_cast(set.GetMessage(number)); + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value) { + return static_cast( + set.GetMessage(number, default_value)); } - static inline MutableType Mutable(int number, ExtensionSet* set) { - return static_cast(set->MutableMessage(number)); + static inline MutableType Mutable(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast( + set->MutableMessage(number, field_type, Type::default_instance())); } }; @@ -535,8 +593,10 @@ class RepeatedMessageTypeTraits { static inline MutableType Mutable(int number, int index, ExtensionSet* set) { return static_cast(set->MutableRepeatedMessage(number, index)); } - static inline MutableType Add(int number, ExtensionSet* set) { - return static_cast(set->AddMessage(number)); + static inline MutableType Add(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast( + set->AddMessage(number, field_type, Type::default_instance())); } }; @@ -546,7 +606,7 @@ class RepeatedMessageTypeTraits { // This is the type of actual extension objects. E.g. if you have: // extends Foo with optional int32 bar = 1234; // then "bar" will be defined in C++ as: -// ExtensionIdentifier> bar(1234); +// ExtensionIdentifier, 1, false> bar(1234); // // Note that we could, in theory, supply the field number as a template // parameter, and thus make an instance of ExtensionIdentifier have no @@ -557,18 +617,145 @@ class RepeatedMessageTypeTraits { // but that would be bad because it would cause this extension to not be // registered at static initialization, and therefore using it would crash. -template -class ExtensionIdentifier { +template +class LIBPROTOBUF_EXPORT ExtensionIdentifier { public: typedef TypeTraitsType TypeTraits; typedef ExtendeeType Extendee; - ExtensionIdentifier(int number): number_(number) {} + ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value) + : number_(number), default_value_(default_value) {} inline int number() const { return number_; } + typename TypeTraits::ConstType default_value() const { + return default_value_; + } + private: const int number_; + const typename TypeTraits::ConstType default_value_; }; +// ------------------------------------------------------------------- +// Generated accessors + +// This macro should be expanded in the context of a generated type which +// has extensions. +// +// We use "_proto_TypeTraits" as a type name below because "TypeTraits" +// causes problems if the class has a nested message or enum type with that +// name and "_TypeTraits" is technically reserved for the C++ library since +// it starts with an underscore followed by a capital letter. +#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \ + /* Has, Size, Clear */ \ + template \ + inline bool HasExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _extensions_.Has(id.number()); \ + } \ + \ + template \ + inline void ClearExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + _extensions_.ClearExtension(id.number()); \ + } \ + \ + template \ + inline int ExtensionSize( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _extensions_.ExtensionSize(id.number()); \ + } \ + \ + /* Singular accessors */ \ + template \ + inline typename _proto_TypeTraits::ConstType GetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _proto_TypeTraits::Get(id.number(), _extensions_, \ + id.default_value()); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType MutableExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + return _proto_TypeTraits::Mutable(id.number(), field_type, &_extensions_);\ + } \ + \ + template \ + inline void SetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Set(id.number(), field_type, value, &_extensions_); \ + } \ + \ + /* Repeated accessors */ \ + template \ + inline typename _proto_TypeTraits::ConstType GetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index) const { \ + return _proto_TypeTraits::Get(id.number(), _extensions_, index); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType MutableExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index) { \ + return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \ + } \ + \ + template \ + inline void SetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index, typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType AddExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + return _proto_TypeTraits::Add(id.number(), field_type, &_extensions_); \ + } \ + \ + template \ + inline void AddExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Add(id.number(), field_type, is_packed, \ + value, &_extensions_); \ + } + } // namespace internal } // namespace protobuf -- cgit v1.2.3