Flutter Engine
The Flutter Engine
hash_map.h
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_HASH_MAP_H_
6#define RUNTIME_VM_HASH_MAP_H_
7
8#include "platform/utils.h"
9#include "vm/flags.h"
10#include "vm/growable_array.h" // For Malloc, EmptyBase
11#include "vm/hash.h"
12#include "vm/zone.h"
13
14namespace dart {
15
16template <typename KeyValueTrait, typename B, typename Allocator = Zone>
18 public:
20 intptr_t initial_size = kInitialSize)
21 : allocator_(allocator) {
22 Resize(initial_size);
23 }
24
26
27 intptr_t Length() const { return next_pair_index_ - deleted_count_; }
28
30 allocator_->template Free<uint32_t>(hash_table_, hash_table_size_);
31 allocator_->template Free<typename KeyValueTrait::Pair>(pairs_,
33 }
34
35 // Assumes that no existing pair in the map has a key equal to [kv.key].
36 void Insert(typename KeyValueTrait::Pair kv);
38
39 // If a pair already exists in the map with an equal key, replace that pair
40 // with this one. Otherwise, insert the pair as a new entry.
41 //
42 // Note: Insert operates in constant time, while Update must walk the chained
43 // entries for a given hash value, checking keys for equality. However, if
44 // multiple value updates are needed for the same key, only using Update
45 // guarantees constant space usage whereas Insert does not.
46 void Update(typename KeyValueTrait::Pair kv);
47
48 typename KeyValueTrait::Value LookupValue(
49 typename KeyValueTrait::Key key) const;
50
51 typename KeyValueTrait::Pair* Lookup(typename KeyValueTrait::Key key) const;
52 bool HasKey(typename KeyValueTrait::Key key) const {
53 return Lookup(key) != nullptr;
54 }
55
56 intptr_t Size() const { return next_pair_index_ - deleted_count_; }
57 bool IsEmpty() const { return Size() == 0; }
58
59 void Clear() {
60 for (uint32_t i = 0; i < hash_table_size_; i++) {
62 }
63 for (uint32_t i = 0; i < next_pair_index_; i++) {
64 pairs_[i] = typename KeyValueTrait::Pair();
65 }
68 }
69
70 class Iterator {
71 public:
72 typename KeyValueTrait::Pair* Next();
73
74 void Reset() { pair_index_ = 0; }
75
76 private:
78 : map_(map), pair_index_(0) {}
79
80 const BaseDirectChainedHashMap& map_;
81 uint32_t pair_index_;
82
83 template <typename T, typename Bs, typename A>
85 };
86
87 Iterator GetIterator() const { return Iterator(*this); }
88
89 protected:
90 static constexpr intptr_t kInitialSize = 16;
91
92 void Resize(intptr_t new_size);
93
95 uint32_t* hash_table_ = nullptr;
96 typename KeyValueTrait::Pair* pairs_ = nullptr;
97 uint32_t hash_table_size_ = 0;
98 uint32_t pairs_size_ = 0;
99 uint32_t next_pair_index_ = 0;
100 uint32_t deleted_count_ = 0;
101
102 static constexpr uint32_t kEmpty = kMaxUint32;
103 static constexpr uint32_t kDeleted = kMaxUint32 - 1;
104 static constexpr uint32_t kMaxPairs = kMaxUint32 - 2;
105
106 private:
107 void operator=(const BaseDirectChainedHashMap& other) = delete;
108};
109
110template <typename KeyValueTrait, typename B, typename Allocator>
112 const BaseDirectChainedHashMap& other)
113 : B(),
114 allocator_(other.allocator_),
115 hash_table_(
116 other.allocator_->template Alloc<uint32_t>(other.hash_table_size_)),
117 pairs_(other.allocator_->template Alloc<typename KeyValueTrait::Pair>(
118 other.pairs_size_)),
119 hash_table_size_(other.hash_table_size_),
120 pairs_size_(other.pairs_size_),
121 next_pair_index_(other.next_pair_index_),
122 deleted_count_(other.deleted_count_) {
123 memmove(hash_table_, other.hash_table_, hash_table_size_ * sizeof(uint32_t));
124 memmove(pairs_, other.pairs_,
125 pairs_size_ * sizeof(typename KeyValueTrait::Pair));
126}
127
128template <typename KeyValueTrait, typename B, typename Allocator>
129typename KeyValueTrait::Pair*
131 typename KeyValueTrait::Key key) const {
133 uint32_t mask = hash_table_size_ - 1;
134 uint32_t hash_index = hash & mask;
135 uint32_t start = hash_index;
136 intptr_t probes = 0;
137 for (;;) {
138 uint32_t pair_index = hash_table_[hash_index];
139 if (pair_index == kEmpty) {
140 return nullptr;
141 }
142 if (pair_index != kDeleted) {
143 ASSERT(pair_index < pairs_size_);
144 RELEASE_ASSERT(++probes < FLAG_hash_map_probes_limit);
145 if (KeyValueTrait::IsKeyEqual(pairs_[pair_index], key)) {
146 return &pairs_[pair_index];
147 }
148 }
149 hash_index = (hash_index + 1) & mask;
150 // Hashtable must contain at least one empty marker.
151 ASSERT(hash_index != start);
152 }
153 UNREACHABLE();
154 return nullptr;
155}
156
157template <typename KeyValueTrait, typename B, typename Allocator>
158typename KeyValueTrait::Value
160 typename KeyValueTrait::Key key) const {
161 const typename KeyValueTrait::Value kNoValue =
162 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
163 typename KeyValueTrait::Pair* pair = Lookup(key);
164 return (pair == nullptr) ? kNoValue : KeyValueTrait::ValueOf(*pair);
165}
166
167template <typename KeyValueTrait, typename B, typename Allocator>
168typename KeyValueTrait::Pair*
170 const typename KeyValueTrait::Value kNoValue =
171 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
172 while (pair_index_ < map_.next_pair_index_) {
173 if (KeyValueTrait::ValueOf(map_.pairs_[pair_index_]) != kNoValue) {
174 intptr_t old_index = pair_index_;
175 pair_index_++;
176 return &map_.pairs_[old_index];
177 }
178 pair_index_++;
179 }
180 return nullptr;
181}
182
183template <typename KeyValueTrait, typename B, typename Allocator>
185 intptr_t new_size) {
186 ASSERT(new_size >= Size());
187
188 uint32_t old_hash_table_size = hash_table_size_;
189 // 75% load factor + at least one kEmpty slot
190 hash_table_size_ = Utils::RoundUpToPowerOfTwo(new_size * 4 / 3 + 1);
191 hash_table_ = allocator_->template Realloc<uint32_t>(
192 hash_table_, old_hash_table_size, hash_table_size_);
193 for (uint32_t i = 0; i < hash_table_size_; i++) {
195 }
196
197 typename KeyValueTrait::Pair* old_pairs = pairs_;
198 uint32_t old_pairs_size = pairs_size_;
199 uint32_t old_next_pair_index = next_pair_index_;
200 uint32_t old_deleted_count = deleted_count_;
202 deleted_count_ = 0;
203 pairs_size_ = new_size;
204 pairs_ =
205 allocator_->template Alloc<typename KeyValueTrait::Pair>(pairs_size_);
206 for (uint32_t i = 0; i < pairs_size_; i++) {
207 pairs_[i] = typename KeyValueTrait::Pair();
208 }
209
210 const typename KeyValueTrait::Value kNoValue =
211 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
212 uint32_t used = 0;
213 uint32_t deleted = 0;
214 for (uint32_t i = 0; i < old_next_pair_index; i++) {
215 if (KeyValueTrait::ValueOf(old_pairs[i]) == kNoValue) {
216 deleted++;
217 } else {
218 Insert(old_pairs[i]);
219 used++;
220 }
221 }
222 ASSERT_EQUAL(deleted, old_deleted_count);
223 ASSERT_EQUAL(used, old_next_pair_index - old_deleted_count);
225 allocator_->template Free<typename KeyValueTrait::Pair>(old_pairs,
226 old_pairs_size);
227}
228
229template <typename KeyValueTrait, typename B, typename Allocator>
231 typename KeyValueTrait::Pair kv) {
232 // TODO(dartbug.com/38018):
233 // ASSERT(Lookup(KeyValueTrait::KeyOf(kv)) == nullptr);
235 uword hash = KeyValueTrait::Hash(KeyValueTrait::KeyOf(kv));
236 uint32_t mask = hash_table_size_ - 1;
237 uint32_t hash_index = hash & mask;
238 uint32_t start = hash_index;
239 intptr_t probes = 0;
240 for (;;) {
241 uint32_t pair_index = hash_table_[hash_index];
242 if ((pair_index == kEmpty) || (pair_index == kDeleted)) {
243 hash_table_[hash_index] = next_pair_index_;
246 break;
247 }
248 RELEASE_ASSERT(++probes < FLAG_hash_map_probes_limit);
249 ASSERT(pair_index < pairs_size_);
250 hash_index = (hash_index + 1) & mask;
251 // Hashtable must contain at least one empty marker.
252 ASSERT(hash_index != start);
253 }
254
256 Resize(Size() << 1);
257 }
258}
259
260template <typename KeyValueTrait, typename B, typename Allocator>
262 typename KeyValueTrait::Pair kv) {
263 const typename KeyValueTrait::Value kNoValue =
264 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
265
266 ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue);
267 if (auto const old_kv = Lookup(KeyValueTrait::KeyOf(kv))) {
268 *old_kv = kv;
269 } else {
270 Insert(kv);
271 }
272}
273
274template <typename KeyValueTrait, typename B, typename Allocator>
276 typename KeyValueTrait::Key key) {
278 uint32_t mask = hash_table_size_ - 1;
279 uint32_t hash_index = hash & mask;
280 uint32_t start = hash_index;
281 intptr_t probes = 0;
282 for (;;) {
283 uint32_t pair_index = hash_table_[hash_index];
284 if (pair_index == kEmpty) {
285 return false;
286 }
287 if (pair_index != kDeleted) {
288 ASSERT(pair_index < pairs_size_);
289 RELEASE_ASSERT(++probes < FLAG_hash_map_probes_limit);
290 if (KeyValueTrait::IsKeyEqual(pairs_[pair_index], key)) {
291 hash_table_[hash_index] = kDeleted;
292 pairs_[pair_index] = typename KeyValueTrait::Pair();
294 return true;
295 }
296 }
297 hash_index = (hash_index + 1) & mask;
298 // Hashtable must contain at least one empty marker.
299 ASSERT(hash_index != start);
300 }
301 UNREACHABLE();
302 return false;
303}
304
305template <typename KeyValueTrait>
307 : public BaseDirectChainedHashMap<KeyValueTrait, ValueObject> {
308 public:
310 : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>(
311 ASSERT_NOTNULL(ThreadState::Current()->zone())) {}
312
314 Zone* zone,
315 intptr_t initial_size = DirectChainedHashMap::kInitialSize)
316 : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>(
317 ASSERT_NOTNULL(zone),
318 initial_size) {}
319
320 // There is a current use of the copy constructor in CSEInstructionSet
321 // (compiler/backend/redundancy_elimination.cc), so work is needed if we
322 // want to disallow it.
324 : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>(other) {}
325
326 private:
327 void operator=(const DirectChainedHashMap& other) = delete;
328};
329
330template <typename KeyValueTrait>
332 : public BaseDirectChainedHashMap<KeyValueTrait, MallocAllocated, Malloc> {
333 public:
335 intptr_t initial_size = MallocDirectChainedHashMap::kInitialSize)
337 nullptr,
338 initial_size) {}
339
340 // The only use of the copy constructor seems to be in hash_map_test.cc.
341 // Not disallowing it for now just in case there are other users.
344 other) {}
345
346 private:
347 void operator=(const MallocDirectChainedHashMap& other) = delete;
348};
349
350template <typename KeyValueTrait>
352 : public BaseDirectChainedHashMap<KeyValueTrait, ZoneAllocated, Zone> {
353 public:
356 ThreadState::Current()->zone()) {}
358 Zone* zone,
359 intptr_t initial_size = ZoneDirectChainedHashMap::kInitialSize)
361 zone,
362 initial_size) {}
363
364 private:
366};
367
368template <typename T>
370 public:
371 typedef T* Value;
372 typedef T* Key;
373 typedef T* Pair;
374
375 static Key KeyOf(Pair kv) { return kv; }
376 static Value ValueOf(Pair kv) { return kv; }
377 static inline uword Hash(Key key) { return key->Hash(); }
378 static inline bool IsKeyEqual(Pair kv, Key key) { return kv->Equals(*key); }
379};
380
381template <typename T>
383
384template <typename T>
386 public:
387 typedef T Value;
388 typedef intptr_t Key;
389 typedef T Pair;
390
391 static intptr_t KeyOf(Pair kv) { return kv.first(); }
392 static T ValueOf(Pair kv) { return kv; }
393 static inline uword Hash(Key key) { return key; }
394 static inline bool IsKeyEqual(Pair kv, Key key) { return kv.first() == key; }
395};
396
397template <typename K, typename V>
399 public:
400 typedef K* Key;
401 typedef V Value;
402
403 struct Pair {
406 Pair() : key(nullptr), value() {}
407 Pair(const Key key, const Value& value) : key(key), value(value) {}
408 Pair(const Pair& other) : key(other.key), value(other.value) {}
409 Pair& operator=(const Pair&) = default;
410 };
411
412 static Key KeyOf(Pair kv) { return kv.key; }
413 static Value ValueOf(Pair kv) { return kv.value; }
414 static uword Hash(Key key) { return reinterpret_cast<intptr_t>(key); }
415 static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
416};
417
419 public:
420 using Key = const char*;
421 using Value = const char*;
422 using Pair = const char*;
423
424 static Key KeyOf(Pair kv) { return kv; }
425 static Value ValueOf(Pair kv) { return kv; }
426 static uword Hash(Key key) {
427 ASSERT(key != nullptr);
428 return Utils::StringHash(key, strlen(key));
429 }
430 static bool IsKeyEqual(Pair kv, Key key) {
431 ASSERT(kv != nullptr && key != nullptr);
432 return kv == key || strcmp(kv, key) == 0;
433 }
434};
435
436template <typename B, typename Allocator>
438 : public BaseDirectChainedHashMap<CStringSetKeyValueTrait, B, Allocator> {
439 public:
440 explicit BaseCStringSet(Allocator* allocator)
442 allocator) {}
443
444 private:
446};
447
448class ZoneCStringSet : public BaseCStringSet<ZoneAllocated, Zone> {
449 public:
451 : BaseCStringSet<ZoneAllocated, Zone>(ThreadState::Current()->zone()) {}
452 explicit ZoneCStringSet(Zone* zone)
454
455 private:
457};
458
460 using Key = const char*;
461 using Value = intptr_t;
462
463 static constexpr Value kNoValue = kIntptrMin;
464
465 struct Pair {
468 Pair() : key(nullptr), value(kNoValue) {}
469 Pair(const Key key, const Value& value) : key(key), value(value) {}
470 Pair(const Pair& other) : key(other.key), value(other.value) {}
471 Pair& operator=(const Pair&) = default;
472 };
473
474 static Key KeyOf(const Pair& pair) { return pair.key; }
475 static Value ValueOf(const Pair& pair) { return pair.value; }
476 static uword Hash(const Key& key) {
477 ASSERT(key != nullptr);
478 return Utils::StringHash(key, strlen(key));
479 }
480 static bool IsKeyEqual(const Pair& kv, const Key& key) {
481 ASSERT(kv.key != nullptr && key != nullptr);
482 return kv.key == key || strcmp(kv.key, key) == 0;
483 }
484};
485
486template <typename B, typename Allocator>
488 : public BaseDirectChainedHashMap<CStringIntMapKeyValueTrait,
489 B,
490 Allocator> {
491 public:
492 explicit BaseCStringIntMap(Allocator* allocator)
494 allocator) {}
495
496 private:
498};
499
500class CStringIntMap : public BaseCStringIntMap<ValueObject, Zone> {
501 public:
503 : BaseCStringIntMap<ValueObject, Zone>(ThreadState::Current()->zone()) {}
504 explicit CStringIntMap(Zone* zone)
506
507 private:
509};
510
511template <typename V>
513 public:
514 typedef intptr_t Key;
515 typedef V Value;
516
517 struct Pair {
520 Pair() : key(0), value() {}
521 Pair(const Key key, const Value& value) : key(key), value(value) {}
522 Pair(const Pair& other) : key(other.key), value(other.value) {}
523 Pair& operator=(const Pair&) = default;
524 };
525
526 static Key KeyOf(Pair kv) { return kv.key; }
527 static Value ValueOf(Pair kv) { return kv.value; }
528 static uword Hash(Key key) { return key; }
529 static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
530};
531
532template <typename V>
533class IntMap : public DirectChainedHashMap<IntKeyRawPointerValueTrait<V>> {
534 public:
536 explicit IntMap(Zone* zone)
538
542
543 inline void Insert(const Key& key, const Value& value) {
544 Pair pair(key, value);
546 }
547
548 inline V Lookup(const Key& key) const {
549 Pair* pair =
551 if (pair == nullptr) {
552 return V();
553 } else {
554 return pair->value;
555 }
556 }
557
558 inline Pair* LookupPair(const Key& key) const {
560 }
561
562 private:
564};
565
566template <typename V>
568 public:
569 // Typedefs needed for the DirectChainedHashMap template.
570 typedef V Key;
571 typedef V Value;
572 typedef V Pair;
573
574 static Key KeyOf(Pair kv) { return kv; }
575
576 static Value ValueOf(Pair kv) { return kv; }
577
578 static inline uword Hash(Key key) {
579 return Utils::StringHash(reinterpret_cast<const char*>(&key), sizeof(key));
580 }
581
582 static inline bool IsKeyEqual(Pair pair, Key key) { return pair == key; }
583};
584
585} // namespace dart
586
587#endif // RUNTIME_VM_HASH_MAP_H_
TArray< uint32_t > Key
static uint32_t hash(const SkShaderBase::GradientInfo &v)
#define UNREACHABLE()
Definition: assert.h:248
#define ASSERT_EQUAL(expected, actual)
Definition: assert.h:309
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
#define ASSERT_NOTNULL(ptr)
Definition: assert.h:323
BaseCStringIntMap(Allocator *allocator)
Definition: hash_map.h:492
BaseCStringSet(Allocator *allocator)
Definition: hash_map.h:440
KeyValueTrait::Pair * Next()
Definition: hash_map.h:169
bool Remove(typename KeyValueTrait::Key key)
Definition: hash_map.h:275
KeyValueTrait::Pair * pairs_
Definition: hash_map.h:96
static constexpr uint32_t kMaxPairs
Definition: hash_map.h:104
Allocator *const allocator_
Definition: hash_map.h:94
void Update(typename KeyValueTrait::Pair kv)
Definition: hash_map.h:261
static constexpr uint32_t kDeleted
Definition: hash_map.h:103
KeyValueTrait::Value LookupValue(typename KeyValueTrait::Key key) const
Definition: hash_map.h:159
void Insert(typename KeyValueTrait::Pair kv)
Definition: hash_map.h:230
BaseDirectChainedHashMap(Allocator *allocator, intptr_t initial_size=kInitialSize)
Definition: hash_map.h:19
static constexpr intptr_t kInitialSize
Definition: hash_map.h:90
BaseDirectChainedHashMap(const BaseDirectChainedHashMap &other)
Definition: hash_map.h:111
intptr_t Size() const
Definition: hash_map.h:56
intptr_t Length() const
Definition: hash_map.h:27
static constexpr uint32_t kEmpty
Definition: hash_map.h:102
bool HasKey(typename KeyValueTrait::Key key) const
Definition: hash_map.h:52
KeyValueTrait::Pair * Lookup(typename KeyValueTrait::Key key) const
Definition: hash_map.h:130
Iterator GetIterator() const
Definition: hash_map.h:87
void Resize(intptr_t new_size)
Definition: hash_map.h:184
CStringIntMap(Zone *zone)
Definition: hash_map.h:504
static uword Hash(Key key)
Definition: hash_map.h:426
static bool IsKeyEqual(Pair kv, Key key)
Definition: hash_map.h:430
static Key KeyOf(Pair kv)
Definition: hash_map.h:424
static Value ValueOf(Pair kv)
Definition: hash_map.h:425
DirectChainedHashMap(Zone *zone, intptr_t initial_size=DirectChainedHashMap::kInitialSize)
Definition: hash_map.h:313
DirectChainedHashMap(const DirectChainedHashMap &other)
Definition: hash_map.h:323
static Key KeyOf(Pair kv)
Definition: hash_map.h:574
static uword Hash(Key key)
Definition: hash_map.h:578
static Value ValueOf(Pair kv)
Definition: hash_map.h:576
static bool IsKeyEqual(Pair pair, Key key)
Definition: hash_map.h:582
static uword Hash(Key key)
Definition: hash_map.h:528
static Value ValueOf(Pair kv)
Definition: hash_map.h:527
static bool IsKeyEqual(Pair kv, Key key)
Definition: hash_map.h:529
static Key KeyOf(Pair kv)
Definition: hash_map.h:526
IntKeyRawPointerValueTrait< V >::Key Key
Definition: hash_map.h:539
V Lookup(const Key &key) const
Definition: hash_map.h:548
IntMap(Zone *zone)
Definition: hash_map.h:536
IntKeyRawPointerValueTrait< V >::Value Value
Definition: hash_map.h:540
Pair * LookupPair(const Key &key) const
Definition: hash_map.h:558
void Insert(const Key &key, const Value &value)
Definition: hash_map.h:543
IntKeyRawPointerValueTrait< V >::Pair Pair
Definition: hash_map.h:541
MallocDirectChainedHashMap(intptr_t initial_size=MallocDirectChainedHashMap::kInitialSize)
Definition: hash_map.h:334
MallocDirectChainedHashMap(const MallocDirectChainedHashMap &other)
Definition: hash_map.h:342
static uword Hash(Key key)
Definition: hash_map.h:393
static bool IsKeyEqual(Pair kv, Key key)
Definition: hash_map.h:394
static T ValueOf(Pair kv)
Definition: hash_map.h:392
static intptr_t KeyOf(Pair kv)
Definition: hash_map.h:391
static Value ValueOf(Pair kv)
Definition: hash_map.h:376
static Key KeyOf(Pair kv)
Definition: hash_map.h:375
static uword Hash(Key key)
Definition: hash_map.h:377
static bool IsKeyEqual(Pair kv, Key key)
Definition: hash_map.h:378
static uword Hash(Key key)
Definition: hash_map.h:414
static Value ValueOf(Pair kv)
Definition: hash_map.h:413
static Key KeyOf(Pair kv)
Definition: hash_map.h:412
static bool IsKeyEqual(Pair kv, Key key)
Definition: hash_map.h:415
static constexpr uintptr_t RoundUpToPowerOfTwo(uintptr_t x)
Definition: utils.h:135
static uint32_t StringHash(const void *data, int length)
Definition: utils.cc:114
ZoneCStringSet(Zone *zone)
Definition: hash_map.h:452
ZoneDirectChainedHashMap(Zone *zone, intptr_t initial_size=ZoneDirectChainedHashMap::kInitialSize)
Definition: hash_map.h:357
static const int K
Definition: daa.cpp:21
#define ASSERT(E)
uint8_t value
T __attribute__((ext_vector_type(N))) V
Definition: dart_vm.cc:33
constexpr intptr_t kIntptrMin
Definition: globals.h:556
constexpr uint32_t kMaxUint32
Definition: globals.h:484
uintptr_t uword
Definition: globals.h:501
static uint32_t Hash(uint32_t key)
Definition: hashmap_test.cc:65
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
#define T
Definition: precompiler.cc:65
#define V(name)
Definition: raw_object.h:125
Pair(const Key key, const Value &value)
Definition: hash_map.h:469
Pair & operator=(const Pair &)=default
static bool IsKeyEqual(const Pair &kv, const Key &key)
Definition: hash_map.h:480
static Value ValueOf(const Pair &pair)
Definition: hash_map.h:475
static Key KeyOf(const Pair &pair)
Definition: hash_map.h:474
static uword Hash(const Key &key)
Definition: hash_map.h:476
Pair & operator=(const Pair &)=default
Pair(const Key key, const Value &value)
Definition: hash_map.h:521
Pair(const Key key, const Value &value)
Definition: hash_map.h:407
Pair & operator=(const Pair &)=default