diff options
Diffstat (limited to 'src/google/protobuf/extension_set.h')
-rw-r--r-- | src/google/protobuf/extension_set.h | 212 |
1 files changed, 192 insertions, 20 deletions
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index f5aa8de9..c4796629 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -38,16 +38,16 @@ #ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__ #define GOOGLE_PROTOBUF_EXTENSION_SET_H__ -#include <vector> +#include <algorithm> +#include <cassert> #include <map> -#include <utility> #include <string> - +#include <utility> +#include <vector> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/once.h> - #include <google/protobuf/repeated_field.h> namespace google { @@ -416,7 +416,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet { uint8* target) const; // For backward-compatibility, versions of two of the above methods that - // are never forced to serialize deterministically. + // serialize deterministically iff SetDefaultSerializationDeterministic() + // has been called. uint8* SerializeWithCachedSizesToArray(int start_field_number, int end_field_number, uint8* target) const; @@ -435,6 +436,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // be linked in). It's up to the protocol compiler to avoid calling this on // such ExtensionSets (easy enough since lite messages don't implement // SpaceUsed()). + size_t SpaceUsedExcludingSelfLong() const; + + // This method just calls SpaceUsedExcludingSelfLong() but it can not be + // inlined because the definition of SpaceUsedExcludingSelfLong() is not + // included in lite runtime and when an inline method refers to it MSVC + // will complain about unresolved symbols when building the lite runtime + // as .dll. int SpaceUsedExcludingSelf() const; private: @@ -456,8 +464,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet { const MessageLite& prototype) = 0; virtual bool IsInitialized() const = 0; - virtual int ByteSize() const = 0; - virtual int SpaceUsed() const = 0; + + PROTOBUF_RUNTIME_DEPRECATED("Please use ByteSizeLong() instead") + virtual int ByteSize() const { + return internal::ToIntSize(ByteSizeLong()); + } + virtual size_t ByteSizeLong() const = 0; + virtual size_t SpaceUsedLong() const = 0; virtual void MergeFrom(const LazyMessageExtension& other) = 0; virtual void Clear() = 0; @@ -475,6 +488,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet { } private: + virtual void UnusedKeyMethod(); // Dummy key method to avoid weak vtable. + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension); }; struct Extension { @@ -556,10 +571,90 @@ class LIBPROTOBUF_EXPORT ExtensionSet { void Clear(); int GetSize() const; void Free(); - int SpaceUsedExcludingSelf() const; + size_t SpaceUsedExcludingSelfLong() const; + bool IsInitialized() const; + }; + + // The Extension struct is small enough to be passed by value, so we use it + // directly as the value type in mappings rather than use pointers. We use + // sorted maps rather than hash-maps because we expect most ExtensionSets will + // only contain a small number of extension. Also, we want AppendToList and + // deterministic serialization to order fields by field number. + + struct KeyValue { + int first; + Extension second; + + struct FirstComparator { + bool operator()(const KeyValue& lhs, const KeyValue& rhs) const { + return lhs.first < rhs.first; + } + bool operator()(const KeyValue& lhs, int key) const { + return lhs.first < key; + } + bool operator()(int key, const KeyValue& rhs) const { + return key < rhs.first; + } + }; }; - typedef std::map<int, Extension> ExtensionMap; + typedef std::map<int, Extension> LargeMap; + + // Wrapper API that switches between flat-map and LargeMap. + + // Finds a key (if present) in the ExtensionSet. + const Extension* FindOrNull(int key) const; + Extension* FindOrNull(int key); + + // Helper-functions that only inspect the LargeMap. + const Extension* FindOrNullInLargeMap(int key) const; + Extension* FindOrNullInLargeMap(int key); + + // Inserts a new (key, Extension) into the ExtensionSet (and returns true), or + // finds the already-existing Extension for that key (returns false). + // The Extension* will point to the new-or-found Extension. + std::pair<Extension*, bool> Insert(int key); + + // Grows the flat_capacity_. + // If flat_capacity_ > kMaximumFlatCapacity, converts to LargeMap. + void GrowCapacity(size_t minimum_new_capacity); + static constexpr uint16 kMaximumFlatCapacity = 256; + bool is_large() const { return flat_capacity_ > kMaximumFlatCapacity; } + + // Removes a key from the ExtensionSet. + void Erase(int key); + + size_t Size() const { + return GOOGLE_PREDICT_FALSE(is_large()) ? map_.large->size() : flat_size_; + } + + // Similar to std::for_each. + // Each Iterator is decomposed into ->first and ->second fields, so + // that the KeyValueFunctor can be agnostic vis-a-vis KeyValue-vs-std::pair. + template <typename Iterator, typename KeyValueFunctor> + static KeyValueFunctor ForEach(Iterator begin, Iterator end, + KeyValueFunctor func) { + for (Iterator it = begin; it != end; ++it) func(it->first, it->second); + return std::move(func); + } + + // Applies a functor to the <int, Extension&> pairs in sorted order. + template <typename KeyValueFunctor> + KeyValueFunctor ForEach(KeyValueFunctor func) { + if (GOOGLE_PREDICT_FALSE(is_large())) { + return ForEach(map_.large->begin(), map_.large->end(), std::move(func)); + } + return ForEach(flat_begin(), flat_end(), std::move(func)); + } + + // Applies a functor to the <int, const Extension&> pairs in sorted order. + template <typename KeyValueFunctor> + KeyValueFunctor ForEach(KeyValueFunctor func) const { + if (GOOGLE_PREDICT_FALSE(is_large())) { + return ForEach(map_.large->begin(), map_.large->end(), std::move(func)); + } + return ForEach(flat_begin(), flat_end(), std::move(func)); + } // Merges existing Extension from other_extension void InternalExtensionMergeFrom(int number, const Extension& other_extension); @@ -620,17 +715,41 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // class. // Defined in extension_set_heavy.cc. - static inline int RepeatedMessage_SpaceUsedExcludingSelf( + static inline size_t RepeatedMessage_SpaceUsedExcludingSelfLong( RepeatedPtrFieldBase* field); - // 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. - ExtensionMap extensions_; + KeyValue* flat_begin() { + assert(!is_large()); + return map_.flat; + } + const KeyValue* flat_begin() const { + assert(!is_large()); + return map_.flat; + } + KeyValue* flat_end() { + assert(!is_large()); + return map_.flat + flat_size_; + } + const KeyValue* flat_end() const { + assert(!is_large()); + return map_.flat + flat_size_; + } + ::google::protobuf::Arena* arena_; + + // Manual memory-management: + // map_.flat is an allocated array of flat_capacity_ elements. + // [map_.flat, map_.flat + flat_size_) is the currently-in-use prefix. + uint16 flat_capacity_; + uint16 flat_size_; + union AllocatedData { + KeyValue* flat; + + // If flat_capacity_ > kMaximumFlatCapacity, switch to LargeMap, + // which guarantees O(n lg n) CPU but larger constant factors. + LargeMap* large; + } map_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet); }; @@ -689,6 +808,10 @@ inline void ExtensionSet::AddString(int number, FieldType type, // ExtensionSet* set); // static inline void Add(int number, ConstType value, ExtensionSet* set); // static inline MutableType Add(int number, ExtensionSet* set); +// This is used by the ExtensionIdentifier constructor to register +// the extension at dynamic initialization. +// template <typename ExtendeeT> +// static void Register(int number, FieldType type, bool is_packed); // }; // // Not all of these methods make sense for all field types. For example, the @@ -720,6 +843,11 @@ class PrimitiveTypeTraits { ConstType default_value); static inline void Set(int number, FieldType field_type, ConstType value, ExtensionSet* set); + template <typename ExtendeeT> + static void Register(int number, FieldType type, bool is_packed) { + ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number, + type, false, is_packed); + } }; template <typename Type> @@ -743,6 +871,11 @@ class RepeatedPrimitiveTypeTraits { bool is_packed, ExtensionSet* set); static const RepeatedFieldType* GetDefaultRepeatedField(); + template <typename ExtendeeT> + static void Register(int number, FieldType type, bool is_packed) { + ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number, + type, true, is_packed); + } }; LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_primitive_generic_type_traits_once_init_; @@ -840,6 +973,11 @@ class LIBPROTOBUF_EXPORT StringTypeTraits { ExtensionSet* set) { return set->MutableString(number, field_type, NULL); } + template <typename ExtendeeT> + static void Register(int number, FieldType type, bool is_packed) { + ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number, + type, false, is_packed); + } }; LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_string_type_traits_once_init_; @@ -892,6 +1030,12 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { return default_repeated_field_; } + template <typename ExtendeeT> + static void Register(int number, FieldType type, bool is_packed) { + ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number, + type, true, is_packed); + } + private: static void InitializeDefaultRepeatedFields(); static void DestroyDefaultRepeatedFields(); @@ -919,6 +1063,11 @@ class EnumTypeTraits { GOOGLE_DCHECK(IsValid(value)); set->SetEnum(number, field_type, value, NULL); } + template <typename ExtendeeT> + static void Register(int number, FieldType type, bool is_packed) { + ExtensionSet::RegisterEnumExtension(&ExtendeeT::default_instance(), number, + type, false, is_packed, IsValid); + } }; template <typename Type, bool IsValid(int)> @@ -972,6 +1121,11 @@ class RepeatedEnumTypeTraits { return reinterpret_cast<const RepeatedField<Type>*>( RepeatedPrimitiveTypeTraits<int32>::GetDefaultRepeatedField()); } + template <typename ExtendeeT> + static void Register(int number, FieldType type, bool is_packed) { + ExtensionSet::RegisterEnumExtension(&ExtendeeT::default_instance(), number, + type, true, is_packed, IsValid); + } }; // ------------------------------------------------------------------- @@ -1017,6 +1171,12 @@ class MessageTypeTraits { return static_cast<Type*>(set->UnsafeArenaReleaseMessage( number, Type::default_instance())); } + template <typename ExtendeeT> + static void Register(int number, FieldType type, bool is_packed) { + ExtensionSet::RegisterMessageExtension(&ExtendeeT::default_instance(), + number, type, false, is_packed, + &Type::default_instance()); + } }; // forward declaration @@ -1062,6 +1222,12 @@ class RepeatedMessageTypeTraits { } static const RepeatedFieldType* GetDefaultRepeatedField(); + template <typename ExtendeeT> + static void Register(int number, FieldType type, bool is_packed) { + ExtensionSet::RegisterMessageExtension(&ExtendeeT::default_instance(), + number, type, true, is_packed, + &Type::default_instance()); + } }; LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_message_generic_type_traits_once_init_; @@ -1070,7 +1236,7 @@ LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_message_generic_type_traits_ // message-type repeated field extensions. class LIBPROTOBUF_EXPORT RepeatedMessageGenericTypeTraits { public: - typedef RepeatedPtrField< ::google::protobuf::MessageLite*> RepeatedFieldType; + typedef RepeatedPtrField<::google::protobuf::MessageLite*> RepeatedFieldType; private: template<typename Type> friend class RepeatedMessageTypeTraits; static void InitializeDefaultRepeatedFields(); @@ -1100,7 +1266,7 @@ template<typename Type> inline // 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 +// of reference to any symbol 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. @@ -1113,12 +1279,18 @@ class ExtensionIdentifier { typedef ExtendeeType Extendee; ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value) - : number_(number), default_value_(default_value) {} + : number_(number), default_value_(default_value) { + Register(number); + } inline int number() const { return number_; } typename TypeTraits::ConstType default_value() const { return default_value_; } + static void Register(int number) { + TypeTraits::template Register<ExtendeeType>(number, field_type, is_packed); + } + private: const int number_; typename TypeTraits::ConstType default_value_; |