diff options
Diffstat (limited to 'src/google/protobuf/extension_set.h')
-rw-r--r-- | src/google/protobuf/extension_set.h | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h new file mode 100644 index 00000000..902ec736 --- /dev/null +++ b/src/google/protobuf/extension_set.h @@ -0,0 +1,555 @@ +// 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. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__ +#define GOOGLE_PROTOBUF_EXTENSION_SET_H__ + +#include <vector> +#include <stack> +#include <map> +#include <utility> +#include <string> + +#include <google/protobuf/message.h> + +namespace google { +namespace protobuf { + class Descriptor; // descriptor.h + class FieldDescriptor; // descriptor.h + class DescriptorPool; // descriptor.h + class Message; // message.h + class MessageFactory; // message.h + namespace io { + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h + } + template <typename Element> class RepeatedField; // repeated_field.h + template <typename Element> class RepeatedPtrField; // repeated_field.h +} + +namespace protobuf { +namespace internal { + +// 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 +// extended. +// +// This class manages extensions for a protocol message object. The +// message's HasExtension(), GetExtension(), MutableExtension(), and +// ClearExtension() methods are just thin wrappers around the embedded +// ExtensionSet. When parsing, if a tag number is encountered which is +// inside one of the message type's extension ranges, the tag is passed +// off to the ExtensionSet for parsing. Etc. +class LIBPROTOBUF_EXPORT ExtensionSet { + public: + // Construct an ExtensionSet. + // extendee: Descriptor for the type being extended. + // 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* extendee, + const DescriptorPool* pool, + MessageFactory* factory); + + ~ExtensionSet(); + + // Search for a known (compiled-in) extension of this type by name or number. + // Returns NULL if no extension is known. + const FieldDescriptor* FindKnownExtensionByName(const string& name) const; + const FieldDescriptor* FindKnownExtensionByNumber(int number) const; + + // Add all fields which are currently present to the given vector. This + // is useful to implement Message::Reflection::ListFields(). + void AppendToList(vector<const FieldDescriptor*>* output) const; + + // ================================================================= + // Accessors + // + // Generated message classes include type-safe templated wrappers around + // these methods. Generally you should use those rather than call these + // directly, unless you are doing low-level memory management. + // + // When calling any of these accessors, the extension number requested + // MUST exist in the DescriptorPool provided to the constructor. Otheriwse, + // the method will fail an assert. Normally, though, you would not call + // these directly; you would either call the generated accessors of your + // message class (e.g. GetExtension()) or you would call the accessors + // of the reflection interface. In both cases, it is impossible to + // trigger this assert failure: the generated accessors only accept + // linked-in extension types as parameters, while the Reflection interface + // requires you to provide the FieldDescriptor describing the extension. + // + // When calling any of these accessors, a protocol-compiler-generated + // implementation of the extension corresponding to the number MUST + // be linked in, and the FieldDescriptor used to refer to it MUST be + // the one generated by that linked-in code. Otherwise, the method will + // die on an assert failure. The message objects returned by the message + // accessors are guaranteed to be of the correct linked-in type. + // + // These methods pretty much match Message::Reflection except that: + // - They're not virtual. + // - They identify fields by number rather than FieldDescriptors. + // - They identify enum values using integers rather than descriptors. + // - Strings provide Mutable() in addition to Set() accessors. + + bool Has(int number) const; + int ExtensionSize(int number) const; // Size of a repeated extension. + void ClearExtension(int number); + + // 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); + + // repeated fields ------------------------------------------------- + + int32 GetRepeatedInt32 (int number, int index) const; + int64 GetRepeatedInt64 (int number, int index) const; + uint32 GetRepeatedUInt32(int number, int index) const; + uint64 GetRepeatedUInt64(int number, int index) const; + float GetRepeatedFloat (int number, int index) const; + double GetRepeatedDouble(int number, int index) const; + bool GetRepeatedBool (int number, int index) const; + int GetRepeatedEnum (int number, int index) const; + const string & GetRepeatedString (int number, int index) const; + const Message& GetRepeatedMessage(int number, int index) const; + + void SetRepeatedInt32 (int number, int index, int32 value); + void SetRepeatedInt64 (int number, int index, int64 value); + void SetRepeatedUInt32(int number, int index, uint32 value); + void SetRepeatedUInt64(int number, int index, uint64 value); + void SetRepeatedFloat (int number, int index, float value); + void SetRepeatedDouble(int number, int index, double value); + void SetRepeatedBool (int number, int index, bool value); + void SetRepeatedEnum (int number, int index, int value); + void SetRepeatedString(int number, int index, const string& value); + 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); + + // ----------------------------------------------------------------- + // TODO(kenton): Hardcore memory management accessors + + // ================================================================= + // convenience methods for implementing methods of Message + // + // These could all be implemented in terms of the other methods of this + // class, but providing them here helps keep the generated code size down. + + void Clear(); + void MergeFrom(const ExtensionSet& other); + bool IsInitialized() const; + + // These parsing and serialization functions all want a pointer to the + // reflection interface 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::Reflection* reflection); + + // 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, + int end_field_number, + const Message::Reflection* reflection, + io::CodedOutputStream* output) const; + + // Returns the total serialized size of all the extensions. + int ByteSize(const Message::Reflection* reflection) 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; + int64 int64_value; + uint32 uint32_value; + uint64 uint64_value; + float float_value; + double double_value; + bool bool_value; + int enum_value; + string* string_value; + Message* message_value; + + RepeatedField <int32 >* repeated_int32_value; + RepeatedField <int64 >* repeated_int64_value; + RepeatedField <uint32 >* repeated_uint32_value; + RepeatedField <uint64 >* repeated_uint64_value; + RepeatedField <float >* repeated_float_value; + RepeatedField <double >* repeated_double_value; + RepeatedField <bool >* repeated_bool_value; + RepeatedField <int >* repeated_enum_value; + RepeatedPtrField<string >* repeated_string_value; + RepeatedPtrField<Message>* repeated_message_value; + }; + + const FieldDescriptor* descriptor; + + // For singular types, indicates if the extension is "cleared". This + // happens when an extension is set and then later cleared by the caller. + // We want to keep the Extension object around for reuse, so instead of + // removing it from the map, we just set is_cleared = true. This has no + // meaning for repeated types; for those, the size of the RepeatedField + // simply becomes zero when cleared. + bool is_cleared; + + Extension(): descriptor(NULL), is_cleared(false) {} + + // Some helper methods for operations on a single Extension. + bool SerializeFieldWithCachedSizes( + const Message::Reflection* reflection, + io::CodedOutputStream* output) const; + int64 ByteSize(const Message::Reflection* reflection) const; + void Clear(); + int GetSize() const; + void Free(); + }; + + // 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 + // only contain a small number of extensions whereas hash_map is optimized + // for 100 elements or more. Also, we want AppendToList() to order fields + // by field number. + map<int, Extension> extensions_; + const Descriptor* 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::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); +} + +// =================================================================== +// Implementation details +// +// DO NOT DEPEND ON ANYTHING BELOW THIS POINT. This is for use from +// generated code only. + +// ------------------------------------------------------------------- +// Template magic + +// First we have a set of classes representing "type traits" for different +// field types. A type traits class knows how to implement basic accessors +// for extensions of a particular type given an ExtensionSet. The signature +// for a type traits class looks like this: +// +// class TypeTraits { +// public: +// typedef ? ConstType; +// typedef ? MutableType; +// +// static inline ConstType Get(int number, const ExtensionSet& set); +// static inline void Set(int number, ConstType value, ExtensionSet* set); +// static inline MutableType Mutable(int number, ExtensionSet* set); +// +// // Variants for repeated fields. +// static inline ConstType Get(int number, const ExtensionSet& set, +// int index); +// static inline void Set(int number, int index, +// ConstType value, ExtensionSet* set); +// static inline MutableType Mutable(int number, int index, +// ExtensionSet* set); +// static inline void Add(int number, ConstType value, ExtensionSet* set); +// static inline MutableType Add(int number, ExtensionSet* set); +// }; +// +// Not all of these methods make sense for all field types. For example, the +// "Mutable" methods only make sense for strings and messages, and the +// repeated methods only make sense for repeated types. So, each type +// traits class implements only the set of methods from this signature that it +// actually supports. This will cause a compiler error if the user tries to +// access an extension using a method that doesn't make sense for its type. +// For example, if "foo" is an extension of type "optional int32", then if you +// try to write code like: +// my_message.MutableExtension(foo) +// you will get a compile error because PrimitiveTypeTraits<int32> does not +// have a "Mutable()" method. + +// ------------------------------------------------------------------- +// PrimitiveTypeTraits + +// Since the ExtensionSet has different methods for each primitive type, +// we must explicitly define the methods of the type traits class for each +// known type. +template <typename Type> +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); +}; + +template <typename Type> +class RepeatedPrimitiveTypeTraits { + public: + typedef Type ConstType; + + 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); +}; + +#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \ +template<> inline TYPE PrimitiveTypeTraits<TYPE>::Get( \ + int number, const ExtensionSet& set) { \ + return set.Get##METHOD(number); \ +} \ +template<> inline void PrimitiveTypeTraits<TYPE>::Set( \ + int number, ConstType value, ExtensionSet* set) { \ + set->Set##METHOD(number, value); \ +} \ + \ +template<> inline TYPE RepeatedPrimitiveTypeTraits<TYPE>::Get( \ + int number, const ExtensionSet& set, int index) { \ + return set.GetRepeated##METHOD(number, index); \ +} \ +template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Set( \ + int number, int index, ConstType value, ExtensionSet* set) { \ + set->SetRepeated##METHOD(number, index, value); \ +} \ +template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add( \ + int number, ConstType value, ExtensionSet* set) { \ + set->Add##METHOD(number, value); \ +} + +PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( int64, Int64) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32, UInt32) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64, UInt64) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( float, Float) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( bool, Bool) + +#undef PROTOBUF_DEFINE_PRIMITIVE_TYPE + +// ------------------------------------------------------------------- +// StringTypeTraits + +// Strings support both Set() and Mutable(). +class LIBPROTOBUF_EXPORT StringTypeTraits { + public: + typedef const string& ConstType; + typedef string* MutableType; + + static inline const string& Get(int number, const ExtensionSet& set) { + return set.GetString(number); + } + static inline void Set(int number, const string& value, ExtensionSet* set) { + set->SetString(number, value); + } + static inline string* Mutable(int number, ExtensionSet* set) { + return set->MutableString(number); + } +}; + +class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { + public: + typedef const string& ConstType; + typedef string* MutableType; + + static inline const string& Get(int number, const ExtensionSet& set, + int index) { + return set.GetRepeatedString(number, index); + } + static inline void Set(int number, int index, + const string& value, ExtensionSet* set) { + set->SetRepeatedString(number, index, value); + } + 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 string* Add(int number, ExtensionSet* set) { + return set->AddString(number); + } +}; + +// ------------------------------------------------------------------- +// EnumTypeTraits + +// ExtensionSet represents enums using integers internally, so we have to +// static_cast around. +template <typename Type> +class EnumTypeTraits { + public: + typedef Type ConstType; + + static inline ConstType Get(int number, const ExtensionSet& set) { + return static_cast<Type>(set.GetEnum(number)); + } + static inline void Set(int number, ConstType value, ExtensionSet* set) { + set->SetEnum(number, value); + } +}; + +template <typename Type> +class RepeatedEnumTypeTraits { + public: + typedef Type ConstType; + + static inline ConstType Get(int number, const ExtensionSet& set, int index) { + return static_cast<Type>(set.GetRepeatedEnum(number, index)); + } + static inline void Set(int number, int index, + ConstType value, ExtensionSet* set) { + set->SetRepeatedEnum(number, index, value); + } + static inline void Add(int number, ConstType value, ExtensionSet* set) { + set->AddEnum(number, value); + } +}; + +// ------------------------------------------------------------------- +// MessageTypeTraits + +// ExtensionSet guarantees that when manipulating extensions with message +// types, the implementation used will be the compiled-in class representing +// that type. So, we can static_cast down to the exact type we expect. +template <typename Type> +class MessageTypeTraits { + public: + typedef const Type& ConstType; + typedef Type* MutableType; + + static inline ConstType Get(int number, const ExtensionSet& set) { + return static_cast<const Type&>(set.GetMessage(number)); + } + static inline MutableType Mutable(int number, ExtensionSet* set) { + return static_cast<Type*>(set->MutableMessage(number)); + } +}; + +template <typename Type> +class RepeatedMessageTypeTraits { + public: + typedef const Type& ConstType; + typedef Type* MutableType; + + static inline ConstType Get(int number, const ExtensionSet& set, int index) { + return static_cast<const Type&>(set.GetRepeatedMessage(number, index)); + } + static inline MutableType Mutable(int number, int index, ExtensionSet* set) { + return static_cast<Type*>(set->MutableRepeatedMessage(number, index)); + } + static inline MutableType Add(int number, ExtensionSet* set) { + return static_cast<Type*>(set->AddMessage(number)); + } +}; + +// ------------------------------------------------------------------- +// ExtensionIdentifier + +// 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<Foo, PrimitiveTypeTraits<int32>> 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 +// actual contents. However, if we did that, then using at extension +// identifier would not necessarily cause the compiler to output any sort +// of reference to any simple defined in the extension's .pb.o file. Some +// linkers will actually drop object files that are not explicitly referenced, +// 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 <typename ExtendeeType, typename TypeTraitsType> +class ExtensionIdentifier { + public: + typedef TypeTraitsType TypeTraits; + typedef ExtendeeType Extendee; + + ExtensionIdentifier(int number): number_(number) {} + inline int number() const { return number_; } + private: + const int number_; +}; + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_EXTENSION_SET_H__ |