4 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
5 file Copyright.txt or https://cmake.org/licensing for details. */
10 #include <initializer_list>
15 #include <cm/type_traits>
18 // Class enum_set offers the capability to manage a set of enum values
19 // Only 'enum class' with unsigned base type are supported.
21 // The methods offered by 'enum_set' are close as possible to the 'std::set'
22 // container plus some useful methods from 'std::bitset' like 'flip'.
24 // Internally, this class use 'std::bitset' container to manage the
25 // set of enum. The size of the bitset is deduced from the underlying type of
31 template <typename EnumSet>
32 class enum_set_iterator
35 enum_set_iterator() = default;
36 enum_set_iterator(const enum_set_iterator& other) = default;
38 using iterator_category = std::bidirectional_iterator_tag;
39 using value_type = typename EnumSet::value_type;
40 using difference_type = typename EnumSet::difference_type;
41 using reference = typename EnumSet::reference;
42 using pointer = typename EnumSet::pointer;
44 enum_set_iterator& operator++()
46 while (++this->Index < this->Set->max_size() &&
47 !this->Set->test(this->Index))
52 enum_set_iterator operator++(int)
59 enum_set_iterator& operator--()
61 if (this->Index == 0) {
65 while (!this->Set->test(--this->Index) && this->Index != 0)
70 enum_set_iterator operator--(int)
77 reference operator*() const { return static_cast<reference>(this->Index); }
79 bool operator==(enum_set_iterator other) const
81 return (this->Set == other.Set) && (this->Index == other.Index);
84 bool operator!=(enum_set_iterator other) const { return !(*this == other); }
89 using size_type = typename EnumSet::size_type;
91 enum_set_iterator(EnumSet* set, bool at_end = false)
94 if (at_end || this->Set->empty()) {
95 this->Index = this->Set->max_size();
97 while (!this->Set->test(this->Index) &&
98 ++this->Index < this->Set->max_size())
102 enum_set_iterator(EnumSet* set, size_type pos)
108 std::size_t Index = 0;
109 EnumSet* Set = nullptr;
114 typename cm::enable_if_t<
115 std::is_enum<Enum>::value &&
116 std::is_unsigned<typename std::underlying_type<Enum>::type>::value,
121 using key_type = Enum;
122 using value_type = Enum;
123 using size_type = typename std::underlying_type<Enum>::type;
124 using difference_type = size_type;
125 using reference = Enum;
126 using const_reference = Enum;
127 using pointer = const Enum*;
128 using const_pointer = const Enum*;
130 using iterator = enum_set_iterator<enum_set>;
131 using const_iterator = enum_set_iterator<const enum_set>;
132 using reverse_iterator = std::reverse_iterator<iterator>;
133 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
135 constexpr enum_set() noexcept = default;
136 enum_set(const enum_set& other) noexcept { this->insert(other); }
137 enum_set(std::initializer_list<value_type> list) { this->insert(list); }
139 enum_set& operator=(const enum_set& other) noexcept
142 this->Set |= other.Set;
145 enum_set& operator=(std::initializer_list<value_type> list)
152 iterator begin() noexcept { return iterator(this); }
153 const_iterator begin() const noexcept { return const_iterator(this); }
154 const_iterator cbegin() const noexcept { return const_iterator(this); }
156 iterator end() noexcept { return iterator(this, true); }
157 const_iterator end() const noexcept { return const_iterator(this, true); }
158 const_iterator cend() const noexcept { return const_iterator(this, true); }
160 reverse_iterator rbegin() noexcept { return reverse_iterator(this->end()); }
161 const_reverse_iterator rbegin() const noexcept
163 return const_reverse_iterator(this->end());
165 const_reverse_iterator crbegin() const noexcept
167 return const_reverse_iterator(this->cend());
170 reverse_iterator rend() noexcept { return reverse_iterator(this->begin()); }
171 const_reverse_iterator rend() const noexcept
173 return const_reverse_iterator(this->begin());
175 const_reverse_iterator crend() const noexcept
177 return const_reverse_iterator(this->cbegin());
181 bool empty() const noexcept { return this->Set.none(); }
183 size_type size() const noexcept { return this->Set.count(); }
185 size_type max_size() const noexcept { return this->Set.size(); }
188 void clear() noexcept { this->Set.reset(); }
190 enum_set& operator+=(key_type e)
195 enum_set& operator+=(const enum_set& other) noexcept
200 enum_set& operator+=(std::initializer_list<value_type> list)
206 enum_set& operator-=(key_type e)
211 enum_set& operator-=(const enum_set& other) noexcept
216 enum_set& operator-=(std::initializer_list<value_type> list)
222 std::pair<iterator, bool> insert(value_type value)
224 auto exist = this->contains(value);
226 this->Set.set(static_cast<size_type>(value));
229 return { iterator(this, static_cast<size_type>(value)), !exist };
231 template <typename InputIt>
232 void insert(InputIt first, InputIt last)
234 for (auto i = first; i != last; i++) {
238 void insert(const enum_set& other) noexcept { this->Set |= other.Set; }
239 void insert(std::initializer_list<value_type> list)
241 for (auto e : list) {
242 this->Set.set(static_cast<size_type>(e));
246 size_type erase(key_type key)
248 if (this->contains(key)) {
249 this->Set.reset(static_cast<size_type>(key));
255 iterator erase(iterator pos)
260 iterator erase(const_iterator pos)
264 return pos == this->cend() ? this->end()
265 : iterator(this, static_cast<size_type>(*pos));
267 void erase(const enum_set& other) noexcept { this->Set &= ~other.Set; }
268 void erase(std::initializer_list<value_type> list)
270 for (auto e : list) {
271 this->Set.reset(static_cast<size_type>(e));
275 void swap(enum_set& other) noexcept
277 auto tmp = this->Set;
278 this->Set = other.Set;
282 // toggle the specified enum
283 void flip(key_type key) { this->Set.flip(static_cast<size_type>(key)); }
284 // toggle all the enums stored in the other enum_set
285 void flip(const enum_set& other) noexcept { this->Set ^= other.Set; }
286 // toggle all the enums specified in the list
287 void flip(std::initializer_list<value_type> list)
289 for (auto e : list) {
290 this->Set.flip(static_cast<size_type>(e));
295 size_type count(key_type e) const { return this->contains(e) ? 1 : 0; }
297 iterator find(key_type e)
299 if (this->contains(e)) {
300 return iterator(this, static_cast<size_type>(e));
305 const_iterator find(key_type e) const
307 if (this->contains(e)) {
308 return const_iterator(this, static_cast<size_type>(e));
314 bool contains(key_type e) const
316 return this->Set.test(static_cast<size_type>(e));
320 template <typename E, typename Predicate>
321 friend inline void erase_if(enum_set<E>& set, Predicate pred);
323 friend class enum_set_iterator<enum_set>;
324 friend class enum_set_iterator<const enum_set>;
326 bool test(size_type pos) const { return this->Set.test(pos); }
328 std::bitset<std::numeric_limits<size_type>::digits> Set;
331 // non-member functions for enum_set
332 template <typename Enum>
333 inline enum_set<Enum> operator+(const enum_set<Enum>& lhs, Enum rhs)
335 return enum_set<Enum>(lhs) += rhs;
337 template <typename Enum>
338 inline enum_set<Enum> operator+(const enum_set<Enum>& lhs,
339 const enum_set<Enum>& rhs) noexcept
341 return enum_set<Enum>(lhs) += rhs;
343 template <typename Enum>
344 inline enum_set<Enum> operator+(const enum_set<Enum>& lhs,
345 const std::initializer_list<Enum> rhs)
347 return enum_set<Enum>(lhs) += rhs;
350 template <typename Enum>
351 inline enum_set<Enum> operator-(const enum_set<Enum>& lhs, Enum rhs)
353 return enum_set<Enum>(lhs) -= rhs;
355 template <typename Enum>
356 inline enum_set<Enum> operator-(const enum_set<Enum>& lhs,
357 const enum_set<Enum>& rhs) noexcept
359 return enum_set<Enum>(lhs) -= rhs;
361 template <typename Enum>
362 inline enum_set<Enum> operator-(const enum_set<Enum>& lhs,
363 const std::initializer_list<Enum> rhs)
365 return enum_set<Enum>(lhs) -= rhs;
368 template <typename Enum>
369 inline bool operator==(const enum_set<Enum>& lhs,
370 const enum_set<Enum>& rhs) noexcept
375 template <typename Enum>
376 inline bool operator!=(const enum_set<Enum>& lhs,
377 const enum_set<Enum>& rhs) noexcept
379 return !(lhs == rhs);
382 template <typename Enum>
383 inline void erase(enum_set<Enum>& set, Enum value)
388 template <typename Enum, typename Predicate>
389 inline void erase_if(enum_set<Enum>& set, Predicate pred)
391 for (std::size_t index = 0; index < set.Set.size(); ++index) {
392 if (set.Set.test(index) && pred(static_cast<Enum>(index))) {
393 set.Set.reset(index);