| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- // -*-c++-*-
- // vim: set ft=cpp:
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #pragma once
- #include <bitset>
- #include <cstddef>
- #include <initializer_list>
- #include <iterator>
- #include <limits>
- #include <utility>
- #include <cm/type_traits>
- //
- // Class enum_set offers the capability to manage a set of enum values
- // Only 'enum class' with unsigned base type are supported.
- //
- // The methods offered by 'enum_set' are close as possible to the 'std::set'
- // container plus some useful methods from 'std::bitset' like 'flip'.
- //
- // Internally, this class use 'std::bitset' container to manage the
- // set of enum. The size of the bitset is deduced from the underlying type of
- // the enum.
- //
- namespace cm {
- template <typename EnumSet>
- class enum_set_iterator
- {
- public:
- enum_set_iterator() = default;
- enum_set_iterator(const enum_set_iterator& other) = default;
- using iterator_category = std::bidirectional_iterator_tag;
- using value_type = typename EnumSet::value_type;
- using difference_type = typename EnumSet::difference_type;
- using reference = typename EnumSet::reference;
- using pointer = typename EnumSet::pointer;
- enum_set_iterator& operator++()
- {
- while (++this->Index < this->Set->max_size() &&
- !this->Set->test(this->Index))
- ;
- return *this;
- }
- enum_set_iterator operator++(int)
- {
- auto retval = *this;
- ++(*this);
- return retval;
- }
- enum_set_iterator& operator--()
- {
- if (this->Index == 0) {
- return *this;
- }
- while (!this->Set->test(--this->Index) && this->Index != 0)
- ;
- return *this;
- }
- enum_set_iterator operator--(int)
- {
- auto retval = *this;
- --(*this);
- return retval;
- }
- reference operator*() const { return static_cast<reference>(this->Index); }
- bool operator==(enum_set_iterator other) const
- {
- return (this->Set == other.Set) && (this->Index == other.Index);
- }
- bool operator!=(enum_set_iterator other) const { return !(*this == other); }
- private:
- friend EnumSet;
- using size_type = typename EnumSet::size_type;
- enum_set_iterator(EnumSet* set, bool at_end = false)
- : Set(set)
- {
- if (at_end || this->Set->empty()) {
- this->Index = this->Set->max_size();
- } else {
- while (!this->Set->test(this->Index) &&
- ++this->Index < this->Set->max_size())
- ;
- }
- }
- enum_set_iterator(EnumSet* set, size_type pos)
- : Index(pos)
- , Set(set)
- {
- }
- std::size_t Index = 0;
- EnumSet* Set = nullptr;
- };
- template <
- typename Enum,
- typename cm::enable_if_t<
- std::is_enum<Enum>::value &&
- std::is_unsigned<typename std::underlying_type<Enum>::type>::value,
- int> = 0>
- class enum_set
- {
- public:
- using key_type = Enum;
- using value_type = Enum;
- using size_type = typename std::underlying_type<Enum>::type;
- using difference_type = size_type;
- using reference = Enum;
- using const_reference = Enum;
- using pointer = const Enum*;
- using const_pointer = const Enum*;
- using iterator = enum_set_iterator<enum_set>;
- using const_iterator = enum_set_iterator<const enum_set>;
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- constexpr enum_set() noexcept = default;
- enum_set(const enum_set& other) noexcept { this->insert(other); }
- enum_set(std::initializer_list<value_type> list) { this->insert(list); }
- enum_set& operator=(const enum_set& other) noexcept
- {
- this->Set.reset();
- this->Set |= other.Set;
- return *this;
- }
- enum_set& operator=(std::initializer_list<value_type> list)
- {
- this->Set.reset();
- this->insert(list);
- return *this;
- }
- // Iterators
- iterator begin() noexcept { return iterator(this); }
- const_iterator begin() const noexcept { return const_iterator(this); }
- const_iterator cbegin() const noexcept { return const_iterator(this); }
- iterator end() noexcept { return iterator(this, true); }
- const_iterator end() const noexcept { return const_iterator(this, true); }
- const_iterator cend() const noexcept { return const_iterator(this, true); }
- reverse_iterator rbegin() noexcept { return reverse_iterator(this->end()); }
- const_reverse_iterator rbegin() const noexcept
- {
- return const_reverse_iterator(this->end());
- }
- const_reverse_iterator crbegin() const noexcept
- {
- return const_reverse_iterator(this->cend());
- }
- reverse_iterator rend() noexcept { return reverse_iterator(this->begin()); }
- const_reverse_iterator rend() const noexcept
- {
- return const_reverse_iterator(this->begin());
- }
- const_reverse_iterator crend() const noexcept
- {
- return const_reverse_iterator(this->cbegin());
- }
- // Capacity
- bool empty() const noexcept { return this->Set.none(); }
- size_type size() const noexcept { return this->Set.count(); }
- size_type max_size() const noexcept { return this->Set.size(); }
- // Modifiers
- void clear() noexcept { this->Set.reset(); }
- enum_set& operator+=(key_type e)
- {
- this->insert(e);
- return *this;
- }
- enum_set& operator+=(const enum_set& other) noexcept
- {
- this->erase(other);
- return *this;
- }
- enum_set& operator+=(std::initializer_list<value_type> list)
- {
- this->insert(list);
- return *this;
- }
- enum_set& operator-=(key_type e)
- {
- this->erase(e);
- return *this;
- }
- enum_set& operator-=(const enum_set& other) noexcept
- {
- this->erase(other);
- return *this;
- }
- enum_set& operator-=(std::initializer_list<value_type> list)
- {
- this->erase(list);
- return *this;
- }
- std::pair<iterator, bool> insert(value_type value)
- {
- auto exist = this->contains(value);
- if (!exist) {
- this->Set.set(static_cast<size_type>(value));
- }
- return { iterator(this, static_cast<size_type>(value)), !exist };
- }
- template <typename InputIt>
- void insert(InputIt first, InputIt last)
- {
- for (auto i = first; i != last; i++) {
- this->insert(*i);
- }
- }
- void insert(const enum_set& other) noexcept { this->Set |= other.Set; }
- void insert(std::initializer_list<value_type> list)
- {
- for (auto e : list) {
- this->Set.set(static_cast<size_type>(e));
- }
- }
- size_type erase(key_type key)
- {
- if (this->contains(key)) {
- this->Set.reset(static_cast<size_type>(key));
- return 1;
- }
- return 0;
- }
- iterator erase(iterator pos)
- {
- this->erase(*pos++);
- return pos;
- }
- iterator erase(const_iterator pos)
- {
- this->erase(*pos++);
- return pos == this->cend() ? this->end()
- : iterator(this, static_cast<size_type>(*pos));
- }
- void erase(const enum_set& other) noexcept { this->Set &= ~other.Set; }
- void erase(std::initializer_list<value_type> list)
- {
- for (auto e : list) {
- this->Set.reset(static_cast<size_type>(e));
- }
- }
- void swap(enum_set& other) noexcept
- {
- auto tmp = this->Set;
- this->Set = other.Set;
- other.Set = tmp;
- }
- // toggle the specified enum
- void flip(key_type key) { this->Set.flip(static_cast<size_type>(key)); }
- // toggle all the enums stored in the other enum_set
- void flip(const enum_set& other) noexcept { this->Set ^= other.Set; }
- // toggle all the enums specified in the list
- void flip(std::initializer_list<value_type> list)
- {
- for (auto e : list) {
- this->Set.flip(static_cast<size_type>(e));
- }
- }
- // Lookup
- size_type count(key_type e) const { return this->contains(e) ? 1 : 0; }
- iterator find(key_type e)
- {
- if (this->contains(e)) {
- return iterator(this, static_cast<size_type>(e));
- }
- return this->end();
- }
- const_iterator find(key_type e) const
- {
- if (this->contains(e)) {
- return const_iterator(this, static_cast<size_type>(e));
- }
- return this->end();
- }
- bool contains(key_type e) const
- {
- return this->Set.test(static_cast<size_type>(e));
- }
- private:
- template <typename E>
- friend inline bool operator==(const enum_set<E>& lhs,
- const enum_set<E>& rhs) noexcept;
- template <typename E, typename Predicate>
- friend inline void erase_if(enum_set<E>& set, Predicate pred);
- friend class enum_set_iterator<enum_set>;
- friend class enum_set_iterator<const enum_set>;
- bool test(size_type pos) const { return this->Set.test(pos); }
- std::bitset<std::numeric_limits<size_type>::digits> Set;
- };
- // non-member functions for enum_set
- template <typename Enum>
- inline enum_set<Enum> operator+(const enum_set<Enum>& lhs, Enum rhs)
- {
- return enum_set<Enum>(lhs) += rhs;
- }
- template <typename Enum>
- inline enum_set<Enum> operator+(const enum_set<Enum>& lhs,
- const enum_set<Enum>& rhs) noexcept
- {
- return enum_set<Enum>(lhs) += rhs;
- }
- template <typename Enum>
- inline enum_set<Enum> operator+(const enum_set<Enum>& lhs,
- const std::initializer_list<Enum> rhs)
- {
- return enum_set<Enum>(lhs) += rhs;
- }
- template <typename Enum>
- inline enum_set<Enum> operator-(const enum_set<Enum>& lhs, Enum rhs)
- {
- return enum_set<Enum>(lhs) -= rhs;
- }
- template <typename Enum>
- inline enum_set<Enum> operator-(const enum_set<Enum>& lhs,
- const enum_set<Enum>& rhs) noexcept
- {
- return enum_set<Enum>(lhs) -= rhs;
- }
- template <typename Enum>
- inline enum_set<Enum> operator-(const enum_set<Enum>& lhs,
- const std::initializer_list<Enum> rhs)
- {
- return enum_set<Enum>(lhs) -= rhs;
- }
- template <typename Enum>
- inline bool operator==(const enum_set<Enum>& lhs,
- const enum_set<Enum>& rhs) noexcept
- {
- return lhs.Set == rhs.Set;
- }
- template <typename Enum>
- inline bool operator!=(const enum_set<Enum>& lhs,
- const enum_set<Enum>& rhs) noexcept
- {
- return !(lhs == rhs);
- }
- template <typename Enum>
- inline void erase(enum_set<Enum>& set, Enum value)
- {
- set.erase(value);
- }
- template <typename Enum, typename Predicate>
- inline void erase_if(enum_set<Enum>& set, Predicate pred)
- {
- for (std::size_t index = 0; index < set.Set.size(); ++index) {
- if (set.Set.test(index) && pred(static_cast<Enum>(index))) {
- set.Set.reset(index);
- }
- }
- }
- } // namespace cm
|