27 #ifndef OR_TOOLS_BASE_LINKED_HASH_MAP_H_
28 #define OR_TOOLS_BASE_LINKED_HASH_MAP_H_
32 #include <type_traits>
35 #include "absl/container/flat_hash_set.h"
36 #include "absl/container/internal/common.h"
47 template <
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<
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(); }
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_); }
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()};
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()};
399 template <
class K = key_type>
401 return LazyEmplaceInternal(key).first->second;
404 template <
class K = key_type, K* =
nullptr>
407 return LazyEmplaceInternal(std::forward<K>(key)).first->second;
411 return InsertInternal(v);
414 return InsertInternal(std::move(v));
421 return insert(std::move(v)).first;
424 void insert(std::initializer_list<value_type> ilist) {
425 insert(ilist.begin(), ilist.end());
428 template <
class InputIt>
429 void insert(InputIt first, InputIt last) {
430 for (; first != last; ++first)
insert(*first);
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()};
443 return insert(std::move(node)).first;
456 return InsertOrAssignInternal(std::forward<K>(k), std::forward<V>(v));
459 template <
class K = key_type,
class V = mapped_type, K* =
nullptr>
461 return InsertOrAssignInternal(std::forward<K>(k), v);
464 template <
class K = key_type,
class V = mapped_type, V* =
nullptr>
466 return InsertOrAssignInternal(k, std::forward<V>(v));
469 template <
class K = key_type,
class V = mapped_type>
471 return InsertOrAssignInternal(k, v);
480 template <
class K = key_type,
class V = mapped_type, K* =
nullptr>
485 template <
class K = key_type,
class V = mapped_type, V* =
nullptr>
490 template <
class K = key_type,
class V = mapped_type>
495 template <
typename... Args>
496 std::pair<iterator, bool>
emplace(Args&&... args) {
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};
506 template <
class K =
key_type,
class... Args, K* =
nullptr>
508 return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
511 template <
typename... Args>
513 return emplace(std::forward<Args>(args)...).first;
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)...);
522 template <
typename H,
typename E>
524 auto itr = src.list_.begin();
525 while (itr != src.list_.end()) {
534 template <
typename H,
typename E>
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));
547 std::enable_if_t<!std::is_same_v<K, iterator>,
int> = 0>
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)...);
560 swap(set_, other.set_);
561 swap(list_, other.list_);
565 if (
a.size() !=
b.size())
return false;
570 auto it = inner->
find(elem.first);
571 if (it == inner->
end())
return false;
572 if (it->second != elem.second)
return false;
582 void rehash(
size_t n) { set_.rehash(n); }
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)));
590 DCHECK_EQ(set_.size(), list_.size()) <<
"Set and list are inconsistent.";
593 template <
typename U>
594 std::pair<iterator, bool> InsertInternal(U&& pair) {
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);
600 return {list_iter,
true};
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};
610 return LazyEmplaceInternal(std::forward<K>(k), std::forward<V>(v));
613 template <
typename K,
typename... Args>
614 std::pair<iterator, bool> LazyEmplaceInternal(K&& key, Args&&... args) {
615 bool constructed =
false;
617 set_.lazy_emplace(key, [
this, &constructed, &key, &args...](
auto ctor) {
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)...));
625 return {*set_iter, constructed};
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
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)
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)
const_reference back() const
float load_factor() const
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
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
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)
ptrdiff_t difference_type
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)
size_type count(const key_arg< K > &key) const
iterator erase(iterator first, iterator last)
mapped_type & operator[](key_arg< K > &&key)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
std::function< int64_t(const Model &)> Value(IntegerVariable v)