Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-23 09:12:53

0001 // Protocol Buffers - Google's data interchange format
0002 // Copyright 2008 Google Inc.  All rights reserved.
0003 //
0004 // Use of this source code is governed by a BSD-style
0005 // license that can be found in the LICENSE file or at
0006 // https://developers.google.com/open-source/licenses/bsd
0007 
0008 // This file defines the map container and its helpers to support protobuf maps.
0009 //
0010 // The Map and MapIterator types are provided by this header file.
0011 // Please avoid using other types defined here, unless they are public
0012 // types within Map or MapIterator, such as Map::value_type.
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 // Must be included last.
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 }  // namespace rust
0069 
0070 namespace internal {
0071 namespace v2 {
0072 class TableDrivenMessage;
0073 }  // namespace v2
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 // The largest valid serialization for a message is INT_MAX, so we can't have
0093 // more than 32-bits worth of elements.
0094 using map_index_t = uint32_t;
0095 
0096 // Internal type traits that can be used to define custom key/value types. These
0097 // are only be specialized by protobuf internals, and never by users.
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 // To save on binary size and simplify generic uses of the map types we collapse
0105 // signed/unsigned versions of the same sized integer to the unsigned version.
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 // Default case: Not transparent.
0119 // We use std::hash<key_type>/std::less<key_type> and all the lookup functions
0120 // only accept `key_type`.
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 // We add transparent support for std::string keys. We use
0135 // absl::Hash<absl::string_view> as it supports the input types we care about.
0136 // The lookup functions accept arbitrary `K`. This will include any key type
0137 // that is convertible to absl::string_view.
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   // Align the node to allow KeyNode to predict the location of the key.
0165   // This way sizeof(NodeBase) contains any possible padding it was going to
0166   // have between NodeBase and the key.
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   // Invariants:
0181   // node_ is always correct. This is handy because the most common
0182   // operations are operator* and operator-> and they only use node_.
0183   // When node_ is set to a non-null value, all the other non-const fields
0184   // are updated to be correct also, but those fields can become stale
0185   // if the underlying map is modified.  When those fields are needed they
0186   // are rechecked, and updated if necessary.
0187 
0188   // We do not provide any constructors for this type. We need it to be a
0189   // trivial type to ensure that we can safely share it with Rust.
0190 
0191   // The definition of operator== is handled by the derived type. If we were
0192   // to do it in this class it would allow comparing iterators of different
0193   // map types.
0194   bool Equals(const UntypedMapIterator& other) const {
0195     return node_ == other.node_;
0196   }
0197 
0198   // The definition of operator++ is handled in the derived type. We would not
0199   // be able to return the right type from here.
0200   void PlusPlus();
0201 
0202   // Conversion to and from a typed iterator child class is used by FFI.
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 // These properties are depended upon by Rust FFI.
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 // Base class for all Map instantiations.
0246 // This class holds all the data and provides the basic functionality shared
0247 // among all instantiations.
0248 // Having an untyped base class helps generic consumers (like the table-driven
0249 // parser) by having non-template code that can handle all instantiations.
0250 class PROTOBUF_EXPORT UntypedMapBase {
0251  public:
0252   using size_type = size_t;
0253 
0254   // Possible types that a key/value can take.
0255   // LINT.IfChange(map_ffi)
0256   enum class TypeKind : uint8_t {
0257     kBool,     // bool
0258     kU32,      // int32_t, uint32_t, enums
0259     kU64,      // int64_t, uint64_t
0260     kFloat,    // float
0261     kDouble,   // double
0262     kString,   // std::string
0263     kMessage,  // Derived from MessageLite
0264   };
0265   // LINT.ThenChange(//depot/google3/third_party/protobuf/rust/cpp.rs:map_ffi)
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     // Equivalent to `sizeof(Node)` in the derived type.
0294     uint16_t node_size;
0295     // Equivalent to `offsetof(Node, kv.second)` in the derived type.
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     // Debug check that `T` matches what we expect from the type info.
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     // Debug check that `T` matches what we expect from the type info.
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   // Space used for the table and nodes.
0348   size_t SpaceUsedExcludingSelfLong() const;
0349 
0350   TypeInfo type_info() const { return type_info_; }
0351 
0352  protected:
0353   // 16 bytes is the minimum useful size for the array cache in the arena.
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   // We make this a static function to reduce the cost in MapField.
0380   // All the end iterators are singletons anyway.
0381   static UntypedMapIterator EndIterator() { return {nullptr, nullptr, 0}; }
0382 
0383   // Calls `f(k)` with the key of the node, where `k` is the appropriate type
0384   // according to the stored TypeInfo.
0385   template <typename F>
0386   auto VisitKey(NodeBase* node, F f) const;
0387 
0388   // Calls `f(v)` with the value of the node, where `v` is the appropriate type
0389   // according to the stored TypeInfo.
0390   // Messages are visited as `MessageLite`, and enums are visited as int32.
0391   template <typename F>
0392   auto VisitValue(NodeBase* node, F f) const;
0393 
0394   // As above, but calls `f(k, v)` for every node in the map.
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   // Calls `f(type_t)` where `type_t` is an unspecified type that has a `::type`
0407   // typedef in it representing the dynamic type of key/value of the node.
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   // Returns whether we should insert after the head of the list. For
0421   // non-optimized builds, we randomly decide whether to insert right at the
0422   // head of the list or just after the head. This helps add a little bit of
0423   // non-determinism to the map ordering.
0424   bool ShouldInsertAfterHead(void* node) {
0425 #ifdef NDEBUG
0426     (void)node;
0427     return false;
0428 #else
0429     // Doing modulo with a prime mixes the bits more.
0430     return absl::HashOf(node, table_) % 13 > 6;
0431 #endif
0432   }
0433 
0434   // Alignment of the nodes is the same as alignment of NodeBase.
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_;  // an array with num_buckets_ entries
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 // Base class used by TcParser to extract the map object from a map field.
0581 // We keep it here to avoid a dependency into map_field.h from the main TcParser
0582 // code, since that would bring in Message too.
0583 class MapFieldBaseForParse {
0584  public:
0585   const UntypedMapBase& GetMap() const {
0586     const auto p = payload_.load(std::memory_order_acquire);
0587     // If this instance has a payload, then it might need sync'n.
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     // If this instance has a payload, then it might need sync'n.
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   // See assertion in TypeDefinedMapFieldBase::TypeDefinedMapFieldBase()
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   // Injected from map_field.cc once we need to use it.
0617   // We can't have a strong dep on it because it would cause protobuf_lite to
0618   // depend on reflection.
0619   using SyncFunc = void (*)(const MapFieldBaseForParse&, bool is_mutable);
0620   static std::atomic<SyncFunc> sync_map_with_repeated;
0621 
0622   // The prototype is a `Message`, but due to restrictions on constexpr in the
0623   // codegen we are receiving it as `void` during constant evaluation.
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     // We should not have a payload on construction.
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 // The value might be of different signedness, so use memcpy to extract it.
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   // Note: we could potentially also use CRC32-based hashing here.
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   // Note: Crc32(salt_int, k) causes the random iteration order test to fail so
0673   // we also rotate.
0674   return Crc32(salt_int, absl::rotr(k, salt_int & 0x3f));
0675 }
0676 
0677 // KeyMapBase is a chaining hash map.
0678 // The implementation doesn't need the full generality of unordered_map,
0679 // and it doesn't have it.  More bells and whistles can be added as needed.
0680 // Some implementation details:
0681 // 1. The number of buckets is a power of two.
0682 // 2. As is typical for hash_map and such, the Keys and Values are always
0683 //    stored in linked list nodes.  Pointers to elements are never invalidated
0684 //    until the element is deleted.
0685 // 3. Mutations to a map do not invalidate the map's iterators, pointers to
0686 //    elements, or references to elements.
0687 // 4. Except for erase(iterator), any non-const method can reorder iterators.
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     // Force bucket_index to be in range.
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       // The bucket index is wrong. The table was modified since the iterator
0729       // was made, so let's find the new bucket.
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     // To allow for the other overload of EraseImpl to do a tail call.
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   // Insert the given node.
0771   // If the key is a duplicate, it inserts the new node and deletes the old one.
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());  // bucket_number
0781     }
0782     InsertUnique(b, node);
0783     ++num_elements_;
0784     return is_new;
0785   }
0786 
0787   // Insert the given Node in bucket b.  If that would make bucket b too big,
0788   // and bucket b is not a tree, create a tree for buckets b.
0789   // Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct
0790   // bucket.  num_elements_ is not modified.
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     // In practice, the code that led to this point may have already
0795     // determined whether we are inserting into an empty list, a short list,
0796     // or whatever.  But it's probably cheap enough to recompute that here;
0797     // it's likely that we're inserting into an empty or short list.
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   // Have it a separate function for testing.
0815   static size_type CalculateHiCutoff(size_type num_buckets) {
0816     // We want the high cutoff to follow this rules:
0817     //  - When num_buckets_ == kGlobalEmptyTableSize, then make it 0 to force an
0818     //    allocation.
0819     //  - When num_buckets_ < 8, then make it num_buckets_ to avoid
0820     //    a reallocation. A large load factor is not that important on small
0821     //    tables and saves memory.
0822     //  - Otherwise, make it 75% of num_buckets_.
0823     return num_buckets - num_buckets / 16 * 4 - num_buckets % 2;
0824   }
0825 
0826   // For a particular size, calculate the lowest capacity `cap` where
0827   // `size <= CalculateHiCutoff(cap)`.
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   // Returns whether it did resize.  Currently this is only used when
0850   // num_elements_ increases, though it could be used in other situations.
0851   // It checks for load too low as well as load too high: because any number
0852   // of erases can occur between inserts, the load could be as low as 0 here.
0853   // Resizing to a lower size is not always helpful, but failing to do so can
0854   // destroy the expected big-O bounds for some operations. By having the
0855   // policy that sometimes we resize down as well as up, clients can easily
0856   // keep O(size()) = O(number of buckets) if they want that.
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     // We don't care how many elements are in trees.  If a lot are,
0861     // we may resize even though there are many empty buckets.  In
0862     // practice, this seems fine.
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       // It's possible we want to shrink a lot here... size() could even be 0.
0874       // So, estimate how much to shrink by making sure we don't shrink so
0875       // much that we would need to grow the table after a few inserts.
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   // Interpret `head` as a linked list and insert all the nodes into `this`.
0892   // REQUIRES: this->empty()
0893   // REQUIRES: the input nodes have unique keys
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   // Resize to the given number of buckets.
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       // This is the global empty array.
0917       // Just overwrite with a new one. No need to transfer or free anything.
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 // The purpose of this class is to give the Rust implementation visibility into
0954 // some of the internals of C++ proto maps. We need access to these internals
0955 // to be able to implement Rust map operations without duplicating the same
0956 // functionality for every message type.
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, /* arena = */ nullptr);
0985   }
0986 };
0987 
0988 }  // namespace internal
0989 
0990 // This is the class for Map's internal value_type.
0991 template <typename Key, typename T>
0992 using MapPair = std::pair<const Key, T>;
0993 
0994 // Map is an associative container type used to store protobuf map
0995 // fields.  Each Map instance may or may not use a different hash function, a
0996 // different iteration order, and so on.  E.g., please don't examine
0997 // implementation details to decide if the following would work:
0998 //  Map<int, int> m0, m1;
0999 //  m0[0] = m1[0] = m0[1] = m1[1] = 0;
1000 //  assert(m0.begin()->first == m1.begin()->first);  // Bug!
1001 //
1002 // Map's interface is similar to std::unordered_map, except that Map is not
1003 // designed to play well with exceptions.
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   // Internal Arena constructors: do not use!
1028   // TODO: remove non internal ctors
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     // Fail-safe in case we miss calling this in a constructor.  Note: this one
1062     // won't trigger for leaked maps that never get destructed.
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     // The Rust implementation that wraps C++ protos relies on the ability to
1103     // create an UntypedMapBase and cast a pointer of it to google::protobuf::Map*.
1104     static_assert(
1105         sizeof(Map) == sizeof(internal::UntypedMapBase),
1106         "Map must not have any data members beyond what is in UntypedMapBase.");
1107 
1108     // Check for MpMap optimizations.
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   // Iterators
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     // Allow implicit conversion to const_iterator.
1214     operator const_iterator() const {  // NOLINT(google-explicit-constructor)
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   // Element access
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       // Disable for integral types to reduce code bloat.
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   // Lookup
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   // insert
1323   template <typename K, typename... Args>
1324   std::pair<iterator, bool> try_emplace(K&& k, Args&&... args)
1325       ABSL_ATTRIBUTE_LIFETIME_BOUND {
1326     // Case 1: `mapped_type` is arena constructible. A temporary object is
1327     // created and then (if `Args` are not empty) assigned to a mapped value
1328     // that was created with the arena.
1329     if constexpr (Arena::is_arena_constructable<mapped_type>::value) {
1330       if constexpr (sizeof...(Args) == 0) {
1331         // case 1.1: "default" constructed (e.g. from arena only).
1332         return TryEmplaceInternal(std::forward<K>(k));
1333       } else {
1334         // case 1.2: "default" constructed + copy/move assignment
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             // Avoid the temporary when the input is the right type.
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       // Case 2: `mapped_type` is not arena constructible. Using in-place
1349       // construction.
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     // We try to construct `init_type` from `Args` with a fall back to
1367     // `value_type`. The latter is less desired as it unconditionally makes a
1368     // copy of `value_type::first`.
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   // Erase and clear
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   // Assign
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   // Linked-list nodes, as one would expect for a chaining hash table.
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     // If K is not key_type, make the conversion to key_type explicit.
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     // Even when arena is nullptr, CreateInArenaStorage is still used to
1484     // ensure the arena of submessage will be consistent. Otherwise,
1485     // submessage may have its own arena when message-owned arena is enabled.
1486     // Note: This only works if `Key` is not arena constructible.
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     // Note: if `T` is arena constructible, `Args` needs to be empty.
1494     Arena::CreateInArenaStorage(&node->kv.second, this->arena_,
1495                                 std::forward<Args>(args)...);
1496     return node;
1497   }
1498 
1499   // Copy all elements from `other`, using the arena from `this`.
1500   // Return them as a linked list, using the `next` pointer in the node.
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     // We split the logic in two: first we clone the data which requires
1520     // Key/Value types, then we insert them all which only requires Key.
1521     // That way we reduce code duplication.
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     // Case 1: key was already present.
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     // Case 2: insert.
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 }  // namespace internal
1569 
1570 }  // namespace protobuf
1571 }  // namespace google
1572 
1573 #include "google/protobuf/port_undef.inc"
1574 
1575 #endif  // GOOGLE_PROTOBUF_MAP_H__