OR-Tools  9.3
linked_hash_map.h
Go to the documentation of this file.
1// Copyright 2010-2021 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// This is a simplistic insertion-ordered map. It behaves similarly to an STL
15// map, but only implements a small subset of the map's methods. Internally, we
16// just keep a map and a list going in parallel.
17//
18// This class provides no thread safety guarantees, beyond what you would
19// normally see with std::list.
20//
21// Iterators point into the list and should be stable in the face of
22// mutations, except for an iterator pointing to an element that was just
23// deleted.
24//
25// This class supports heterogeneous lookups.
26//
27#ifndef OR_TOOLS_BASE_LINKED_HASH_MAP_H_
28#define OR_TOOLS_BASE_LINKED_HASH_MAP_H_
29
30#include <list>
31#include <tuple>
32#include <type_traits>
33#include <utility>
34
35#include "absl/container/flat_hash_set.h"
36#include "absl/container/internal/common.h"
38
39namespace gtl {
40
41// This holds a list of pair<Key, Value> items. This list is what gets
42// traversed, and it's iterators from this list that we return from
43// begin/end/find.
44//
45// We also keep a set<list::iterator> for find. Since std::list is a
46// doubly-linked list, the iterators should remain stable.
47template <typename Key, typename Value,
48 typename KeyHash = typename absl::flat_hash_set<Key>::hasher,
49 typename KeyEq =
50 typename absl::flat_hash_set<Key, KeyHash>::key_equal,
51 typename Alloc = std::allocator<std::pair<const Key, Value>>>
53 using KeyArgImpl = absl::container_internal::KeyArg<
56 // Alias used for heterogeneous lookup functions.
57 // `key_arg<K>` evaluates to `K` when the functors are transparent and to
58 // `key_type` otherwise. It permits template argument deduction on `K` for the
59 // transparent case.
60 template <class K>
61 using key_arg = typename KeyArgImpl::template type<K, Key>;
62
63 public:
64 using key_type = Key;
66 using hasher = KeyHash;
67 using key_equal = KeyEq;
68 using value_type = std::pair<const key_type, mapped_type>;
69 using allocator_type = Alloc;
70 using difference_type = ptrdiff_t;
71
72 private:
73 using ListType = std::list<value_type, Alloc>;
74
75 template <class Fn>
76 class Wrapped {
77 template <typename K>
78 static const K& ToKey(const K& k) {
79 return k;
80 }
81 static const key_type& ToKey(typename ListType::const_iterator it) {
82 return it->first;
83 }
84 static const key_type& ToKey(typename ListType::iterator it) {
85 return it->first;
86 }
87
88 Fn fn_;
89
90 friend linked_hash_map;
91
92 public:
93 using is_transparent = void;
94
95 Wrapped() = default;
96 explicit Wrapped(Fn fn) : fn_(std::move(fn)) {}
97
98 template <class... Args>
99 auto operator()(Args&&... args) const
100 -> decltype(this->fn_(ToKey(args)...)) {
101 return fn_(ToKey(args)...);
102 }
103 };
104 using SetType =
105 absl::flat_hash_set<typename ListType::iterator, Wrapped<hasher>,
106 Wrapped<key_equal>, Alloc>;
107
108 class NodeHandle {
109 public:
113
114 constexpr NodeHandle() noexcept = default;
115 NodeHandle(NodeHandle&& nh) noexcept = default;
116 ~NodeHandle() = default;
117 NodeHandle& operator=(NodeHandle&& node) noexcept = default;
118 bool empty() const noexcept { return list_.empty(); }
119 explicit operator bool() const noexcept { return !empty(); }
120 allocator_type get_allocator() const { return list_.get_allocator(); }
121 const key_type& key() const { return list_.front().first; }
122 mapped_type& mapped() { return list_.front().second; }
123 void swap(NodeHandle& nh) noexcept { list_.swap(nh.list_); }
124
125 private:
126 friend linked_hash_map;
127
128 explicit NodeHandle(ListType list) : list_(std::move(list)) {}
129 ListType list_;
130 };
131
132 template <class Iterator, class NodeType>
133 struct InsertReturnType {
134 Iterator position;
135 bool inserted;
136 NodeType node;
137 };
138
139 public:
140 using iterator = typename ListType::iterator;
141 using const_iterator = typename ListType::const_iterator;
142 using reverse_iterator = typename ListType::reverse_iterator;
143 using const_reverse_iterator = typename ListType::const_reverse_iterator;
144 using reference = typename ListType::reference;
145 using const_reference = typename ListType::const_reference;
146 using size_type = typename ListType::size_type;
147 using pointer = typename std::allocator_traits<allocator_type>::pointer;
149 typename std::allocator_traits<allocator_type>::const_pointer;
150 using node_type = NodeHandle;
151 using insert_return_type = InsertReturnType<iterator, node_type>;
152
154
155 explicit linked_hash_map(size_t bucket_count, const hasher& hash = hasher(),
156 const key_equal& eq = key_equal(),
157 const allocator_type& alloc = allocator_type())
158 : set_(bucket_count, Wrapped<hasher>(hash), Wrapped<key_equal>(eq),
159 alloc),
160 list_(alloc) {}
161
163 const allocator_type& alloc)
165
168
169 explicit linked_hash_map(const allocator_type& alloc)
170 : linked_hash_map(0, hasher(), key_equal(), alloc) {}
171
172 template <class InputIt>
173 linked_hash_map(InputIt first, InputIt last, size_t bucket_count = 0,
174 const hasher& hash = hasher(),
175 const key_equal& eq = key_equal(),
176 const allocator_type& alloc = allocator_type())
177 : linked_hash_map(bucket_count, hash, eq, alloc) {
178 insert(first, last);
179 }
180
181 template <class InputIt>
182 linked_hash_map(InputIt first, InputIt last, size_t bucket_count,
183 const hasher& hash, const allocator_type& alloc)
184 : linked_hash_map(first, last, bucket_count, hash, key_equal(), alloc) {}
185
186 template <class InputIt>
187 linked_hash_map(InputIt first, InputIt last, size_t bucket_count,
188 const allocator_type& alloc)
189 : linked_hash_map(first, last, bucket_count, hasher(), key_equal(),
190 alloc) {}
191
192 template <class InputIt>
193 linked_hash_map(InputIt first, InputIt last, const allocator_type& alloc)
194 : linked_hash_map(first, last, /*bucket_count=*/0, hasher(), key_equal(),
195 alloc) {}
196
197 linked_hash_map(std::initializer_list<value_type> init,
198 size_t bucket_count = 0, const hasher& hash = hasher(),
199 const key_equal& eq = key_equal(),
200 const allocator_type& alloc = allocator_type())
201 : linked_hash_map(init.begin(), init.end(), bucket_count, hash, eq,
202 alloc) {}
203
204 linked_hash_map(std::initializer_list<value_type> init, size_t bucket_count,
205 const hasher& hash, const allocator_type& alloc)
206 : linked_hash_map(init, bucket_count, hash, key_equal(), alloc) {}
207
208 linked_hash_map(std::initializer_list<value_type> init, size_t bucket_count,
209 const allocator_type& alloc)
210 : linked_hash_map(init, bucket_count, hasher(), key_equal(), alloc) {}
211
212 linked_hash_map(std::initializer_list<value_type> init,
213 const allocator_type& alloc)
214 : linked_hash_map(init, /*bucket_count=*/0, hasher(), key_equal(),
215 alloc) {}
216
218 : linked_hash_map(other.bucket_count(), other.hash_function(),
219 other.key_eq(), other.get_allocator()) {
220 CopyFrom(other);
221 }
222
224 : linked_hash_map(other.bucket_count(), other.hash_function(),
225 other.key_eq(), alloc) {
226 CopyFrom(other);
227 }
228
230 : set_(std::move(other.set_)), list_(std::move(other.list_)) {
231 // Since the list and set must agree for other to end up "valid",
232 // explicitly clear them.
233 other.set_.clear();
234 other.list_.clear();
235 }
236
238 : linked_hash_map(0, other.hash_function(), other.key_eq(), alloc) {
239 if (get_allocator() == other.get_allocator()) {
240 *this = std::move(other);
241 } else {
242 CopyFrom(std::move(other));
243 }
244 }
245
247 if (this == &other) return *this;
248 // Make a new set, with other's hash/eq/alloc.
249 set_ = SetType(other.bucket_count(), other.set_.hash_function(),
250 other.set_.key_eq(), other.get_allocator());
251 // Copy the list, with other's allocator.
252 list_ = ListType(other.get_allocator());
253 CopyFrom(other);
254 return *this;
255 }
256
258 // underlying containers will handle progagate_on_container_move details
259 set_ = std::move(other.set_);
260 list_ = std::move(other.list_);
261 other.set_.clear();
262 other.list_.clear();
263 return *this;
264 }
265
266 linked_hash_map& operator=(std::initializer_list<value_type> values) {
267 clear();
268 insert(values.begin(), values.end());
269 return *this;
270 }
271
272 // Derive size_ from set_, as list::size might be O(N).
273 size_type size() const { return set_.size(); }
274 size_type max_size() const noexcept { return ~size_type{}; }
275 bool empty() const { return set_.empty(); }
276
277 // Iteration is list-like, in insertion order.
278 // These are all forwarded.
279 iterator begin() { return list_.begin(); }
280 iterator end() { return list_.end(); }
281 const_iterator begin() const { return list_.begin(); }
282 const_iterator end() const { return list_.end(); }
283 const_iterator cbegin() const { return list_.cbegin(); }
284 const_iterator cend() const { return list_.cend(); }
285 reverse_iterator rbegin() { return list_.rbegin(); }
286 reverse_iterator rend() { return list_.rend(); }
287 const_reverse_iterator rbegin() const { return list_.rbegin(); }
288 const_reverse_iterator rend() const { return list_.rend(); }
289 const_reverse_iterator crbegin() const { return list_.crbegin(); }
290 const_reverse_iterator crend() const { return list_.crend(); }
291 reference front() { return list_.front(); }
292 reference back() { return list_.back(); }
293 const_reference front() const { return list_.front(); }
294 const_reference back() const { return list_.back(); }
295
296 void pop_front() { erase(begin()); }
297 void pop_back() { erase(std::prev(end())); }
298
299 ABSL_ATTRIBUTE_REINITIALIZES void clear() {
300 set_.clear();
301 list_.clear();
302 }
303
304 void reserve(size_t n) { set_.reserve(n); }
305 size_t capacity() const { return set_.capacity(); }
306 size_t bucket_count() const { return set_.bucket_count(); }
307 float load_factor() const { return set_.load_factor(); }
308
309 hasher hash_function() const { return set_.hash_function().fn_; }
310 key_equal key_eq() const { return set_.key_eq().fn_; }
311 allocator_type get_allocator() const { return list_.get_allocator(); }
312
313 template <class K = key_type>
314 size_type erase(const key_arg<K>& key) {
315 auto found = set_.find(key);
316 if (found == set_.end()) return 0;
317 auto list_it = *found;
318 // Erase set entry first since it refers to the list element.
319 set_.erase(found);
320 list_.erase(list_it);
321 return 1;
322 }
323
325 auto found = set_.find(position);
326 CHECK(*found == position) << "Inconsistent iterator for set and list, "
327 "or the iterator is invalid.";
328 set_.erase(found);
329 return list_.erase(position);
330 }
331
333 return erase(static_cast<const_iterator>(position));
334 }
335
337 while (first != last) first = erase(first);
338 return first;
339 }
340
342 while (first != last) first = erase(first);
343 if (first == end()) return end();
344 return *set_.find(first);
345 }
346
347 template <class K = key_type>
348 iterator find(const key_arg<K>& key) {
349 auto found = set_.find(key);
350 if (found == set_.end()) return end();
351 return *found;
352 }
353
354 template <class K = key_type>
355 const_iterator find(const key_arg<K>& key) const {
356 auto found = set_.find(key);
357 if (found == set_.end()) return end();
358 return *found;
359 }
360
361 template <class K = key_type>
362 size_type count(const key_arg<K>& key) const {
363 return contains(key) ? 1 : 0;
364 }
365 template <class K = key_type>
366 bool contains(const key_arg<K>& key) const {
367 return set_.contains(key);
368 }
369
370 template <class K = key_type>
371 mapped_type& at(const key_arg<K>& key) {
372 auto it = find(key);
373 if (ABSL_PREDICT_FALSE(it == end())) {
374 LOG(FATAL) << "linked_hash_map::at failed bounds check";
375 }
376 return it->second;
377 }
378
379 template <class K = key_type>
380 const mapped_type& at(const key_arg<K>& key) const {
381 return const_cast<linked_hash_map*>(this)->at(key);
382 }
383
384 template <class K = key_type>
385 std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
386 auto iter = set_.find(key);
387 if (iter == set_.end()) return {end(), end()};
388 return {*iter, std::next(*iter)};
389 }
390
391 template <class K = key_type>
392 std::pair<const_iterator, const_iterator> equal_range(
393 const key_arg<K>& key) const {
394 auto iter = set_.find(key);
395 if (iter == set_.end()) return {end(), end()};
396 return {*iter, std::next(*iter)};
397 }
398
399 template <class K = key_type>
400 mapped_type& operator[](const key_arg<K>& key) {
401 return LazyEmplaceInternal(key).first->second;
402 }
403
404 template <class K = key_type, K* = nullptr>
405 mapped_type& operator[](key_arg<K>&& key) {
406 // K* = nullptr parameter above.
407 return LazyEmplaceInternal(std::forward<K>(key)).first->second;
408 }
409
410 std::pair<iterator, bool> insert(const value_type& v) {
411 return InsertInternal(v);
412 }
413 std::pair<iterator, bool> insert(value_type&& v) { // NOLINT(build/c++11)
414 return InsertInternal(std::move(v));
415 }
416
418 return insert(v).first;
419 }
421 return insert(std::move(v)).first;
422 }
423
424 void insert(std::initializer_list<value_type> ilist) {
425 insert(ilist.begin(), ilist.end());
426 }
427
428 template <class InputIt>
429 void insert(InputIt first, InputIt last) {
430 for (; first != last; ++first) insert(*first);
431 }
432
434 if (!node) return {end(), false, node_type()};
435 auto itr = find(node.key());
436 if (itr != end()) return {itr, false, std::move(node)};
437 list_.splice(list_.end(), node.list_);
438 set_.insert(--list_.end());
439 return {--list_.end(), true, node_type()};
440 }
441
443 return insert(std::move(node)).first;
444 }
445
446 // The last two template parameters ensure that both arguments are rvalues
447 // (lvalue arguments are handled by the overloads below). This is necessary
448 // for supporting bitfield arguments.
449 //
450 // union { int n : 1; };
451 // linked_hash_map<int, int> m;
452 // m.insert_or_assign(n, n);
453 template <class K = key_type, class V = mapped_type, K* = nullptr,
454 V* = nullptr>
455 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) {
456 return InsertOrAssignInternal(std::forward<K>(k), std::forward<V>(v));
457 }
458
459 template <class K = key_type, class V = mapped_type, K* = nullptr>
460 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v) {
461 return InsertOrAssignInternal(std::forward<K>(k), v);
462 }
463
464 template <class K = key_type, class V = mapped_type, V* = nullptr>
465 std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v) {
466 return InsertOrAssignInternal(k, std::forward<V>(v));
467 }
468
469 template <class K = key_type, class V = mapped_type>
470 std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v) {
471 return InsertOrAssignInternal(k, v);
472 }
473
474 template <class K = key_type, class V = mapped_type, K* = nullptr,
475 V* = nullptr>
476 iterator insert_or_assign(const_iterator, key_arg<K>&& k, V&& v) {
477 return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
478 }
479
480 template <class K = key_type, class V = mapped_type, K* = nullptr>
481 iterator insert_or_assign(const_iterator, key_arg<K>&& k, const V& v) {
482 return insert_or_assign(std::forward<K>(k), v).first;
483 }
484
485 template <class K = key_type, class V = mapped_type, V* = nullptr>
486 iterator insert_or_assign(const_iterator, const key_arg<K>& k, V&& v) {
487 return insert_or_assign(k, std::forward<V>(v)).first;
488 }
489
490 template <class K = key_type, class V = mapped_type>
491 iterator insert_or_assign(const_iterator, const key_arg<K>& k, const V& v) {
492 return insert_or_assign(k, v).first;
493 }
494
495 template <typename... Args>
496 std::pair<iterator, bool> emplace(Args&&... args) {
497 ListType node_donor;
498 auto list_iter =
499 node_donor.emplace(node_donor.end(), std::forward<Args>(args)...);
500 auto ins = set_.insert(list_iter);
501 if (!ins.second) return {*ins.first, false};
502 list_.splice(list_.end(), node_donor, list_iter);
503 return {list_iter, true};
504 }
505
506 template <class K = key_type, class... Args, K* = nullptr>
507 iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args) {
508 return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
509 }
510
511 template <typename... Args>
513 return emplace(std::forward<Args>(args)...).first;
514 }
515
516 template <class K = key_type, typename... Args, K* = nullptr>
517 std::pair<iterator, bool> try_emplace(key_arg<K>&& key, Args&&... args) {
518 return LazyEmplaceInternal(std::forward<key_arg<K>>(key),
519 std::forward<Args>(args)...);
520 }
521
522 template <typename H, typename E>
524 auto itr = src.list_.begin();
525 while (itr != src.list_.end()) {
526 if (contains(itr->first)) {
527 ++itr;
528 } else {
529 insert(src.extract(itr++));
530 }
531 }
532 }
533
534 template <typename H, typename E>
536 merge(src);
537 }
538
540 set_.erase(position->first);
541 ListType extracted_node_list;
542 extracted_node_list.splice(extracted_node_list.end(), list_, position);
543 return node_type(std::move(extracted_node_list));
544 }
545
546 template <class K = key_type,
547 std::enable_if_t<!std::is_same_v<K, iterator>, int> = 0>
548 node_type extract(const key_arg<K>& key) {
549 auto it = find(key);
550 return it == end() ? node_type() : extract(const_iterator{it});
551 }
552
553 template <class K = key_type, typename... Args>
554 std::pair<iterator, bool> try_emplace(const key_arg<K>& key, Args&&... args) {
555 return LazyEmplaceInternal(key, std::forward<Args>(args)...);
556 }
557
558 void swap(linked_hash_map& other) {
559 using std::swap;
560 swap(set_, other.set_);
561 swap(list_, other.list_);
562 }
563
564 friend bool operator==(const linked_hash_map& a, const linked_hash_map& b) {
565 if (a.size() != b.size()) return false;
566 const linked_hash_map* outer = &a;
567 const linked_hash_map* inner = &b;
568 if (outer->capacity() > inner->capacity()) std::swap(outer, inner);
569 for (const value_type& elem : *outer) {
570 auto it = inner->find(elem.first);
571 if (it == inner->end()) return false;
572 if (it->second != elem.second) return false;
573 }
574
575 return true;
576 }
577
578 friend bool operator!=(const linked_hash_map& a, const linked_hash_map& b) {
579 return !(a == b);
580 }
581
582 void rehash(size_t n) { set_.rehash(n); }
583
584 private:
585 template <typename Other>
586 void CopyFrom(Other&& other) {
587 for (auto& elem : other.list_) {
588 set_.insert(list_.insert(list_.end(), std::move(elem)));
589 }
590 DCHECK_EQ(set_.size(), list_.size()) << "Set and list are inconsistent.";
591 }
592
593 template <typename U>
594 std::pair<iterator, bool> InsertInternal(U&& pair) { // NOLINT(build/c++11)
595 auto iter = set_.find(pair.first);
596 if (iter != set_.end()) return {*iter, false};
597 auto list_iter = list_.insert(list_.end(), std::forward<U>(pair));
598 auto inserted = set_.insert(list_iter);
599 DCHECK(inserted.second);
600 return {list_iter, true};
601 }
602
603 template <class K, class V>
604 std::pair<iterator, bool> InsertOrAssignInternal(K&& k, V&& v) {
605 auto iter = set_.find(k);
606 if (iter != set_.end()) {
607 (*iter)->second = std::forward<V>(v);
608 return {*iter, false};
609 }
610 return LazyEmplaceInternal(std::forward<K>(k), std::forward<V>(v));
611 }
612
613 template <typename K, typename... Args>
614 std::pair<iterator, bool> LazyEmplaceInternal(K&& key, Args&&... args) {
615 bool constructed = false;
616 auto set_iter =
617 set_.lazy_emplace(key, [this, &constructed, &key, &args...](auto ctor) {
618 auto list_iter =
619 list_.emplace(list_.end(), std::piecewise_construct,
620 std::forward_as_tuple(std::forward<K>(key)),
621 std::forward_as_tuple(std::forward<Args>(args)...));
622 constructed = true;
623 ctor(list_iter);
624 });
625 return {*set_iter, constructed};
626 }
627
628 // The set component, used for speedy lookups.
629 SetType set_;
630
631 // The list component, used for maintaining insertion order.
632 ListType list_;
633};
634
635} // namespace gtl
636
637#endif // OR_TOOLS_BASE_LINKED_HASH_MAP_H_
#define CHECK(condition)
Definition: base/logging.h:495
#define LOG(severity)
Definition: base/logging.h:420
#define DCHECK(condition)
Definition: base/logging.h:890
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:891
const_reverse_iterator rend() const
linked_hash_map(const linked_hash_map &other)
const_reference front() const
linked_hash_map(InputIt first, InputIt last, size_t bucket_count, const allocator_type &alloc)
std::pair< const key_type, mapped_type > value_type
key_equal key_eq() const
std::pair< iterator, bool > insert(value_type &&v)
iterator insert(const_iterator, value_type &&v)
iterator erase(const_iterator position)
linked_hash_map(linked_hash_map &&other) noexcept
bool contains(const key_arg< K > &key) const
typename std::allocator_traits< allocator_type >::pointer pointer
insert_return_type insert(node_type &&node)
linked_hash_map(std::initializer_list< value_type > init, size_t bucket_count=0, const hasher &hash=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
iterator insert_or_assign(const_iterator, const key_arg< K > &k, V &&v)
iterator emplace_hint(const_iterator, Args &&... args)
const_iterator begin() const
mapped_type & operator[](key_arg< K > &&key)
void insert(InputIt first, InputIt last)
void merge(linked_hash_map< Key, Value, H, E, Alloc > &src)
typename ListType::const_reverse_iterator const_reverse_iterator
linked_hash_map(std::initializer_list< value_type > init, const allocator_type &alloc)
const_iterator cbegin() const
std::pair< const_iterator, const_iterator > equal_range(const key_arg< K > &key) const
typename ListType::const_iterator const_iterator
linked_hash_map(linked_hash_map &&other, const allocator_type &alloc)
typename std::allocator_traits< allocator_type >::const_pointer const_pointer
linked_hash_map & operator=(const linked_hash_map &other)
typename ListType::size_type size_type
size_t bucket_count() const
InsertReturnType< iterator, node_type > insert_return_type
linked_hash_map(InputIt first, InputIt last, size_t bucket_count, const hasher &hash, const allocator_type &alloc)
mapped_type & at(const key_arg< K > &key)
node_type extract(const_iterator position)
size_type size() const
const_reference back() const
float load_factor() const
std::pair< iterator, bool > insert(const value_type &v)
reverse_iterator rend()
typename ListType::iterator iterator
linked_hash_map(InputIt first, InputIt last, size_t bucket_count=0, const hasher &hash=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
allocator_type get_allocator() const
std::pair< iterator, bool > try_emplace(const key_arg< K > &key, Args &&... args)
size_t capacity() const
hasher hash_function() const
linked_hash_map & operator=(linked_hash_map &&other) noexcept
iterator erase(iterator position)
iterator find(const key_arg< K > &key)
iterator insert(const_iterator, node_type &&node)
friend bool operator!=(const linked_hash_map &a, const linked_hash_map &b)
const_reverse_iterator crbegin() const
linked_hash_map(const allocator_type &alloc)
iterator insert_or_assign(const_iterator, key_arg< K > &&k, const V &v)
linked_hash_map(const linked_hash_map &other, const allocator_type &alloc)
size_type erase(const key_arg< K > &key)
iterator insert_or_assign(const_iterator, const key_arg< K > &k, const V &v)
const_iterator cend() const
const mapped_type & at(const key_arg< K > &key) const
linked_hash_map(std::initializer_list< value_type > init, size_t bucket_count, const hasher &hash, const allocator_type &alloc)
typename ListType::const_reference const_reference
std::pair< iterator, iterator > equal_range(const key_arg< K > &key)
ABSL_ATTRIBUTE_REINITIALIZES void clear()
mapped_type & operator[](const key_arg< K > &key)
const_iterator find(const key_arg< K > &key) const
friend bool operator==(const linked_hash_map &a, const linked_hash_map &b)
iterator erase(const_iterator first, const_iterator last)
typename ListType::reference reference
linked_hash_map & operator=(std::initializer_list< value_type > values)
node_type extract(const key_arg< K > &key)
iterator insert(const_iterator, const value_type &v)
void merge(linked_hash_map< Key, Value, H, E, Alloc > &&src)
linked_hash_map(size_t bucket_count, const hasher &hash, const allocator_type &alloc)
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, V &&v)
std::pair< iterator, bool > emplace(Args &&... args)
const_reverse_iterator crend() const
void rehash(size_t n)
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, V &&v)
size_type max_size() const noexcept
const_iterator end() const
reverse_iterator rbegin()
linked_hash_map(std::initializer_list< value_type > init, size_t bucket_count, const allocator_type &alloc)
void insert(std::initializer_list< value_type > ilist)
linked_hash_map(size_t bucket_count, const allocator_type &alloc)
std::pair< iterator, bool > try_emplace(key_arg< K > &&key, Args &&... args)
typename ListType::reverse_iterator reverse_iterator
linked_hash_map(size_t bucket_count, const hasher &hash=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
linked_hash_map(InputIt first, InputIt last, const allocator_type &alloc)
void swap(linked_hash_map &other)
iterator try_emplace(const_iterator, key_arg< K > &&k, Args &&... args)
const_reverse_iterator rbegin() const
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, const V &v)
iterator insert_or_assign(const_iterator, key_arg< K > &&k, V &&v)
void reserve(size_t n)
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, const V &v)
size_type count(const key_arg< K > &key) const
iterator erase(iterator first, iterator last)
int64_t b
int64_t a
Block * next
int64_t value
const int FATAL
Definition: log_severity.h:32
int64_t hash
Definition: matrix_utils.cc:61
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:262
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Definition: integer.h:1683
STL namespace.