OR-Tools  9.2
id_set.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 #ifndef OR_TOOLS_MATH_OPT_CPP_ID_SET_H_
15 #define OR_TOOLS_MATH_OPT_CPP_ID_SET_H_
16 
17 #include <initializer_list>
18 #include <iterator>
19 #include <utility>
20 
21 #include "ortools/base/logging.h"
22 #include "absl/container/flat_hash_set.h"
26 
27 namespace operations_research {
28 namespace math_opt {
29 
30 // Similar to a absl::flat_hash_set<K> for K as Variable or LinearConstraint.
31 //
32 // Important differences:
33 // * The storage is more efficient, as we store the underlying ids directly.
34 // * The consequence of that is that the keys are usually returned by value in
35 // situations where the flat_hash_set would return references.
36 // * You cannot mix variables/constraints from multiple models in these maps.
37 // Doing so results in a CHECK failure.
38 //
39 // Implementation notes:
40 // * Emptying the set (with clear() or erase()) resets the underlying model to
41 // nullptr, enabling reusing the same instance with a different model.
42 // * Operator= and swap() support operating with different models by
43 // respectively replacing or swapping it.
44 // * For details requirements on K, see key_types.h.
45 //
46 // See also IdMap for the equivalent class for maps.
47 template <typename K>
48 class IdSet {
49  public:
50  using IdType = typename K::IdType;
51  using StorageType = absl::flat_hash_set<IdType>;
52  using key_type = K;
54  using size_type = typename StorageType::size_type;
55  using difference_type = typename StorageType::difference_type;
56  using reference = K;
57  using const_reference = const K;
58  using pointer = void;
59  using const_pointer = void;
60 
62  public:
67  using iterator_category = std::forward_iterator_tag;
68 
69  const_iterator() = default;
70 
71  inline const_reference operator*() const;
73  inline const_iterator& operator++();
74  inline const_iterator operator++(int);
75 
76  friend bool operator==(const const_iterator& lhs,
77  const const_iterator& rhs) {
78  return lhs.storage_iterator_ == rhs.storage_iterator_;
79  }
80  friend bool operator!=(const const_iterator& lhs,
81  const const_iterator& rhs) {
82  return lhs.storage_iterator_ != rhs.storage_iterator_;
83  }
84 
85  private:
86  friend class IdSet;
87 
88  inline const_iterator(
89  const IdSet* set,
90  typename StorageType::const_iterator storage_iterator);
91 
92  const IdSet* set_ = nullptr;
93  typename StorageType::const_iterator storage_iterator_;
94  };
95 
96  // All iterators on sets are const; but STL still defines the `iterator`
97  // type. The `flat_hash_set` defines two classes the but the policy makes both
98  // constant. Here to simplify the code we use the same type.
100 
101  IdSet() = default;
102  template <typename InputIt>
103  inline IdSet(InputIt first, InputIt last);
104  inline IdSet(std::initializer_list<value_type> ilist);
105 
106  // Typically for internal use only.
107  inline IdSet(IndexedModel* model, StorageType values);
108 
109  inline const_iterator cbegin() const;
110  inline const_iterator begin() const;
111 
112  inline const_iterator cend() const;
113  inline const_iterator end() const;
114 
115  bool empty() const { return set_.empty(); }
116  size_type size() const { return set_.size(); }
117  inline void clear();
118  void reserve(size_type count) { set_.reserve(count); }
119 
120  inline std::pair<const_iterator, bool> insert(const K& k);
121  template <typename InputIt>
122  inline void insert(InputIt first, InputIt last);
123  inline void insert(std::initializer_list<value_type> ilist);
124 
125  inline std::pair<const_iterator, bool> emplace(const K& k);
126 
127  // Returns the number of elements erased (zero or one).
128  inline int erase(const K& k);
129  // In STL erase(const_iterator) returns an iterator. But flat_hash_set instead
130  // has void return types. So here we also use void.
131  inline void erase(const_iterator pos);
132  inline const_iterator erase(const_iterator first, const_iterator last);
133 
134  inline void swap(IdSet& other);
135 
136  inline size_type count(const K& k) const;
137  inline bool contains(const K& k) const;
138  inline const_iterator find(const K& k) const;
139  inline std::pair<const_iterator, const_iterator> equal_range(
140  const K& k) const;
141 
142  const StorageType& raw_set() const { return set_; }
143  IndexedModel* model() const { return model_; }
144 
145  friend bool operator==(const IdSet& lhs, const IdSet& rhs) {
146  return lhs.model_ == rhs.model_ && lhs.set_ == rhs.set_;
147  }
148  friend bool operator!=(const IdSet& lhs, const IdSet& rhs) {
149  return !(lhs == rhs);
150  }
151 
152  private:
153  // CHECKs that model_ and k.model() matches when this set is not empty
154  // (i.e. its model_ is not null). When it is empty, simply check that
155  // k.model() is not null.
156  inline void CheckModel(const K& k) const;
157  // Sets model_ to k.model() if this set is empty (i.e. its model_ is
158  // null). Else CHECK that it has the same model. It also CHECK that k.model()
159  // is not null.
160  inline void CheckOrSetModel(const K& k);
161 
162  // Invariant: model == nullptr if and only if set_.empty().
163  IndexedModel* model_ = nullptr;
164  StorageType set_;
165 };
166 
167 // Calls a.swap(b).
168 //
169 // This function is used for making IdSet "swappable".
170 // Ref: https://en.cppreference.com/w/cpp/named_req/Swappable.
171 template <typename K>
173  a.swap(b);
174 }
175 
177 // Inline implementations
179 
181 // IdSet::const_iterator
183 
184 template <typename K>
187  return K(set_->model_, *storage_iterator_);
188 }
189 
190 template <typename K>
194 }
195 
196 template <typename K>
198  ++storage_iterator_;
199  return *this;
200 }
201 
202 template <typename K>
204  const_iterator ret = *this;
205  ++(*this);
206  return ret;
207 }
208 
209 template <typename K>
211  const IdSet* set, typename StorageType::const_iterator storage_iterator)
212  : set_(set), storage_iterator_(std::move(storage_iterator)) {}
213 
215 // IdSet
217 
218 template <typename K>
220  : model_(model), set_(std::move(values)) {
221  if (!set_.empty()) {
222  CHECK(model_ != nullptr);
223  }
224 }
225 
226 template <typename K>
227 template <typename InputIt>
228 IdSet<K>::IdSet(InputIt first, InputIt last) {
229  insert(first, last);
230 }
231 
232 template <typename K>
233 IdSet<K>::IdSet(std::initializer_list<value_type> ilist) {
234  insert(ilist);
235 }
236 
237 template <typename K>
239  return const_iterator(this, set_.cbegin());
240 }
241 
242 template <typename K>
244  return cbegin();
245 }
246 
247 template <typename K>
249  return const_iterator(this, set_.cend());
250 }
251 
252 template <typename K>
254  return cend();
255 }
256 
257 template <typename K>
259  model_ = nullptr;
260  set_.clear();
261 }
262 
263 template <typename K>
264 std::pair<typename IdSet<K>::const_iterator, bool> IdSet<K>::insert(
265  const K& k) {
266  return emplace(k);
267 }
268 
269 template <typename K>
270 template <typename InputIt>
271 void IdSet<K>::insert(const InputIt first, const InputIt last) {
272  for (InputIt it = first; it != last; ++it) {
273  insert(*it);
274  }
275 }
276 
277 template <typename K>
278 void IdSet<K>::insert(std::initializer_list<value_type> ilist) {
279  insert(ilist.begin(), ilist.end());
280 }
281 
282 template <typename K>
283 std::pair<typename IdSet<K>::const_iterator, bool> IdSet<K>::emplace(
284  const K& k) {
285  CheckOrSetModel(k);
286  auto initial_ret = set_.emplace(k.typed_id());
287  return std::make_pair(const_iterator(this, std::move(initial_ret.first)),
288  initial_ret.second);
289 }
290 
291 template <typename K>
292 int IdSet<K>::erase(const K& k) {
293  CheckModel(k);
294  const int ret = set_.erase(k.typed_id());
295  if (set_.empty()) {
296  model_ = nullptr;
297  }
298  return ret;
299 }
300 
301 template <typename K>
303  set_.erase(pos.storage_iterator_);
304  if (set_.empty()) {
305  model_ = nullptr;
306  }
307 }
308 
309 template <typename K>
311  const const_iterator last) {
312  auto ret = set_.erase(first.storage_iterator_, last.storage_iterator_);
313  if (set_.empty()) {
314  model_ = nullptr;
315  }
316  return const_iterator(this, std::move(ret));
317 }
318 
319 template <typename K>
320 void IdSet<K>::swap(IdSet& other) {
321  using std::swap;
322  swap(model_, other.model_);
323  swap(set_, other.set_);
324 }
325 
326 template <typename K>
327 typename IdSet<K>::size_type IdSet<K>::count(const K& k) const {
328  CheckModel(k);
329  return set_.count(k.typed_id());
330 }
331 
332 template <typename K>
333 bool IdSet<K>::contains(const K& k) const {
334  CheckModel(k);
335  return set_.contains(k.typed_id());
336 }
337 
338 template <typename K>
339 typename IdSet<K>::const_iterator IdSet<K>::find(const K& k) const {
340  CheckModel(k);
341  return const_iterator(this, set_.find(k.typed_id()));
342 }
343 
344 template <typename K>
345 std::pair<typename IdSet<K>::const_iterator, typename IdSet<K>::const_iterator>
346 IdSet<K>::equal_range(const K& k) const {
347  const auto it = find(k);
348  if (it == end()) {
349  return {it, it};
350  }
351  return {it, std::next(it)};
352 }
353 
354 template <typename K>
355 void IdSet<K>::CheckModel(const K& k) const {
356  CHECK(k.model() != nullptr) << internal::kKeyHasNullIndexedModel;
357  CHECK(model_ == nullptr || model_ == k.model())
359 }
360 
361 template <typename K>
362 void IdSet<K>::CheckOrSetModel(const K& k) {
363  CHECK(k.model() != nullptr) << internal::kKeyHasNullIndexedModel;
364  if (model_ == nullptr) {
365  model_ = k.model();
366  } else {
368  }
369 }
370 
371 } // namespace math_opt
372 } // namespace operations_research
373 
374 #endif // OR_TOOLS_MATH_OPT_CPP_ID_SET_H_
#define CHECK(condition)
Definition: base/logging.h:495
const_iterator find(const K &k) const
Definition: id_set.h:339
constexpr absl::string_view kObjectsFromOtherIndexedModel
Definition: key_types.h:56
friend bool operator==(const const_iterator &lhs, const const_iterator &rhs)
Definition: id_set.h:76
bool contains(const K &k) const
Definition: id_set.h:333
size_type count(const K &k) const
Definition: id_set.h:327
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:263
std::pair< const_iterator, const_iterator > equal_range(const K &k) const
Definition: id_set.h:346
typename StorageType::difference_type difference_type
Definition: id_set.h:55
typename StorageType::size_type size_type
Definition: id_set.h:54
int64_t b
const_iterator cbegin() const
Definition: id_set.h:238
Block * next
const StorageType & raw_set() const
Definition: id_set.h:142
absl::flat_hash_set< IdType > StorageType
Definition: id_set.h:51
internal::ArrowOperatorProxy< reference > operator->() const
Definition: id_set.h:192
std::pair< const_iterator, bool > emplace(const K &k)
Definition: id_set.h:283
const_iterator begin() const
Definition: id_set.h:243
IndexedModel * model() const
Definition: id_set.h:143
constexpr absl::string_view kKeyHasNullIndexedModel
Definition: key_types.h:51
std::forward_iterator_tag iterator_category
Definition: id_set.h:67
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:702
std::pair< const_iterator, bool > insert(const K &k)
Definition: id_set.h:264
void reserve(size_type count)
Definition: id_set.h:118
const_iterator cend() const
Definition: id_set.h:248
const_iterator end() const
Definition: id_set.h:253
friend bool operator==(const IdSet &lhs, const IdSet &rhs)
Definition: id_set.h:145
friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs)
Definition: id_set.h:80
Collection of objects used to extend the Constraint Solver library.
typename K::IdType IdType
Definition: id_set.h:50
friend bool operator!=(const IdSet &lhs, const IdSet &rhs)
Definition: id_set.h:148
int64_t a
void swap(IdSet< K > &a, IdSet< K > &b)
Definition: id_set.h:172