Skip to content

Move part of the TypeDefinedMapFieldBase implementation into MapFieldBase #19730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/google/protobuf/dynamic_message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,9 @@ class DynamicMapField final
static void ClearMapNoSyncImpl(MapFieldBase& base);
static bool DeleteMapValueImpl(MapFieldBase& map, const MapKey& map_key);
static void SetMapIteratorValueImpl(MapIterator* map_iter);
static bool LookupMapValueImpl(const MapFieldBase& self,
const MapKey& map_key, MapValueConstRef* val);
static bool LookupMapValueNoSyncImpl(const MapFieldBase& self,
const MapKey& map_key,
MapValueConstRef* val);

static void UnsafeShallowSwapImpl(MapFieldBase& lhs, MapFieldBase& rhs) {
static_cast<DynamicMapField&>(lhs).Swap(
Expand Down Expand Up @@ -278,10 +279,10 @@ void DynamicMapField::SetMapIteratorValueImpl(MapIterator* map_iter) {
map_iter->value_.CopyFrom(iter->second);
}

bool DynamicMapField::LookupMapValueImpl(const MapFieldBase& self,
const MapKey& map_key,
MapValueConstRef* val) {
const auto& map = static_cast<const DynamicMapField&>(self).GetMap();
bool DynamicMapField::LookupMapValueNoSyncImpl(const MapFieldBase& self,
const MapKey& map_key,
MapValueConstRef* val) {
const auto& map = static_cast<const DynamicMapField&>(self).map_;
auto iter = map.find(map_key);
if (map.end() == iter) {
return false;
Expand Down
4 changes: 4 additions & 0 deletions src/google/protobuf/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,10 @@ class KeyMapBase : public UntypedMapBase {
friend class RustMapHelper;
friend class v2::TableDriven;

Key* GetKey(NodeBase* node) const {
return UntypedMapBase::GetKey<Key>(node);
}

PROTOBUF_NOINLINE size_type EraseImpl(map_index_t b, KeyNode* node,
bool do_destroy) {
// Force bucket_index to be in range.
Expand Down
94 changes: 67 additions & 27 deletions src/google/protobuf/map_field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <cstddef>
#include <cstdint>
#include <string>
#include <type_traits>

#include "absl/functional/overload.h"
#include "absl/log/absl_check.h"
Expand All @@ -35,6 +36,58 @@ MapFieldBase::~MapFieldBase() {
delete maybe_payload();
}

template <typename Map, typename F>
auto VisitMapKey(const MapKey& map_key, Map& map, F f) {
switch (map_key.type()) {
#define HANDLE_TYPE(CPPTYPE, Type, KeyBaseType) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
using KMB = KeyMapBase<KeyBaseType>; \
return f( \
static_cast< \
std::conditional_t<std::is_const_v<Map>, const KMB&, KMB&>>(map), \
TransparentSupport<KeyBaseType>::ToView(map_key.Get##Type##Value())); \
}
HANDLE_TYPE(INT32, Int32, uint32_t);
HANDLE_TYPE(UINT32, UInt32, uint32_t);
HANDLE_TYPE(INT64, Int64, uint64_t);
HANDLE_TYPE(UINT64, UInt64, uint64_t);
HANDLE_TYPE(BOOL, Bool, bool);
HANDLE_TYPE(STRING, String, std::string);
#undef HANDLE_TYPE
default:
Unreachable();
}
}

bool MapFieldBase::InsertOrLookupMapValueNoSyncImpl(MapFieldBase& self,
const MapKey& map_key,
MapValueRef* val) {
if (LookupMapValueNoSyncImpl(self, map_key,
static_cast<MapValueConstRef*>(val))) {
return false;
}

auto& map = self.GetMapRaw();

NodeBase* node = map.AllocNode();
map.VisitValue(node, [&](auto* v) { self.InitializeKeyValue(v); });
val->SetValue(map.GetVoidValue(node));

return VisitMapKey(map_key, map, [&](auto& map, const auto& key) {
self.InitializeKeyValue(map.GetKey(node), key);
map.InsertOrReplaceNode(
static_cast<typename std::decay_t<decltype(map)>::KeyNode*>(node));
return true;
});
}

bool MapFieldBase::DeleteMapValueImpl(MapFieldBase& self,
const MapKey& map_key) {
return VisitMapKey(
map_key, *self.MutableMap(),
[](auto& map, const auto& key) { return map.EraseImpl(key); });
}

void MapFieldBase::ClearMapNoSyncImpl(MapFieldBase& self) {
self.GetMapRaw().ClearTable(true, nullptr);
}
Expand All @@ -56,35 +109,22 @@ void MapFieldBase::SetMapIteratorValueImpl(MapIterator* map_iter) {
map_iter->value_.SetValue(map.GetVoidValue(node));
}

bool MapFieldBase::LookupMapValueImpl(const MapFieldBase& self,
const MapKey& map_key,
MapValueConstRef* val) {
auto& map = self.GetMap();
bool MapFieldBase::LookupMapValueNoSyncImpl(const MapFieldBase& self,
const MapKey& map_key,
MapValueConstRef* val) {
auto& map = self.GetMapRaw();
if (map.empty()) return false;

switch (map_key.type()) {
#define HANDLE_TYPE(CPPTYPE, Type, KeyBaseType) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
auto& key_map = static_cast<const KeyMapBase<KeyBaseType>&>(map); \
auto res = key_map.FindHelper(map_key.Get##Type##Value()); \
if (res.node == nullptr) { \
return false; \
} \
if (val != nullptr) { \
val->SetValue(map.GetVoidValue(res.node)); \
} \
return true; \
}
HANDLE_TYPE(INT32, Int32, uint32_t);
HANDLE_TYPE(UINT32, UInt32, uint32_t);
HANDLE_TYPE(INT64, Int64, uint64_t);
HANDLE_TYPE(UINT64, UInt64, uint64_t);
HANDLE_TYPE(BOOL, Bool, bool);
HANDLE_TYPE(STRING, String, std::string);
#undef HANDLE_TYPE
default:
Unreachable();
}
return VisitMapKey(map_key, map, [&](auto& map, const auto& key) {
auto res = map.FindHelper(key);
if (res.node == nullptr) {
return false;
}
if (val != nullptr) {
val->SetValue(map.GetVoidValue(res.node));
}
return true;
});
}

size_t MapFieldBase::SpaceUsedExcludingSelfNoLockImpl(const MapFieldBase& map) {
Expand Down
47 changes: 36 additions & 11 deletions src/google/protobuf/map_field.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ template <typename MessageT>
struct MapDynamicFieldInfo;
struct MapFieldTestPeer;

// Return the prototype message for a Map entry.
// REQUIRES: `default_entry` is a map entry message.
// REQUIRES: mapped_type is of type message.
inline const Message& GetMapEntryValuePrototype(const Message& default_entry) {
return default_entry.GetReflection()->GetMessage(
default_entry, default_entry.GetDescriptor()->map_value());
}

// This class provides access to map field using reflection, which is the same
// as those provided for RepeatedPtrField<Message>. It is used for internal
// reflection implementation only. Users should never use this directly.
Expand All @@ -302,8 +310,9 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
~MapFieldBase();

struct VTable : MapFieldBaseForParse::VTable {
bool (*lookup_map_value)(const MapFieldBase& map, const MapKey& map_key,
MapValueConstRef* val);
bool (*lookup_map_value_no_sync)(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,
Expand All @@ -321,7 +330,7 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
static constexpr VTable MakeVTable() {
VTable out{};
out.get_map = &T::GetMapImpl;
out.lookup_map_value = &T::LookupMapValueImpl;
out.lookup_map_value_no_sync = &T::LookupMapValueNoSyncImpl;
out.delete_map_value = &T::DeleteMapValueImpl;
out.set_map_iterator_value = &T::SetMapIteratorValueImpl;
out.insert_or_lookup_no_sync = &T::InsertOrLookupMapValueNoSyncImpl;
Expand Down Expand Up @@ -349,7 +358,8 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
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);
SyncMapWithRepeatedField();
return vtable()->lookup_map_value_no_sync(*this, map_key, val);
}
bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;

Expand Down Expand Up @@ -503,8 +513,13 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
bool is_mutable);
static void ClearMapNoSyncImpl(MapFieldBase& self);
static void SetMapIteratorValueImpl(MapIterator* map_iter);
static bool LookupMapValueImpl(const MapFieldBase& self,
const MapKey& map_key, MapValueConstRef* val);
static bool LookupMapValueNoSyncImpl(const MapFieldBase& self,
const MapKey& map_key,
MapValueConstRef* val);
static bool InsertOrLookupMapValueNoSyncImpl(MapFieldBase& self,
const MapKey& map_key,
MapValueRef* val);
static bool DeleteMapValueImpl(MapFieldBase& self, const MapKey& map_key);

private:
friend class ContendedMapCleanTest;
Expand All @@ -513,6 +528,21 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
friend class google::protobuf::Reflection;
friend class google::protobuf::DynamicMessage;

template <typename T, typename... U>
void InitializeKeyValue(T* v, const U&... init) {
::new (static_cast<void*>(v)) T(init...);
if constexpr (std::is_same_v<std::string, T>) {
if (arena() != nullptr) {
arena()->OwnDestructor(v);
}
}
}

void InitializeKeyValue(MessageLite* msg) {
GetClassData(GetMapEntryValuePrototype(*GetPrototype()))
->PlacementNew(msg, arena());
}

// See assertion in TypeDefinedMapFieldBase::TypeDefinedMapFieldBase()
const UntypedMapBase& GetMapRaw() const {
return *reinterpret_cast<const UntypedMapBase*>(this + 1);
Expand Down Expand Up @@ -614,11 +644,6 @@ class TypeDefinedMapFieldBase : public MapFieldBase {

using Iter = typename Map<Key, T>::const_iterator;

static bool DeleteMapValueImpl(MapFieldBase& map, const MapKey& map_key);
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);
Expand Down
44 changes: 0 additions & 44 deletions src/google/protobuf/map_field_inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,51 +33,7 @@
namespace google {
namespace protobuf {
namespace internal {
// UnwrapMapKey template. We're using overloading rather than template
// specialization so that we can return a value or reference type depending on
// `T`.
inline int32_t UnwrapMapKeyImpl(const MapKey& map_key, const int32_t*) {
return map_key.GetInt32Value();
}
inline uint32_t UnwrapMapKeyImpl(const MapKey& map_key, const uint32_t*) {
return map_key.GetUInt32Value();
}
inline int64_t UnwrapMapKeyImpl(const MapKey& map_key, const int64_t*) {
return map_key.GetInt64Value();
}
inline uint64_t UnwrapMapKeyImpl(const MapKey& map_key, const uint64_t*) {
return map_key.GetUInt64Value();
}
inline bool UnwrapMapKeyImpl(const MapKey& map_key, const bool*) {
return map_key.GetBoolValue();
}
inline absl::string_view UnwrapMapKeyImpl(const MapKey& map_key,
const std::string*) {
return map_key.GetStringValue();
}

template <typename T>
decltype(auto) UnwrapMapKey(const MapKey& map_key) {
return UnwrapMapKeyImpl(map_key, static_cast<T*>(nullptr));
}

// ------------------------TypeDefinedMapFieldBase---------------
template <typename Key, typename T>
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>::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>::SwapImpl(MapFieldBase& lhs,
MapFieldBase& rhs) {
Expand Down
Loading