Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
linked_hash_map.h
Go to the documentation of this file.
1// Copyright 2010-2024 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<
54 absl::container_internal::IsTransparent<KeyEq>::value &&
55 absl::container_internal::IsTransparent<KeyHash>::value>;
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;
65 using mapped_type = Value;
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:
110 using key_type = linked_hash_map::key_type;
111 using mapped_type = linked_hash_map::mapped_type;
112 using allocator_type = linked_hash_map::allocator_type;
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
153 linked_hash_map() = default;
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 return LazyEmplaceInternal(std::forward<K>(key)).first->second;
407 }
408
409 std::pair<iterator, bool> insert(const value_type& v) {
410 return InsertInternal(v);
411 }
412 std::pair<iterator, bool> insert(value_type&& v) { // NOLINT(build/c++11)
413 return InsertInternal(std::move(v));
414 }
415
417 return insert(v).first;
418 }
420 return insert(std::move(v)).first;
421 }
422
423 void insert(std::initializer_list<value_type> ilist) {
424 insert(ilist.begin(), ilist.end());
425 }
426
427 template <class InputIt>
428 void insert(InputIt first, InputIt last) {
429 for (; first != last; ++first) insert(*first);
430 }
431
433 if (!node) return {end(), false, node_type()};
434 auto itr = find(node.key());
435 if (itr != end()) return {itr, false, std::move(node)};
436 list_.splice(list_.end(), node.list_);
437 set_.insert(--list_.end());
438 return {--list_.end(), true, node_type()};
439 }
440
442 return insert(std::move(node)).first;
443 }
444
445 // The last two template parameters ensure that both arguments are rvalues
446 // (lvalue arguments are handled by the overloads below). This is necessary
447 // for supporting bitfield arguments.
448 //
449 // union { int n : 1; };
450 // linked_hash_map<int, int> m;
451 // m.insert_or_assign(n, n);
452 template <class K = key_type, class V = mapped_type, K* = nullptr,
453 V* = nullptr>
454 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) {
455 return InsertOrAssignInternal(std::forward<K>(k), std::forward<V>(v));
456 }
457
458 template <class K = key_type, class V = mapped_type, K* = nullptr>
459 std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v) {
460 return InsertOrAssignInternal(std::forward<K>(k), v);
461 }
462
463 template <class K = key_type, class V = mapped_type, V* = nullptr>
464 std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v) {
465 return InsertOrAssignInternal(k, std::forward<V>(v));
466 }
467
468 template <class K = key_type, class V = mapped_type>
469 std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v) {
470 return InsertOrAssignInternal(k, v);
471 }
472
473 template <class K = key_type, class V = mapped_type, K* = nullptr,
474 V* = nullptr>
475 iterator insert_or_assign(const_iterator, key_arg<K>&& k, V&& v) {
476 return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
477 }
478
479 template <class K = key_type, class V = mapped_type, K* = nullptr>
480 iterator insert_or_assign(const_iterator, key_arg<K>&& k, const V& v) {
481 return insert_or_assign(std::forward<K>(k), v).first;
482 }
483
484 template <class K = key_type, class V = mapped_type, V* = nullptr>
485 iterator insert_or_assign(const_iterator, const key_arg<K>& k, V&& v) {
486 return insert_or_assign(k, std::forward<V>(v)).first;
487 }
488
489 template <class K = key_type, class V = mapped_type>
490 iterator insert_or_assign(const_iterator, const key_arg<K>& k, const V& v) {
491 return insert_or_assign(k, v).first;
492 }
493
494 template <typename... Args>
495 std::pair<iterator, bool> emplace(Args&&... args) {
496 ListType node_donor;
497 auto list_iter =
498 node_donor.emplace(node_donor.end(), std::forward<Args>(args)...);
499 auto ins = set_.insert(list_iter);
500 if (!ins.second) return {*ins.first, false};
501 list_.splice(list_.end(), node_donor, list_iter);
502 return {list_iter, true};
503 }
504
505 template <class K = key_type, class... Args, K* = nullptr>
506 iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args) {
507 return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
508 }
509
510 template <typename... Args>
512 return emplace(std::forward<Args>(args)...).first;
513 }
514
515 template <class K = key_type, typename... Args, K* = nullptr>
516 std::pair<iterator, bool> try_emplace(key_arg<K>&& key, Args&&... args) {
517 return LazyEmplaceInternal(std::forward<key_arg<K>>(key),
518 std::forward<Args>(args)...);
519 }
520
521 template <typename H, typename E>
523 auto itr = src.list_.begin();
524 while (itr != src.list_.end()) {
525 if (contains(itr->first)) {
526 ++itr;
527 } else {
528 insert(src.extract(itr++));
529 }
530 }
531 }
532
533 template <typename H, typename E>
537
539 set_.erase(position->first);
540 ListType extracted_node_list;
541 extracted_node_list.splice(extracted_node_list.end(), list_, position);
542 return node_type(std::move(extracted_node_list));
543 }
544
545 template <class K = key_type,
546 std::enable_if_t<!std::is_same_v<K, iterator>, int> = 0>
547 node_type extract(const key_arg<K>& key) {
548 auto it = find(key);
549 return it == end() ? node_type() : extract(const_iterator{it});
550 }
551
552 template <class K = key_type, typename... Args>
553 std::pair<iterator, bool> try_emplace(const key_arg<K>& key, Args&&... args) {
554 return LazyEmplaceInternal(key, std::forward<Args>(args)...);
555 }
556
557 void swap(linked_hash_map& other) {
558 using std::swap;
559 swap(set_, other.set_);
560 swap(list_, other.list_);
561 }
562
563 friend bool operator==(const linked_hash_map& a, const linked_hash_map& b) {
564 if (a.size() != b.size()) return false;
565 const linked_hash_map* outer = &a;
566 const linked_hash_map* inner = &b;
567 if (outer->capacity() > inner->capacity()) std::swap(outer, inner);
568 for (const value_type& elem : *outer) {
569 auto it = inner->find(elem.first);
570 if (it == inner->end()) return false;
571 if (it->second != elem.second) return false;
572 }
573
574 return true;
575 }
576
577 friend bool operator!=(const linked_hash_map& a, const linked_hash_map& b) {
578 return !(a == b);
579 }
580
581 void rehash(size_t n) { set_.rehash(n); }
582
583 private:
584 template <typename Other>
585 void CopyFrom(Other&& other) {
586 for (auto& elem : other.list_) {
587 set_.insert(list_.insert(list_.end(), std::move(elem)));
588 }
589 DCHECK_EQ(set_.size(), list_.size()) << "Set and list are inconsistent.";
590 }
591
592 template <typename U>
593 std::pair<iterator, bool> InsertInternal(U&& pair) { // NOLINT(build/c++11)
594 auto iter = set_.find(pair.first);
595 if (iter != set_.end()) return {*iter, false};
596 auto list_iter = list_.insert(list_.end(), std::forward<U>(pair));
597 auto inserted = set_.insert(list_iter);
598 DCHECK(inserted.second);
599 return {list_iter, true};
600 }
601
602 template <class K, class V>
603 std::pair<iterator, bool> InsertOrAssignInternal(K&& k, V&& v) {
604 auto iter = set_.find(k);
605 if (iter != set_.end()) {
606 (*iter)->second = std::forward<V>(v);
607 return {*iter, false};
608 }
609 return LazyEmplaceInternal(std::forward<K>(k), std::forward<V>(v));
610 }
611
612 template <typename K, typename... Args>
613 std::pair<iterator, bool> LazyEmplaceInternal(K&& key, Args&&... args) {
614 bool constructed = false;
615 auto set_iter =
616 set_.lazy_emplace(key, [this, &constructed, &key, &args...](auto ctor) {
617 auto list_iter =
618 list_.emplace(list_.end(), std::piecewise_construct,
619 std::forward_as_tuple(std::forward<K>(key)),
620 std::forward_as_tuple(std::forward<Args>(args)...));
621 constructed = true;
622 ctor(list_iter);
623 });
624 return {*set_iter, constructed};
625 }
626
627 // The set component, used for speedy lookups.
628 SetType set_;
629
630 // The list component, used for maintaining insertion order.
631 ListType list_;
632};
633
634} // namespace gtl
635
636#endif // OR_TOOLS_BASE_LINKED_HASH_MAP_H_
void merge(linked_hash_map< Key, Value, H, E, Alloc > &src)
iterator try_emplace(const_iterator, key_arg< K > &&k, Args &&... args)
hasher hash_function() const
const_iterator find(const key_arg< K > &key) const
iterator emplace_hint(const_iterator, Args &&... args)
linked_hash_map(InputIt first, InputIt last, size_t bucket_count, const allocator_type &alloc)
size_t bucket_count() const
linked_hash_map(linked_hash_map &&other, const allocator_type &alloc)
iterator insert(const_iterator, node_type &&node)
iterator insert(const_iterator, const value_type &v)
reverse_iterator rbegin()
mapped_type & operator[](const key_arg< K > &key)
typename ListType::const_reverse_iterator const_reverse_iterator
allocator_type get_allocator() const
const_reverse_iterator rbegin() const
std::pair< const key_type, mapped_type > value_type
const_iterator cbegin() const
InsertReturnType< iterator, node_type > insert_return_type
bool contains(const key_arg< K > &key) const
linked_hash_map(size_t bucket_count, const hasher &hash, const allocator_type &alloc)
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, const V &v)
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, V &&v)
linked_hash_map & operator=(const linked_hash_map &other)
mapped_type & at(const key_arg< K > &key)
const mapped_type & at(const key_arg< K > &key) const
reverse_iterator rend()
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, V &&v)
iterator erase(iterator first, iterator last)
const_reverse_iterator crend() const
void swap(linked_hash_map &other)
iterator erase(const_iterator first, const_iterator last)
linked_hash_map(std::initializer_list< value_type > init, size_t bucket_count, const allocator_type &alloc)
linked_hash_map & operator=(std::initializer_list< value_type > values)
void merge(linked_hash_map< Key, Value, H, E, Alloc > &&src)
std::pair< iterator, iterator > equal_range(const key_arg< K > &key)
const_iterator begin() const
float load_factor() const
linked_hash_map(std::initializer_list< value_type > init, size_t bucket_count, const hasher &hash, const allocator_type &alloc)
size_type max_size() const noexcept
const_reference front() const
std::pair< iterator, bool > try_emplace(const key_arg< K > &key, Args &&... args)
iterator insert_or_assign(const_iterator, const key_arg< K > &k, V &&v)
std::pair< iterator, bool > insert(const value_type &v)
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 find(const key_arg< K > &key)
typename ListType::iterator iterator
typename std::allocator_traits< allocator_type >::pointer pointer
friend bool operator!=(const linked_hash_map &a, const linked_hash_map &b)
const_reverse_iterator rend() const
typename ListType::const_iterator const_iterator
insert_return_type insert(node_type &&node)
size_type erase(const key_arg< K > &key)
linked_hash_map(linked_hash_map &&other) noexcept
typename ListType::const_reference const_reference
std::pair< iterator, bool > try_emplace(key_arg< K > &&key, Args &&... args)
const_reference back() const
typename ListType::size_type size_type
typename ListType::reference reference
void insert(InputIt first, InputIt last)
linked_hash_map(InputIt first, InputIt last, size_t bucket_count, const hasher &hash, const allocator_type &alloc)
ABSL_ATTRIBUTE_REINITIALIZES void clear()
iterator erase(iterator position)
const_iterator end() const
friend bool operator==(const linked_hash_map &a, const linked_hash_map &b)
linked_hash_map(const allocator_type &alloc)
iterator erase(const_iterator position)
iterator insert(const_iterator, value_type &&v)
key_equal key_eq() const
const_reverse_iterator crbegin() const
linked_hash_map(std::initializer_list< value_type > init, const allocator_type &alloc)
iterator insert_or_assign(const_iterator, key_arg< K > &&k, const V &v)
const_iterator cend() const
linked_hash_map & operator=(linked_hash_map &&other) noexcept
std::pair< const_iterator, const_iterator > equal_range(const key_arg< K > &key) const
linked_hash_map()=default
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, const V &v)
size_type size() const
Derive size_ from set_, as list::size might be O(N).
size_type count(const key_arg< K > &key) const
iterator insert_or_assign(const_iterator, key_arg< K > &&k, V &&v)
linked_hash_map(size_t bucket_count, const allocator_type &alloc)
iterator insert_or_assign(const_iterator, const key_arg< K > &k, const V &v)
linked_hash_map(InputIt first, InputIt last, const allocator_type &alloc)
void insert(std::initializer_list< value_type > ilist)
std::pair< iterator, bool > emplace(Args &&... args)
node_type extract(const key_arg< K > &key)
linked_hash_map(const linked_hash_map &other, const allocator_type &alloc)
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())
linked_hash_map(const linked_hash_map &other)
linked_hash_map(size_t bucket_count, const hasher &hash=hasher(), const key_equal &eq=key_equal(), const allocator_type &alloc=allocator_type())
size_t capacity() const
mapped_type & operator[](key_arg< K > &&key)
typename ListType::reverse_iterator reverse_iterator
typename std::allocator_traits< allocator_type >::const_pointer const_pointer
std::pair< iterator, bool > insert(value_type &&v)
node_type extract(const_iterator position)
int64_t b
Definition table.cc:45
int64_t a
Definition table.cc:44
int64_t hash
std::function< int64_t(const Model &)> Value(IntegerVariable v)
This checks that the variable is fixed.
Definition integer.h:1975
STL namespace.