Coverage Report

Created: 2025-04-27 06:20

/src/LPM/external.protobuf/include/google/protobuf/map.h
Line
Count
Source (jump to first uncovered line)
1
// Protocol Buffers - Google's data interchange format
2
// Copyright 2008 Google Inc.  All rights reserved.
3
//
4
// Use of this source code is governed by a BSD-style
5
// license that can be found in the LICENSE file or at
6
// https://developers.google.com/open-source/licenses/bsd
7
8
// This file defines the map container and its helpers to support protobuf maps.
9
//
10
// The Map and MapIterator types are provided by this header file.
11
// Please avoid using other types defined here, unless they are public
12
// types within Map or MapIterator, such as Map::value_type.
13
14
#ifndef GOOGLE_PROTOBUF_MAP_H__
15
#define GOOGLE_PROTOBUF_MAP_H__
16
17
#include <algorithm>
18
#include <cstddef>
19
#include <cstdint>
20
#include <functional>
21
#include <initializer_list>
22
#include <iterator>
23
#include <limits>  // To support Visual Studio 2008
24
#include <string>
25
#include <type_traits>
26
#include <utility>
27
28
#if !defined(GOOGLE_PROTOBUF_NO_RDTSC) && defined(__APPLE__)
29
#include <time.h>
30
#endif
31
32
#include "google/protobuf/stubs/common.h"
33
#include "absl/base/attributes.h"
34
#include "absl/container/btree_map.h"
35
#include "absl/hash/hash.h"
36
#include "absl/log/absl_check.h"
37
#include "absl/meta/type_traits.h"
38
#include "absl/strings/string_view.h"
39
#include "google/protobuf/arena.h"
40
#include "google/protobuf/generated_enum_util.h"
41
#include "google/protobuf/internal_visibility.h"
42
#include "google/protobuf/map_type_handler.h"
43
#include "google/protobuf/port.h"
44
#include "google/protobuf/wire_format_lite.h"
45
46
47
#ifdef SWIG
48
#error "You cannot SWIG proto headers"
49
#endif
50
51
// Must be included last.
52
#include "google/protobuf/port_def.inc"
53
54
namespace google {
55
namespace protobuf {
56
57
template <typename Key, typename T>
58
class Map;
59
60
class MapIterator;
61
62
template <typename Enum>
63
struct is_proto_enum;
64
65
namespace rust {
66
struct PtrAndLen;
67
}  // namespace rust
68
69
namespace internal {
70
template <typename Key, typename T>
71
class MapFieldLite;
72
73
template <typename Derived, typename Key, typename T,
74
          WireFormatLite::FieldType key_wire_type,
75
          WireFormatLite::FieldType value_wire_type>
76
class MapField;
77
78
struct MapTestPeer;
79
struct MapBenchmarkPeer;
80
81
template <typename Key, typename T>
82
class TypeDefinedMapFieldBase;
83
84
class DynamicMapField;
85
86
class GeneratedMessageReflection;
87
88
// The largest valid serialization for a message is INT_MAX, so we can't have
89
// more than 32-bits worth of elements.
90
using map_index_t = uint32_t;
91
92
// Internal type traits that can be used to define custom key/value types. These
93
// are only be specialized by protobuf internals, and never by users.
94
template <typename T, typename VoidT = void>
95
struct is_internal_map_key_type : std::false_type {};
96
97
template <typename T, typename VoidT = void>
98
struct is_internal_map_value_type : std::false_type {};
99
100
// re-implement std::allocator to use arena allocator for memory allocation.
101
// Used for Map implementation. Users should not use this class
102
// directly.
103
template <typename U>
104
class MapAllocator {
105
 public:
106
  using value_type = U;
107
  using pointer = value_type*;
108
  using const_pointer = const value_type*;
109
  using reference = value_type&;
110
  using const_reference = const value_type&;
111
  using size_type = size_t;
112
  using difference_type = ptrdiff_t;
113
114
  constexpr MapAllocator() : arena_(nullptr) {}
115
  explicit constexpr MapAllocator(Arena* arena) : arena_(arena) {}
116
  template <typename X>
117
  MapAllocator(const MapAllocator<X>& allocator)  // NOLINT(runtime/explicit)
118
      : arena_(allocator.arena()) {}
119
120
  // MapAllocator does not support alignments beyond 8. Technically we should
121
  // support up to std::max_align_t, but this fails with ubsan and tcmalloc
122
  // debug allocation logic which assume 8 as default alignment.
123
  static_assert(alignof(value_type) <= 8, "");
124
125
0
  pointer allocate(size_type n, const void* /* hint */ = nullptr) {
126
0
    // If arena is not given, malloc needs to be called which doesn't
127
0
    // construct element object.
128
0
    if (arena_ == nullptr) {
129
0
      return static_cast<pointer>(::operator new(n * sizeof(value_type)));
130
0
    } else {
131
0
      return reinterpret_cast<pointer>(
132
0
          Arena::CreateArray<uint8_t>(arena_, n * sizeof(value_type)));
133
0
    }
134
0
  }
Unexecuted instantiation: google::protobuf::internal::MapAllocator<google::protobuf::internal::NodeBase>::allocate(unsigned long, void const*)
Unexecuted instantiation: google::protobuf::internal::MapAllocator<google::protobuf::internal::TableEntryPtr>::allocate(unsigned long, void const*)
135
136
0
  void deallocate(pointer p, size_type n) {
137
0
    if (arena_ == nullptr) {
138
0
      internal::SizedDelete(p, n * sizeof(value_type));
139
0
    }
140
0
  }
141
142
#if !defined(GOOGLE_PROTOBUF_OS_APPLE) && !defined(GOOGLE_PROTOBUF_OS_NACL) && \
143
    !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN)
144
  template <class NodeType, class... Args>
145
  void construct(NodeType* p, Args&&... args) {
146
    // Clang 3.6 doesn't compile static casting to void* directly. (Issue
147
    // #1266) According C++ standard 5.2.9/1: "The static_cast operator shall
148
    // not cast away constness". So first the maybe const pointer is casted to
149
    // const void* and after the const void* is const casted.
150
    new (const_cast<void*>(static_cast<const void*>(p)))
151
        NodeType(std::forward<Args>(args)...);
152
  }
153
154
  template <class NodeType>
155
  void destroy(NodeType* p) {
156
    p->~NodeType();
157
  }
158
#else
159
  void construct(pointer p, const_reference t) { new (p) value_type(t); }
160
161
  void destroy(pointer p) { p->~value_type(); }
162
#endif
163
164
  template <typename X>
165
  struct rebind {
166
    using other = MapAllocator<X>;
167
  };
168
169
  template <typename X>
170
  bool operator==(const MapAllocator<X>& other) const {
171
    return arena_ == other.arena_;
172
  }
173
174
  template <typename X>
175
  bool operator!=(const MapAllocator<X>& other) const {
176
    return arena_ != other.arena_;
177
  }
178
179
  // To support Visual Studio 2008
180
  size_type max_size() const {
181
    // parentheses around (std::...:max) prevents macro warning of max()
182
    return (std::numeric_limits<size_type>::max)();
183
  }
184
185
  // To support gcc-4.4, which does not properly
186
  // support templated friend classes
187
0
  Arena* arena() const { return arena_; }
188
189
 private:
190
  using DestructorSkippable_ = void;
191
  Arena* arena_;
192
};
193
194
// To save on binary size and simplify generic uses of the map types we collapse
195
// signed/unsigned versions of the same sized integer to the unsigned version.
196
template <typename T, typename = void>
197
struct KeyForBaseImpl {
198
  using type = T;
199
};
200
template <typename T>
201
struct KeyForBaseImpl<T, std::enable_if_t<std::is_integral<T>::value &&
202
                                          std::is_signed<T>::value>> {
203
  using type = std::make_unsigned_t<T>;
204
};
205
template <typename T>
206
using KeyForBase = typename KeyForBaseImpl<T>::type;
207
208
// Default case: Not transparent.
209
// We use std::hash<key_type>/std::less<key_type> and all the lookup functions
210
// only accept `key_type`.
211
template <typename key_type>
212
struct TransparentSupport {
213
  // We hash all the scalars as uint64_t so that we can implement the same hash
214
  // function for VariantKey. This way we can have MapKey provide the same hash
215
  // as the underlying value would have.
216
  using hash = absl::Hash<
217
      std::conditional_t<std::is_scalar<key_type>::value, uint64_t, key_type>>;
218
219
  static bool Equals(const key_type& a, const key_type& b) { return a == b; }
220
221
  template <typename K>
222
  using key_arg = key_type;
223
224
  using ViewType = std::conditional_t<std::is_scalar<key_type>::value, key_type,
225
                                      const key_type&>;
226
  static ViewType ToView(const key_type& v) { return v; }
227
};
228
229
// We add transparent support for std::string keys. We use
230
// absl::Hash<absl::string_view> as it supports the input types we care about.
231
// The lookup functions accept arbitrary `K`. This will include any key type
232
// that is convertible to absl::string_view.
233
template <>
234
struct TransparentSupport<std::string> {
235
  // Use go/ranked-overloads for dispatching.
236
  struct Rank0 {};
237
  struct Rank1 : Rank0 {};
238
  struct Rank2 : Rank1 {};
239
  template <typename T, typename = std::enable_if_t<
240
                            std::is_convertible<T, absl::string_view>::value>>
241
  static absl::string_view ImplicitConvertImpl(T&& str, Rank2) {
242
    absl::string_view ref = str;
243
    return ref;
244
  }
245
  template <typename T, typename = std::enable_if_t<
246
                            std::is_convertible<T, const std::string&>::value>>
247
  static absl::string_view ImplicitConvertImpl(T&& str, Rank1) {
248
    const std::string& ref = str;
249
    return ref;
250
  }
251
  template <typename T>
252
  static absl::string_view ImplicitConvertImpl(T&& str, Rank0) {
253
    return {str.data(), str.size()};
254
  }
255
256
  template <typename T>
257
  static absl::string_view ImplicitConvert(T&& str) {
258
    return ImplicitConvertImpl(std::forward<T>(str), Rank2{});
259
  }
260
261
  struct hash : public absl::Hash<absl::string_view> {
262
    using is_transparent = void;
263
264
    template <typename T>
265
    size_t operator()(T&& str) const {
266
      return absl::Hash<absl::string_view>::operator()(
267
          ImplicitConvert(std::forward<T>(str)));
268
    }
269
  };
270
271
  template <typename T, typename U>
272
  static bool Equals(T&& t, U&& u) {
273
    return ImplicitConvert(std::forward<T>(t)) ==
274
           ImplicitConvert(std::forward<U>(u));
275
  }
276
277
  template <typename K>
278
  using key_arg = K;
279
280
  using ViewType = absl::string_view;
281
  template <typename T>
282
  static ViewType ToView(const T& v) {
283
    return ImplicitConvert(v);
284
  }
285
};
286
287
enum class MapNodeSizeInfoT : uint32_t;
288
0
inline uint16_t SizeFromInfo(MapNodeSizeInfoT node_size_info) {
289
0
  return static_cast<uint16_t>(static_cast<uint32_t>(node_size_info) >> 16);
290
0
}
291
0
inline uint16_t ValueOffsetFromInfo(MapNodeSizeInfoT node_size_info) {
292
0
  return static_cast<uint16_t>(static_cast<uint32_t>(node_size_info) >> 0);
293
0
}
294
0
constexpr MapNodeSizeInfoT MakeNodeInfo(uint16_t size, uint16_t value_offset) {
295
0
  return static_cast<MapNodeSizeInfoT>((static_cast<uint32_t>(size) << 16) |
296
0
                                       value_offset);
297
0
}
298
299
struct NodeBase {
300
  // Align the node to allow KeyNode to predict the location of the key.
301
  // This way sizeof(NodeBase) contains any possible padding it was going to
302
  // have between NodeBase and the key.
303
  alignas(kMaxMessageAlignment) NodeBase* next;
304
305
0
  void* GetVoidKey() { return this + 1; }
306
0
  const void* GetVoidKey() const { return this + 1; }
307
308
0
  void* GetVoidValue(MapNodeSizeInfoT size_info) {
309
0
    return reinterpret_cast<char*>(this) + ValueOffsetFromInfo(size_info);
310
0
  }
311
};
312
313
0
inline NodeBase* EraseFromLinkedList(NodeBase* item, NodeBase* head) {
314
0
  if (head == item) {
315
0
    return head->next;
316
0
  } else {
317
0
    head->next = EraseFromLinkedList(item, head->next);
318
0
    return head;
319
0
  }
320
0
}
321
322
0
constexpr size_t MapTreeLengthThreshold() { return 8; }
323
0
inline bool TableEntryIsTooLong(NodeBase* node) {
324
0
  const size_t kMaxLength = MapTreeLengthThreshold();
325
0
  size_t count = 0;
326
0
  do {
327
0
    ++count;
328
0
    node = node->next;
329
0
  } while (node != nullptr);
330
0
  // Invariant: no linked list ever is more than kMaxLength in length.
331
0
  ABSL_DCHECK_LE(count, kMaxLength);
332
0
  return count >= kMaxLength;
333
0
}
334
335
// Similar to the public MapKey, but specialized for the internal
336
// implementation.
337
struct VariantKey {
338
  // We make this value 16 bytes to make it cheaper to pass in the ABI.
339
  // Can't overload string_view this way, so we unpack the fields.
340
  // data==nullptr means this is a number and `integral` is the value.
341
  // data!=nullptr means this is a string and `integral` is the size.
342
  const char* data;
343
  uint64_t integral;
344
345
0
  explicit VariantKey(uint64_t v) : data(nullptr), integral(v) {}
346
  explicit VariantKey(absl::string_view v)
347
0
      : data(v.data()), integral(v.size()) {
348
0
    // We use `data` to discriminate between the types, so make sure it is never
349
0
    // null here.
350
0
    if (data == nullptr) data = "";
351
0
  }
352
353
0
  friend bool operator<(const VariantKey& left, const VariantKey& right) {
354
0
    ABSL_DCHECK_EQ(left.data == nullptr, right.data == nullptr);
355
0
    if (left.integral != right.integral) {
356
0
      // If they are numbers with different value, or strings with different
357
0
      // size, check the number only.
358
0
      return left.integral < right.integral;
359
0
    }
360
0
    if (left.data == nullptr) {
361
0
      // If they are numbers they have the same value, so return.
362
0
      return false;
363
0
    }
364
0
    // They are strings of the same size, so check the bytes.
365
0
    return memcmp(left.data, right.data, left.integral) < 0;
366
0
  }
367
};
368
369
// This is to be specialized by MapKey.
370
template <typename T>
371
struct RealKeyToVariantKey {
372
  VariantKey operator()(T value) const { return VariantKey(value); }
373
};
374
375
template <typename T, typename = void>
376
struct RealKeyToVariantKeyAlternative;
377
378
template <typename T>
379
struct RealKeyToVariantKeyAlternative<
380
    T, typename std::enable_if<std::is_integral<T>::value>::type> {
381
  uint64_t operator()(uint64_t value) const { return value; }
382
};
383
384
template <>
385
struct RealKeyToVariantKey<std::string> {
386
  template <typename T>
387
  VariantKey operator()(const T& value) const {
388
    return VariantKey(TransparentSupport<std::string>::ImplicitConvert(value));
389
  }
390
};
391
392
template <>
393
struct RealKeyToVariantKeyAlternative<std::string> {
394
0
  absl::string_view operator()(absl::string_view value) const { return value; }
395
};
396
397
// We use a single kind of tree for all maps. This reduces code duplication.
398
using TreeForMap =
399
    absl::btree_map<VariantKey, NodeBase*, std::less<VariantKey>,
400
                    MapAllocator<std::pair<const VariantKey, NodeBase*>>>;
401
402
// Type safe tagged pointer.
403
// We convert to/from nodes and trees using the operations below.
404
// They ensure that the tags are used correctly.
405
// There are three states:
406
//  - x == 0: the entry is empty
407
//  - x != 0 && (x&1) == 0: the entry is a node list
408
//  - x != 0 && (x&1) == 1: the entry is a tree
409
enum class TableEntryPtr : uintptr_t;
410
411
0
inline bool TableEntryIsEmpty(TableEntryPtr entry) {
412
0
  return entry == TableEntryPtr{};
413
0
}
414
0
inline bool TableEntryIsTree(TableEntryPtr entry) {
415
0
  return (static_cast<uintptr_t>(entry) & 1) == 1;
416
0
}
417
0
inline bool TableEntryIsList(TableEntryPtr entry) {
418
0
  return !TableEntryIsTree(entry);
419
0
}
420
0
inline bool TableEntryIsNonEmptyList(TableEntryPtr entry) {
421
0
  return !TableEntryIsEmpty(entry) && TableEntryIsList(entry);
422
0
}
423
0
inline NodeBase* TableEntryToNode(TableEntryPtr entry) {
424
0
  ABSL_DCHECK(TableEntryIsList(entry));
425
0
  return reinterpret_cast<NodeBase*>(static_cast<uintptr_t>(entry));
426
0
}
427
0
inline TableEntryPtr NodeToTableEntry(NodeBase* node) {
428
0
  ABSL_DCHECK((reinterpret_cast<uintptr_t>(node) & 1) == 0);
429
0
  return static_cast<TableEntryPtr>(reinterpret_cast<uintptr_t>(node));
430
0
}
431
0
inline TreeForMap* TableEntryToTree(TableEntryPtr entry) {
432
0
  ABSL_DCHECK(TableEntryIsTree(entry));
433
0
  return reinterpret_cast<TreeForMap*>(static_cast<uintptr_t>(entry) - 1);
434
0
}
435
0
inline TableEntryPtr TreeToTableEntry(TreeForMap* node) {
436
0
  ABSL_DCHECK((reinterpret_cast<uintptr_t>(node) & 1) == 0);
437
0
  return static_cast<TableEntryPtr>(reinterpret_cast<uintptr_t>(node) | 1);
438
0
}
439
440
// This captures all numeric types.
441
0
inline size_t MapValueSpaceUsedExcludingSelfLong(bool) { return 0; }
442
0
inline size_t MapValueSpaceUsedExcludingSelfLong(const std::string& str) {
443
0
  return StringSpaceUsedExcludingSelfLong(str);
444
0
}
445
template <typename T,
446
          typename = decltype(std::declval<const T&>().SpaceUsedLong())>
447
size_t MapValueSpaceUsedExcludingSelfLong(const T& message) {
448
  return message.SpaceUsedLong() - sizeof(T);
449
}
450
451
constexpr size_t kGlobalEmptyTableSize = 1;
452
PROTOBUF_EXPORT extern const TableEntryPtr
453
    kGlobalEmptyTable[kGlobalEmptyTableSize];
454
455
template <typename Map,
456
          typename = typename std::enable_if<
457
              !std::is_scalar<typename Map::key_type>::value ||
458
              !std::is_scalar<typename Map::mapped_type>::value>::type>
459
size_t SpaceUsedInValues(const Map* map) {
460
  size_t size = 0;
461
  for (const auto& v : *map) {
462
    size += internal::MapValueSpaceUsedExcludingSelfLong(v.first) +
463
            internal::MapValueSpaceUsedExcludingSelfLong(v.second);
464
  }
465
  return size;
466
}
467
468
0
inline size_t SpaceUsedInValues(const void*) { return 0; }
469
470
class UntypedMapBase;
471
472
class UntypedMapIterator {
473
 public:
474
  // Invariants:
475
  // node_ is always correct. This is handy because the most common
476
  // operations are operator* and operator-> and they only use node_.
477
  // When node_ is set to a non-null value, all the other non-const fields
478
  // are updated to be correct also, but those fields can become stale
479
  // if the underlying map is modified.  When those fields are needed they
480
  // are rechecked, and updated if necessary.
481
482
  // We do not provide any constructors for this type. We need it to be a
483
  // trivial type to ensure that we can safely share it with Rust.
484
485
  // Advance through buckets, looking for the first that isn't empty.
486
  // If nothing non-empty is found then leave node_ == nullptr.
487
  void SearchFrom(map_index_t start_bucket);
488
489
  // The definition of operator== is handled by the derived type. If we were
490
  // to do it in this class it would allow comparing iterators of different
491
  // map types.
492
0
  bool Equals(const UntypedMapIterator& other) const {
493
0
    return node_ == other.node_;
494
0
  }
495
496
  // The definition of operator++ is handled in the derived type. We would not
497
  // be able to return the right type from here.
498
0
  void PlusPlus() {
499
0
    if (node_->next == nullptr) {
500
0
      SearchFrom(bucket_index_ + 1);
501
0
    } else {
502
0
      node_ = node_->next;
503
0
    }
504
0
  }
505
506
  // Conversion to and from a typed iterator child class is used by FFI.
507
  template <class Iter>
508
  static UntypedMapIterator FromTyped(Iter it) {
509
    static_assert(
510
#if defined(__cpp_lib_is_layout_compatible) && \
511
    __cpp_lib_is_layout_compatible >= 201907L
512
        std::is_layout_compatible_v<Iter, UntypedMapIterator>,
513
#else
514
        sizeof(it) == sizeof(UntypedMapIterator),
515
#endif
516
        "Map iterator must not have extra state that the base class"
517
        "does not define.");
518
    return static_cast<UntypedMapIterator>(it);
519
  }
520
521
  template <class Iter>
522
  Iter ToTyped() const {
523
    return Iter(*this);
524
  }
525
  NodeBase* node_;
526
  const UntypedMapBase* m_;
527
  map_index_t bucket_index_;
528
};
529
530
// These properties are depended upon by Rust FFI.
531
static_assert(std::is_trivial<UntypedMapIterator>::value,
532
              "UntypedMapIterator must be a trivial type.");
533
static_assert(std::is_trivially_copyable<UntypedMapIterator>::value,
534
              "UntypedMapIterator must be trivially copyable.");
535
static_assert(std::is_trivially_destructible<UntypedMapIterator>::value,
536
              "UntypedMapIterator must be trivially destructible.");
537
static_assert(std::is_standard_layout<UntypedMapIterator>::value,
538
              "UntypedMapIterator must be standard layout.");
539
static_assert(offsetof(UntypedMapIterator, node_) == 0,
540
              "node_ must be the first field of UntypedMapIterator.");
541
static_assert(sizeof(UntypedMapIterator) ==
542
                  sizeof(void*) * 2 +
543
                      std::max(sizeof(uint32_t), alignof(void*)),
544
              "UntypedMapIterator does not have the expected size for FFI");
545
static_assert(
546
    alignof(UntypedMapIterator) == std::max(alignof(void*), alignof(uint32_t)),
547
    "UntypedMapIterator does not have the expected alignment for FFI");
548
549
// Base class for all Map instantiations.
550
// This class holds all the data and provides the basic functionality shared
551
// among all instantiations.
552
// Having an untyped base class helps generic consumers (like the table-driven
553
// parser) by having non-template code that can handle all instantiations.
554
class PROTOBUF_EXPORT UntypedMapBase {
555
  using Allocator = internal::MapAllocator<void*>;
556
  using Tree = internal::TreeForMap;
557
558
 public:
559
  using size_type = size_t;
560
561
  explicit constexpr UntypedMapBase(Arena* arena)
562
      : num_elements_(0),
563
        num_buckets_(internal::kGlobalEmptyTableSize),
564
        seed_(0),
565
        index_of_first_non_null_(internal::kGlobalEmptyTableSize),
566
        table_(const_cast<TableEntryPtr*>(internal::kGlobalEmptyTable)),
567
0
        alloc_(arena) {}
568
569
  UntypedMapBase(const UntypedMapBase&) = delete;
570
  UntypedMapBase& operator=(const UntypedMapBase&) = delete;
571
572
 protected:
573
  // 16 bytes is the minimum useful size for the array cache in the arena.
574
  enum : map_index_t { kMinTableSize = 16 / sizeof(void*) };
575
576
 public:
577
0
  Arena* arena() const { return this->alloc_.arena(); }
578
579
0
  void InternalSwap(UntypedMapBase* other) {
580
0
    std::swap(num_elements_, other->num_elements_);
581
0
    std::swap(num_buckets_, other->num_buckets_);
582
0
    std::swap(seed_, other->seed_);
583
0
    std::swap(index_of_first_non_null_, other->index_of_first_non_null_);
584
0
    std::swap(table_, other->table_);
585
0
    std::swap(alloc_, other->alloc_);
586
0
  }
587
588
0
  static size_type max_size() {
589
0
    return std::numeric_limits<map_index_t>::max();
590
0
  }
591
0
  size_type size() const { return num_elements_; }
592
0
  bool empty() const { return size() == 0; }
593
  UntypedMapIterator begin() const;
594
595
  // We make this a static function to reduce the cost in MapField.
596
  // All the end iterators are singletons anyway.
597
0
  static UntypedMapIterator EndIterator() { return {nullptr, nullptr, 0}; }
598
599
 protected:
600
  friend class TcParser;
601
  friend struct MapTestPeer;
602
  friend struct MapBenchmarkPeer;
603
  friend class UntypedMapIterator;
604
  friend class RustMapHelper;
605
606
  struct NodeAndBucket {
607
    NodeBase* node;
608
    map_index_t bucket;
609
  };
610
611
  // Returns whether we should insert after the head of the list. For
612
  // non-optimized builds, we randomly decide whether to insert right at the
613
  // head of the list or just after the head. This helps add a little bit of
614
  // non-determinism to the map ordering.
615
0
  bool ShouldInsertAfterHead(void* node) {
616
0
#ifdef NDEBUG
617
0
    (void)node;
618
0
    return false;
619
0
#else
620
0
    // Doing modulo with a prime mixes the bits more.
621
0
    return (reinterpret_cast<uintptr_t>(node) ^ seed_) % 13 > 6;
622
0
#endif
623
0
  }
624
625
  // Helper for InsertUnique.  Handles the case where bucket b is a
626
  // not-too-long linked list.
627
0
  void InsertUniqueInList(map_index_t b, NodeBase* node) {
628
0
    if (!TableEntryIsEmpty(b) && ShouldInsertAfterHead(node)) {
629
0
      auto* first = TableEntryToNode(table_[b]);
630
0
      node->next = first->next;
631
0
      first->next = node;
632
0
    } else {
633
0
      node->next = TableEntryToNode(table_[b]);
634
0
      table_[b] = NodeToTableEntry(node);
635
0
    }
636
0
  }
637
638
0
  bool TableEntryIsEmpty(map_index_t b) const {
639
0
    return internal::TableEntryIsEmpty(table_[b]);
640
0
  }
641
0
  bool TableEntryIsNonEmptyList(map_index_t b) const {
642
0
    return internal::TableEntryIsNonEmptyList(table_[b]);
643
0
  }
644
0
  bool TableEntryIsTree(map_index_t b) const {
645
0
    return internal::TableEntryIsTree(table_[b]);
646
0
  }
647
0
  bool TableEntryIsList(map_index_t b) const {
648
0
    return internal::TableEntryIsList(table_[b]);
649
0
  }
650
651
  // Return whether table_[b] is a linked list that seems awfully long.
652
  // Requires table_[b] to point to a non-empty linked list.
653
0
  bool TableEntryIsTooLong(map_index_t b) {
654
0
    return internal::TableEntryIsTooLong(TableEntryToNode(table_[b]));
655
0
  }
656
657
  // Return a power of two no less than max(kMinTableSize, n).
658
  // Assumes either n < kMinTableSize or n is a power of two.
659
0
  map_index_t TableSize(map_index_t n) {
660
0
    return n < kMinTableSize ? kMinTableSize : n;
661
0
  }
662
663
  template <typename T>
664
  using AllocFor = absl::allocator_traits<Allocator>::template rebind_alloc<T>;
665
666
  // Alignment of the nodes is the same as alignment of NodeBase.
667
0
  NodeBase* AllocNode(MapNodeSizeInfoT size_info) {
668
0
    return AllocNode(SizeFromInfo(size_info));
669
0
  }
670
671
0
  NodeBase* AllocNode(size_t node_size) {
672
0
    PROTOBUF_ASSUME(node_size % sizeof(NodeBase) == 0);
673
0
    return AllocFor<NodeBase>(alloc_).allocate(node_size / sizeof(NodeBase));
674
0
  }
675
676
0
  void DeallocNode(NodeBase* node, MapNodeSizeInfoT size_info) {
677
0
    DeallocNode(node, SizeFromInfo(size_info));
678
0
  }
679
680
0
  void DeallocNode(NodeBase* node, size_t node_size) {
681
0
    PROTOBUF_ASSUME(node_size % sizeof(NodeBase) == 0);
682
0
    AllocFor<NodeBase>(alloc_).deallocate(node, node_size / sizeof(NodeBase));
683
0
  }
684
685
0
  void DeleteTable(TableEntryPtr* table, map_index_t n) {
686
0
    if (auto* a = arena()) {
687
0
      a->ReturnArrayMemory(table, n * sizeof(TableEntryPtr));
688
0
    } else {
689
0
      internal::SizedDelete(table, n * sizeof(TableEntryPtr));
690
0
    }
691
0
  }
692
693
  NodeBase* DestroyTree(Tree* tree);
694
  using GetKey = VariantKey (*)(NodeBase*);
695
  void InsertUniqueInTree(map_index_t b, GetKey get_key, NodeBase* node);
696
  void TransferTree(Tree* tree, GetKey get_key);
697
  TableEntryPtr ConvertToTree(NodeBase* node, GetKey get_key);
698
  void EraseFromTree(map_index_t b, typename Tree::iterator tree_it);
699
700
0
  map_index_t VariantBucketNumber(VariantKey key) const {
701
0
    return key.data == nullptr
702
0
               ? VariantBucketNumber(key.integral)
703
0
               : VariantBucketNumber(absl::string_view(
704
0
                     key.data, static_cast<size_t>(key.integral)));
705
0
  }
706
707
0
  map_index_t VariantBucketNumber(absl::string_view key) const {
708
0
    return static_cast<map_index_t>(absl::HashOf(seed_, key) &
709
0
                                    (num_buckets_ - 1));
710
0
  }
711
712
0
  map_index_t VariantBucketNumber(uint64_t key) const {
713
0
    return static_cast<map_index_t>(absl::HashOf(key ^ seed_) &
714
0
                                    (num_buckets_ - 1));
715
0
  }
716
717
0
  TableEntryPtr* CreateEmptyTable(map_index_t n) {
718
0
    ABSL_DCHECK_GE(n, kMinTableSize);
719
0
    ABSL_DCHECK_EQ(n & (n - 1), 0u);
720
0
    TableEntryPtr* result = AllocFor<TableEntryPtr>(alloc_).allocate(n);
721
0
    memset(result, 0, n * sizeof(result[0]));
722
0
    return result;
723
0
  }
724
725
  // Return a randomish value.
726
0
  map_index_t Seed() const {
727
0
    uint64_t s = 0;
728
0
#if !defined(GOOGLE_PROTOBUF_NO_RDTSC)
729
0
#if defined(__APPLE__)
730
0
    // Use a commpage-based fast time function on Apple environments (MacOS,
731
0
    // iOS, tvOS, watchOS, etc).
732
0
    s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
733
0
#elif defined(__x86_64__) && defined(__GNUC__)
734
0
    uint32_t hi, lo;
735
0
    asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
736
0
    s = ((static_cast<uint64_t>(hi) << 32) | lo);
737
0
#elif defined(__aarch64__) && defined(__GNUC__)
738
0
    // There is no rdtsc on ARMv8. CNTVCT_EL0 is the virtual counter of the
739
0
    // system timer. It runs at a different frequency than the CPU's, but is
740
0
    // the best source of time-based entropy we get.
741
0
    uint64_t virtual_timer_value;
742
0
    asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
743
0
    s = virtual_timer_value;
744
0
#endif
745
0
#endif  // !defined(GOOGLE_PROTOBUF_NO_RDTSC)
746
0
    // Add entropy from the address of the map and the address of the table
747
0
    // array.
748
0
    return static_cast<map_index_t>(
749
0
        absl::HashOf(s, table_, static_cast<const void*>(this)));
750
0
  }
751
752
  enum {
753
    kKeyIsString = 1 << 0,
754
    kValueIsString = 1 << 1,
755
    kValueIsProto = 1 << 2,
756
    kUseDestructFunc = 1 << 3,
757
  };
758
  template <typename Key, typename Value>
759
  static constexpr uint8_t MakeDestroyBits() {
760
    uint8_t result = 0;
761
    if (!std::is_trivially_destructible<Key>::value) {
762
      if (std::is_same<Key, std::string>::value) {
763
        result |= kKeyIsString;
764
      } else {
765
        return kUseDestructFunc;
766
      }
767
    }
768
    if (!std::is_trivially_destructible<Value>::value) {
769
      if (std::is_same<Value, std::string>::value) {
770
        result |= kValueIsString;
771
      } else if (std::is_base_of<MessageLite, Value>::value) {
772
        result |= kValueIsProto;
773
      } else {
774
        return kUseDestructFunc;
775
      }
776
    }
777
    return result;
778
  }
779
780
  struct ClearInput {
781
    MapNodeSizeInfoT size_info;
782
    uint8_t destroy_bits;
783
    bool reset_table;
784
    void (*destroy_node)(NodeBase*);
785
  };
786
787
  template <typename Node>
788
  static void DestroyNode(NodeBase* node) {
789
    static_cast<Node*>(node)->~Node();
790
  }
791
792
  template <typename Node>
793
  static constexpr ClearInput MakeClearInput(bool reset) {
794
    constexpr auto bits =
795
        MakeDestroyBits<typename Node::key_type, typename Node::mapped_type>();
796
    return ClearInput{Node::size_info(), bits, reset,
797
                      bits & kUseDestructFunc ? DestroyNode<Node> : nullptr};
798
  }
799
800
  void ClearTable(ClearInput input);
801
802
  NodeAndBucket FindFromTree(map_index_t b, VariantKey key,
803
                             Tree::iterator* it) const;
804
805
  // Space used for the table, trees, and nodes.
806
  // Does not include the indirect space used. Eg the data of a std::string.
807
  size_t SpaceUsedInTable(size_t sizeof_node) const;
808
809
  map_index_t num_elements_;
810
  map_index_t num_buckets_;
811
  map_index_t seed_;
812
  map_index_t index_of_first_non_null_;
813
  TableEntryPtr* table_;  // an array with num_buckets_ entries
814
  Allocator alloc_;
815
};
816
817
0
inline UntypedMapIterator UntypedMapBase::begin() const {
818
0
  map_index_t bucket_index;
819
0
  NodeBase* node;
820
0
  if (index_of_first_non_null_ == num_buckets_) {
821
0
    bucket_index = 0;
822
0
    node = nullptr;
823
0
  } else {
824
0
    bucket_index = index_of_first_non_null_;
825
0
    TableEntryPtr entry = table_[bucket_index];
826
0
    node = PROTOBUF_PREDICT_TRUE(internal::TableEntryIsList(entry))
827
0
               ? TableEntryToNode(entry)
828
0
               : TableEntryToTree(entry)->begin()->second;
829
0
    PROTOBUF_ASSUME(node != nullptr);
830
0
  }
831
0
  return UntypedMapIterator{node, this, bucket_index};
832
0
}
833
834
0
inline void UntypedMapIterator::SearchFrom(map_index_t start_bucket) {
835
0
  ABSL_DCHECK(m_->index_of_first_non_null_ == m_->num_buckets_ ||
836
0
              !m_->TableEntryIsEmpty(m_->index_of_first_non_null_));
837
0
  for (map_index_t i = start_bucket; i < m_->num_buckets_; ++i) {
838
0
    TableEntryPtr entry = m_->table_[i];
839
0
    if (entry == TableEntryPtr{}) continue;
840
0
    bucket_index_ = i;
841
0
    if (PROTOBUF_PREDICT_TRUE(TableEntryIsList(entry))) {
842
0
      node_ = TableEntryToNode(entry);
843
0
    } else {
844
0
      TreeForMap* tree = TableEntryToTree(entry);
845
0
      ABSL_DCHECK(!tree->empty());
846
0
      node_ = tree->begin()->second;
847
0
    }
848
0
    return;
849
0
  }
850
0
  node_ = nullptr;
851
0
  bucket_index_ = 0;
852
0
}
853
854
// Base class used by TcParser to extract the map object from a map field.
855
// We keep it here to avoid a dependency into map_field.h from the main TcParser
856
// code, since that would bring in Message too.
857
class MapFieldBaseForParse {
858
 public:
859
0
  const UntypedMapBase& GetMap() const {
860
0
    return vtable_->get_map(*this, false);
861
0
  }
862
0
  UntypedMapBase* MutableMap() {
863
0
    return &const_cast<UntypedMapBase&>(vtable_->get_map(*this, true));
864
0
  }
865
866
 protected:
867
  struct VTable {
868
    const UntypedMapBase& (*get_map)(const MapFieldBaseForParse&,
869
                                     bool is_mutable);
870
  };
871
  explicit constexpr MapFieldBaseForParse(const VTable* vtable)
872
0
      : vtable_(vtable) {}
873
  ~MapFieldBaseForParse() = default;
874
875
  const VTable* vtable_;
876
};
877
878
// The value might be of different signedness, so use memcpy to extract it.
879
template <typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
880
T ReadKey(const void* ptr) {
881
  T out;
882
  memcpy(&out, ptr, sizeof(T));
883
  return out;
884
}
885
886
template <typename T, std::enable_if_t<!std::is_integral<T>::value, int> = 0>
887
const T& ReadKey(const void* ptr) {
888
  return *reinterpret_cast<const T*>(ptr);
889
}
890
891
template <typename Key>
892
struct KeyNode : NodeBase {
893
  static constexpr size_t kOffset = sizeof(NodeBase);
894
  decltype(auto) key() const { return ReadKey<Key>(GetVoidKey()); }
895
};
896
897
// KeyMapBase is a chaining hash map with the additional feature that some
898
// buckets can be converted to use an ordered container.  This ensures O(lg n)
899
// bounds on find, insert, and erase, while avoiding the overheads of ordered
900
// containers most of the time.
901
//
902
// The implementation doesn't need the full generality of unordered_map,
903
// and it doesn't have it.  More bells and whistles can be added as needed.
904
// Some implementation details:
905
// 1. The number of buckets is a power of two.
906
// 2. As is typical for hash_map and such, the Keys and Values are always
907
//    stored in linked list nodes.  Pointers to elements are never invalidated
908
//    until the element is deleted.
909
// 3. The trees' payload type is pointer to linked-list node.  Tree-converting
910
//    a bucket doesn't copy Key-Value pairs.
911
// 4. Once we've tree-converted a bucket, it is never converted back unless the
912
//    bucket is completely emptied out. Note that the items a tree contains may
913
//    wind up assigned to trees or lists upon a rehash.
914
// 5. Mutations to a map do not invalidate the map's iterators, pointers to
915
//    elements, or references to elements.
916
// 6. Except for erase(iterator), any non-const method can reorder iterators.
917
// 7. Uses VariantKey when using the Tree representation, which holds all
918
//    possible key types as a variant value.
919
920
template <typename Key>
921
class KeyMapBase : public UntypedMapBase {
922
  static_assert(!std::is_signed<Key>::value || !std::is_integral<Key>::value,
923
                "");
924
925
  using TS = TransparentSupport<Key>;
926
927
 public:
928
  using hasher = typename TS::hash;
929
930
  using UntypedMapBase::UntypedMapBase;
931
932
 protected:
933
  using KeyNode = internal::KeyNode<Key>;
934
935
  // Trees. The payload type is a copy of Key, so that we can query the tree
936
  // with Keys that are not in any particular data structure.
937
  // The value is a void* pointing to Node. We use void* instead of Node* to
938
  // avoid code bloat. That way there is only one instantiation of the tree
939
  // class per key type.
940
  using Tree = internal::TreeForMap;
941
  using TreeIterator = typename Tree::iterator;
942
943
 public:
944
  hasher hash_function() const { return {}; }
945
946
 protected:
947
  friend class TcParser;
948
  friend struct MapTestPeer;
949
  friend struct MapBenchmarkPeer;
950
  friend class RustMapHelper;
951
952
  PROTOBUF_NOINLINE void erase_no_destroy(map_index_t b, KeyNode* node) {
953
    TreeIterator tree_it;
954
    const bool is_list = revalidate_if_necessary(b, node, &tree_it);
955
    if (is_list) {
956
      ABSL_DCHECK(TableEntryIsNonEmptyList(b));
957
      auto* head = TableEntryToNode(table_[b]);
958
      head = EraseFromLinkedList(node, head);
959
      table_[b] = NodeToTableEntry(head);
960
    } else {
961
      EraseFromTree(b, tree_it);
962
    }
963
    --num_elements_;
964
    if (PROTOBUF_PREDICT_FALSE(b == index_of_first_non_null_)) {
965
      while (index_of_first_non_null_ < num_buckets_ &&
966
             TableEntryIsEmpty(index_of_first_non_null_)) {
967
        ++index_of_first_non_null_;
968
      }
969
    }
970
  }
971
972
  NodeAndBucket FindHelper(typename TS::ViewType k,
973
                           TreeIterator* it = nullptr) const {
974
    map_index_t b = BucketNumber(k);
975
    if (TableEntryIsNonEmptyList(b)) {
976
      auto* node = internal::TableEntryToNode(table_[b]);
977
      do {
978
        if (TS::Equals(static_cast<KeyNode*>(node)->key(), k)) {
979
          return {node, b};
980
        } else {
981
          node = node->next;
982
        }
983
      } while (node != nullptr);
984
    } else if (TableEntryIsTree(b)) {
985
      return FindFromTree(b, internal::RealKeyToVariantKey<Key>{}(k), it);
986
    }
987
    return {nullptr, b};
988
  }
989
990
  // Insert the given node.
991
  // If the key is a duplicate, it inserts the new node and returns the old one.
992
  // Gives ownership to the caller.
993
  // If the key is unique, it returns `nullptr`.
994
  KeyNode* InsertOrReplaceNode(KeyNode* node) {
995
    KeyNode* to_erase = nullptr;
996
    auto p = this->FindHelper(node->key());
997
    map_index_t b = p.bucket;
998
    if (p.node != nullptr) {
999
      erase_no_destroy(p.bucket, static_cast<KeyNode*>(p.node));
1000
      to_erase = static_cast<KeyNode*>(p.node);
1001
    } else if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) {
1002
      b = BucketNumber(node->key());  // bucket_number
1003
    }
1004
    InsertUnique(b, node);
1005
    ++num_elements_;
1006
    return to_erase;
1007
  }
1008
1009
  // Insert the given Node in bucket b.  If that would make bucket b too big,
1010
  // and bucket b is not a tree, create a tree for buckets b.
1011
  // Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct
1012
  // bucket.  num_elements_ is not modified.
1013
  void InsertUnique(map_index_t b, KeyNode* node) {
1014
    ABSL_DCHECK(index_of_first_non_null_ == num_buckets_ ||
1015
                !TableEntryIsEmpty(index_of_first_non_null_));
1016
    // In practice, the code that led to this point may have already
1017
    // determined whether we are inserting into an empty list, a short list,
1018
    // or whatever.  But it's probably cheap enough to recompute that here;
1019
    // it's likely that we're inserting into an empty or short list.
1020
    ABSL_DCHECK(FindHelper(node->key()).node == nullptr);
1021
    if (TableEntryIsEmpty(b)) {
1022
      InsertUniqueInList(b, node);
1023
      index_of_first_non_null_ = (std::min)(index_of_first_non_null_, b);
1024
    } else if (TableEntryIsNonEmptyList(b) && !TableEntryIsTooLong(b)) {
1025
      InsertUniqueInList(b, node);
1026
    } else {
1027
      InsertUniqueInTree(b, NodeToVariantKey, node);
1028
    }
1029
  }
1030
1031
  static VariantKey NodeToVariantKey(NodeBase* node) {
1032
    return internal::RealKeyToVariantKey<Key>{}(
1033
        static_cast<KeyNode*>(node)->key());
1034
  }
1035
1036
  // Have it a separate function for testing.
1037
  static size_type CalculateHiCutoff(size_type num_buckets) {
1038
    // We want the high cutoff to follow this rules:
1039
    //  - When num_buckets_ == kGlobalEmptyTableSize, then make it 0 to force an
1040
    //    allocation.
1041
    //  - When num_buckets_ < 8, then make it num_buckets_ to avoid
1042
    //    a reallocation. A large load factor is not that important on small
1043
    //    tables and saves memory.
1044
    //  - Otherwise, make it 75% of num_buckets_.
1045
    return num_buckets - num_buckets / 16 * 4 - num_buckets % 2;
1046
  }
1047
1048
  // Returns whether it did resize.  Currently this is only used when
1049
  // num_elements_ increases, though it could be used in other situations.
1050
  // It checks for load too low as well as load too high: because any number
1051
  // of erases can occur between inserts, the load could be as low as 0 here.
1052
  // Resizing to a lower size is not always helpful, but failing to do so can
1053
  // destroy the expected big-O bounds for some operations. By having the
1054
  // policy that sometimes we resize down as well as up, clients can easily
1055
  // keep O(size()) = O(number of buckets) if they want that.
1056
  bool ResizeIfLoadIsOutOfRange(size_type new_size) {
1057
    const size_type hi_cutoff = CalculateHiCutoff(num_buckets_);
1058
    const size_type lo_cutoff = hi_cutoff / 4;
1059
    // We don't care how many elements are in trees.  If a lot are,
1060
    // we may resize even though there are many empty buckets.  In
1061
    // practice, this seems fine.
1062
    if (PROTOBUF_PREDICT_FALSE(new_size > hi_cutoff)) {
1063
      if (num_buckets_ <= max_size() / 2) {
1064
        Resize(num_buckets_ * 2);
1065
        return true;
1066
      }
1067
    } else if (PROTOBUF_PREDICT_FALSE(new_size <= lo_cutoff &&
1068
                                      num_buckets_ > kMinTableSize)) {
1069
      size_type lg2_of_size_reduction_factor = 1;
1070
      // It's possible we want to shrink a lot here... size() could even be 0.
1071
      // So, estimate how much to shrink by making sure we don't shrink so
1072
      // much that we would need to grow the table after a few inserts.
1073
      const size_type hypothetical_size = new_size * 5 / 4 + 1;
1074
      while ((hypothetical_size << lg2_of_size_reduction_factor) < hi_cutoff) {
1075
        ++lg2_of_size_reduction_factor;
1076
      }
1077
      size_type new_num_buckets = std::max<size_type>(
1078
          kMinTableSize, num_buckets_ >> lg2_of_size_reduction_factor);
1079
      if (new_num_buckets != num_buckets_) {
1080
        Resize(new_num_buckets);
1081
        return true;
1082
      }
1083
    }
1084
    return false;
1085
  }
1086
1087
  // Resize to the given number of buckets.
1088
  void Resize(map_index_t new_num_buckets) {
1089
    if (num_buckets_ == kGlobalEmptyTableSize) {
1090
      // This is the global empty array.
1091
      // Just overwrite with a new one. No need to transfer or free anything.
1092
      num_buckets_ = index_of_first_non_null_ = kMinTableSize;
1093
      table_ = CreateEmptyTable(num_buckets_);
1094
      seed_ = Seed();
1095
      return;
1096
    }
1097
1098
    ABSL_DCHECK_GE(new_num_buckets, kMinTableSize);
1099
    const auto old_table = table_;
1100
    const map_index_t old_table_size = num_buckets_;
1101
    num_buckets_ = new_num_buckets;
1102
    table_ = CreateEmptyTable(num_buckets_);
1103
    const map_index_t start = index_of_first_non_null_;
1104
    index_of_first_non_null_ = num_buckets_;
1105
    for (map_index_t i = start; i < old_table_size; ++i) {
1106
      if (internal::TableEntryIsNonEmptyList(old_table[i])) {
1107
        TransferList(static_cast<KeyNode*>(TableEntryToNode(old_table[i])));
1108
      } else if (internal::TableEntryIsTree(old_table[i])) {
1109
        this->TransferTree(TableEntryToTree(old_table[i]), NodeToVariantKey);
1110
      }
1111
    }
1112
    DeleteTable(old_table, old_table_size);
1113
  }
1114
1115
  // Transfer all nodes in the list `node` into `this`.
1116
  void TransferList(KeyNode* node) {
1117
    do {
1118
      auto* next = static_cast<KeyNode*>(node->next);
1119
      InsertUnique(BucketNumber(node->key()), node);
1120
      node = next;
1121
    } while (node != nullptr);
1122
  }
1123
1124
  map_index_t BucketNumber(typename TS::ViewType k) const {
1125
    ABSL_DCHECK_EQ(
1126
        VariantBucketNumber(RealKeyToVariantKeyAlternative<Key>{}(k)),
1127
        VariantBucketNumber(RealKeyToVariantKey<Key>{}(k)));
1128
    return VariantBucketNumber(RealKeyToVariantKeyAlternative<Key>{}(k));
1129
  }
1130
1131
  // Assumes node_ and m_ are correct and non-null, but other fields may be
1132
  // stale.  Fix them as needed.  Then return true iff node_ points to a
1133
  // Node in a list.  If false is returned then *it is modified to be
1134
  // a valid iterator for node_.
1135
  bool revalidate_if_necessary(map_index_t& bucket_index, KeyNode* node,
1136
                               TreeIterator* it) const {
1137
    // Force bucket_index to be in range.
1138
    bucket_index &= (num_buckets_ - 1);
1139
    // Common case: the bucket we think is relevant points to `node`.
1140
    if (table_[bucket_index] == NodeToTableEntry(node)) return true;
1141
    // Less common: the bucket is a linked list with node_ somewhere in it,
1142
    // but not at the head.
1143
    if (TableEntryIsNonEmptyList(bucket_index)) {
1144
      auto* l = TableEntryToNode(table_[bucket_index]);
1145
      while ((l = l->next) != nullptr) {
1146
        if (l == node) {
1147
          return true;
1148
        }
1149
      }
1150
    }
1151
    // Well, bucket_index_ still might be correct, but probably
1152
    // not.  Revalidate just to be sure.  This case is rare enough that we
1153
    // don't worry about potential optimizations, such as having a custom
1154
    // find-like method that compares Node* instead of the key.
1155
    auto res = FindHelper(node->key(), it);
1156
    bucket_index = res.bucket;
1157
    return TableEntryIsList(bucket_index);
1158
  }
1159
};
1160
1161
template <typename T, typename K>
1162
bool InitializeMapKey(T*, K&&, Arena*) {
1163
  return false;
1164
}
1165
1166
1167
// The purpose of this class is to give the Rust implementation visibility into
1168
// some of the internals of C++ proto maps. We need access to these internals
1169
// to be able to implement Rust map operations without duplicating the same
1170
// functionality for every message type.
1171
class RustMapHelper {
1172
 public:
1173
  using NodeAndBucket = UntypedMapBase::NodeAndBucket;
1174
  using ClearInput = UntypedMapBase::ClearInput;
1175
1176
  template <typename Key, typename Value>
1177
  static constexpr MapNodeSizeInfoT SizeInfo() {
1178
    return Map<Key, Value>::Node::size_info();
1179
  }
1180
1181
  enum {
1182
    kKeyIsString = UntypedMapBase::kKeyIsString,
1183
    kValueIsProto = UntypedMapBase::kValueIsProto,
1184
  };
1185
1186
0
  static NodeBase* AllocNode(UntypedMapBase* m, MapNodeSizeInfoT size_info) {
1187
0
    return m->AllocNode(size_info);
1188
0
  }
1189
1190
  static void DeallocNode(UntypedMapBase* m, NodeBase* node,
1191
0
                          MapNodeSizeInfoT size_info) {
1192
0
    return m->DeallocNode(node, size_info);
1193
0
  }
1194
1195
  template <typename Map, typename Key>
1196
  static NodeAndBucket FindHelper(Map* m, Key key) {
1197
    return m->FindHelper(key);
1198
  }
1199
1200
  template <typename Map>
1201
  static typename Map::KeyNode* InsertOrReplaceNode(Map* m, NodeBase* node) {
1202
    return m->InsertOrReplaceNode(static_cast<typename Map::KeyNode*>(node));
1203
  }
1204
1205
  template <typename Map>
1206
  static void EraseNoDestroy(Map* m, map_index_t bucket, NodeBase* node) {
1207
    m->erase_no_destroy(bucket, static_cast<typename Map::KeyNode*>(node));
1208
  }
1209
1210
  static google::protobuf::MessageLite* PlacementNew(const MessageLite* prototype,
1211
0
                                           void* mem) {
1212
0
    return prototype->GetClassData()->PlacementNew(mem, /* arena = */ nullptr);
1213
0
  }
1214
1215
0
  static void DestroyMessage(MessageLite* m) { m->DestroyInstance(); }
1216
1217
0
  static void ClearTable(UntypedMapBase* m, ClearInput input) {
1218
0
    m->ClearTable(input);
1219
0
  }
1220
1221
0
  static bool IsGlobalEmptyTable(const UntypedMapBase* m) {
1222
0
    return m->num_buckets_ == kGlobalEmptyTableSize;
1223
0
  }
1224
};
1225
1226
}  // namespace internal
1227
1228
// This is the class for Map's internal value_type.
1229
template <typename Key, typename T>
1230
using MapPair = std::pair<const Key, T>;
1231
1232
// Map is an associative container type used to store protobuf map
1233
// fields.  Each Map instance may or may not use a different hash function, a
1234
// different iteration order, and so on.  E.g., please don't examine
1235
// implementation details to decide if the following would work:
1236
//  Map<int, int> m0, m1;
1237
//  m0[0] = m1[0] = m0[1] = m1[1] = 0;
1238
//  assert(m0.begin()->first == m1.begin()->first);  // Bug!
1239
//
1240
// Map's interface is similar to std::unordered_map, except that Map is not
1241
// designed to play well with exceptions.
1242
template <typename Key, typename T>
1243
class Map : private internal::KeyMapBase<internal::KeyForBase<Key>> {
1244
  using Base = typename Map::KeyMapBase;
1245
1246
  using TS = internal::TransparentSupport<Key>;
1247
1248
 public:
1249
  using key_type = Key;
1250
  using mapped_type = T;
1251
  using init_type = std::pair<Key, T>;
1252
  using value_type = MapPair<Key, T>;
1253
1254
  using pointer = value_type*;
1255
  using const_pointer = const value_type*;
1256
  using reference = value_type&;
1257
  using const_reference = const value_type&;
1258
1259
  using size_type = size_t;
1260
  using hasher = typename TS::hash;
1261
1262
  constexpr Map() : Base(nullptr) { StaticValidityCheck(); }
1263
  Map(const Map& other) : Map(nullptr, other) {}
1264
1265
  // Internal Arena constructors: do not use!
1266
  // TODO: remove non internal ctors
1267
  explicit Map(Arena* arena) : Base(arena) { StaticValidityCheck(); }
1268
  Map(internal::InternalVisibility, Arena* arena) : Map(arena) {}
1269
  Map(internal::InternalVisibility, Arena* arena, const Map& other)
1270
      : Map(arena, other) {}
1271
1272
  Map(Map&& other) noexcept : Map() {
1273
    if (other.arena() != nullptr) {
1274
      *this = other;
1275
    } else {
1276
      swap(other);
1277
    }
1278
  }
1279
1280
  Map& operator=(Map&& other) noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
1281
    if (this != &other) {
1282
      if (arena() != other.arena()) {
1283
        *this = other;
1284
      } else {
1285
        swap(other);
1286
      }
1287
    }
1288
    return *this;
1289
  }
1290
1291
  template <class InputIt>
1292
  Map(const InputIt& first, const InputIt& last) : Map() {
1293
    insert(first, last);
1294
  }
1295
1296
  ~Map() {
1297
    // Fail-safe in case we miss calling this in a constructor.  Note: this one
1298
    // won't trigger for leaked maps that never get destructed.
1299
    StaticValidityCheck();
1300
1301
    if (this->num_buckets_ != internal::kGlobalEmptyTableSize) {
1302
      this->ClearTable(this->template MakeClearInput<Node>(false));
1303
    }
1304
  }
1305
1306
 private:
1307
  Map(Arena* arena, const Map& other) : Base(arena) {
1308
    StaticValidityCheck();
1309
    insert(other.begin(), other.end());
1310
  }
1311
  static_assert(!std::is_const<mapped_type>::value &&
1312
                    !std::is_const<key_type>::value,
1313
                "We do not support const types.");
1314
  static_assert(!std::is_volatile<mapped_type>::value &&
1315
                    !std::is_volatile<key_type>::value,
1316
                "We do not support volatile types.");
1317
  static_assert(!std::is_pointer<mapped_type>::value &&
1318
                    !std::is_pointer<key_type>::value,
1319
                "We do not support pointer types.");
1320
  static_assert(!std::is_reference<mapped_type>::value &&
1321
                    !std::is_reference<key_type>::value,
1322
                "We do not support reference types.");
1323
  static constexpr PROTOBUF_ALWAYS_INLINE void StaticValidityCheck() {
1324
    static_assert(alignof(internal::NodeBase) >= alignof(mapped_type),
1325
                  "Alignment of mapped type is too high.");
1326
    static_assert(
1327
        absl::disjunction<internal::is_supported_integral_type<key_type>,
1328
                          internal::is_supported_string_type<key_type>,
1329
                          internal::is_internal_map_key_type<key_type>>::value,
1330
        "We only support integer, string, or designated internal key "
1331
        "types.");
1332
    static_assert(absl::disjunction<
1333
                      internal::is_supported_scalar_type<mapped_type>,
1334
                      is_proto_enum<mapped_type>,
1335
                      internal::is_supported_message_type<mapped_type>,
1336
                      internal::is_internal_map_value_type<mapped_type>>::value,
1337
                  "We only support scalar, Message, and designated internal "
1338
                  "mapped types.");
1339
    // The Rust implementation that wraps C++ protos relies on the ability to
1340
    // create an UntypedMapBase and cast a pointer of it to google::protobuf::Map*.
1341
    static_assert(
1342
        sizeof(Map) == sizeof(internal::UntypedMapBase),
1343
        "Map must not have any data members beyond what is in UntypedMapBase.");
1344
  }
1345
1346
  template <typename P>
1347
  struct SameAsElementReference
1348
      : std::is_same<typename std::remove_cv<
1349
                         typename std::remove_reference<reference>::type>::type,
1350
                     typename std::remove_cv<
1351
                         typename std::remove_reference<P>::type>::type> {};
1352
1353
  template <class P>
1354
  using RequiresInsertable =
1355
      typename std::enable_if<std::is_convertible<P, init_type>::value ||
1356
                                  SameAsElementReference<P>::value,
1357
                              int>::type;
1358
  template <class P>
1359
  using RequiresNotInit =
1360
      typename std::enable_if<!std::is_same<P, init_type>::value, int>::type;
1361
1362
  template <typename LookupKey>
1363
  using key_arg = typename TS::template key_arg<LookupKey>;
1364
1365
 public:
1366
  // Iterators
1367
  class const_iterator : private internal::UntypedMapIterator {
1368
    using BaseIt = internal::UntypedMapIterator;
1369
1370
   public:
1371
    using iterator_category = std::forward_iterator_tag;
1372
    using value_type = typename Map::value_type;
1373
    using difference_type = ptrdiff_t;
1374
    using pointer = const value_type*;
1375
    using reference = const value_type&;
1376
1377
    const_iterator() : BaseIt{nullptr, nullptr, 0} {}
1378
    const_iterator(const const_iterator&) = default;
1379
    const_iterator& operator=(const const_iterator&) = default;
1380
    explicit const_iterator(BaseIt it) : BaseIt(it) {}
1381
1382
    reference operator*() const { return static_cast<Node*>(this->node_)->kv; }
1383
    pointer operator->() const { return &(operator*()); }
1384
1385
    const_iterator& operator++() {
1386
      this->PlusPlus();
1387
      return *this;
1388
    }
1389
    const_iterator operator++(int) {
1390
      auto copy = *this;
1391
      this->PlusPlus();
1392
      return copy;
1393
    }
1394
1395
    friend bool operator==(const const_iterator& a, const const_iterator& b) {
1396
      return a.Equals(b);
1397
    }
1398
    friend bool operator!=(const const_iterator& a, const const_iterator& b) {
1399
      return !a.Equals(b);
1400
    }
1401
1402
   private:
1403
    using BaseIt::BaseIt;
1404
    friend class Map;
1405
    friend class internal::UntypedMapIterator;
1406
    friend class internal::TypeDefinedMapFieldBase<Key, T>;
1407
  };
1408
1409
  class iterator : private internal::UntypedMapIterator {
1410
    using BaseIt = internal::UntypedMapIterator;
1411
1412
   public:
1413
    using iterator_category = std::forward_iterator_tag;
1414
    using value_type = typename Map::value_type;
1415
    using difference_type = ptrdiff_t;
1416
    using pointer = value_type*;
1417
    using reference = value_type&;
1418
1419
    iterator() : BaseIt{nullptr, nullptr, 0} {}
1420
    iterator(const iterator&) = default;
1421
    iterator& operator=(const iterator&) = default;
1422
    explicit iterator(BaseIt it) : BaseIt(it) {}
1423
1424
    reference operator*() const { return static_cast<Node*>(this->node_)->kv; }
1425
    pointer operator->() const { return &(operator*()); }
1426
1427
    iterator& operator++() {
1428
      this->PlusPlus();
1429
      return *this;
1430
    }
1431
    iterator operator++(int) {
1432
      auto copy = *this;
1433
      this->PlusPlus();
1434
      return copy;
1435
    }
1436
1437
    // Allow implicit conversion to const_iterator.
1438
    operator const_iterator() const {  // NOLINT(runtime/explicit)
1439
      return const_iterator(static_cast<const BaseIt&>(*this));
1440
    }
1441
1442
    friend bool operator==(const iterator& a, const iterator& b) {
1443
      return a.Equals(b);
1444
    }
1445
    friend bool operator!=(const iterator& a, const iterator& b) {
1446
      return !a.Equals(b);
1447
    }
1448
1449
   private:
1450
    using BaseIt::BaseIt;
1451
    friend class Map;
1452
  };
1453
1454
  iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
1455
    return iterator(Base::begin());
1456
  }
1457
  iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return iterator(); }
1458
  const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1459
    return const_iterator(Base::begin());
1460
  }
1461
  const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1462
    return const_iterator();
1463
  }
1464
  const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1465
    return begin();
1466
  }
1467
  const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
1468
1469
  using Base::empty;
1470
  using Base::size;
1471
1472
  // Element access
1473
  template <typename K = key_type>
1474
  T& operator[](const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1475
    return try_emplace(key).first->second;
1476
  }
1477
  template <
1478
      typename K = key_type,
1479
      // Disable for integral types to reduce code bloat.
1480
      typename = typename std::enable_if<!std::is_integral<K>::value>::type>
1481
  T& operator[](key_arg<K>&& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1482
    return try_emplace(std::forward<K>(key)).first->second;
1483
  }
1484
1485
  template <typename K = key_type>
1486
  const T& at(const key_arg<K>& key) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1487
    const_iterator it = find(key);
1488
    ABSL_CHECK(it != end()) << "key not found: " << static_cast<Key>(key);
1489
    return it->second;
1490
  }
1491
1492
  template <typename K = key_type>
1493
  T& at(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1494
    iterator it = find(key);
1495
    ABSL_CHECK(it != end()) << "key not found: " << static_cast<Key>(key);
1496
    return it->second;
1497
  }
1498
1499
  // Lookup
1500
  template <typename K = key_type>
1501
  size_type count(const key_arg<K>& key) const {
1502
    return find(key) == end() ? 0 : 1;
1503
  }
1504
1505
  template <typename K = key_type>
1506
  const_iterator find(const key_arg<K>& key) const
1507
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
1508
    return const_cast<Map*>(this)->find(key);
1509
  }
1510
  template <typename K = key_type>
1511
  iterator find(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1512
    auto res = this->FindHelper(TS::ToView(key));
1513
    return iterator(internal::UntypedMapIterator{static_cast<Node*>(res.node),
1514
                                                 this, res.bucket});
1515
  }
1516
1517
  template <typename K = key_type>
1518
  bool contains(const key_arg<K>& key) const {
1519
    return find(key) != end();
1520
  }
1521
1522
  template <typename K = key_type>
1523
  std::pair<const_iterator, const_iterator> equal_range(
1524
      const key_arg<K>& key) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1525
    const_iterator it = find(key);
1526
    if (it == end()) {
1527
      return std::pair<const_iterator, const_iterator>(it, it);
1528
    } else {
1529
      const_iterator begin = it++;
1530
      return std::pair<const_iterator, const_iterator>(begin, it);
1531
    }
1532
  }
1533
1534
  template <typename K = key_type>
1535
  std::pair<iterator, iterator> equal_range(const key_arg<K>& key)
1536
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
1537
    iterator it = find(key);
1538
    if (it == end()) {
1539
      return std::pair<iterator, iterator>(it, it);
1540
    } else {
1541
      iterator begin = it++;
1542
      return std::pair<iterator, iterator>(begin, it);
1543
    }
1544
  }
1545
1546
  // insert
1547
  template <typename K, typename... Args>
1548
  std::pair<iterator, bool> try_emplace(K&& k, Args&&... args)
1549
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
1550
    // Inserts a new element into the container if there is no element with the
1551
    // key in the container.
1552
    // The new element is:
1553
    //  (1) Constructed in-place with the given args, if mapped_type is not
1554
    //      arena constructible.
1555
    //  (2) Constructed in-place with the arena and then assigned with a
1556
    //      mapped_type temporary constructed with the given args, otherwise.
1557
    return ArenaAwareTryEmplace(Arena::is_arena_constructable<mapped_type>(),
1558
                                std::forward<K>(k),
1559
                                std::forward<Args>(args)...);
1560
  }
1561
  std::pair<iterator, bool> insert(init_type&& value)
1562
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
1563
    return try_emplace(std::move(value.first), std::move(value.second));
1564
  }
1565
  template <typename P, RequiresInsertable<P> = 0>
1566
  std::pair<iterator, bool> insert(P&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1567
    return try_emplace(std::forward<P>(value).first,
1568
                       std::forward<P>(value).second);
1569
  }
1570
  template <typename... Args>
1571
  std::pair<iterator, bool> emplace(Args&&... args)
1572
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
1573
    return EmplaceInternal(Rank0{}, std::forward<Args>(args)...);
1574
  }
1575
  template <class InputIt>
1576
  void insert(InputIt first, InputIt last) {
1577
    for (; first != last; ++first) {
1578
      auto&& pair = *first;
1579
      try_emplace(pair.first, pair.second);
1580
    }
1581
  }
1582
  void insert(std::initializer_list<init_type> values) {
1583
    insert(values.begin(), values.end());
1584
  }
1585
  template <typename P, RequiresNotInit<P> = 0,
1586
            RequiresInsertable<const P&> = 0>
1587
  void insert(std::initializer_list<P> values) {
1588
    insert(values.begin(), values.end());
1589
  }
1590
1591
  // Erase and clear
1592
  template <typename K = key_type>
1593
  size_type erase(const key_arg<K>& key) {
1594
    iterator it = find(key);
1595
    if (it == end()) {
1596
      return 0;
1597
    } else {
1598
      erase(it);
1599
      return 1;
1600
    }
1601
  }
1602
1603
  iterator erase(iterator pos) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1604
    auto next = std::next(pos);
1605
    ABSL_DCHECK_EQ(pos.m_, static_cast<Base*>(this));
1606
    auto* node = static_cast<Node*>(pos.node_);
1607
    this->erase_no_destroy(pos.bucket_index_, node);
1608
    DestroyNode(node);
1609
    return next;
1610
  }
1611
1612
  void erase(iterator first, iterator last) {
1613
    while (first != last) {
1614
      first = erase(first);
1615
    }
1616
  }
1617
1618
  void clear() {
1619
    if (this->num_buckets_ == internal::kGlobalEmptyTableSize) return;
1620
    this->ClearTable(this->template MakeClearInput<Node>(true));
1621
  }
1622
1623
  // Assign
1624
  Map& operator=(const Map& other) ABSL_ATTRIBUTE_LIFETIME_BOUND {
1625
    if (this != &other) {
1626
      clear();
1627
      insert(other.begin(), other.end());
1628
    }
1629
    return *this;
1630
  }
1631
1632
  void swap(Map& other) {
1633
    if (arena() == other.arena()) {
1634
      InternalSwap(&other);
1635
    } else {
1636
      // TODO: optimize this. The temporary copy can be allocated
1637
      // in the same arena as the other message, and the "other = copy" can
1638
      // be replaced with the fast-path swap above.
1639
      Map copy = *this;
1640
      *this = other;
1641
      other = copy;
1642
    }
1643
  }
1644
1645
  void InternalSwap(Map* other) {
1646
    internal::UntypedMapBase::InternalSwap(other);
1647
  }
1648
1649
  hasher hash_function() const { return {}; }
1650
1651
  size_t SpaceUsedExcludingSelfLong() const {
1652
    if (empty()) return 0;
1653
    return SpaceUsedInternal() + internal::SpaceUsedInValues(this);
1654
  }
1655
1656
  static constexpr size_t InternalGetArenaOffset(internal::InternalVisibility) {
1657
    return PROTOBUF_FIELD_OFFSET(Map, alloc_);
1658
  }
1659
1660
 private:
1661
  struct Rank1 {};
1662
  struct Rank0 : Rank1 {};
1663
1664
  // Linked-list nodes, as one would expect for a chaining hash table.
1665
  struct Node : Base::KeyNode {
1666
    using key_type = Key;
1667
    using mapped_type = T;
1668
    static constexpr internal::MapNodeSizeInfoT size_info() {
1669
      return internal::MakeNodeInfo(sizeof(Node),
1670
                                    PROTOBUF_FIELD_OFFSET(Node, kv.second));
1671
    }
1672
    value_type kv;
1673
  };
1674
1675
  using Tree = internal::TreeForMap;
1676
  using TreeIterator = typename Tree::iterator;
1677
  using TableEntryPtr = internal::TableEntryPtr;
1678
1679
  static Node* NodeFromTreeIterator(TreeIterator it) {
1680
    static_assert(
1681
        PROTOBUF_FIELD_OFFSET(Node, kv.first) == Base::KeyNode::kOffset, "");
1682
    static_assert(alignof(Node) == alignof(internal::NodeBase), "");
1683
    return static_cast<Node*>(it->second);
1684
  }
1685
1686
  void DestroyNode(Node* node) {
1687
    if (this->alloc_.arena() == nullptr) {
1688
      node->kv.first.~key_type();
1689
      node->kv.second.~mapped_type();
1690
      this->DeallocNode(node, sizeof(Node));
1691
    }
1692
  }
1693
1694
  size_t SpaceUsedInternal() const {
1695
    return this->SpaceUsedInTable(sizeof(Node));
1696
  }
1697
1698
  // We try to construct `init_type` from `Args` with a fall back to
1699
  // `value_type`. The latter is less desired as it unconditionally makes a copy
1700
  // of `value_type::first`.
1701
  template <typename... Args>
1702
  auto EmplaceInternal(Rank0, Args&&... args) ->
1703
      typename std::enable_if<std::is_constructible<init_type, Args...>::value,
1704
                              std::pair<iterator, bool>>::type {
1705
    return insert(init_type(std::forward<Args>(args)...));
1706
  }
1707
  template <typename... Args>
1708
  std::pair<iterator, bool> EmplaceInternal(Rank1, Args&&... args) {
1709
    return insert(value_type(std::forward<Args>(args)...));
1710
  }
1711
1712
  template <typename K, typename... Args>
1713
  std::pair<iterator, bool> TryEmplaceInternal(K&& k, Args&&... args) {
1714
    auto p = this->FindHelper(TS::ToView(k));
1715
    internal::map_index_t b = p.bucket;
1716
    // Case 1: key was already present.
1717
    if (p.node != nullptr)
1718
      return std::make_pair(iterator(internal::UntypedMapIterator{
1719
                                static_cast<Node*>(p.node), this, p.bucket}),
1720
                            false);
1721
    // Case 2: insert.
1722
    if (this->ResizeIfLoadIsOutOfRange(this->num_elements_ + 1)) {
1723
      b = this->BucketNumber(TS::ToView(k));
1724
    }
1725
    // If K is not key_type, make the conversion to key_type explicit.
1726
    using TypeToInit = typename std::conditional<
1727
        std::is_same<typename std::decay<K>::type, key_type>::value, K&&,
1728
        key_type>::type;
1729
    Node* node = static_cast<Node*>(this->AllocNode(sizeof(Node)));
1730
1731
    // Even when arena is nullptr, CreateInArenaStorage is still used to
1732
    // ensure the arena of submessage will be consistent. Otherwise,
1733
    // submessage may have its own arena when message-owned arena is enabled.
1734
    // Note: This only works if `Key` is not arena constructible.
1735
    if (!internal::InitializeMapKey(const_cast<Key*>(&node->kv.first),
1736
                                    std::forward<K>(k), this->alloc_.arena())) {
1737
      Arena::CreateInArenaStorage(const_cast<Key*>(&node->kv.first),
1738
                                  this->alloc_.arena(),
1739
                                  static_cast<TypeToInit>(std::forward<K>(k)));
1740
    }
1741
    // Note: if `T` is arena constructible, `Args` needs to be empty.
1742
    Arena::CreateInArenaStorage(&node->kv.second, this->alloc_.arena(),
1743
                                std::forward<Args>(args)...);
1744
1745
    this->InsertUnique(b, node);
1746
    ++this->num_elements_;
1747
    return std::make_pair(iterator(internal::UntypedMapIterator{node, this, b}),
1748
                          true);
1749
  }
1750
1751
  // A helper function to perform an assignment of `mapped_type`.
1752
  // If the first argument is true, then it is a regular assignment.
1753
  // Otherwise, we first create a temporary and then perform an assignment.
1754
  template <typename V>
1755
  static void AssignMapped(std::true_type, mapped_type& mapped, V&& v) {
1756
    mapped = std::forward<V>(v);
1757
  }
1758
  template <typename... Args>
1759
  static void AssignMapped(std::false_type, mapped_type& mapped,
1760
                           Args&&... args) {
1761
    mapped = mapped_type(std::forward<Args>(args)...);
1762
  }
1763
1764
  // Case 1: `mapped_type` is arena constructible. A temporary object is
1765
  // created and then (if `Args` are not empty) assigned to a mapped value
1766
  // that was created with the arena.
1767
  template <typename K>
1768
  std::pair<iterator, bool> ArenaAwareTryEmplace(std::true_type, K&& k) {
1769
    // case 1.1: "default" constructed (e.g. from arena only).
1770
    return TryEmplaceInternal(std::forward<K>(k));
1771
  }
1772
  template <typename K, typename... Args>
1773
  std::pair<iterator, bool> ArenaAwareTryEmplace(std::true_type, K&& k,
1774
                                                 Args&&... args) {
1775
    // case 1.2: "default" constructed + copy/move assignment
1776
    auto p = TryEmplaceInternal(std::forward<K>(k));
1777
    if (p.second) {
1778
      AssignMapped(std::is_same<void(typename std::decay<Args>::type...),
1779
                                void(mapped_type)>(),
1780
                   p.first->second, std::forward<Args>(args)...);
1781
    }
1782
    return p;
1783
  }
1784
  // Case 2: `mapped_type` is not arena constructible. Using in-place
1785
  // construction.
1786
  template <typename... Args>
1787
  std::pair<iterator, bool> ArenaAwareTryEmplace(std::false_type,
1788
                                                 Args&&... args) {
1789
    return TryEmplaceInternal(std::forward<Args>(args)...);
1790
  }
1791
1792
  using Base::arena;
1793
1794
  friend class Arena;
1795
  template <typename, typename>
1796
  friend class internal::TypeDefinedMapFieldBase;
1797
  using InternalArenaConstructable_ = void;
1798
  using DestructorSkippable_ = void;
1799
  template <typename K, typename V>
1800
  friend class internal::MapFieldLite;
1801
  friend class internal::TcParser;
1802
  friend struct internal::MapTestPeer;
1803
  friend struct internal::MapBenchmarkPeer;
1804
  friend class internal::RustMapHelper;
1805
};
1806
1807
namespace internal {
1808
template <typename... T>
1809
PROTOBUF_NOINLINE void MapMergeFrom(Map<T...>& dest, const Map<T...>& src) {
1810
  for (const auto& elem : src) {
1811
    dest[elem.first] = elem.second;
1812
  }
1813
}
1814
}  // namespace internal
1815
1816
}  // namespace protobuf
1817
}  // namespace google
1818
1819
#include "google/protobuf/port_undef.inc"
1820
1821
#endif  // GOOGLE_PROTOBUF_MAP_H__