blob: 902ec7364f11fcc5c8865f6b41fec4edc4091b62 [file] [log] [blame]
// 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__