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