OR-Tools  9.0
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"
37 #include "ortools/base/logging.h"
38 
39 namespace 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.
47 template <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;
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:
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)
164  : linked_hash_map(bucket_count, hash, key_equal(), alloc) {}
165 
167  : linked_hash_map(bucket_count, hasher(), key_equal(), alloc) {}
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 
223  linked_hash_map(const linked_hash_map& other, const allocator_type& alloc)
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 
332  iterator erase(iterator position) {
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:498
#define LOG(severity)
Definition: base/logging.h:423
#define DCHECK(condition)
Definition: base/logging.h:892
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:893
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
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, V &&v)
key_equal key_eq() const
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
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, V &&v)
std::pair< iterator, bool > emplace(Args &&... args)
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
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
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)
std::pair< iterator, bool > try_emplace(const key_arg< K > &key, Args &&... args)
std::pair< iterator, bool > insert_or_assign(key_arg< K > &&k, const V &v)
node_type extract(const_iterator position)
std::pair< iterator, bool > try_emplace(key_arg< K > &&key, Args &&... args)
size_type size() const
const_reference back() const
float load_factor() const
reverse_iterator rend()
linked_hash_map & operator=(std::initializer_list< value_type > values)
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
size_t capacity() const
hasher hash_function() const
std::pair< const_iterator, const_iterator > equal_range(const key_arg< K > &key) const
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
std::pair< iterator, bool > insert_or_assign(const key_arg< K > &k, const V &v)
linked_hash_map & operator=(linked_hash_map &&other) noexcept
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
ABSL_ATTRIBUTE_REINITIALIZES void clear()
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
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)
linked_hash_map & operator=(const linked_hash_map &other)
const_reverse_iterator crend() const
void rehash(size_t n)
std::pair< iterator, bool > insert(value_type &&v)
size_type max_size() const noexcept
std::pair< iterator, bool > insert(const value_type &v)
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, iterator > equal_range(const key_arg< K > &key)
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())
const mapped_type & at(const key_arg< K > &key) const
linked_hash_map(InputIt first, InputIt last, const allocator_type &alloc)
void swap(linked_hash_map &other)
mapped_type & operator[](const key_arg< K > &key)
mapped_type & at(const key_arg< K > &key)
iterator try_emplace(const_iterator, key_arg< K > &&k, Args &&... args)
const_reverse_iterator rbegin() const
iterator insert_or_assign(const_iterator, key_arg< K > &&k, V &&v)
void reserve(size_t n)
size_type count(const key_arg< K > &key) const
iterator erase(iterator first, iterator last)
mapped_type & operator[](key_arg< K > &&key)
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:263
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Definition: integer.h:1492