diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index 30481dbd64..29b9bc1d16 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.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. diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc index 76d065baef..0d70c65301 100644 --- a/src/google/protobuf/map_field.cc +++ b/src/google/protobuf/map_field.cc @@ -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; diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 86f1eeee29..8aa9e45fe3 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -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 diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index 6a1fc8a6fe..499d8ed2ec 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -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(); } diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc index eed1f216bf..8ef859eff5 100644 --- a/src/google/protobuf/map_field_test.cc +++ b/src/google/protobuf/map_field_test.cc @@ -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 { diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h index fcc3186b6c..51c8065685 100644 --- a/src/google/protobuf/repeated_ptr_field.h +++ b/src/google/protobuf/repeated_ptr_field.h @@ -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>.