File indexing completed on 2026-08-23 09:12:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef GOOGLE_PROTOBUF_MAP_H__
0015 #define GOOGLE_PROTOBUF_MAP_H__
0016
0017 #include <algorithm>
0018 #include <atomic>
0019 #include <cstddef>
0020 #include <cstdint>
0021 #include <cstring>
0022 #include <functional>
0023 #include <initializer_list>
0024 #include <iterator>
0025 #include <limits> // To support Visual Studio 2008
0026 #include <new> // IWYU pragma: keep for ::operator new.
0027 #include <string>
0028 #include <type_traits>
0029 #include <utility>
0030
0031 #include "absl/base/attributes.h"
0032 #include "absl/base/optimization.h"
0033 #include "absl/base/prefetch.h"
0034 #include "absl/container/btree_map.h"
0035 #include "absl/hash/hash.h"
0036 #include "absl/log/absl_check.h"
0037 #include "absl/meta/type_traits.h"
0038 #include "absl/numeric/bits.h"
0039 #include "absl/strings/string_view.h"
0040 #include "google/protobuf/arena.h"
0041 #include "google/protobuf/generated_enum_util.h"
0042 #include "google/protobuf/internal_visibility.h"
0043 #include "google/protobuf/message_lite.h"
0044 #include "google/protobuf/port.h"
0045 #include "google/protobuf/wire_format_lite.h"
0046
0047
0048 #ifdef SWIG
0049 #error "You cannot SWIG proto headers"
0050 #endif
0051
0052
0053 #include "google/protobuf/port_def.inc"
0054
0055 namespace google {
0056 namespace protobuf {
0057
0058 template <typename Key, typename T>
0059 class Map;
0060
0061 class MapIterator;
0062
0063 template <typename Enum>
0064 struct is_proto_enum;
0065
0066 namespace rust {
0067 struct PtrAndLen;
0068 }
0069
0070 namespace internal {
0071 namespace v2 {
0072 class TableDrivenMessage;
0073 }
0074
0075 template <typename Key, typename T>
0076 class MapFieldLite;
0077 class MapFieldBase;
0078
0079 template <typename Derived, typename Key, typename T,
0080 WireFormatLite::FieldType key_wire_type,
0081 WireFormatLite::FieldType value_wire_type>
0082 class MapField;
0083
0084 struct MapTestPeer;
0085 struct MapBenchmarkPeer;
0086
0087 template <typename Key, typename T>
0088 class TypeDefinedMapFieldBase;
0089
0090 class GeneratedMessageReflection;
0091
0092
0093
0094 using map_index_t = uint32_t;
0095
0096
0097
0098 template <typename T, typename VoidT = void>
0099 struct is_internal_map_key_type : std::false_type {};
0100
0101 template <typename T, typename VoidT = void>
0102 struct is_internal_map_value_type : std::false_type {};
0103
0104
0105
0106 template <typename T, typename = void>
0107 struct KeyForBaseImpl {
0108 using type = T;
0109 };
0110 template <typename T>
0111 struct KeyForBaseImpl<T, std::enable_if_t<std::is_integral<T>::value &&
0112 std::is_signed<T>::value>> {
0113 using type = std::make_unsigned_t<T>;
0114 };
0115 template <typename T>
0116 using KeyForBase = typename KeyForBaseImpl<T>::type;
0117
0118
0119
0120
0121 template <typename key_type>
0122 struct TransparentSupport {
0123 static_assert(std::is_scalar<key_type>::value,
0124 "Should only be used for ints.");
0125
0126 template <typename K>
0127 using key_arg = key_type;
0128
0129 using ViewType = key_type;
0130
0131 static key_type ToView(key_type v) { return v; }
0132 };
0133
0134
0135
0136
0137
0138 template <>
0139 struct TransparentSupport<std::string> {
0140 template <typename T>
0141 static absl::string_view ImplicitConvert(T&& str) {
0142 if constexpr (std::is_convertible<T, absl::string_view>::value) {
0143 absl::string_view res = str;
0144 return res;
0145 } else if constexpr (std::is_convertible<T, const std::string&>::value) {
0146 const std::string& ref = str;
0147 return ref;
0148 } else {
0149 return {str.data(), str.size()};
0150 }
0151 }
0152
0153 template <typename K>
0154 using key_arg = K;
0155
0156 using ViewType = absl::string_view;
0157 template <typename T>
0158 static ViewType ToView(const T& v) {
0159 return ImplicitConvert(v);
0160 }
0161 };
0162
0163 struct NodeBase {
0164
0165
0166
0167 alignas(kMaxMessageAlignment) NodeBase* next;
0168
0169 void* GetVoidKey() { return this + 1; }
0170 const void* GetVoidKey() const { return this + 1; }
0171 };
0172
0173 constexpr size_t kGlobalEmptyTableSize = 1;
0174 PROTOBUF_EXPORT extern NodeBase* const kGlobalEmptyTable[kGlobalEmptyTableSize];
0175
0176 class UntypedMapBase;
0177
0178 class UntypedMapIterator {
0179 public:
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194 bool Equals(const UntypedMapIterator& other) const {
0195 return node_ == other.node_;
0196 }
0197
0198
0199
0200 void PlusPlus();
0201
0202
0203 template <class Iter>
0204 static UntypedMapIterator FromTyped(Iter it) {
0205 static_assert(
0206 #if defined(__cpp_lib_is_layout_compatible) && \
0207 __cpp_lib_is_layout_compatible >= 201907L
0208 std::is_layout_compatible_v<Iter, UntypedMapIterator>,
0209 #else
0210 sizeof(it) == sizeof(UntypedMapIterator),
0211 #endif
0212 "Map iterator must not have extra state that the base class"
0213 "does not define.");
0214 return static_cast<UntypedMapIterator>(it);
0215 }
0216
0217 template <class Iter>
0218 Iter ToTyped() const {
0219 return Iter(*this);
0220 }
0221 NodeBase* node_;
0222 const UntypedMapBase* m_;
0223 map_index_t bucket_index_;
0224 };
0225
0226
0227 static_assert(std::is_trivial<UntypedMapIterator>::value,
0228 "UntypedMapIterator must be a trivial type.");
0229 static_assert(std::is_trivially_copyable<UntypedMapIterator>::value,
0230 "UntypedMapIterator must be trivially copyable.");
0231 static_assert(std::is_trivially_destructible<UntypedMapIterator>::value,
0232 "UntypedMapIterator must be trivially destructible.");
0233 static_assert(std::is_standard_layout<UntypedMapIterator>::value,
0234 "UntypedMapIterator must be standard layout.");
0235 static_assert(offsetof(UntypedMapIterator, node_) == 0,
0236 "node_ must be the first field of UntypedMapIterator.");
0237 static_assert(sizeof(UntypedMapIterator) ==
0238 sizeof(void*) * 2 +
0239 std::max(sizeof(uint32_t), alignof(void*)),
0240 "UntypedMapIterator does not have the expected size for FFI");
0241 static_assert(
0242 alignof(UntypedMapIterator) == std::max(alignof(void*), alignof(uint32_t)),
0243 "UntypedMapIterator does not have the expected alignment for FFI");
0244
0245
0246
0247
0248
0249
0250 class PROTOBUF_EXPORT UntypedMapBase {
0251 public:
0252 using size_type = size_t;
0253
0254
0255
0256 enum class TypeKind : uint8_t {
0257 kBool,
0258 kU32,
0259 kU64,
0260 kFloat,
0261 kDouble,
0262 kString,
0263 kMessage,
0264 };
0265
0266
0267 template <typename T>
0268 static constexpr TypeKind StaticTypeKind() {
0269 if constexpr (std::is_same_v<T, bool>) {
0270 return TypeKind::kBool;
0271 } else if constexpr (std::is_same_v<T, int32_t> ||
0272 std::is_same_v<T, uint32_t> || std::is_enum_v<T>) {
0273 static_assert(sizeof(T) == 4,
0274 "Only enums with the right underlying type are supported.");
0275 return TypeKind::kU32;
0276 } else if constexpr (std::is_same_v<T, int64_t> ||
0277 std::is_same_v<T, uint64_t>) {
0278 return TypeKind::kU64;
0279 } else if constexpr (std::is_same_v<T, float>) {
0280 return TypeKind::kFloat;
0281 } else if constexpr (std::is_same_v<T, double>) {
0282 return TypeKind::kDouble;
0283 } else if constexpr (std::is_same_v<T, std::string>) {
0284 return TypeKind::kString;
0285 } else if constexpr (std::is_base_of_v<MessageLite, T>) {
0286 return TypeKind::kMessage;
0287 } else {
0288 static_assert(false && sizeof(T));
0289 }
0290 }
0291
0292 struct TypeInfo {
0293
0294 uint16_t node_size;
0295
0296 uint8_t value_offset;
0297 uint8_t key_type : 4;
0298 uint8_t value_type : 4;
0299
0300 TypeKind key_type_kind() const { return static_cast<TypeKind>(key_type); }
0301 TypeKind value_type_kind() const {
0302 return static_cast<TypeKind>(value_type);
0303 }
0304 };
0305 static_assert(sizeof(TypeInfo) == 4);
0306
0307 static TypeInfo GetTypeInfoDynamic(
0308 TypeKind key_type, TypeKind value_type,
0309 const MessageLite* value_prototype_if_message);
0310
0311 explicit constexpr UntypedMapBase(Arena* arena, TypeInfo type_info)
0312 : num_elements_(0),
0313 num_buckets_(internal::kGlobalEmptyTableSize),
0314 index_of_first_non_null_(internal::kGlobalEmptyTableSize),
0315 type_info_(type_info),
0316 table_(const_cast<NodeBase**>(internal::kGlobalEmptyTable)),
0317 arena_(arena) {}
0318
0319 UntypedMapBase(const UntypedMapBase&) = delete;
0320 UntypedMapBase& operator=(const UntypedMapBase&) = delete;
0321
0322 template <typename T>
0323 T* GetKey(NodeBase* node) const {
0324
0325 ABSL_DCHECK_EQ(static_cast<int>(StaticTypeKind<T>()),
0326 static_cast<int>(type_info_.key_type));
0327 return reinterpret_cast<T*>(node->GetVoidKey());
0328 }
0329
0330 void* GetVoidValue(NodeBase* node) const {
0331 return reinterpret_cast<char*>(node) + type_info_.value_offset;
0332 }
0333
0334 template <typename T>
0335 T* GetValue(NodeBase* node) const {
0336
0337 ABSL_DCHECK_EQ(static_cast<int>(StaticTypeKind<T>()),
0338 static_cast<int>(type_info_.value_type));
0339 return reinterpret_cast<T*>(GetVoidValue(node));
0340 }
0341
0342 void ClearTable(bool reset) {
0343 if (num_buckets_ == internal::kGlobalEmptyTableSize) return;
0344 ClearTableImpl(reset);
0345 }
0346
0347
0348 size_t SpaceUsedExcludingSelfLong() const;
0349
0350 TypeInfo type_info() const { return type_info_; }
0351
0352 protected:
0353
0354 static constexpr map_index_t kMinTableSize = 16 / sizeof(void*);
0355 static constexpr map_index_t kMaxTableSize = map_index_t{1} << 31;
0356
0357 public:
0358 Arena* arena() const { return arena_; }
0359
0360 void InternalSwap(UntypedMapBase* other) {
0361 std::swap(num_elements_, other->num_elements_);
0362 std::swap(num_buckets_, other->num_buckets_);
0363 std::swap(index_of_first_non_null_, other->index_of_first_non_null_);
0364 std::swap(type_info_, other->type_info_);
0365 std::swap(table_, other->table_);
0366 std::swap(arena_, other->arena_);
0367 }
0368
0369 void UntypedMergeFrom(const UntypedMapBase& other);
0370 void UntypedSwap(UntypedMapBase& other);
0371
0372 static size_type max_size() {
0373 return std::numeric_limits<map_index_t>::max();
0374 }
0375 size_type size() const { return num_elements_; }
0376 bool empty() const { return size() == 0; }
0377 UntypedMapIterator begin() const;
0378
0379
0380
0381 static UntypedMapIterator EndIterator() { return {nullptr, nullptr, 0}; }
0382
0383
0384
0385 template <typename F>
0386 auto VisitKey(NodeBase* node, F f) const;
0387
0388
0389
0390
0391 template <typename F>
0392 auto VisitValue(NodeBase* node, F f) const;
0393
0394
0395 template <typename F>
0396 void VisitAllNodes(F f) const;
0397
0398 protected:
0399 friend class MapFieldBase;
0400 friend class TcParser;
0401 friend struct MapTestPeer;
0402 friend struct MapBenchmarkPeer;
0403 friend class UntypedMapIterator;
0404 friend class RustMapHelper;
0405
0406
0407
0408 template <typename F>
0409 auto VisitKeyType(F f) const;
0410 template <typename F>
0411 auto VisitValueType(F f) const;
0412
0413 struct NodeAndBucket {
0414 NodeBase* node;
0415 map_index_t bucket;
0416 };
0417
0418 void ClearTableImpl(bool reset);
0419
0420
0421
0422
0423
0424 bool ShouldInsertAfterHead(void* node) {
0425 #ifdef NDEBUG
0426 (void)node;
0427 return false;
0428 #else
0429
0430 return absl::HashOf(node, table_) % 13 > 6;
0431 #endif
0432 }
0433
0434
0435 NodeBase* AllocNode() { return AllocNode(type_info_.node_size); }
0436
0437 NodeBase* AllocNode(size_t node_size) {
0438 return static_cast<NodeBase*>(arena_ == nullptr
0439 ? ::operator new(node_size)
0440 : arena_->AllocateAligned(node_size));
0441 }
0442
0443 void DeallocNode(NodeBase* node) { DeallocNode(node, type_info_.node_size); }
0444
0445 void DeallocNode(NodeBase* node, size_t node_size) {
0446 ABSL_DCHECK(arena_ == nullptr);
0447 internal::SizedDelete(node, node_size);
0448 }
0449
0450 void DeleteTable(NodeBase** table, map_index_t n) {
0451 if (auto* a = arena()) {
0452 a->ReturnArrayMemory(table, n * sizeof(NodeBase*));
0453 } else {
0454 internal::SizedDelete(table, n * sizeof(NodeBase*));
0455 }
0456 }
0457
0458 NodeBase** CreateEmptyTable(map_index_t n) {
0459 ABSL_DCHECK_GE(n, kMinTableSize);
0460 ABSL_DCHECK_EQ(n & (n - 1), 0u);
0461 NodeBase** result =
0462 arena_ == nullptr
0463 ? static_cast<NodeBase**>(::operator new(n * sizeof(NodeBase*)))
0464 : Arena::CreateArray<NodeBase*>(arena_, n);
0465 memset(result, 0, n * sizeof(result[0]));
0466 return result;
0467 }
0468
0469 void DeleteNode(NodeBase* node);
0470
0471 map_index_t num_elements_;
0472 map_index_t num_buckets_;
0473 map_index_t index_of_first_non_null_;
0474 TypeInfo type_info_;
0475 NodeBase** table_;
0476 Arena* arena_;
0477 };
0478
0479 template <typename F>
0480 auto UntypedMapBase::VisitKeyType(F f) const {
0481 switch (type_info_.key_type_kind()) {
0482 case TypeKind::kBool:
0483 return f(std::enable_if<true, bool>{});
0484 case TypeKind::kU32:
0485 return f(std::enable_if<true, uint32_t>{});
0486 case TypeKind::kU64:
0487 return f(std::enable_if<true, uint64_t>{});
0488 case TypeKind::kString:
0489 return f(std::enable_if<true, std::string>{});
0490
0491 case TypeKind::kFloat:
0492 case TypeKind::kDouble:
0493 case TypeKind::kMessage:
0494 default:
0495 Unreachable();
0496 }
0497 }
0498
0499 template <typename F>
0500 auto UntypedMapBase::VisitValueType(F f) const {
0501 switch (type_info_.value_type_kind()) {
0502 case TypeKind::kBool:
0503 return f(std::enable_if<true, bool>{});
0504 case TypeKind::kU32:
0505 return f(std::enable_if<true, uint32_t>{});
0506 case TypeKind::kU64:
0507 return f(std::enable_if<true, uint64_t>{});
0508 case TypeKind::kFloat:
0509 return f(std::enable_if<true, float>{});
0510 case TypeKind::kDouble:
0511 return f(std::enable_if<true, double>{});
0512 case TypeKind::kString:
0513 return f(std::enable_if<true, std::string>{});
0514 case TypeKind::kMessage:
0515 return f(std::enable_if<true, MessageLite>{});
0516
0517 default:
0518 Unreachable();
0519 }
0520 }
0521
0522 template <typename F>
0523 void UntypedMapBase::VisitAllNodes(F f) const {
0524 VisitKeyType([&](auto key_type) {
0525 VisitValueType([&](auto value_type) {
0526 for (auto it = begin(); !it.Equals(EndIterator()); it.PlusPlus()) {
0527 f(GetKey<typename decltype(key_type)::type>(it.node_),
0528 GetValue<typename decltype(value_type)::type>(it.node_));
0529 }
0530 });
0531 });
0532 }
0533
0534 template <typename F>
0535 auto UntypedMapBase::VisitKey(NodeBase* node, F f) const {
0536 return VisitKeyType([&](auto key_type) {
0537 return f(GetKey<typename decltype(key_type)::type>(node));
0538 });
0539 }
0540
0541 template <typename F>
0542 auto UntypedMapBase::VisitValue(NodeBase* node, F f) const {
0543 return VisitValueType([&](auto value_type) {
0544 return f(GetValue<typename decltype(value_type)::type>(node));
0545 });
0546 }
0547
0548 inline UntypedMapIterator UntypedMapBase::begin() const {
0549 map_index_t bucket_index;
0550 NodeBase* node;
0551 if (index_of_first_non_null_ == num_buckets_) {
0552 bucket_index = 0;
0553 node = nullptr;
0554 } else {
0555 bucket_index = index_of_first_non_null_;
0556 node = table_[bucket_index];
0557 PROTOBUF_ASSUME(node != nullptr);
0558 }
0559 return UntypedMapIterator{node, this, bucket_index};
0560 }
0561
0562 inline void UntypedMapIterator::PlusPlus() {
0563 if (node_->next != nullptr) {
0564 node_ = node_->next;
0565 return;
0566 }
0567
0568 for (map_index_t i = bucket_index_ + 1; i < m_->num_buckets_; ++i) {
0569 NodeBase* node = m_->table_[i];
0570 if (node == nullptr) continue;
0571 node_ = node;
0572 bucket_index_ = i;
0573 return;
0574 }
0575
0576 node_ = nullptr;
0577 bucket_index_ = 0;
0578 }
0579
0580
0581
0582
0583 class MapFieldBaseForParse {
0584 public:
0585 const UntypedMapBase& GetMap() const {
0586 const auto p = payload_.load(std::memory_order_acquire);
0587
0588 if (ABSL_PREDICT_FALSE(IsPayload(p))) {
0589 sync_map_with_repeated.load(std::memory_order_relaxed)(*this, false);
0590 }
0591 return GetMapRaw();
0592 }
0593
0594 UntypedMapBase* MutableMap() {
0595 const auto p = payload_.load(std::memory_order_acquire);
0596
0597 if (ABSL_PREDICT_FALSE(IsPayload(p))) {
0598 sync_map_with_repeated.load(std::memory_order_relaxed)(*this, true);
0599 }
0600 return &GetMapRaw();
0601 }
0602
0603 protected:
0604 static constexpr size_t MapOffset() { return sizeof(MapFieldBaseForParse); }
0605
0606
0607 const UntypedMapBase& GetMapRaw() const {
0608 return *reinterpret_cast<const UntypedMapBase*>(
0609 reinterpret_cast<const char*>(this) + MapOffset());
0610 }
0611 UntypedMapBase& GetMapRaw() {
0612 return *reinterpret_cast<UntypedMapBase*>(reinterpret_cast<char*>(this) +
0613 MapOffset());
0614 }
0615
0616
0617
0618
0619 using SyncFunc = void (*)(const MapFieldBaseForParse&, bool is_mutable);
0620 static std::atomic<SyncFunc> sync_map_with_repeated;
0621
0622
0623
0624 explicit constexpr MapFieldBaseForParse(const void* prototype_as_void)
0625 : prototype_as_void_(prototype_as_void) {}
0626
0627 enum class TaggedPtr : uintptr_t {};
0628 explicit MapFieldBaseForParse(const Message* prototype, TaggedPtr ptr)
0629 : payload_(ptr), prototype_as_void_(prototype) {
0630
0631 ABSL_DCHECK(!IsPayload(ptr));
0632 }
0633
0634 ~MapFieldBaseForParse() = default;
0635
0636 static constexpr uintptr_t kHasPayloadBit = 1;
0637
0638 static bool IsPayload(TaggedPtr p) {
0639 return static_cast<uintptr_t>(p) & kHasPayloadBit;
0640 }
0641
0642 mutable std::atomic<TaggedPtr> payload_{};
0643 const void* prototype_as_void_;
0644 };
0645
0646
0647 template <typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
0648 T ReadKey(const void* ptr) {
0649 T out;
0650 memcpy(&out, ptr, sizeof(T));
0651 return out;
0652 }
0653
0654 template <typename T, std::enable_if_t<!std::is_integral<T>::value, int> = 0>
0655 const T& ReadKey(const void* ptr) {
0656 return *reinterpret_cast<const T*>(ptr);
0657 }
0658
0659 template <typename Key>
0660 struct KeyNode : NodeBase {
0661 static constexpr size_t kOffset = sizeof(NodeBase);
0662 decltype(auto) key() const { return ReadKey<Key>(GetVoidKey()); }
0663 };
0664
0665 inline map_index_t Hash(absl::string_view k, void* salt) {
0666
0667 return absl::HashOf(k, salt);
0668 }
0669 inline map_index_t Hash(uint64_t k, void* salt) {
0670 if constexpr (!HasCrc32()) return absl::HashOf(k, salt);
0671 uintptr_t salt_int = reinterpret_cast<uintptr_t>(salt);
0672
0673
0674 return Crc32(salt_int, absl::rotr(k, salt_int & 0x3f));
0675 }
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689 template <typename Key>
0690 class KeyMapBase : public UntypedMapBase {
0691 static_assert(!std::is_signed<Key>::value || !std::is_integral<Key>::value,
0692 "");
0693
0694 using TS = TransparentSupport<Key>;
0695
0696 public:
0697 using UntypedMapBase::UntypedMapBase;
0698
0699 protected:
0700 using KeyNode = internal::KeyNode<Key>;
0701
0702 protected:
0703 friend UntypedMapBase;
0704 friend class MapFieldBase;
0705 friend class TcParser;
0706 friend struct MapTestPeer;
0707 friend struct MapBenchmarkPeer;
0708 friend class RustMapHelper;
0709
0710 Key* GetKey(NodeBase* node) const {
0711 return UntypedMapBase::GetKey<Key>(node);
0712 }
0713
0714 PROTOBUF_NOINLINE size_type EraseImpl(map_index_t b, KeyNode* node,
0715 bool do_destroy) {
0716
0717 b &= (num_buckets_ - 1);
0718
0719 const auto find_prev = [&] {
0720 NodeBase** prev = table_ + b;
0721 for (; *prev != nullptr && *prev != node; prev = &(*prev)->next) {
0722 }
0723 return prev;
0724 };
0725
0726 NodeBase** prev = find_prev();
0727 if (*prev == nullptr) {
0728
0729
0730 b = FindHelper(TS::ToView(node->key())).bucket;
0731 prev = find_prev();
0732 }
0733 ABSL_DCHECK_EQ(*prev, node);
0734 *prev = (*prev)->next;
0735
0736 --num_elements_;
0737 if (ABSL_PREDICT_FALSE(b == index_of_first_non_null_)) {
0738 while (index_of_first_non_null_ < num_buckets_ &&
0739 table_[index_of_first_non_null_] == nullptr) {
0740 ++index_of_first_non_null_;
0741 }
0742 }
0743
0744 if (arena() == nullptr && do_destroy) {
0745 DeleteNode(node);
0746 }
0747
0748
0749 return 1;
0750 }
0751
0752 PROTOBUF_NOINLINE size_type EraseImpl(typename TS::ViewType k) {
0753 if (auto result = FindHelper(k); result.node != nullptr) {
0754 return EraseImpl(result.bucket, static_cast<KeyNode*>(result.node), true);
0755 }
0756 return 0;
0757 }
0758
0759 NodeAndBucket FindHelper(typename TS::ViewType k) const {
0760 AssertLoadFactor();
0761 map_index_t b = BucketNumber(k);
0762 for (auto* node = table_[b]; node != nullptr; node = node->next) {
0763 if (TS::ToView(static_cast<KeyNode*>(node)->key()) == k) {
0764 return {node, b};
0765 }
0766 }
0767 return {nullptr, b};
0768 }
0769
0770
0771
0772 bool InsertOrReplaceNode(KeyNode* node) {
0773 bool is_new = true;
0774 auto p = this->FindHelper(node->key());
0775 map_index_t b = p.bucket;
0776 if (ABSL_PREDICT_FALSE(p.node != nullptr)) {
0777 EraseImpl(p.bucket, static_cast<KeyNode*>(p.node), true);
0778 is_new = false;
0779 } else if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) {
0780 b = BucketNumber(node->key());
0781 }
0782 InsertUnique(b, node);
0783 ++num_elements_;
0784 return is_new;
0785 }
0786
0787
0788
0789
0790
0791 void InsertUnique(map_index_t b, KeyNode* node) {
0792 ABSL_DCHECK(index_of_first_non_null_ == num_buckets_ ||
0793 table_[index_of_first_non_null_] != nullptr);
0794
0795
0796
0797
0798 ABSL_DCHECK(FindHelper(TS::ToView(node->key())).node == nullptr);
0799 AssertLoadFactor();
0800 auto*& head = table_[b];
0801 if (head == nullptr) {
0802 head = node;
0803 node->next = nullptr;
0804 index_of_first_non_null_ = (std::min)(index_of_first_non_null_, b);
0805 } else if (ShouldInsertAfterHead(node)) {
0806 node->next = head->next;
0807 head->next = node;
0808 } else {
0809 node->next = head;
0810 head = node;
0811 }
0812 }
0813
0814
0815 static size_type CalculateHiCutoff(size_type num_buckets) {
0816
0817
0818
0819
0820
0821
0822
0823 return num_buckets - num_buckets / 16 * 4 - num_buckets % 2;
0824 }
0825
0826
0827
0828 static size_type CalculateCapacityForSize(size_type size) {
0829 ABSL_DCHECK_NE(size, 0u);
0830
0831 if (size > kMaxTableSize / 2) {
0832 return kMaxTableSize;
0833 }
0834
0835 size_t capacity = size_type{1} << (std::numeric_limits<size_type>::digits -
0836 absl::countl_zero(size - 1));
0837
0838 if (size > CalculateHiCutoff(capacity)) {
0839 capacity *= 2;
0840 }
0841
0842 return std::max<size_type>(capacity, kMinTableSize);
0843 }
0844
0845 void AssertLoadFactor() const {
0846 ABSL_DCHECK_LE(num_elements_, CalculateHiCutoff(num_buckets_));
0847 }
0848
0849
0850
0851
0852
0853
0854
0855
0856
0857 bool ResizeIfLoadIsOutOfRange(size_type new_size) {
0858 const size_type hi_cutoff = CalculateHiCutoff(num_buckets_);
0859 const size_type lo_cutoff = hi_cutoff / 4;
0860
0861
0862
0863 if (ABSL_PREDICT_FALSE(new_size > hi_cutoff)) {
0864 if (num_buckets_ <= max_size() / 2) {
0865 Resize(kMinTableSize > kGlobalEmptyTableSize * 2
0866 ? std::max(kMinTableSize, num_buckets_ * 2)
0867 : num_buckets_ * 2);
0868 return true;
0869 }
0870 } else if (ABSL_PREDICT_FALSE(new_size <= lo_cutoff &&
0871 num_buckets_ > kMinTableSize)) {
0872 size_type lg2_of_size_reduction_factor = 1;
0873
0874
0875
0876 const size_type hypothetical_size = new_size * 5 / 4 + 1;
0877 while ((hypothetical_size << (1 + lg2_of_size_reduction_factor)) <
0878 hi_cutoff) {
0879 ++lg2_of_size_reduction_factor;
0880 }
0881 size_type new_num_buckets = std::max<size_type>(
0882 kMinTableSize, num_buckets_ >> lg2_of_size_reduction_factor);
0883 if (new_num_buckets != num_buckets_) {
0884 Resize(new_num_buckets);
0885 return true;
0886 }
0887 }
0888 return false;
0889 }
0890
0891
0892
0893
0894 PROTOBUF_NOINLINE void MergeIntoEmpty(NodeBase* head, size_t num_nodes) {
0895 ABSL_DCHECK_EQ(size(), size_t{0});
0896 ABSL_DCHECK_NE(num_nodes, size_t{0});
0897 if (const map_index_t needed_capacity = CalculateCapacityForSize(num_nodes);
0898 needed_capacity != this->num_buckets_) {
0899 Resize(std::max(kMinTableSize, needed_capacity));
0900 }
0901 num_elements_ = num_nodes;
0902 AssertLoadFactor();
0903 while (head != nullptr) {
0904 KeyNode* node = static_cast<KeyNode*>(head);
0905 head = head->next;
0906 absl::PrefetchToLocalCacheNta(head);
0907 InsertUnique(BucketNumber(TS::ToView(node->key())), node);
0908 }
0909 }
0910
0911
0912 void Resize(map_index_t new_num_buckets) {
0913 ABSL_DCHECK_GE(new_num_buckets, kMinTableSize);
0914 ABSL_DCHECK(absl::has_single_bit(new_num_buckets));
0915 if (num_buckets_ == kGlobalEmptyTableSize) {
0916
0917
0918 num_buckets_ = index_of_first_non_null_ = new_num_buckets;
0919 table_ = CreateEmptyTable(num_buckets_);
0920 return;
0921 }
0922
0923 ABSL_DCHECK_GE(new_num_buckets, kMinTableSize);
0924 const auto old_table = table_;
0925 const map_index_t old_table_size = num_buckets_;
0926 num_buckets_ = new_num_buckets;
0927 table_ = CreateEmptyTable(num_buckets_);
0928 const map_index_t start = index_of_first_non_null_;
0929 index_of_first_non_null_ = num_buckets_;
0930 for (map_index_t i = start; i < old_table_size; ++i) {
0931 for (KeyNode* node = static_cast<KeyNode*>(old_table[i]);
0932 node != nullptr;) {
0933 auto* next = static_cast<KeyNode*>(node->next);
0934 InsertUnique(BucketNumber(TS::ToView(node->key())), node);
0935 node = next;
0936 }
0937 }
0938 DeleteTable(old_table, old_table_size);
0939 AssertLoadFactor();
0940 }
0941
0942 map_index_t BucketNumber(typename TS::ViewType k) const {
0943 return Hash(k, table_) & (num_buckets_ - 1);
0944 }
0945 };
0946
0947 template <typename T, typename K>
0948 bool InitializeMapKey(T*, K&&, Arena*) {
0949 return false;
0950 }
0951
0952
0953
0954
0955
0956
0957 class RustMapHelper {
0958 public:
0959 using NodeAndBucket = UntypedMapBase::NodeAndBucket;
0960
0961 static NodeBase* AllocNode(UntypedMapBase* m) { return m->AllocNode(); }
0962
0963 static void DeleteNode(UntypedMapBase* m, NodeBase* node) {
0964 return m->DeleteNode(node);
0965 }
0966
0967 template <typename Map, typename Key>
0968 static NodeAndBucket FindHelper(Map* m, Key key) {
0969 return m->FindHelper(key);
0970 }
0971
0972 template <typename Map>
0973 static bool InsertOrReplaceNode(Map* m, NodeBase* node) {
0974 return m->InsertOrReplaceNode(static_cast<typename Map::KeyNode*>(node));
0975 }
0976
0977 template <typename Map, typename Key>
0978 static bool EraseImpl(Map* m, const Key& key) {
0979 return m->EraseImpl(key);
0980 }
0981
0982 static google::protobuf::MessageLite* PlacementNew(const MessageLite* prototype,
0983 void* mem) {
0984 return prototype->GetClassData()->PlacementNew(mem, nullptr);
0985 }
0986 };
0987
0988 }
0989
0990
0991 template <typename Key, typename T>
0992 using MapPair = std::pair<const Key, T>;
0993
0994
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004 template <typename Key, typename T>
1005 class Map : private internal::KeyMapBase<internal::KeyForBase<Key>> {
1006 using Base = typename Map::KeyMapBase;
1007
1008 using TS = internal::TransparentSupport<Key>;
1009
1010 public:
1011 using key_type = Key;
1012 using mapped_type = T;
1013 using init_type = std::pair<Key, T>;
1014 using value_type = MapPair<Key, T>;
1015
1016 using pointer = value_type*;
1017 using const_pointer = const value_type*;
1018 using reference = value_type&;
1019 using const_reference = const value_type&;
1020
1021 using size_type = size_t;
1022 using hasher = absl::Hash<typename TS::ViewType>;
1023
1024 constexpr Map() : Base(nullptr, GetTypeInfo()) { StaticValidityCheck(); }
1025 Map(const Map& other) : Map(nullptr, other) {}
1026
1027
1028
1029 explicit Map(Arena* arena) : Base(arena, GetTypeInfo()) {
1030 StaticValidityCheck();
1031 }
1032 Map(internal::InternalVisibility, Arena* arena) : Map(arena) {}
1033 Map(internal::InternalVisibility, Arena* arena, const Map& other)
1034 : Map(arena, other) {}
1035
1036 Map(Map&& other) noexcept : Map() {
1037 if (other.arena() != nullptr) {
1038 *this = other;
1039 } else {
1040 swap(other);
1041 }
1042 }
1043
1044 Map& operator=(Map&& other) noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
1045 if (this != &other) {
1046 if (arena() != other.arena()) {
1047 *this = other;
1048 } else {
1049 swap(other);
1050 }
1051 }
1052 return *this;
1053 }
1054
1055 template <class InputIt>
1056 Map(const InputIt& first, const InputIt& last) : Map() {
1057 insert(first, last);
1058 }
1059
1060 ~Map() {
1061
1062
1063 StaticValidityCheck();
1064
1065 this->AssertLoadFactor();
1066 this->ClearTable(false);
1067 }
1068
1069 private:
1070 Map(Arena* arena, const Map& other) : Map(arena) {
1071 StaticValidityCheck();
1072 CopyFromImpl(other);
1073 }
1074 static_assert(!std::is_const<mapped_type>::value &&
1075 !std::is_const<key_type>::value,
1076 "We do not support const types.");
1077 static_assert(!std::is_volatile<mapped_type>::value &&
1078 !std::is_volatile<key_type>::value,
1079 "We do not support volatile types.");
1080 static_assert(!std::is_pointer<mapped_type>::value &&
1081 !std::is_pointer<key_type>::value,
1082 "We do not support pointer types.");
1083 static_assert(!std::is_reference<mapped_type>::value &&
1084 !std::is_reference<key_type>::value,
1085 "We do not support reference types.");
1086 static constexpr PROTOBUF_ALWAYS_INLINE void StaticValidityCheck() {
1087 static_assert(alignof(internal::NodeBase) >= alignof(mapped_type),
1088 "Alignment of mapped type is too high.");
1089 static_assert(
1090 absl::disjunction<internal::is_supported_integral_type<key_type>,
1091 internal::is_supported_string_type<key_type>,
1092 internal::is_internal_map_key_type<key_type>>::value,
1093 "We only support integer, string, or designated internal key "
1094 "types.");
1095 static_assert(absl::disjunction<
1096 internal::is_supported_scalar_type<mapped_type>,
1097 is_proto_enum<mapped_type>,
1098 internal::is_supported_message_type<mapped_type>,
1099 internal::is_internal_map_value_type<mapped_type>>::value,
1100 "We only support scalar, Message, and designated internal "
1101 "mapped types.");
1102
1103
1104 static_assert(
1105 sizeof(Map) == sizeof(internal::UntypedMapBase),
1106 "Map must not have any data members beyond what is in UntypedMapBase.");
1107
1108
1109 if constexpr (std::is_scalar_v<key_type>) {
1110 static_assert(sizeof(key_type) <= sizeof(uint64_t),
1111 "Scalar must be <= than uint64_t");
1112 }
1113 if constexpr (std::is_scalar_v<mapped_type>) {
1114 static_assert(sizeof(mapped_type) <= sizeof(uint64_t),
1115 "Scalar must be <= than uint64_t");
1116 }
1117 static_assert(internal::kMaxMessageAlignment >= sizeof(uint64_t));
1118 static_assert(sizeof(Node) - sizeof(internal::NodeBase) >= sizeof(uint64_t),
1119 "We must have at least this bytes for MpMap initialization");
1120 }
1121
1122 template <typename P>
1123 struct SameAsElementReference
1124 : std::is_same<typename std::remove_cv<
1125 typename std::remove_reference<reference>::type>::type,
1126 typename std::remove_cv<
1127 typename std::remove_reference<P>::type>::type> {};
1128
1129 template <class P>
1130 using RequiresInsertable =
1131 typename std::enable_if<std::is_convertible<P, init_type>::value ||
1132 SameAsElementReference<P>::value,
1133 int>::type;
1134 template <class P>
1135 using RequiresNotInit =
1136 typename std::enable_if<!std::is_same<P, init_type>::value, int>::type;
1137
1138 template <typename LookupKey>
1139 using key_arg = typename TS::template key_arg<LookupKey>;
1140
1141 public:
1142
1143 class const_iterator : private internal::UntypedMapIterator {
1144 using BaseIt = internal::UntypedMapIterator;
1145
1146 public:
1147 using iterator_category = std::forward_iterator_tag;
1148 using value_type = typename Map::value_type;
1149 using difference_type = ptrdiff_t;
1150 using pointer = const value_type*;
1151 using reference = const value_type&;
1152
1153 const_iterator() : BaseIt{nullptr, nullptr, 0} {}
1154 const_iterator(const const_iterator&) = default;
1155 const_iterator& operator=(const const_iterator&) = default;
1156 explicit const_iterator(BaseIt it) : BaseIt(it) {}
1157
1158 reference operator*() const { return static_cast<Node*>(this->node_)->kv; }
1159 pointer operator->() const { return &(operator*()); }
1160
1161 const_iterator& operator++() {
1162 this->PlusPlus();
1163 return *this;
1164 }
1165 const_iterator operator++(int) {
1166 auto copy = *this;
1167 this->PlusPlus();
1168 return copy;
1169 }
1170
1171 friend bool operator==(const const_iterator& a, const const_iterator& b) {
1172 return a.Equals(b);
1173 }
1174 friend bool operator!=(const const_iterator& a, const const_iterator& b) {
1175 return !a.Equals(b);
1176 }
1177
1178 private:
1179 using BaseIt::BaseIt;
1180 friend class Map;
1181 friend class internal::UntypedMapIterator;
1182 friend class internal::TypeDefinedMapFieldBase<Key, T>;
1183 };
1184
1185 class iterator : private internal::UntypedMapIterator {
1186 using BaseIt = internal::UntypedMapIterator;
1187
1188 public:
1189 using iterator_category = std::forward_iterator_tag;
1190 using value_type = typename Map::value_type;
1191 using difference_type = ptrdiff_t;
1192 using pointer = value_type*;
1193 using reference = value_type&;
1194
1195 iterator() : BaseIt{nullptr, nullptr, 0} {}
1196 iterator(const iterator&) = default;
1197 iterator& operator=(const iterator&) = default;
1198 explicit iterator(BaseIt it) : BaseIt(it) {}
1199
1200 reference operator*() const { return static_cast<Node*>(this->node_)->kv; }
1201 pointer operator->() const { return &(operator*()); }
1202
1203 iterator& operator++() {
1204 this->PlusPlus();
1205 return *this;
1206 }
1207 iterator operator++(int) {
1208 auto copy = *this;
1209 this->PlusPlus();
1210 return copy;
1211 }
1212
1213
1214 operator const_iterator() const {
1215 return const_iterator(static_cast<const BaseIt&>(*this));
1216 }
1217
1218 friend bool operator==(const iterator& a, const iterator& b) {
1219 return a.Equals(b);
1220 }
1221 friend bool operator!=(const iterator& a, const iterator& b) {
1222 return !a.Equals(b);
1223 }
1224
1225 private:
1226 using BaseIt::BaseIt;
1227 friend class Map;
1228 };
1229
1230 iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
1231 return iterator(Base::begin());
1232 }
1233 iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return iterator(); }
1234 const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1235 return const_iterator(Base::begin());
1236 }
1237 const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1238 return const_iterator();
1239 }
1240 const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1241 return begin();
1242 }
1243 const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
1244
1245 using Base::empty;
1246 using Base::size;
1247
1248
1249 template <typename K = key_type>
1250 T& operator[](const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1251 return try_emplace(key).first->second;
1252 }
1253 template <
1254 typename K = key_type,
1255
1256 typename = typename std::enable_if<!std::is_integral<K>::value>::type>
1257 T& operator[](key_arg<K>&& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1258 return try_emplace(std::forward<K>(key)).first->second;
1259 }
1260
1261 template <typename K = key_type>
1262 const T& at(const key_arg<K>& key) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1263 const_iterator it = find(key);
1264 ABSL_CHECK(it != end()) << "key not found: " << static_cast<Key>(key);
1265 return it->second;
1266 }
1267
1268 template <typename K = key_type>
1269 T& at(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1270 iterator it = find(key);
1271 ABSL_CHECK(it != end()) << "key not found: " << static_cast<Key>(key);
1272 return it->second;
1273 }
1274
1275
1276 template <typename K = key_type>
1277 size_type count(const key_arg<K>& key) const {
1278 return find(key) == end() ? 0 : 1;
1279 }
1280
1281 template <typename K = key_type>
1282 const_iterator find(const key_arg<K>& key) const
1283 ABSL_ATTRIBUTE_LIFETIME_BOUND {
1284 return const_cast<Map*>(this)->find(key);
1285 }
1286 template <typename K = key_type>
1287 iterator find(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1288 auto res = this->FindHelper(TS::ToView(key));
1289 return iterator(internal::UntypedMapIterator{static_cast<Node*>(res.node),
1290 this, res.bucket});
1291 }
1292
1293 template <typename K = key_type>
1294 bool contains(const key_arg<K>& key) const {
1295 return find(key) != end();
1296 }
1297
1298 template <typename K = key_type>
1299 std::pair<const_iterator, const_iterator> equal_range(
1300 const key_arg<K>& key) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1301 const_iterator it = find(key);
1302 if (it == end()) {
1303 return std::pair<const_iterator, const_iterator>(it, it);
1304 } else {
1305 const_iterator begin = it++;
1306 return std::pair<const_iterator, const_iterator>(begin, it);
1307 }
1308 }
1309
1310 template <typename K = key_type>
1311 std::pair<iterator, iterator> equal_range(const key_arg<K>& key)
1312 ABSL_ATTRIBUTE_LIFETIME_BOUND {
1313 iterator it = find(key);
1314 if (it == end()) {
1315 return std::pair<iterator, iterator>(it, it);
1316 } else {
1317 iterator begin = it++;
1318 return std::pair<iterator, iterator>(begin, it);
1319 }
1320 }
1321
1322
1323 template <typename K, typename... Args>
1324 std::pair<iterator, bool> try_emplace(K&& k, Args&&... args)
1325 ABSL_ATTRIBUTE_LIFETIME_BOUND {
1326
1327
1328
1329 if constexpr (Arena::is_arena_constructable<mapped_type>::value) {
1330 if constexpr (sizeof...(Args) == 0) {
1331
1332 return TryEmplaceInternal(std::forward<K>(k));
1333 } else {
1334
1335 auto p = TryEmplaceInternal(std::forward<K>(k));
1336 if (p.second) {
1337 if constexpr (std::is_same<void(typename std::decay<Args>::type...),
1338 void(mapped_type)>::value) {
1339
1340 p.first->second = (std::forward<Args>(args), ...);
1341 } else {
1342 p.first->second = mapped_type(std::forward<Args>(args)...);
1343 }
1344 }
1345 return p;
1346 }
1347 } else {
1348
1349
1350 return TryEmplaceInternal(std::forward<K>(k),
1351 std::forward<Args>(args)...);
1352 }
1353 }
1354 std::pair<iterator, bool> insert(init_type&& value)
1355 ABSL_ATTRIBUTE_LIFETIME_BOUND {
1356 return try_emplace(std::move(value.first), std::move(value.second));
1357 }
1358 template <typename P, RequiresInsertable<P> = 0>
1359 std::pair<iterator, bool> insert(P&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1360 return try_emplace(std::forward<P>(value).first,
1361 std::forward<P>(value).second);
1362 }
1363 template <typename... Args>
1364 std::pair<iterator, bool> emplace(Args&&... args)
1365 ABSL_ATTRIBUTE_LIFETIME_BOUND {
1366
1367
1368
1369 if constexpr (std::is_constructible<init_type, Args...>::value) {
1370 return insert(init_type(std::forward<Args>(args)...));
1371 } else {
1372 return insert(value_type(std::forward<Args>(args)...));
1373 }
1374 }
1375 template <class InputIt>
1376 void insert(InputIt first, InputIt last) {
1377 for (; first != last; ++first) {
1378 auto&& pair = *first;
1379 try_emplace(pair.first, pair.second);
1380 }
1381 }
1382 void insert(std::initializer_list<init_type> values) {
1383 insert(values.begin(), values.end());
1384 }
1385 template <typename P, RequiresNotInit<P> = 0,
1386 RequiresInsertable<const P&> = 0>
1387 void insert(std::initializer_list<P> values) {
1388 insert(values.begin(), values.end());
1389 }
1390
1391
1392 template <typename K = key_type>
1393 size_type erase(const key_arg<K>& key) {
1394 return this->EraseImpl(TS::ToView(key));
1395 }
1396
1397 iterator erase(iterator pos) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1398 auto next = std::next(pos);
1399 ABSL_DCHECK_EQ(pos.m_, static_cast<Base*>(this));
1400 this->EraseImpl(pos.bucket_index_, static_cast<Node*>(pos.node_), true);
1401 return next;
1402 }
1403
1404 void erase(iterator first, iterator last) {
1405 while (first != last) {
1406 first = erase(first);
1407 }
1408 }
1409
1410 void clear() { this->ClearTable(true); }
1411
1412
1413 Map& operator=(const Map& other) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1414 if (this != &other) {
1415 clear();
1416 CopyFromImpl(other);
1417 }
1418 return *this;
1419 }
1420
1421 void swap(Map& other) {
1422 if (arena() == other.arena()) {
1423 InternalSwap(&other);
1424 } else {
1425 size_t other_size = other.size();
1426 Node* other_copy = this->CloneFromOther(other);
1427 other = *this;
1428 this->clear();
1429 if (other_size != 0) {
1430 this->MergeIntoEmpty(other_copy, other_size);
1431 }
1432 }
1433 }
1434
1435 void InternalSwap(Map* other) {
1436 internal::UntypedMapBase::InternalSwap(other);
1437 }
1438
1439 hasher hash_function() const { return {}; }
1440
1441 size_t SpaceUsedExcludingSelfLong() const {
1442 if (empty()) return 0;
1443 return internal::UntypedMapBase::SpaceUsedExcludingSelfLong();
1444 }
1445
1446 static constexpr size_t InternalGetArenaOffset(internal::InternalVisibility) {
1447 return PROTOBUF_FIELD_OFFSET(Map, arena_);
1448 }
1449
1450 private:
1451
1452 struct Node : Base::KeyNode {
1453 using key_type = Key;
1454 using mapped_type = T;
1455 value_type kv;
1456 };
1457
1458 static constexpr auto GetTypeInfo() {
1459 return internal::UntypedMapBase::TypeInfo{
1460 sizeof(Node),
1461 PROTOBUF_FIELD_OFFSET(Node, kv.second),
1462 static_cast<uint8_t>(internal::UntypedMapBase::StaticTypeKind<Key>()),
1463 static_cast<uint8_t>(internal::UntypedMapBase::StaticTypeKind<T>()),
1464 };
1465 }
1466
1467 void DeleteNode(Node* node) {
1468 if (this->arena_ == nullptr) {
1469 node->kv.first.~key_type();
1470 node->kv.second.~mapped_type();
1471 this->DeallocNode(node, sizeof(Node));
1472 }
1473 }
1474
1475 template <typename K, typename... Args>
1476 PROTOBUF_ALWAYS_INLINE Node* CreateNode(K&& k, Args&&... args) {
1477
1478 using TypeToInit = typename std::conditional<
1479 std::is_same<typename std::decay<K>::type, key_type>::value, K&&,
1480 key_type>::type;
1481 Node* node = static_cast<Node*>(this->AllocNode(sizeof(Node)));
1482
1483
1484
1485
1486
1487 if (!internal::InitializeMapKey(const_cast<Key*>(&node->kv.first),
1488 std::forward<K>(k), this->arena_)) {
1489 Arena::CreateInArenaStorage(const_cast<Key*>(&node->kv.first),
1490 this->arena_,
1491 static_cast<TypeToInit>(std::forward<K>(k)));
1492 }
1493
1494 Arena::CreateInArenaStorage(&node->kv.second, this->arena_,
1495 std::forward<Args>(args)...);
1496 return node;
1497 }
1498
1499
1500
1501 PROTOBUF_NOINLINE Node* CloneFromOther(const Map& other) {
1502 Node* head = nullptr;
1503 for (const auto& [key, value] : other) {
1504 Node* new_node;
1505 if constexpr (std::is_base_of_v<MessageLite, mapped_type>) {
1506 new_node = CreateNode(key);
1507 new_node->kv.second = value;
1508 } else {
1509 new_node = CreateNode(key, value);
1510 }
1511 new_node->next = head;
1512 head = new_node;
1513 }
1514 return head;
1515 }
1516
1517 void CopyFromImpl(const Map& other) {
1518 if (other.empty()) return;
1519
1520
1521
1522 this->MergeIntoEmpty(CloneFromOther(other), other.size());
1523 }
1524
1525 template <typename K, typename... Args>
1526 std::pair<iterator, bool> TryEmplaceInternal(K&& k, Args&&... args) {
1527 auto p = this->FindHelper(TS::ToView(k));
1528 internal::map_index_t b = p.bucket;
1529
1530 if (p.node != nullptr) {
1531 return std::make_pair(iterator(internal::UntypedMapIterator{
1532 static_cast<Node*>(p.node), this, p.bucket}),
1533 false);
1534 }
1535
1536 if (this->ResizeIfLoadIsOutOfRange(this->num_elements_ + 1)) {
1537 b = this->BucketNumber(TS::ToView(k));
1538 }
1539 auto* node = CreateNode(std::forward<K>(k), std::forward<Args>(args)...);
1540 this->InsertUnique(b, node);
1541 ++this->num_elements_;
1542 return std::make_pair(iterator(internal::UntypedMapIterator{node, this, b}),
1543 true);
1544 }
1545
1546 using Base::arena;
1547
1548 friend class Arena;
1549 template <typename, typename>
1550 friend class internal::TypeDefinedMapFieldBase;
1551 using InternalArenaConstructable_ = void;
1552 using DestructorSkippable_ = void;
1553 template <typename K, typename V>
1554 friend class internal::MapFieldLite;
1555 friend class internal::TcParser;
1556 friend struct internal::MapTestPeer;
1557 friend struct internal::MapBenchmarkPeer;
1558 friend class internal::RustMapHelper;
1559 };
1560
1561 namespace internal {
1562 template <typename... T>
1563 PROTOBUF_NOINLINE void MapMergeFrom(Map<T...>& dest, const Map<T...>& src) {
1564 for (const auto& elem : src) {
1565 dest[elem.first] = elem.second;
1566 }
1567 }
1568 }
1569
1570 }
1571 }
1572
1573 #include "google/protobuf/port_undef.inc"
1574
1575 #endif