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.
class MapFieldBaseForParse {
public:
const UntypedMapBase& GetMap() const { return GetMapImpl(false); }
const UntypedMapBase& GetMap() const {
return vtable_->get_map(*this, false);
}
UntypedMapBase* MutableMap() {
return &const_cast<UntypedMapBase&>(GetMapImpl(true));
return &const_cast<UntypedMapBase&>(vtable_->get_map(*this, true));
}
protected:
struct VTable {
const UntypedMapBase& (*get_map)(const MapFieldBaseForParse&,
bool is_mutable);
};
explicit constexpr MapFieldBaseForParse(const VTable* vtable)
: vtable_(vtable) {}
~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.

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

@ -18,6 +18,7 @@
#include "google/protobuf/generated_message_reflection.h"
#include "google/protobuf/generated_message_util.h"
#include "google/protobuf/internal_visibility.h"
#include "google/protobuf/map.h"
#include "google/protobuf/map_entry.h"
#include "google/protobuf/map_field_lite.h"
#include "google/protobuf/map_type_handler.h"
@ -295,8 +296,10 @@ class MapFieldAccessor;
// reflection implementation only. Users should never use this directly.
class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
public:
constexpr MapFieldBase() {}
explicit MapFieldBase(Arena* arena) : payload_{ToTaggedPtr(arena)} {}
explicit constexpr MapFieldBase(const VTable* vtable)
: MapFieldBaseForParse(vtable) {}
explicit MapFieldBase(const VTable* vtable, Arena* arena)
: MapFieldBaseForParse(vtable), payload_{ToTaggedPtr(arena)} {}
MapFieldBase(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 *`
~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:
// Returns reference to internal repeated field. Data written using
// 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.
RepeatedPtrFieldBase* MutableRepeatedField();
// Pure virtual map APIs for Map Reflection.
virtual bool ContainsMapKey(const MapKey& map_key) const = 0;
virtual bool LookupMapValue(const MapKey& map_key,
MapValueConstRef* val) const = 0;
const VTable* vtable() const { return static_cast<const VTable*>(vtable_); }
bool ContainsMapKey(const MapKey& map_key) const {
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 InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val);
@ -325,19 +365,26 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
bool IsRepeatedFieldValid() const;
// Insures operations after won't get executed before calling this.
bool IsMapValid() const;
virtual bool DeleteMapValue(const MapKey& map_key) = 0;
virtual void MergeFrom(const MapFieldBase& other) = 0;
virtual void Swap(MapFieldBase* other);
virtual void UnsafeShallowSwap(MapFieldBase* other);
bool DeleteMapValue(const MapKey& map_key) {
return vtable()->delete_map_value(*this, map_key);
}
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.
int size() const;
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 MapEnd(MapIterator* map_iter) 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
// sizeof(*this)
@ -349,10 +396,12 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
protected:
// 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;
virtual void ClearMapNoSync() = 0;
const Message* GetPrototype() const { return vtable()->get_prototype(*this); }
void ClearMapNoSync() { return vtable()->clear_map_no_sync(*this); }
// Synchronizes the content in Map to RepeatedPtrField if there is any change
// to Map after last synchronization.
@ -364,6 +413,9 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
void SyncMapWithRepeatedField() const;
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.
void SetMapDirty();
@ -373,8 +425,9 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
// Provides derived class the access to repeated field.
void* MutableRepeatedPtrField() const;
virtual bool InsertOrLookupMapValueNoSync(const MapKey& map_key,
MapValueRef* val) = 0;
bool InsertOrLookupMapValueNoSync(const MapKey& map_key, MapValueRef* val) {
return vtable()->insert_or_lookup_no_sync(*this, map_key, val);
}
void InternalSwap(MapFieldBase* other);
@ -439,6 +492,9 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
: STATE_MODIFIED_MAP;
}
static const UntypedMapBase& GetMapImpl(const MapFieldBaseForParse& map,
bool is_mutable);
private:
friend class ContendedMapCleanTest;
friend class GeneratedMessageReflection;
@ -501,7 +557,8 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
template <typename Key, typename T>
class TypeDefinedMapFieldBase : public MapFieldBase {
public:
constexpr TypeDefinedMapFieldBase() : map_() {
explicit constexpr TypeDefinedMapFieldBase(const VTable* vtable)
: MapFieldBase(vtable), map_() {
// This invariant is required by MapFieldBase to easily access the map
// member without paying for dynamic dispatch. It reduces code size.
static_assert(PROTOBUF_FIELD_OFFSET(TypeDefinedMapFieldBase, map_) ==
@ -511,10 +568,8 @@ class TypeDefinedMapFieldBase : public MapFieldBase {
TypeDefinedMapFieldBase(const TypeDefinedMapFieldBase&) = delete;
TypeDefinedMapFieldBase& operator=(const TypeDefinedMapFieldBase&) = delete;
explicit TypeDefinedMapFieldBase(Arena* arena)
: MapFieldBase(arena), map_(arena) {}
TypeDefinedMapFieldBase(ArenaInitialized, Arena* arena)
: TypeDefinedMapFieldBase(arena) {}
TypeDefinedMapFieldBase(const VTable* vtable, Arena* arena)
: MapFieldBase(vtable, arena), map_(arena) {}
protected:
~TypeDefinedMapFieldBase() { map_.~Map(); }
@ -535,33 +590,36 @@ class TypeDefinedMapFieldBase : public MapFieldBase {
return &map_;
}
void ClearMapNoSync() override { map_.clear(); }
static void ClearMapNoSyncImpl(MapFieldBase& map) {
static_cast<TypeDefinedMapFieldBase&>(map).map_.clear();
}
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:
friend struct MapFieldTestPeer;
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
// destruction
union {
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
@ -584,19 +642,18 @@ class MapField final : public TypeDefinedMapFieldBase<Key, T> {
static constexpr WireFormatLite::FieldType kKeyFieldType = kKeyFieldType_;
static constexpr WireFormatLite::FieldType kValueFieldType = kValueFieldType_;
constexpr MapField() {}
constexpr MapField() : MapField::TypeDefinedMapFieldBase(&kVTable) {}
MapField(const MapField&) = delete;
MapField& operator=(const MapField&) = delete;
~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(InternalVisibility, Arena* arena)
: TypeDefinedMapFieldBase<Key, T>(arena) {}
MapField(InternalVisibility, Arena* arena) : MapField(arena) {}
MapField(InternalVisibility, Arena* arena, const MapField& from)
: TypeDefinedMapFieldBase<Key, T>(arena) {
TypeDefinedMapFieldBase<Key, T>::MergeFrom(from);
: MapField(arena) {
this->MergeFromImpl(*this, from);
}
// 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 DestructorSkippable_;
// Implements MapFieldBase
const Message* GetPrototype() const final;
static const Message* GetPrototypeImpl(const MapFieldBase& map);
static const MapFieldBase::VTable kVTable;
friend class google::protobuf::Arena;
friend class MapFieldBase;
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>
bool AllAreInitialized(const TypeDefinedMapFieldBase<Key, T>& field) {
for (const auto& p : field.GetMap()) {
@ -639,24 +705,31 @@ class PROTOBUF_EXPORT DynamicMapField final
DynamicMapField(const Message* default_entry, Arena* arena);
DynamicMapField(const DynamicMapField&) = delete;
DynamicMapField& operator=(const DynamicMapField&) = delete;
virtual ~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;
~DynamicMapField();
private:
friend class MapFieldBase;
const Message* default_entry_;
static const VTable kVTable;
void AllocateMapValue(MapValueRef* map_val);
// Implements MapFieldBase
const Message* GetPrototype() const final;
size_t SpaceUsedExcludingSelfNoLock() const final;
static void MergeFromImpl(MapFieldBase& base, const MapFieldBase& other);
static bool InsertOrLookupMapValueNoSyncImpl(MapFieldBase& base,
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

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

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

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

Loading…
Cancel
Save