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