27#ifndef OR_TOOLS_BASE_LINKED_HASH_MAP_H_
28#define OR_TOOLS_BASE_LINKED_HASH_MAP_H_
35#include "absl/container/flat_hash_set.h"
36#include "absl/container/internal/common.h"
47template <
typename Key,
typename Value,
48 typename KeyHash =
typename absl::flat_hash_set<Key>::hasher,
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>;
61 using key_arg =
typename KeyArgImpl::template type<K, Key>;
68 using value_type = std::pair<const key_type, mapped_type>;
73 using ListType = std::list<value_type, Alloc>;
78 static const K& ToKey(
const K& k) {
81 static const key_type& ToKey(
typename ListType::const_iterator it) {
84 static const key_type& ToKey(
typename ListType::iterator it) {
93 using is_transparent = void;
96 explicit Wrapped(Fn fn) : fn_(std::move(fn)) {}
98 template <
class... Args>
99 auto operator()(Args&&... args)
const
100 ->
decltype(this->fn_(ToKey(args)...)) {
101 return fn_(ToKey(args)...);
105 absl::flat_hash_set<typename ListType::iterator, Wrapped<hasher>,
106 Wrapped<key_equal>, Alloc>;
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_); }
126 friend linked_hash_map;
128 explicit NodeHandle(ListType list) : list_(
std::move(list)) {}
132 template <
class Iterator,
class NodeType>
133 struct InsertReturnType {
147 using pointer =
typename std::allocator_traits<allocator_type>::pointer;
149 typename std::allocator_traits<allocator_type>::const_pointer;
172 template <
class InputIt>
181 template <
class InputIt>
186 template <
class InputIt>
192 template <
class InputIt>
230 : set_(std::move(other.set_)), list_(std::move(other.list_)) {
240 *this = std::move(other);
242 CopyFrom(std::move(other));
247 if (
this == &other)
return *
this;
249 set_ = SetType(other.
bucket_count(), other.set_.hash_function(),
259 set_ = std::move(other.set_);
260 list_ = std::move(other.list_);
268 insert(values.begin(), values.end());
275 bool empty()
const {
return set_.empty(); }
299 ABSL_ATTRIBUTE_REINITIALIZES
void clear() {
305 size_t capacity()
const {
return set_.capacity(); }
313 template <
class K = key_type>
315 auto found = set_.find(key);
316 if (found == set_.end())
return 0;
317 auto list_it = *found;
320 list_.erase(list_it);
325 auto found = set_.find(position);
326 CHECK(*found == position) <<
"Inconsistent iterator for set and list, "
327 "or the iterator is invalid.";
329 return list_.erase(position);
337 while (first != last) first =
erase(first);
342 while (first != last) first =
erase(first);
343 if (first ==
end())
return end();
344 return *set_.find(first);
347 template <
class K = key_type>
349 auto found = set_.find(key);
350 if (found == set_.end())
return end();
354 template <
class K = key_type>
356 auto found = set_.find(key);
357 if (found == set_.end())
return end();
361 template <
class K = key_type>
365 template <
class K = key_type>
367 return set_.contains(key);
370 template <
class K = key_type>
373 if (ABSL_PREDICT_FALSE(it ==
end())) {
374 LOG(FATAL) <<
"linked_hash_map::at failed bounds check";
379 template <
class K = key_type>
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)};
391 template <
class K = key_type>
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)};
399 template <
class K = key_type>
401 return LazyEmplaceInternal(key).first->second;
404 template <
class K = key_type, K* =
nullptr>
406 return LazyEmplaceInternal(std::forward<K>(key)).first->second;
410 return InsertInternal(v);
413 return InsertInternal(std::move(v));
420 return insert(std::move(v)).first;
423 void insert(std::initializer_list<value_type> ilist) {
424 insert(ilist.begin(), ilist.end());
427 template <
class InputIt>
428 void insert(InputIt first, InputIt last) {
429 for (; first != last; ++first)
insert(*first);
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()};
442 return insert(std::move(node)).first;
455 return InsertOrAssignInternal(std::forward<K>(k), std::forward<V>(v));
458 template <
class K = key_type,
class V = mapped_type, K* =
nullptr>
460 return InsertOrAssignInternal(std::forward<K>(k), v);
463 template <
class K = key_type,
class V = mapped_type, V* =
nullptr>
465 return InsertOrAssignInternal(k, std::forward<V>(v));
468 template <
class K = key_type,
class V = mapped_type>
470 return InsertOrAssignInternal(k, v);
479 template <
class K = key_type,
class V = mapped_type, K* =
nullptr>
484 template <
class K = key_type,
class V = mapped_type, V* =
nullptr>
489 template <
class K = key_type,
class V = mapped_type>
494 template <
typename... Args>
495 std::pair<iterator, bool>
emplace(Args&&... args) {
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};
505 template <
class K =
key_type,
class... Args, K* =
nullptr>
507 return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
510 template <
typename... Args>
512 return emplace(std::forward<Args>(args)...).first;
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)...);
521 template <
typename H,
typename E>
523 auto itr = src.list_.begin();
524 while (itr != src.list_.end()) {
533 template <
typename H,
typename E>
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));
546 std::enable_if_t<!std::is_same_v<K, iterator>,
int> = 0>
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)...);
559 swap(set_, other.set_);
560 swap(list_, other.list_);
564 if (
a.size() !=
b.size())
return false;
569 auto it = inner->
find(elem.first);
570 if (it == inner->
end())
return false;
571 if (it->second != elem.second)
return false;
581 void rehash(
size_t n) { set_.rehash(n); }
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)));
589 DCHECK_EQ(set_.size(), list_.size()) <<
"Set and list are inconsistent.";
592 template <
typename U>
593 std::pair<iterator, bool> InsertInternal(U&& pair) {
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};
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};
609 return LazyEmplaceInternal(std::forward<K>(k), std::forward<V>(v));
612 template <
typename K,
typename... Args>
613 std::pair<iterator, bool> LazyEmplaceInternal(K&& key, Args&&... args) {
614 bool constructed =
false;
616 set_.lazy_emplace(key, [
this, &constructed, &key, &args...](
auto ctor) {
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)...));
624 return {*set_iter, constructed};
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
ptrdiff_t difference_type
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
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)
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())
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)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
This checks that the variable is fixed.