diff options
Diffstat (limited to 'src/google/protobuf/map_entry_lite.h')
-rw-r--r-- | src/google/protobuf/map_entry_lite.h | 292 |
1 files changed, 198 insertions, 94 deletions
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h index bb1d7e06..0bccf4d2 100644 --- a/src/google/protobuf/map_entry_lite.h +++ b/src/google/protobuf/map_entry_lite.h @@ -32,22 +32,22 @@ #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__ #include <assert.h> + +#include <google/protobuf/arena.h> +#include <google/protobuf/map.h> #include <google/protobuf/map_type_handler.h> #include <google/protobuf/wire_format_lite_inl.h> namespace google { namespace protobuf { -class Arena; namespace internal { -template <typename Key, typename Value, +template <typename Derived, typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType, - WireFormatLite::FieldType kValueFieldType, - int default_enum_value> + WireFormatLite::FieldType kValueFieldType, int default_enum_value> class MapEntry; -template <typename Key, typename Value, +template <typename Derived, typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType, - WireFormatLite::FieldType kValueFieldType, - int default_enum_value> + WireFormatLite::FieldType kValueFieldType, int default_enum_value> class MapFieldLite; } // namespace internal } // namespace protobuf @@ -87,13 +87,14 @@ struct MoveHelper<false, false, true, T> { // strings and similar } }; -// MapEntryLite is used to implement parsing and serialization of map for lite -// runtime. -template <typename Key, typename Value, +// MapEntryImpl is used to implement parsing and serialization of map entries. +// It uses Curious Recursive Template Pattern (CRTP) to provide the type of +// the eventual code to the template code. +template <typename Derived, typename Base, typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType, - WireFormatLite::FieldType kValueFieldType, - int default_enum_value> -class MapEntryLite : public MessageLite { + WireFormatLite::FieldType kValueFieldType, int default_enum_value> +class MapEntryImpl : public Base { + protected: // Provide utilities to parse/serialize key/value. Provide utilities to // manipulate internal stored type. typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; @@ -122,7 +123,30 @@ class MapEntryLite : public MessageLite { static const size_t kTagSize = 1; public: - ~MapEntryLite() { + // Work-around for a compiler bug (see repeated_field.h). + typedef void MapEntryHasMergeTypeTrait; + typedef Derived EntryType; + typedef Key EntryKeyType; + typedef Value EntryValueType; + static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType; + static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType; + static const int kEntryDefaultEnumValue = default_enum_value; + + MapEntryImpl() : default_instance_(NULL), arena_(NULL) { + KeyTypeHandler::Initialize(&key_, NULL); + ValueTypeHandler::InitializeMaybeByDefaultEnum(&value_, default_enum_value, + NULL); + _has_bits_[0] = 0; + } + + explicit MapEntryImpl(Arena* arena) : default_instance_(NULL), arena_(arena) { + KeyTypeHandler::Initialize(&key_, arena); + ValueTypeHandler::InitializeMaybeByDefaultEnum(&value_, default_enum_value, + arena); + _has_bits_[0] = 0; + } + + ~MapEntryImpl() { if (this != default_instance_) { if (GetArenaNoVirtual() != NULL) return; KeyTypeHandler::DeleteNoArena(key_); @@ -151,12 +175,12 @@ class MapEntryLite : public MessageLite { // implements MessageLite ========================================= - // MapEntryLite is for implementation only and this function isn't called + // MapEntryImpl is for implementation only and this function isn't called // anywhere. Just provide a fake implementation here for MessageLite. string GetTypeName() const { return ""; } void CheckTypeAndMergeFrom(const MessageLite& other) { - MergeFrom(*::google::protobuf::down_cast<const MapEntryLite*>(&other)); + MergeFromInternal(*::google::protobuf::down_cast<const Derived*>(&other)); } bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) { @@ -203,8 +227,10 @@ class MapEntryLite : public MessageLite { size_t ByteSizeLong() const { size_t size = 0; - size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0; - size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0; + size += has_key() ? + kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key())) : 0; + size += has_value() ? + kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value())) : 0; return size; } @@ -221,44 +247,45 @@ class MapEntryLite : public MessageLite { deterministic, output); return output; } - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } + + // Don't override SerializeWithCachedSizesToArray. Use MessageLite's. int GetCachedSize() const { int size = 0; size += has_key() - ? kTagSize + KeyTypeHandler::GetCachedSize(key()) + ? static_cast<int>(kTagSize) + KeyTypeHandler::GetCachedSize(key()) : 0; size += has_value() - ? kTagSize + ValueTypeHandler::GetCachedSize( - value()) + ? static_cast<int>(kTagSize) + ValueTypeHandler::GetCachedSize(value()) : 0; return size; } bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); } - MessageLite* New() const { - MapEntryLite* entry = new MapEntryLite; + Base* New() const { + Derived* entry = new Derived; entry->default_instance_ = default_instance_; return entry; } - MessageLite* New(Arena* arena) const { - MapEntryLite* entry = Arena::CreateMessage<MapEntryLite>(arena); + Base* New(Arena* arena) const { + Derived* entry = Arena::CreateMessage<Derived>(arena); entry->default_instance_ = default_instance_; return entry; } - int SpaceUsed() const { - int size = sizeof(MapEntryLite); - size += KeyTypeHandler::SpaceUsedInMapEntry(key_); - size += ValueTypeHandler::SpaceUsedInMapEntry(value_); + size_t SpaceUsedLong() const { + size_t size = sizeof(Derived); + size += KeyTypeHandler::SpaceUsedInMapEntryLong(key_); + size += ValueTypeHandler::SpaceUsedInMapEntryLong(value_); return size; } - void MergeFrom(const MapEntryLite& from) { + protected: + // We can't declare this function directly here as it would hide the other + // overload (const Message&). + void MergeFromInternal(const MapEntryImpl& from) { if (from._has_bits_[0]) { if (from.has_key()) { KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual()); @@ -273,6 +300,7 @@ class MapEntryLite : public MessageLite { } } + public: void Clear() { KeyTypeHandler::Clear(&key_, GetArenaNoVirtual()); ValueTypeHandler::ClearMaybeByDefaultEnum( @@ -281,6 +309,10 @@ class MapEntryLite : public MessageLite { clear_has_value(); } + void set_default_instance(MapEntryImpl* default_instance) { + default_instance_ = default_instance; + } + void InitAsDefaultInstance() { KeyTypeHandler::AssignDefaultValue(&key_); ValueTypeHandler::AssignDefaultValue(&value_); @@ -290,24 +322,18 @@ class MapEntryLite : public MessageLite { return GetArenaNoVirtual(); } - // Create a MapEntryLite for given key and value from google::protobuf::Map in + // Create a MapEntryImpl for given key and value from google::protobuf::Map in // serialization. This function is only called when value is enum. Enum is // treated differently because its type in MapEntry is int and its type in // google::protobuf::Map is enum. We cannot create a reference to int from an enum. - static MapEntryLite* EnumWrap(const Key& key, const Value value, - Arena* arena) { - return Arena::CreateMessage<MapEnumEntryWrapper< - Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> >( - arena, key, value); + static Derived* EnumWrap(const Key& key, const Value value, Arena* arena) { + return Arena::CreateMessage<MapEnumEntryWrapper>(arena, key, value); } // Like above, but for all the other types. This avoids value copy to create - // MapEntryLite from google::protobuf::Map in serialization. - static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) { - return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType, - kValueFieldType, - default_enum_value> >( - arena, key, value); + // MapEntryImpl from google::protobuf::Map in serialization. + static Derived* Wrap(const Key& key, const Value& value, Arena* arena) { + return Arena::CreateMessage<MapEntryWrapper>(arena, key, value); } // Parsing using MergePartialFromCodedStream, above, is not as @@ -412,7 +438,7 @@ class MapEntryLite : public MessageLite { Value* value_ptr_; // On the fast path entry_ is not used. And, when entry_ is used, it's set // to mf_->NewEntry(), so in the arena case we must call entry_.release. - google::protobuf::scoped_ptr<MapEntryLite> entry_; + google::protobuf::scoped_ptr<MapEntryImpl> entry_; }; protected: @@ -434,21 +460,17 @@ class MapEntryLite : public MessageLite { // involves copy of key and value to construct a MapEntry. In order to avoid // this copy in constructing a MapEntry, we need the following class which // only takes references of given key and value. - template <typename K, typename V, WireFormatLite::FieldType k_wire_type, - WireFormatLite::FieldType v_wire_type, int default_enum> - class MapEntryWrapper - : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> { - typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base; - typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType; - typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType; + class MapEntryWrapper : public Derived { + typedef Derived BaseClass; + typedef typename BaseClass::KeyMapEntryAccessorType KeyMapEntryAccessorType; + typedef + typename BaseClass::ValueMapEntryAccessorType ValueMapEntryAccessorType; public: - MapEntryWrapper(Arena* arena, const K& key, const V& value) - : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena), - key_(key), - value_(value) { - Base::set_has_key(); - Base::set_has_value(); + MapEntryWrapper(Arena* arena, const Key& key, const Value& value) + : Derived(arena), key_(key), value_(value) { + BaseClass::set_has_key(); + BaseClass::set_has_value(); } inline const KeyMapEntryAccessorType& key() const { return key_; } inline const ValueMapEntryAccessorType& value() const { return value_; } @@ -468,21 +490,17 @@ class MapEntryLite : public MessageLite { // initialize a reference to int with a reference to enum, compiler will // generate a temporary int from enum and initialize the reference to int with // the temporary. - template <typename K, typename V, WireFormatLite::FieldType k_wire_type, - WireFormatLite::FieldType v_wire_type, int default_enum> - class MapEnumEntryWrapper - : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> { - typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base; - typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType; - typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType; + class MapEnumEntryWrapper : public Derived { + typedef Derived BaseClass; + typedef typename BaseClass::KeyMapEntryAccessorType KeyMapEntryAccessorType; + typedef + typename BaseClass::ValueMapEntryAccessorType ValueMapEntryAccessorType; public: - MapEnumEntryWrapper(Arena* arena, const K& key, const V& value) - : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena), - key_(key), - value_(value) { - Base::set_has_key(); - Base::set_has_value(); + MapEnumEntryWrapper(Arena* arena, const Key& key, const Value& value) + : Derived(arena), key_(key), value_(value) { + BaseClass::set_has_key(); + BaseClass::set_has_value(); } inline const KeyMapEntryAccessorType& key() const { return key_; } inline const ValueMapEntryAccessorType& value() const { return value_; } @@ -495,30 +513,11 @@ class MapEntryLite : public MessageLite { typedef void DestructorSkippable_; }; - MapEntryLite() : default_instance_(NULL), arena_(NULL) { - KeyTypeHandler::Initialize(&key_, NULL); - ValueTypeHandler::InitializeMaybeByDefaultEnum( - &value_, default_enum_value, NULL); - _has_bits_[0] = 0; - } - - explicit MapEntryLite(Arena* arena) - : default_instance_(NULL), arena_(arena) { - KeyTypeHandler::Initialize(&key_, arena); - ValueTypeHandler::InitializeMaybeByDefaultEnum( - &value_, default_enum_value, arena); - _has_bits_[0] = 0; - } - inline Arena* GetArenaNoVirtual() const { return arena_; } - void set_default_instance(MapEntryLite* default_instance) { - default_instance_ = default_instance; - } - - MapEntryLite* default_instance_; + MapEntryImpl* default_instance_; KeyOnMemory key_; ValueOnMemory value_; @@ -528,15 +527,51 @@ class MapEntryLite : public MessageLite { friend class ::google::protobuf::Arena; typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; - template <typename K, typename V, WireFormatLite::FieldType, + template <typename C, typename K, typename V, WireFormatLite::FieldType, WireFormatLite::FieldType, int> friend class internal::MapEntry; - template <typename K, typename V, WireFormatLite::FieldType, + template <typename C, typename K, typename V, WireFormatLite::FieldType, WireFormatLite::FieldType, int> friend class internal::MapFieldLite; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryImpl); +}; + +template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType, + WireFormatLite::FieldType kValueFieldType, int default_enum_value> +class MapEntryLite + : public MapEntryImpl<MapEntryLite<Key, Value, kKeyFieldType, + kValueFieldType, default_enum_value>, + MessageLite, Key, Value, kKeyFieldType, + kValueFieldType, default_enum_value> { + public: + typedef MapEntryImpl<MapEntryLite, MessageLite, Key, Value, kKeyFieldType, + kValueFieldType, default_enum_value> + SuperType; + MapEntryLite() {} + explicit MapEntryLite(Arena* arena) : SuperType(arena) {} + void MergeFrom(const MapEntryLite<Key, Value, kKeyFieldType, kValueFieldType, + default_enum_value>& other) { + MergeFromInternal(other); + } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite); }; +// The completely unprincipled and unwieldy use of template parameters in +// the map code necessitates wrappers to make the code a little bit more +// manageable. +template <typename Derived> +struct DeconstructMapEntry; + +template <typename K, typename V, WireFormatLite::FieldType key, + WireFormatLite::FieldType value, int default_enum> +struct DeconstructMapEntry<MapEntryLite<K, V, key, value, default_enum> > { + typedef K Key; + typedef V Value; + static const WireFormatLite::FieldType kKeyFieldType = key; + static const WireFormatLite::FieldType kValueFieldType = value; + static const int default_enum_value = default_enum; +}; // Helpers for deterministic serialization ============================= @@ -564,6 +599,75 @@ template <typename T> struct CompareByDerefFirst { } }; +// Helper for table driven serialization + +template <WireFormatLite::FieldType FieldType> +struct FromHelper { + template <typename T> + static const T& From(const T& x) { + return x; + } +}; + +template <> +struct FromHelper<WireFormatLite::TYPE_STRING> { + static ArenaStringPtr From(const string& x) { + ArenaStringPtr res; + res.UnsafeArenaSetAllocated(NULL, const_cast<string*>(&x), NULL); + return res; + } +}; +template <> +struct FromHelper<WireFormatLite::TYPE_BYTES> { + static ArenaStringPtr From(const string& x) { + ArenaStringPtr res; + res.UnsafeArenaSetAllocated(NULL, const_cast<string*>(&x), NULL); + return res; + } +}; +template <> +struct FromHelper<WireFormatLite::TYPE_MESSAGE> { + template <typename T> + static T* From(const T& x) { + return const_cast<T*>(&x); + } +}; + +template <typename MapEntryType> +struct MapEntryHelper; + +template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType, + WireFormatLite::FieldType kValueFieldType, int default_enum_value> +struct MapEntryHelper<MapEntryLite<Key, Value, kKeyFieldType, kValueFieldType, + default_enum_value> > { + // Provide utilities to parse/serialize key/value. Provide utilities to + // manipulate internal stored type. + typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; + typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler; + + // Define internal memory layout. Strings and messages are stored as + // pointers, while other types are stored as values. + typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory; + typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory; + + explicit MapEntryHelper(const MapPair<Key, Value>& map_pair) + : _has_bits_(3), + _cached_size_(2 + KeyTypeHandler::GetCachedSize(map_pair.first) + + ValueTypeHandler::GetCachedSize(map_pair.second)), + key_(FromHelper<kKeyFieldType>::From(map_pair.first)), + value_(FromHelper<kValueFieldType>::From(map_pair.second)) {} + + // Purposely not folowing the style guide naming. These are the names + // the proto compiler would generate given the map entry descriptor. + // The proto compiler generates the offsets in this struct as if this was + // a regular message. This way the table driven code barely notices it's + // dealing with a map field. + uint32 _has_bits_; // NOLINT + uint32 _cached_size_; // NOLINT + KeyOnMemory key_; // NOLINT + ValueOnMemory value_; // NOLINT +}; + } // namespace internal } // namespace protobuf |