Move all virtual functions in MapFieldBase to be a manually written vtable.

This is preparation work to merge the vtable with the `ReflectionPayload`
object to reduce the size of MapField by 8 bytes.

PiperOrigin-RevId: 570387900
pull/14275/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent e912bc2e3a
commit 95d57237b3
  1. 14
      src/google/protobuf/map.h
  2. 102
      src/google/protobuf/map_field.cc
  3. 191
      src/google/protobuf/map_field.h
  4. 74
      src/google/protobuf/map_field_inl.h
  5. 43
      src/google/protobuf/map_field_test.cc
  6. 2
      src/google/protobuf/repeated_ptr_field.h

@ -806,15 +806,23 @@ inline void UntypedMapIterator::SearchFrom(size_t start_bucket) {
// code, since that would bring in Message too. // code, since that would bring in Message too.
class MapFieldBaseForParse { class MapFieldBaseForParse {
public: public:
const UntypedMapBase& GetMap() const { return GetMapImpl(false); } const UntypedMapBase& GetMap() const {
return vtable_->get_map(*this, false);
}
UntypedMapBase* MutableMap() { UntypedMapBase* MutableMap() {
return &const_cast<UntypedMapBase&>(GetMapImpl(true)); return &const_cast<UntypedMapBase&>(vtable_->get_map(*this, true));
} }
protected: protected:
struct VTable {
const UntypedMapBase& (*get_map)(const MapFieldBaseForParse&,
bool is_mutable);
};
explicit constexpr MapFieldBaseForParse(const VTable* vtable)
: vtable_(vtable) {}
~MapFieldBaseForParse() = default; ~MapFieldBaseForParse() = default;
virtual const UntypedMapBase& GetMapImpl(bool is_mutable) const = 0; const VTable* vtable_;
}; };
// The value might be of different signedness, so use memcpy to extract it. // The value might be of different signedness, so use memcpy to extract it.

@ -10,6 +10,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "absl/log/absl_check.h"
#include "google/protobuf/map.h"
#include "google/protobuf/map_field_inl.h" #include "google/protobuf/map_field_inl.h"
#include "google/protobuf/port.h" #include "google/protobuf/port.h"
@ -46,10 +48,12 @@ MapFieldBase::~MapFieldBase() {
delete maybe_payload(); delete maybe_payload();
} }
const UntypedMapBase& MapFieldBase::GetMapImpl(bool is_mutable) const { const UntypedMapBase& MapFieldBase::GetMapImpl(const MapFieldBaseForParse& map,
SyncMapWithRepeatedField(); bool is_mutable) {
if (is_mutable) const_cast<MapFieldBase*>(this)->SetMapDirty(); const auto& self = static_cast<const MapFieldBase&>(map);
return GetMapRaw(); self.SyncMapWithRepeatedField();
if (is_mutable) const_cast<MapFieldBase&>(self).SetMapDirty();
return self.GetMapRaw();
} }
void MapFieldBase::MapBegin(MapIterator* map_iter) const { void MapFieldBase::MapBegin(MapIterator* map_iter) const {
@ -121,24 +125,24 @@ MapFieldBase::ReflectionPayload& MapFieldBase::PayloadSlow() const {
return *ToPayload(p); return *ToPayload(p);
} }
void MapFieldBase::Swap(MapFieldBase* other) { void MapFieldBase::SwapImpl(MapFieldBase& lhs, MapFieldBase& rhs) {
if (arena() == other->arena()) { if (lhs.arena() == rhs.arena()) {
InternalSwap(other); lhs.InternalSwap(&rhs);
return; return;
} }
auto* p1 = maybe_payload(); auto* p1 = lhs.maybe_payload();
auto* p2 = other->maybe_payload(); auto* p2 = rhs.maybe_payload();
if (p1 == nullptr && p2 == nullptr) return; if (p1 == nullptr && p2 == nullptr) return;
if (p1 == nullptr) p1 = &payload(); if (p1 == nullptr) p1 = &lhs.payload();
if (p2 == nullptr) p2 = &other->payload(); if (p2 == nullptr) p2 = &rhs.payload();
p1->repeated_field.Swap(&p2->repeated_field); p1->repeated_field.Swap(&p2->repeated_field);
SwapRelaxed(p1->state, p2->state); SwapRelaxed(p1->state, p2->state);
} }
void MapFieldBase::UnsafeShallowSwap(MapFieldBase* other) { void MapFieldBase::UnsafeShallowSwapImpl(MapFieldBase& lhs, MapFieldBase& rhs) {
ABSL_DCHECK_EQ(arena(), other->arena()); ABSL_DCHECK_EQ(lhs.arena(), rhs.arena());
InternalSwap(other); lhs.InternalSwap(&rhs);
} }
void MapFieldBase::InternalSwap(MapFieldBase* other) { void MapFieldBase::InternalSwap(MapFieldBase* other) {
@ -158,14 +162,6 @@ size_t MapFieldBase::SpaceUsedExcludingSelfLong() const {
return size; return size;
} }
size_t MapFieldBase::SpaceUsedExcludingSelfNoLock() const {
if (auto* p = maybe_payload()) {
return p->repeated_field.SpaceUsedExcludingSelfLong();
} else {
return 0;
}
}
bool MapFieldBase::IsMapValid() const { bool MapFieldBase::IsMapValid() const {
ConstAccess(); ConstAccess();
// "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get // "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get
@ -402,12 +398,16 @@ bool MapFieldBase::InsertOrLookupMapValue(const MapKey& map_key,
// ------------------DynamicMapField------------------ // ------------------DynamicMapField------------------
DynamicMapField::DynamicMapField(const Message* default_entry) DynamicMapField::DynamicMapField(const Message* default_entry)
: default_entry_(default_entry) {} : DynamicMapField::TypeDefinedMapFieldBase(&kVTable),
default_entry_(default_entry) {}
DynamicMapField::DynamicMapField(const Message* default_entry, Arena* arena) DynamicMapField::DynamicMapField(const Message* default_entry, Arena* arena)
: TypeDefinedMapFieldBase<MapKey, MapValueRef>(arena), : TypeDefinedMapFieldBase<MapKey, MapValueRef>(&kVTable, arena),
default_entry_(default_entry) {} default_entry_(default_entry) {}
constexpr DynamicMapField::VTable DynamicMapField::kVTable =
MakeVTable<DynamicMapField>();
DynamicMapField::~DynamicMapField() { DynamicMapField::~DynamicMapField() {
ABSL_DCHECK_EQ(arena(), nullptr); ABSL_DCHECK_EQ(arena(), nullptr);
// DynamicMapField owns map values. Need to delete them before clearing the // DynamicMapField owns map values. Need to delete them before clearing the
@ -418,14 +418,15 @@ DynamicMapField::~DynamicMapField() {
map_.clear(); map_.clear();
} }
void DynamicMapField::ClearMapNoSync() { void DynamicMapField::ClearMapNoSyncImpl(MapFieldBase& base) {
if (arena() == nullptr) { auto& self = static_cast<DynamicMapField&>(base);
for (auto& elem : map_) { if (self.arena() == nullptr) {
for (auto& elem : self.map_) {
elem.second.DeleteData(); elem.second.DeleteData();
} }
} }
map_.clear(); self.map_.clear();
} }
void DynamicMapField::AllocateMapValue(MapValueRef* map_val) { void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
@ -460,12 +461,14 @@ void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
} }
} }
bool DynamicMapField::InsertOrLookupMapValueNoSync(const MapKey& map_key, bool DynamicMapField::InsertOrLookupMapValueNoSyncImpl(MapFieldBase& base,
MapValueRef* val) { const MapKey& map_key,
Map<MapKey, MapValueRef>::iterator iter = map_.find(map_key); MapValueRef* val) {
if (iter == map_.end()) { auto& self = static_cast<DynamicMapField&>(base);
MapValueRef& map_val = map_[map_key]; Map<MapKey, MapValueRef>::iterator iter = self.map_.find(map_key);
AllocateMapValue(&map_val); if (iter == self.map_.end()) {
MapValueRef& map_val = self.map_[map_key];
self.AllocateMapValue(&map_val);
val->CopyFrom(map_val); val->CopyFrom(map_val);
return true; return true;
} }
@ -475,9 +478,11 @@ bool DynamicMapField::InsertOrLookupMapValueNoSync(const MapKey& map_key,
return false; return false;
} }
void DynamicMapField::MergeFrom(const MapFieldBase& other) { void DynamicMapField::MergeFromImpl(MapFieldBase& base,
ABSL_DCHECK(IsMapValid() && other.IsMapValid()); const MapFieldBase& other) {
Map<MapKey, MapValueRef>* map = MutableMap(); auto& self = static_cast<DynamicMapField&>(base);
ABSL_DCHECK(self.IsMapValid() && other.IsMapValid());
Map<MapKey, MapValueRef>* map = self.MutableMap();
const DynamicMapField& other_field = const DynamicMapField& other_field =
reinterpret_cast<const DynamicMapField&>(other); reinterpret_cast<const DynamicMapField&>(other);
for (Map<MapKey, MapValueRef>::const_iterator other_it = for (Map<MapKey, MapValueRef>::const_iterator other_it =
@ -486,15 +491,15 @@ void DynamicMapField::MergeFrom(const MapFieldBase& other) {
Map<MapKey, MapValueRef>::iterator iter = map->find(other_it->first); Map<MapKey, MapValueRef>::iterator iter = map->find(other_it->first);
MapValueRef* map_val; MapValueRef* map_val;
if (iter == map->end()) { if (iter == map->end()) {
map_val = &map_[other_it->first]; map_val = &self.map_[other_it->first];
AllocateMapValue(map_val); self.AllocateMapValue(map_val);
} else { } else {
map_val = &iter->second; map_val = &iter->second;
} }
// Copy map value // Copy map value
const FieldDescriptor* field_descriptor = const FieldDescriptor* field_descriptor =
default_entry_->GetDescriptor()->map_value(); self.default_entry_->GetDescriptor()->map_value();
switch (field_descriptor->cpp_type()) { switch (field_descriptor->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32: { case FieldDescriptor::CPPTYPE_INT32: {
map_val->SetInt32Value(other_it->second.GetInt32Value()); map_val->SetInt32Value(other_it->second.GetInt32Value());
@ -541,17 +546,20 @@ void DynamicMapField::MergeFrom(const MapFieldBase& other) {
} }
} }
const Message* DynamicMapField::GetPrototype() const { return default_entry_; } const Message* DynamicMapField::GetPrototypeImpl(const MapFieldBase& map) {
return static_cast<const DynamicMapField&>(map).default_entry_;
}
size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const { size_t DynamicMapField::SpaceUsedExcludingSelfNoLockImpl(
const MapFieldBase& map) {
auto& self = static_cast<const DynamicMapField&>(map);
size_t size = 0; size_t size = 0;
if (auto* p = maybe_payload()) { if (auto* p = self.maybe_payload()) {
size += p->repeated_field.SpaceUsedExcludingSelfLong(); size += p->repeated_field.SpaceUsedExcludingSelfLong();
} }
size += sizeof(map_); size_t map_size = self.map_.size();
size_t map_size = map_.size();
if (map_size) { if (map_size) {
Map<MapKey, MapValueRef>::const_iterator it = map_.begin(); Map<MapKey, MapValueRef>::const_iterator it = self.map_.begin();
size += sizeof(it->first) * map_size; size += sizeof(it->first) * map_size;
size += sizeof(it->second) * map_size; size += sizeof(it->second) * map_size;
// If key is string, add the allocated space. // If key is string, add the allocated space.
@ -576,7 +584,7 @@ size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const {
HANDLE_TYPE(ENUM, int32_t); HANDLE_TYPE(ENUM, int32_t);
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE: { case FieldDescriptor::CPPTYPE_MESSAGE: {
while (it != map_.end()) { while (it != self.map_.end()) {
const Message& message = it->second.GetMessageValue(); const Message& message = it->second.GetMessageValue();
size += message.GetReflection()->SpaceUsedLong(message); size += message.GetReflection()->SpaceUsedLong(message);
++it; ++it;

@ -18,6 +18,7 @@
#include "google/protobuf/generated_message_reflection.h" #include "google/protobuf/generated_message_reflection.h"
#include "google/protobuf/generated_message_util.h" #include "google/protobuf/generated_message_util.h"
#include "google/protobuf/internal_visibility.h" #include "google/protobuf/internal_visibility.h"
#include "google/protobuf/map.h"
#include "google/protobuf/map_entry.h" #include "google/protobuf/map_entry.h"
#include "google/protobuf/map_field_lite.h" #include "google/protobuf/map_field_lite.h"
#include "google/protobuf/map_type_handler.h" #include "google/protobuf/map_type_handler.h"
@ -295,8 +296,10 @@ class MapFieldAccessor;
// reflection implementation only. Users should never use this directly. // reflection implementation only. Users should never use this directly.
class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse { class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
public: public:
constexpr MapFieldBase() {} explicit constexpr MapFieldBase(const VTable* vtable)
explicit MapFieldBase(Arena* arena) : payload_{ToTaggedPtr(arena)} {} : MapFieldBaseForParse(vtable) {}
explicit MapFieldBase(const VTable* vtable, Arena* arena)
: MapFieldBaseForParse(vtable), payload_{ToTaggedPtr(arena)} {}
MapFieldBase(const MapFieldBase&) = delete; MapFieldBase(const MapFieldBase&) = delete;
MapFieldBase& operator=(const MapFieldBase&) = delete; MapFieldBase& operator=(const MapFieldBase&) = delete;
@ -304,6 +307,39 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
// "protected" stops users from deleting a `MapFieldBase *` // "protected" stops users from deleting a `MapFieldBase *`
~MapFieldBase(); ~MapFieldBase();
struct VTable : MapFieldBaseForParse::VTable {
bool (*lookup_map_value)(const MapFieldBase& map, const MapKey& map_key,
MapValueConstRef* val);
bool (*delete_map_value)(MapFieldBase& map, const MapKey& map_key);
void (*set_map_iterator_value)(MapIterator* map_iter);
bool (*insert_or_lookup_no_sync)(MapFieldBase& map, const MapKey& map_key,
MapValueRef* val);
void (*clear_map_no_sync)(MapFieldBase& map);
void (*merge_from)(MapFieldBase& map, const MapFieldBase& other);
void (*swap)(MapFieldBase& lhs, MapFieldBase& rhs);
void (*unsafe_shallow_swap)(MapFieldBase& lhs, MapFieldBase& rhs);
size_t (*space_used_excluding_self_nolock)(const MapFieldBase& map);
const Message* (*get_prototype)(const MapFieldBase& map);
};
template <typename T>
static constexpr VTable MakeVTable() {
VTable out{};
out.get_map = &T::GetMapImpl;
out.lookup_map_value = &T::LookupMapValueImpl;
out.delete_map_value = &T::DeleteMapValueImpl;
out.set_map_iterator_value = &T::SetMapIteratorValueImpl;
out.insert_or_lookup_no_sync = &T::InsertOrLookupMapValueNoSyncImpl;
out.clear_map_no_sync = &T::ClearMapNoSyncImpl;
out.merge_from = &T::MergeFromImpl;
out.swap = &T::SwapImpl;
out.unsafe_shallow_swap = &T::UnsafeShallowSwapImpl;
out.space_used_excluding_self_nolock = &T::SpaceUsedExcludingSelfNoLockImpl;
out.get_prototype = &T::GetPrototypeImpl;
return out;
}
public: public:
// Returns reference to internal repeated field. Data written using // Returns reference to internal repeated field. Data written using
// Map's api prior to calling this function is guarantted to be // Map's api prior to calling this function is guarantted to be
@ -313,10 +349,14 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
// Like above. Returns mutable pointer to the internal repeated field. // Like above. Returns mutable pointer to the internal repeated field.
RepeatedPtrFieldBase* MutableRepeatedField(); RepeatedPtrFieldBase* MutableRepeatedField();
// Pure virtual map APIs for Map Reflection. const VTable* vtable() const { return static_cast<const VTable*>(vtable_); }
virtual bool ContainsMapKey(const MapKey& map_key) const = 0;
virtual bool LookupMapValue(const MapKey& map_key, bool ContainsMapKey(const MapKey& map_key) const {
MapValueConstRef* val) const = 0; return LookupMapValue(map_key, static_cast<MapValueConstRef*>(nullptr));
}
bool LookupMapValue(const MapKey& map_key, MapValueConstRef* val) const {
return vtable()->lookup_map_value(*this, map_key, val);
}
bool LookupMapValue(const MapKey&, MapValueRef*) const = delete; bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val); bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val);
@ -325,19 +365,26 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
bool IsRepeatedFieldValid() const; bool IsRepeatedFieldValid() const;
// Insures operations after won't get executed before calling this. // Insures operations after won't get executed before calling this.
bool IsMapValid() const; bool IsMapValid() const;
virtual bool DeleteMapValue(const MapKey& map_key) = 0; bool DeleteMapValue(const MapKey& map_key) {
virtual void MergeFrom(const MapFieldBase& other) = 0; return vtable()->delete_map_value(*this, map_key);
virtual void Swap(MapFieldBase* other); }
virtual void UnsafeShallowSwap(MapFieldBase* other); void MergeFrom(const MapFieldBase& other) {
vtable()->merge_from(*this, other);
}
void Swap(MapFieldBase* other) { vtable()->swap(*this, *other); }
void UnsafeShallowSwap(MapFieldBase* other) {
vtable()->unsafe_shallow_swap(*this, *other);
}
// Sync Map with repeated field and returns the size of map. // Sync Map with repeated field and returns the size of map.
int size() const; int size() const;
void Clear(); void Clear();
virtual void SetMapIteratorValue(MapIterator* map_iter) const = 0; void SetMapIteratorValue(MapIterator* map_iter) const {
return vtable()->set_map_iterator_value(map_iter);
}
void MapBegin(MapIterator* map_iter) const; void MapBegin(MapIterator* map_iter) const;
void MapEnd(MapIterator* map_iter) const; void MapEnd(MapIterator* map_iter) const;
bool EqualIterator(const MapIterator& a, const MapIterator& b) const; bool EqualIterator(const MapIterator& a, const MapIterator& b) const;
const UntypedMapBase& GetMapImpl(bool is_mutable) const final;
// Returns the number of bytes used by the repeated field, excluding // Returns the number of bytes used by the repeated field, excluding
// sizeof(*this) // sizeof(*this)
@ -349,10 +396,12 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
protected: protected:
// Gets the size of space used by map field. // Gets the size of space used by map field.
virtual size_t SpaceUsedExcludingSelfNoLock() const; size_t SpaceUsedExcludingSelfNoLock() const {
return vtable()->space_used_excluding_self_nolock(*this);
}
virtual const Message* GetPrototype() const = 0; const Message* GetPrototype() const { return vtable()->get_prototype(*this); }
virtual void ClearMapNoSync() = 0; void ClearMapNoSync() { return vtable()->clear_map_no_sync(*this); }
// Synchronizes the content in Map to RepeatedPtrField if there is any change // Synchronizes the content in Map to RepeatedPtrField if there is any change
// to Map after last synchronization. // to Map after last synchronization.
@ -364,6 +413,9 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
void SyncMapWithRepeatedField() const; void SyncMapWithRepeatedField() const;
void SyncMapWithRepeatedFieldNoLock(); void SyncMapWithRepeatedFieldNoLock();
static void SwapImpl(MapFieldBase& lhs, MapFieldBase& rhs);
static void UnsafeShallowSwapImpl(MapFieldBase& lhs, MapFieldBase& rhs);
// Tells MapFieldBase that there is new change to Map. // Tells MapFieldBase that there is new change to Map.
void SetMapDirty(); void SetMapDirty();
@ -373,8 +425,9 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
// Provides derived class the access to repeated field. // Provides derived class the access to repeated field.
void* MutableRepeatedPtrField() const; void* MutableRepeatedPtrField() const;
virtual bool InsertOrLookupMapValueNoSync(const MapKey& map_key, bool InsertOrLookupMapValueNoSync(const MapKey& map_key, MapValueRef* val) {
MapValueRef* val) = 0; return vtable()->insert_or_lookup_no_sync(*this, map_key, val);
}
void InternalSwap(MapFieldBase* other); void InternalSwap(MapFieldBase* other);
@ -439,6 +492,9 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
: STATE_MODIFIED_MAP; : STATE_MODIFIED_MAP;
} }
static const UntypedMapBase& GetMapImpl(const MapFieldBaseForParse& map,
bool is_mutable);
private: private:
friend class ContendedMapCleanTest; friend class ContendedMapCleanTest;
friend class GeneratedMessageReflection; friend class GeneratedMessageReflection;
@ -501,7 +557,8 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
template <typename Key, typename T> template <typename Key, typename T>
class TypeDefinedMapFieldBase : public MapFieldBase { class TypeDefinedMapFieldBase : public MapFieldBase {
public: public:
constexpr TypeDefinedMapFieldBase() : map_() { explicit constexpr TypeDefinedMapFieldBase(const VTable* vtable)
: MapFieldBase(vtable), map_() {
// This invariant is required by MapFieldBase to easily access the map // This invariant is required by MapFieldBase to easily access the map
// member without paying for dynamic dispatch. It reduces code size. // member without paying for dynamic dispatch. It reduces code size.
static_assert(PROTOBUF_FIELD_OFFSET(TypeDefinedMapFieldBase, map_) == static_assert(PROTOBUF_FIELD_OFFSET(TypeDefinedMapFieldBase, map_) ==
@ -511,10 +568,8 @@ class TypeDefinedMapFieldBase : public MapFieldBase {
TypeDefinedMapFieldBase(const TypeDefinedMapFieldBase&) = delete; TypeDefinedMapFieldBase(const TypeDefinedMapFieldBase&) = delete;
TypeDefinedMapFieldBase& operator=(const TypeDefinedMapFieldBase&) = delete; TypeDefinedMapFieldBase& operator=(const TypeDefinedMapFieldBase&) = delete;
explicit TypeDefinedMapFieldBase(Arena* arena) TypeDefinedMapFieldBase(const VTable* vtable, Arena* arena)
: MapFieldBase(arena), map_(arena) {} : MapFieldBase(vtable, arena), map_(arena) {}
TypeDefinedMapFieldBase(ArenaInitialized, Arena* arena)
: TypeDefinedMapFieldBase(arena) {}
protected: protected:
~TypeDefinedMapFieldBase() { map_.~Map(); } ~TypeDefinedMapFieldBase() { map_.~Map(); }
@ -535,33 +590,36 @@ class TypeDefinedMapFieldBase : public MapFieldBase {
return &map_; return &map_;
} }
void ClearMapNoSync() override { map_.clear(); } static void ClearMapNoSyncImpl(MapFieldBase& map) {
static_cast<TypeDefinedMapFieldBase&>(map).map_.clear();
}
void InternalSwap(TypeDefinedMapFieldBase* other); void InternalSwap(TypeDefinedMapFieldBase* other);
void Swap(MapFieldBase* other) final;
void UnsafeShallowSwap(MapFieldBase* other) override;
size_t SpaceUsedExcludingSelfNoLock() const override;
void MergeFrom(const MapFieldBase& other) override;
protected: protected:
friend struct MapFieldTestPeer;
using Iter = typename Map<Key, T>::const_iterator; using Iter = typename Map<Key, T>::const_iterator;
static bool DeleteMapValueImpl(MapFieldBase& map, const MapKey& map_key);
static bool LookupMapValueImpl(const MapFieldBase& self,
const MapKey& map_key, MapValueConstRef* val);
static void SetMapIteratorValueImpl(MapIterator* map_iter);
static bool InsertOrLookupMapValueNoSyncImpl(MapFieldBase& map,
const MapKey& map_key,
MapValueRef* val);
static void MergeFromImpl(MapFieldBase& base, const MapFieldBase& other);
static void SwapImpl(MapFieldBase& lhs, MapFieldBase& rhs);
static void UnsafeShallowSwapImpl(MapFieldBase& lhs, MapFieldBase& rhs);
static size_t SpaceUsedExcludingSelfNoLockImpl(const MapFieldBase& map);
// map_ is inside an anonymous union so we can explicitly control its // map_ is inside an anonymous union so we can explicitly control its
// destruction // destruction
union { union {
Map<Key, T> map_; Map<Key, T> map_;
}; };
private:
void SetMapIteratorValue(MapIterator* map_iter) const final;
bool ContainsMapKey(const MapKey& map_key) const final;
bool LookupMapValue(const MapKey& map_key, MapValueConstRef* val) const final;
bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
bool DeleteMapValue(const MapKey& map_key) final;
bool InsertOrLookupMapValueNoSync(const MapKey& map_key,
MapValueRef* val) override;
}; };
// This class provides access to map field using generated api. It is used for // This class provides access to map field using generated api. It is used for
@ -584,19 +642,18 @@ class MapField final : public TypeDefinedMapFieldBase<Key, T> {
static constexpr WireFormatLite::FieldType kKeyFieldType = kKeyFieldType_; static constexpr WireFormatLite::FieldType kKeyFieldType = kKeyFieldType_;
static constexpr WireFormatLite::FieldType kValueFieldType = kValueFieldType_; static constexpr WireFormatLite::FieldType kValueFieldType = kValueFieldType_;
constexpr MapField() {} constexpr MapField() : MapField::TypeDefinedMapFieldBase(&kVTable) {}
MapField(const MapField&) = delete; MapField(const MapField&) = delete;
MapField& operator=(const MapField&) = delete; MapField& operator=(const MapField&) = delete;
~MapField() {} ~MapField() {}
explicit MapField(Arena* arena) : TypeDefinedMapFieldBase<Key, T>(arena) {} explicit MapField(Arena* arena)
: TypeDefinedMapFieldBase<Key, T>(&kVTable, arena) {}
MapField(ArenaInitialized, Arena* arena) : MapField(arena) {} MapField(ArenaInitialized, Arena* arena) : MapField(arena) {}
MapField(InternalVisibility, Arena* arena) : MapField(arena) {}
MapField(InternalVisibility, Arena* arena)
: TypeDefinedMapFieldBase<Key, T>(arena) {}
MapField(InternalVisibility, Arena* arena, const MapField& from) MapField(InternalVisibility, Arena* arena, const MapField& from)
: TypeDefinedMapFieldBase<Key, T>(arena) { : MapField(arena) {
TypeDefinedMapFieldBase<Key, T>::MergeFrom(from); this->MergeFromImpl(*this, from);
} }
// Used in the implementation of parsing. Caller should take the ownership iff // Used in the implementation of parsing. Caller should take the ownership iff
@ -609,13 +666,22 @@ class MapField final : public TypeDefinedMapFieldBase<Key, T> {
typedef void InternalArenaConstructable_; typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_; typedef void DestructorSkippable_;
// Implements MapFieldBase static const Message* GetPrototypeImpl(const MapFieldBase& map);
const Message* GetPrototype() const final;
static const MapFieldBase::VTable kVTable;
friend class google::protobuf::Arena; friend class google::protobuf::Arena;
friend class MapFieldBase;
friend class MapFieldStateTest; // For testing, it needs raw access to impl_ friend class MapFieldStateTest; // For testing, it needs raw access to impl_
}; };
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType_,
WireFormatLite::FieldType kValueFieldType_>
constexpr MapFieldBase::VTable
MapField<Derived, Key, T, kKeyFieldType_, kValueFieldType_>::kVTable =
MapField::template MakeVTable<MapField>();
template <typename Key, typename T> template <typename Key, typename T>
bool AllAreInitialized(const TypeDefinedMapFieldBase<Key, T>& field) { bool AllAreInitialized(const TypeDefinedMapFieldBase<Key, T>& field) {
for (const auto& p : field.GetMap()) { for (const auto& p : field.GetMap()) {
@ -639,24 +705,31 @@ class PROTOBUF_EXPORT DynamicMapField final
DynamicMapField(const Message* default_entry, Arena* arena); DynamicMapField(const Message* default_entry, Arena* arena);
DynamicMapField(const DynamicMapField&) = delete; DynamicMapField(const DynamicMapField&) = delete;
DynamicMapField& operator=(const DynamicMapField&) = delete; DynamicMapField& operator=(const DynamicMapField&) = delete;
virtual ~DynamicMapField(); ~DynamicMapField();
// Implement MapFieldBase
bool InsertOrLookupMapValueNoSync(const MapKey& map_key,
MapValueRef* val) final;
void MergeFrom(const MapFieldBase& other) final;
void UnsafeShallowSwap(MapFieldBase* other) final { Swap(other); }
void ClearMapNoSync() final;
private: private:
friend class MapFieldBase;
const Message* default_entry_; const Message* default_entry_;
static const VTable kVTable;
void AllocateMapValue(MapValueRef* map_val); void AllocateMapValue(MapValueRef* map_val);
// Implements MapFieldBase static void MergeFromImpl(MapFieldBase& base, const MapFieldBase& other);
const Message* GetPrototype() const final; static bool InsertOrLookupMapValueNoSyncImpl(MapFieldBase& base,
size_t SpaceUsedExcludingSelfNoLock() const final; const MapKey& map_key,
MapValueRef* val);
static void ClearMapNoSyncImpl(MapFieldBase& base);
static void UnsafeShallowSwapImpl(MapFieldBase& lhs, MapFieldBase& rhs) {
static_cast<DynamicMapField&>(lhs).Swap(
static_cast<DynamicMapField*>(&rhs));
}
static size_t SpaceUsedExcludingSelfNoLockImpl(const MapFieldBase& map);
static const Message* GetPrototypeImpl(const MapFieldBase& map);
}; };
} // namespace internal } // namespace internal

@ -8,6 +8,7 @@
#ifndef GOOGLE_PROTOBUF_MAP_FIELD_INL_H__ #ifndef GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
#define GOOGLE_PROTOBUF_MAP_FIELD_INL_H__ #define GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
#include <cstddef>
#include <memory> #include <memory>
#include <string> #include <string>
#include <tuple> #include <tuple>
@ -17,6 +18,7 @@
#include "google/protobuf/map.h" #include "google/protobuf/map.h"
#include "google/protobuf/map_field.h" #include "google/protobuf/map_field.h"
#include "google/protobuf/map_type_handler.h" #include "google/protobuf/map_type_handler.h"
#include "google/protobuf/message.h"
#include "google/protobuf/port.h" #include "google/protobuf/port.h"
// must be last // must be last
@ -86,8 +88,8 @@ inline void SetMapKey(MapKey* map_key, const MapKey& value) {
// ------------------------TypeDefinedMapFieldBase--------------- // ------------------------TypeDefinedMapFieldBase---------------
template <typename Key, typename T> template <typename Key, typename T>
void TypeDefinedMapFieldBase<Key, T>::SetMapIteratorValue( void TypeDefinedMapFieldBase<Key, T>::SetMapIteratorValueImpl(
MapIterator* map_iter) const { MapIterator* map_iter) {
if (map_iter->iter_.Equals(UntypedMapBase::EndIterator())) return; if (map_iter->iter_.Equals(UntypedMapBase::EndIterator())) return;
auto iter = typename Map<Key, T>::const_iterator(map_iter->iter_); auto iter = typename Map<Key, T>::const_iterator(map_iter->iter_);
SetMapKey(&map_iter->key_, iter->first); SetMapKey(&map_iter->key_, iter->first);
@ -95,56 +97,60 @@ void TypeDefinedMapFieldBase<Key, T>::SetMapIteratorValue(
} }
template <typename Key, typename T> template <typename Key, typename T>
bool TypeDefinedMapFieldBase<Key, T>::ContainsMapKey( bool TypeDefinedMapFieldBase<Key, T>::InsertOrLookupMapValueNoSyncImpl(
const MapKey& map_key) const { MapFieldBase& map, const MapKey& map_key, MapValueRef* val) {
return GetMap().contains(UnwrapMapKey<Key>(map_key)); auto res = static_cast<TypeDefinedMapFieldBase&>(map).map_.try_emplace(
} UnwrapMapKey<Key>(map_key));
template <typename Key, typename T>
bool TypeDefinedMapFieldBase<Key, T>::InsertOrLookupMapValueNoSync(
const MapKey& map_key, MapValueRef* val) {
auto res = map_.try_emplace(UnwrapMapKey<Key>(map_key));
val->SetValue(&res.first->second); val->SetValue(&res.first->second);
return res.second; return res.second;
} }
template <typename Key, typename T> template <typename Key, typename T>
bool TypeDefinedMapFieldBase<Key, T>::LookupMapValue( bool TypeDefinedMapFieldBase<Key, T>::LookupMapValueImpl(
const MapKey& map_key, MapValueConstRef* val) const { const MapFieldBase& self, const MapKey& map_key, MapValueConstRef* val) {
const auto& map = GetMap(); const auto& map = static_cast<const TypeDefinedMapFieldBase&>(self).GetMap();
auto iter = map.find(UnwrapMapKey<Key>(map_key)); auto iter = map.find(UnwrapMapKey<Key>(map_key));
if (map.end() == iter) { if (map.end() == iter) {
return false; return false;
} }
val->SetValueOrCopy(&iter->second); if (val != nullptr) {
val->SetValueOrCopy(&iter->second);
}
return true; return true;
} }
template <typename Key, typename T> template <typename Key, typename T>
bool TypeDefinedMapFieldBase<Key, T>::DeleteMapValue(const MapKey& map_key) { bool TypeDefinedMapFieldBase<Key, T>::DeleteMapValueImpl(
return MutableMap()->erase(UnwrapMapKey<Key>(map_key)); MapFieldBase& map, const MapKey& map_key) {
return static_cast<TypeDefinedMapFieldBase&>(map).MutableMap()->erase(
UnwrapMapKey<Key>(map_key));
} }
template <typename Key, typename T> template <typename Key, typename T>
void TypeDefinedMapFieldBase<Key, T>::Swap(MapFieldBase* other) { void TypeDefinedMapFieldBase<Key, T>::SwapImpl(MapFieldBase& lhs,
MapFieldBase::Swap(other); MapFieldBase& rhs) {
auto* other_field = DownCast<TypeDefinedMapFieldBase*>(other); MapFieldBase::SwapImpl(lhs, rhs);
map_.swap(other_field->map_); static_cast<TypeDefinedMapFieldBase&>(lhs).map_.swap(
static_cast<TypeDefinedMapFieldBase&>(rhs).map_);
} }
template <typename Key, typename T> template <typename Key, typename T>
void TypeDefinedMapFieldBase<Key, T>::MergeFrom(const MapFieldBase& other) { void TypeDefinedMapFieldBase<Key, T>::MergeFromImpl(MapFieldBase& base,
SyncMapWithRepeatedField(); const MapFieldBase& other) {
auto& self = static_cast<TypeDefinedMapFieldBase&>(base);
self.SyncMapWithRepeatedField();
const auto& other_field = static_cast<const TypeDefinedMapFieldBase&>(other); const auto& other_field = static_cast<const TypeDefinedMapFieldBase&>(other);
other_field.SyncMapWithRepeatedField(); other_field.SyncMapWithRepeatedField();
internal::MapMergeFrom(map_, other_field.map_); internal::MapMergeFrom(self.map_, other_field.map_);
SetMapDirty(); self.SetMapDirty();
} }
template <typename Key, typename T> template <typename Key, typename T>
size_t TypeDefinedMapFieldBase<Key, T>::SpaceUsedExcludingSelfNoLock() const { size_t TypeDefinedMapFieldBase<Key, T>::SpaceUsedExcludingSelfNoLockImpl(
const MapFieldBase& map) {
auto& self = static_cast<const TypeDefinedMapFieldBase&>(map);
size_t size = 0; size_t size = 0;
if (auto* p = maybe_payload()) { if (auto* p = self.maybe_payload()) {
size += p->repeated_field.SpaceUsedExcludingSelfLong(); size += p->repeated_field.SpaceUsedExcludingSelfLong();
} }
// We can't compile this expression for DynamicMapField even though it is // We can't compile this expression for DynamicMapField even though it is
@ -152,14 +158,15 @@ size_t TypeDefinedMapFieldBase<Key, T>::SpaceUsedExcludingSelfNoLock() const {
std::get<std::is_same<Map<Key, T>, Map<MapKey, MapValueRef>>::value>( std::get<std::is_same<Map<Key, T>, Map<MapKey, MapValueRef>>::value>(
std::make_tuple( std::make_tuple(
[&](const auto& map) { size += map.SpaceUsedExcludingSelfLong(); }, [&](const auto& map) { size += map.SpaceUsedExcludingSelfLong(); },
[](const auto&) {}))(map_); [](const auto&) {}))(self.map_);
return size; return size;
} }
template <typename Key, typename T> template <typename Key, typename T>
void TypeDefinedMapFieldBase<Key, T>::UnsafeShallowSwap(MapFieldBase* other) { void TypeDefinedMapFieldBase<Key, T>::UnsafeShallowSwapImpl(MapFieldBase& lhs,
InternalSwap(DownCast<TypeDefinedMapFieldBase*>(other)); MapFieldBase& rhs) {
static_cast<TypeDefinedMapFieldBase&>(lhs).InternalSwap(
static_cast<TypeDefinedMapFieldBase*>(&rhs));
} }
template <typename Key, typename T> template <typename Key, typename T>
@ -174,8 +181,9 @@ void TypeDefinedMapFieldBase<Key, T>::InternalSwap(
template <typename Derived, typename Key, typename T, template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType, WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType> WireFormatLite::FieldType kValueFieldType>
const Message* MapField<Derived, Key, T, kKeyFieldType, const Message*
kValueFieldType>::GetPrototype() const { MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::GetPrototypeImpl(
const MapFieldBase&) {
return Derived::internal_default_instance(); return Derived::internal_default_instance();
} }

@ -5,6 +5,7 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // https://developers.google.com/open-source/licenses/bsd
#include <cstdint>
#include <memory> #include <memory>
#include <gmock/gmock.h> #include <gmock/gmock.h>
@ -24,6 +25,7 @@
#include "google/protobuf/message.h" #include "google/protobuf/message.h"
#include "google/protobuf/repeated_field.h" #include "google/protobuf/repeated_field.h"
#include "google/protobuf/unittest.pb.h" #include "google/protobuf/unittest.pb.h"
#include "google/protobuf/wire_format_lite.h"
// Must be included last. // Must be included last.
#include "google/protobuf/port_def.inc" #include "google/protobuf/port_def.inc"
@ -35,28 +37,19 @@ namespace internal {
using unittest::TestAllTypes; using unittest::TestAllTypes;
class MapFieldBaseStub : public TypeDefinedMapFieldBase<int32_t, int32_t> { struct MapFieldTestPeer {
public: static auto GetArena(const RepeatedPtrFieldBase& v) { return v.GetArena(); }
using InternalArenaConstructable_ = void; template <typename T>
typedef void DestructorSkippable_; static auto& GetMap(T& t) {
MapFieldBaseStub() {} return t.map_;
virtual ~MapFieldBaseStub() {}
explicit MapFieldBaseStub(Arena* arena)
: MapFieldBaseStub::TypeDefinedMapFieldBase(arena) {}
const Message* GetPrototype() const override {
return unittest::TestMap_MapInt32Int32Entry_DoNotUse::
internal_default_instance();
} }
Arena* GetArenaForInternalRepeatedField() {
auto* repeated_field = MutableRepeatedField();
return repeated_field->GetArena();
}
using MapFieldBaseStub::TypeDefinedMapFieldBase::map_;
}; };
using TestMapField = ::google::protobuf::internal::MapField<
unittest::TestMap_MapInt32Int32Entry_DoNotUse, ::int32_t, ::int32_t,
::google::protobuf::internal::WireFormatLite::TYPE_INT32,
::google::protobuf::internal::WireFormatLite::TYPE_INT32>;
class MapFieldBasePrimitiveTest : public testing::TestWithParam<bool> { class MapFieldBasePrimitiveTest : public testing::TestWithParam<bool> {
protected: protected:
typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType; typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
@ -156,20 +149,20 @@ TEST_P(MapFieldBasePrimitiveTest, Arena) {
// repeated fields are allocated from arenas. // repeated fields are allocated from arenas.
// NoHeapChecker no_heap; // NoHeapChecker no_heap;
MapFieldBaseStub* map_field = TestMapField* map_field = Arena::CreateMessage<TestMapField>(&arena);
Arena::CreateMessage<MapFieldBaseStub>(&arena);
// Trigger conversion to repeated field. // Trigger conversion to repeated field.
EXPECT_TRUE(map_field->MutableRepeatedField() != nullptr); EXPECT_TRUE(map_field->MutableRepeatedField() != nullptr);
EXPECT_EQ(map_field->GetArenaForInternalRepeatedField(), &arena); EXPECT_EQ(MapFieldTestPeer::GetArena(map_field->GetRepeatedField()),
&arena);
} }
} }
TEST_P(MapFieldBasePrimitiveTest, EnforceNoArena) { TEST_P(MapFieldBasePrimitiveTest, EnforceNoArena) {
std::unique_ptr<MapFieldBaseStub> map_field( std::unique_ptr<TestMapField> map_field(
Arena::CreateMessage<MapFieldBaseStub>(nullptr)); Arena::CreateMessage<TestMapField>(nullptr));
EXPECT_EQ(map_field->GetArenaForInternalRepeatedField(), nullptr); EXPECT_EQ(MapFieldTestPeer::GetArena(map_field->GetRepeatedField()), nullptr);
} }
namespace { namespace {

@ -662,7 +662,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// reinterpreting pointers as being to Message instead of a specific Message // reinterpreting pointers as being to Message instead of a specific Message
// subclass. // subclass.
friend class MapFieldBase; friend class MapFieldBase;
friend class MapFieldBaseStub; friend struct MapFieldTestPeer;
// The table-driven MergePartialFromCodedStream implementation needs to // The table-driven MergePartialFromCodedStream implementation needs to
// operate on RepeatedPtrField<MessageLite>. // operate on RepeatedPtrField<MessageLite>.

Loading…
Cancel
Save