Coverage Report

Created: 2024-07-27 06:53

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