OR-Tools  9.3
id_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// A faster version of flat_hash_map for Variable and LinearConstraint keys.
15#ifndef OR_TOOLS_MATH_OPT_CPP_ID_MAP_H_
16#define OR_TOOLS_MATH_OPT_CPP_ID_MAP_H_
17
18#include <algorithm>
19#include <initializer_list>
20#include <utility>
21#include <vector>
22
23#include "absl/container/flat_hash_map.h"
24#include "absl/container/flat_hash_set.h"
25#include "absl/types/span.h"
28#include "ortools/math_opt/core/arrow_operator_proxy.h" // IWYU pragma: export
31
32namespace operations_research {
33namespace math_opt {
34
35// Similar to a absl::flat_hash_map<K, V> for K as Variable or LinearConstraint.
36//
37// Important differences:
38// * The storage is more efficient, as we store the underlying ids directly.
39// * The consequence of that is that the keys are usually returned by value in
40// situations where the flat_hash_map would return references.
41// * You cannot mix variables/constraints from multiple models in these maps.
42// Doing so results in a CHECK failure.
43//
44// Implementation notes:
45// * Emptying the map (with clear() or erase()) resets the underlying model to
46// nullptr, enabling reusing the same instance with a different model.
47// * Operator= and swap() support operating with different models by
48// respectively replacing or swapping it.
49// * For details requirements on K, see key_types.h.
50//
51// See also IdSet for the equivalent class for sets.
52template <typename K, typename V>
53class IdMap {
54 public:
55 using IdType = typename K::IdType;
56 using StorageType = absl::flat_hash_map<IdType, V>;
57 using key_type = K;
58 using mapped_type = V;
59 using value_type = std::pair<const K, V>;
60 using size_type = typename StorageType::size_type;
61 using difference_type = typename StorageType::difference_type;
62 using reference = std::pair<const K, V&>;
63 using const_reference = std::pair<const K, const V&>;
64 using pointer = void;
65 using const_pointer = void;
66
67 class iterator {
68 public:
73 using iterator_category = std::forward_iterator_tag;
74
75 iterator() = default;
76
77 inline reference operator*() const;
80 inline iterator operator++(int);
81
82 friend bool operator==(const iterator& lhs, const iterator& rhs) {
83 return lhs.storage_iterator_ == rhs.storage_iterator_;
84 }
85 friend bool operator!=(const iterator& lhs, const iterator& rhs) {
86 return lhs.storage_iterator_ != rhs.storage_iterator_;
87 }
88
89 private:
90 friend class IdMap;
91
92 inline iterator(const IdMap* map,
93 typename StorageType::iterator storage_iterator);
94
95 const IdMap* map_ = nullptr;
96 typename StorageType::iterator storage_iterator_;
97 };
98
100 public:
105 using iterator_category = std::forward_iterator_tag;
106
107 const_iterator() = default;
108 inline const_iterator(const iterator& non_const_iterator); // NOLINT
109
110 inline reference operator*() const;
114
115 friend bool operator==(const const_iterator& lhs,
116 const const_iterator& rhs) {
117 return lhs.storage_iterator_ == rhs.storage_iterator_;
118 }
119 friend bool operator!=(const const_iterator& lhs,
120 const const_iterator& rhs) {
121 return lhs.storage_iterator_ != rhs.storage_iterator_;
122 }
123
124 private:
125 friend class IdMap;
126
127 inline const_iterator(
128 const IdMap* map,
129 typename StorageType::const_iterator storage_iterator);
130
131 const IdMap* map_ = nullptr;
132 typename StorageType::const_iterator storage_iterator_;
133 };
134
135 IdMap() = default;
136 template <typename InputIt>
137 inline IdMap(InputIt first, InputIt last);
138 inline IdMap(std::initializer_list<value_type> ilist);
139
140 // Typically for internal use only.
141 inline IdMap(const ModelStorage* storage, StorageType values);
142
143 inline const_iterator cbegin() const;
144 inline const_iterator begin() const;
145 inline iterator begin();
146
147 inline const_iterator cend() const;
148 inline const_iterator end() const;
149 inline iterator end();
150
151 bool empty() const { return map_.empty(); }
152 size_type size() const { return map_.size(); }
153 inline void clear();
154 void reserve(size_type count) { map_.reserve(count); }
155
156 inline std::pair<iterator, bool> insert(std::pair<K, V> k_v);
157 template <typename InputIt>
158 inline void insert(InputIt first, InputIt last);
159 inline void insert(std::initializer_list<value_type> ilist);
160
161 inline std::pair<iterator, bool> emplace(const K& k, V v);
162 template <typename... Args>
163 inline std::pair<iterator, bool> try_emplace(const K& k, Args&&... args);
164
165 // Returns the number of elements erased (zero or one).
166 inline size_type erase(const K& k);
167 // In STL erase(const_iterator) and erase(iterator) both return an
168 // iterator. But flat_hash_map instead has void return types. So here we also
169 // use void.
170 //
171 // In flat_hash_map, both erase(const_iterator) and erase(iterator) are
172 // defined since there is also the erase<K>(const K&) that exists and that
173 // would be used. Since we don't have this overload, we can rely on the
174 // automatic cast of the iterator in const_iterator.
175 inline void erase(const_iterator pos);
176 inline iterator erase(const_iterator first, const_iterator last);
177
178 inline void swap(IdMap& other);
179
180 inline const V& at(const K& k) const;
181 inline V& at(const K& k);
182 inline V& operator[](const K& k);
183 inline size_type count(const K& k) const;
184 inline bool contains(const K& k) const;
185 inline iterator find(const K& k);
186 inline const_iterator find(const K& k) const;
187 inline std::pair<iterator, iterator> equal_range(const K& k);
188 inline std::pair<const_iterator, const_iterator> equal_range(
189 const K& k) const;
190
191 // Updates the values in this map by adding the value of the corresponding
192 // keys in the other map. For keys only in the other map, insert their value.
193 //
194 // This function is only available when type V supports operator+=.
195 //
196 // This is equivalent to (but is more efficient than):
197 // for (const auto pair : other) {
198 // (*this)[pair.first] += pair.second;
199 // }
200 //
201 // This function CHECK that all the keys in the two maps have the same model.
202 inline void Add(const IdMap& other);
203
204 // Updates the values in this map by subtracting the value of the
205 // corresponding keys in the other map. For keys only in the other map, insert
206 // the opposite of their value.
207 //
208 // This function is only available when type V supports operator-=.
209 //
210 // This is equivalent to (but is more efficient than):
211 // for (const auto pair : other) {
212 // (*this)[pair.first] -= pair.second;
213 // }
214 //
215 // This function CHECK that all the keys in the two maps have the same model.
216 inline void Subtract(const IdMap& other);
217
218 inline std::vector<V> Values(absl::Span<const K> keys) const;
219 inline absl::flat_hash_map<K, V> Values(
220 const absl::flat_hash_set<K>& keys) const;
221
222 inline std::vector<K> SortedKeys() const;
223
224 // Returns the values in sorted KEY order.
225 inline std::vector<V> SortedValues() const;
226
227 const StorageType& raw_map() const { return map_; }
228 const ModelStorage* storage() const { return storage_; }
229
230 friend bool operator==(const IdMap& lhs, const IdMap& rhs) {
231 return lhs.storage_ == rhs.storage_ && lhs.map_ == rhs.map_;
232 }
233 friend bool operator!=(const IdMap& lhs, const IdMap& rhs) {
234 return !(lhs == rhs);
235 }
236
237 private:
238 inline std::vector<IdType> SortedIds() const;
239 // CHECKs that storage_ and k.storage() matches when this map is not empty
240 // (i.e. its storage_ is not null). When it is empty, simply check that
241 // k.storage() is not null.
242 inline void CheckModel(const K& k) const;
243 // Sets storage_ to k.storage() if this map is empty (i.e. its storage_ is
244 // null). Else CHECK that it has the same model. It also CHECK that
245 // k.storage() is not null.
246 inline void CheckOrSetModel(const K& k);
247 // Sets storage_ to other.storage_ if this map is empty (i.e. its storage_ is
248 // null). Else if the other map is not empty, CHECK that it has the same
249 // model.
250 inline void CheckOrSetModel(const IdMap& other);
251
252 // Invariant: storage == nullptr if and only if map_.empty().
253 const ModelStorage* storage_ = nullptr;
254 StorageType map_;
255};
256
257// Calls a.swap(b).
258//
259// This function is used for making MapId "swappable".
260// Ref: https://en.cppreference.com/w/cpp/named_req/Swappable.
261template <typename K, typename V>
263 a.swap(b);
264}
265
267// Inline implementations
269
271// IdMap::iterator
273
274template <typename K, typename V>
276 return reference(K(map_->storage_, storage_iterator_->first),
277 storage_iterator_->second);
278}
279
280template <typename K, typename V>
284}
285
286template <typename K, typename V>
288 ++storage_iterator_;
289 return *this;
290}
291
292template <typename K, typename V>
294 iterator ret = *this;
295 ++(*this);
296 return ret;
297}
298
299template <typename K, typename V>
301 typename StorageType::iterator storage_iterator)
302 : map_(map), storage_iterator_(std::move(storage_iterator)) {}
303
305// IdMap::const_iterator
307
308template <typename K, typename V>
310 : map_(non_const_iterator.map_),
311 storage_iterator_(non_const_iterator.storage_iterator_) {}
312
313template <typename K, typename V>
316 return reference(K(map_->storage_, storage_iterator_->first),
317 storage_iterator_->second);
318}
319
320template <typename K, typename V>
324}
325
326template <typename K, typename V>
329 ++storage_iterator_;
330 return *this;
331}
332
333template <typename K, typename V>
335 int) {
336 const_iterator ret = *this;
337 ++(*this);
338 return ret;
339}
340
341template <typename K, typename V>
343 const IdMap* map, typename StorageType::const_iterator storage_iterator)
344 : map_(map), storage_iterator_(std::move(storage_iterator)) {}
345
347// IdMap
349
350template <typename K, typename V>
352 : storage_(storage), map_(std::move(values)) {
353 if (!map_.empty()) {
354 CHECK(storage_ != nullptr);
355 }
356}
357
358template <typename K, typename V>
359template <typename InputIt>
360IdMap<K, V>::IdMap(InputIt first, InputIt last) {
361 insert(first, last);
362}
363
364template <typename K, typename V>
365IdMap<K, V>::IdMap(std::initializer_list<value_type> ilist) {
366 insert(ilist);
367}
368
369template <typename K, typename V>
371 return const_iterator(this, map_.cbegin());
372}
373
374template <typename K, typename V>
376 return cbegin();
377}
378
379template <typename K, typename V>
381 return iterator(this, map_.begin());
382}
383
384template <typename K, typename V>
386 return const_iterator(this, map_.cend());
387}
388
389template <typename K, typename V>
391 return cend();
392}
393
394template <typename K, typename V>
396 return iterator(this, map_.end());
397}
398
399template <typename K, typename V>
401 storage_ = nullptr;
402 map_.clear();
403}
404
405template <typename K, typename V>
406std::pair<typename IdMap<K, V>::iterator, bool> IdMap<K, V>::insert(
407 std::pair<K, V> k_v) {
408 return emplace(k_v.first, std::move(k_v.second));
409}
410
411template <typename K, typename V>
412template <typename InputIt>
413void IdMap<K, V>::insert(const InputIt first, const InputIt last) {
414 for (InputIt it = first; it != last; ++it) {
415 insert(*it);
416 }
417}
418
419template <typename K, typename V>
420void IdMap<K, V>::insert(std::initializer_list<value_type> ilist) {
421 insert(ilist.begin(), ilist.end());
422}
423
424template <typename K, typename V>
425std::pair<typename IdMap<K, V>::iterator, bool> IdMap<K, V>::emplace(const K& k,
426 V v) {
427 CheckOrSetModel(k);
428 auto initial_ret = map_.emplace(k.typed_id(), std::move(v));
429 return std::make_pair(iterator(this, std::move(initial_ret.first)),
430 initial_ret.second);
431}
432
433template <typename K, typename V>
434template <typename... Args>
435std::pair<typename IdMap<K, V>::iterator, bool> IdMap<K, V>::try_emplace(
436 const K& k, Args&&... args) {
437 CheckOrSetModel(k);
438 auto initial_ret =
439 map_.try_emplace(k.typed_id(), std::forward<Args>(args)...);
440 return std::make_pair(iterator(this, std::move(initial_ret.first)),
441 initial_ret.second);
442}
443
444template <typename K, typename V>
446 CheckModel(k);
447 const size_type ret = map_.erase(k.typed_id());
448 if (map_.empty()) {
449 storage_ = nullptr;
450 }
451 return ret;
452}
453
454template <typename K, typename V>
456 map_.erase(pos.storage_iterator_);
457 if (map_.empty()) {
458 storage_ = nullptr;
459 }
460}
461
462template <typename K, typename V>
464 const const_iterator last) {
465 auto ret = map_.erase(first.storage_iterator_, last.storage_iterator_);
466 if (map_.empty()) {
467 storage_ = nullptr;
468 }
469 return iterator(this, std::move(ret));
470}
471
472template <typename K, typename V>
474 using std::swap;
475 swap(storage_, other.storage_);
476 swap(map_, other.map_);
477}
478
479template <typename K, typename V>
480const V& IdMap<K, V>::at(const K& k) const {
481 CheckModel(k);
482 return map_.at(k.typed_id());
483}
484
485template <typename K, typename V>
486V& IdMap<K, V>::at(const K& k) {
487 CheckModel(k);
488 return map_.at(k.typed_id());
489}
490
491template <typename K, typename V>
493 CheckOrSetModel(k);
494 return map_[k.typed_id()];
495}
496
497template <typename K, typename V>
498typename IdMap<K, V>::size_type IdMap<K, V>::count(const K& k) const {
499 CheckModel(k);
500 return map_.count(k.typed_id());
501}
502
503template <typename K, typename V>
504bool IdMap<K, V>::contains(const K& k) const {
505 CheckModel(k);
506 return map_.contains(k.typed_id());
507}
508
509template <typename K, typename V>
511 CheckModel(k);
512 return iterator(this, map_.find(k.typed_id()));
513}
514
515template <typename K, typename V>
517 CheckModel(k);
518 return const_iterator(this, map_.find(k.typed_id()));
519}
520
521template <typename K, typename V>
522std::pair<typename IdMap<K, V>::iterator, typename IdMap<K, V>::iterator>
524 const auto it = find(k);
525 if (it == end()) {
526 return {it, it};
527 }
528 return {it, std::next(it)};
529}
530
531template <typename K, typename V>
532std::pair<typename IdMap<K, V>::const_iterator,
534IdMap<K, V>::equal_range(const K& k) const {
535 const auto it = find(k);
536 if (it == end()) {
537 return {it, it};
538 }
539 return {it, std::next(it)};
540}
541
542template <typename K, typename V>
543void IdMap<K, V>::Add(const IdMap& other) {
544 CheckOrSetModel(other);
545 for (const auto& pair : other.map_) {
546 map_[pair.first] += pair.second;
547 }
548}
549
550template <typename K, typename V>
551void IdMap<K, V>::Subtract(const IdMap& other) {
552 CheckOrSetModel(other);
553 for (const auto& pair : other.map_) {
554 map_[pair.first] -= pair.second;
555 }
556}
557
558template <typename K, typename V>
559std::vector<V> IdMap<K, V>::Values(const absl::Span<const K> keys) const {
560 std::vector<V> result;
561 result.reserve(keys.size());
562 for (const K key : keys) {
563 result.push_back(at(key));
564 }
565 return result;
566}
567
568template <typename K, typename V>
569absl::flat_hash_map<K, V> IdMap<K, V>::Values(
570 const absl::flat_hash_set<K>& keys) const {
571 absl::flat_hash_map<K, V> result;
572 for (const K key : keys) {
573 result[key] = at(key);
574 }
575 return result;
576}
577
578template <typename K, typename V>
579std::vector<K> IdMap<K, V>::SortedKeys() const {
580 std::vector<K> result;
581 result.reserve(map_.size());
582 for (const IdType id : SortedIds()) {
583 result.push_back(K(storage_, id));
584 }
585 return result;
586}
587
588template <typename K, typename V>
589std::vector<V> IdMap<K, V>::SortedValues() const {
590 std::vector<V> result;
591 result.reserve(map_.size());
592 for (const IdType id : SortedIds()) {
593 result.push_back(map_.at(id));
594 }
595 return result;
596}
597
598template <typename K, typename V>
599std::vector<typename K::IdType> IdMap<K, V>::SortedIds() const {
600 std::vector<IdType> result;
601 result.reserve(map_.size());
602 for (const auto& [id, _] : map_) {
603 result.push_back(id);
604 }
605 std::sort(result.begin(), result.end());
606 return result;
607}
608
609template <typename K, typename V>
610void IdMap<K, V>::CheckModel(const K& k) const {
611 CHECK(k.storage() != nullptr) << internal::kKeyHasNullModelStorage;
612 CHECK(storage_ == nullptr || storage_ == k.storage())
614}
615
616template <typename K, typename V>
617void IdMap<K, V>::CheckOrSetModel(const K& k) {
618 CHECK(k.storage() != nullptr) << internal::kKeyHasNullModelStorage;
619 if (storage_ == nullptr) {
620 storage_ = k.storage();
621 } else {
622 CHECK_EQ(storage_, k.storage()) << internal::kObjectsFromOtherModelStorage;
623 }
624}
625
626template <typename K, typename V>
627void IdMap<K, V>::CheckOrSetModel(const IdMap& other) {
628 if (storage_ == nullptr) {
629 storage_ = other.storage_;
630 } else if (other.storage_ != nullptr) {
631 CHECK_EQ(storage_, other.storage_)
633 } else {
634 // By construction when other is not empty, it has a non null `storage_`.
635 DCHECK(other.empty());
636 }
637}
638
639} // namespace math_opt
640} // namespace operations_research
641
642#endif // OR_TOOLS_MATH_OPT_CPP_ID_MAP_H_
#define CHECK(condition)
Definition: base/logging.h:495
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:703
#define DCHECK(condition)
Definition: base/logging.h:890
friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs)
Definition: id_map.h:119
internal::ArrowOperatorProxy< reference > operator->() const
Definition: id_map.h:322
friend bool operator==(const const_iterator &lhs, const const_iterator &rhs)
Definition: id_map.h:115
friend bool operator==(const iterator &lhs, const iterator &rhs)
Definition: id_map.h:82
IdMap::difference_type difference_type
Definition: id_map.h:72
std::forward_iterator_tag iterator_category
Definition: id_map.h:73
friend bool operator!=(const iterator &lhs, const iterator &rhs)
Definition: id_map.h:85
internal::ArrowOperatorProxy< reference > operator->() const
Definition: id_map.h:282
void Subtract(const IdMap &other)
Definition: id_map.h:551
std::pair< iterator, bool > try_emplace(const K &k, Args &&... args)
IdMap(InputIt first, InputIt last)
Definition: id_map.h:360
void reserve(size_type count)
Definition: id_map.h:154
const_iterator begin() const
Definition: id_map.h:375
std::pair< const K, V > value_type
Definition: id_map.h:59
IdMap(const ModelStorage *storage, StorageType values)
Definition: id_map.h:351
size_type erase(const K &k)
Definition: id_map.h:445
void insert(InputIt first, InputIt last)
Definition: id_map.h:413
std::vector< K > SortedKeys() const
Definition: id_map.h:579
std::vector< V > SortedValues() const
Definition: id_map.h:589
absl::flat_hash_map< IdType, V > StorageType
Definition: id_map.h:56
std::pair< iterator, bool > emplace(const K &k, V v)
Definition: id_map.h:425
std::pair< const K, const V & > const_reference
Definition: id_map.h:63
std::vector< V > Values(absl::Span< const K > keys) const
Definition: id_map.h:559
friend bool operator==(const IdMap &lhs, const IdMap &rhs)
Definition: id_map.h:230
bool contains(const K &k) const
Definition: id_map.h:504
iterator erase(const_iterator first, const_iterator last)
Definition: id_map.h:463
typename StorageType::size_type size_type
Definition: id_map.h:60
const_iterator end() const
Definition: id_map.h:390
std::pair< iterator, bool > insert(std::pair< K, V > k_v)
Definition: id_map.h:406
IdMap(std::initializer_list< value_type > ilist)
Definition: id_map.h:365
std::pair< const_iterator, const_iterator > equal_range(const K &k) const
Definition: id_map.h:534
typename K::IdType IdType
Definition: id_map.h:55
const StorageType & raw_map() const
Definition: id_map.h:227
absl::flat_hash_map< K, V > Values(const absl::flat_hash_set< K > &keys) const
Definition: id_map.h:569
const_iterator cend() const
Definition: id_map.h:385
size_type count(const K &k) const
Definition: id_map.h:498
const V & at(const K &k) const
Definition: id_map.h:480
const_iterator cbegin() const
Definition: id_map.h:370
friend bool operator!=(const IdMap &lhs, const IdMap &rhs)
Definition: id_map.h:233
void insert(std::initializer_list< value_type > ilist)
Definition: id_map.h:420
const_iterator find(const K &k) const
Definition: id_map.h:516
typename StorageType::difference_type difference_type
Definition: id_map.h:61
void erase(const_iterator pos)
Definition: id_map.h:455
std::pair< iterator, iterator > equal_range(const K &k)
Definition: id_map.h:523
void Add(const IdMap &other)
Definition: id_map.h:543
iterator find(const K &k)
Definition: id_map.h:510
const ModelStorage * storage() const
Definition: id_map.h:228
std::pair< const K, V & > reference
Definition: id_map.h:62
int64_t b
int64_t a
Block * next
constexpr absl::string_view kKeyHasNullModelStorage
Definition: key_types.h:51
constexpr absl::string_view kObjectsFromOtherModelStorage
Definition: key_types.h:56
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:262
Collection of objects used to extend the Constraint Solver library.
STL namespace.
std::optional< int64_t > end