aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/map_entry_lite.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/map_entry_lite.h')
-rw-r--r--src/google/protobuf/map_entry_lite.h292
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