| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639 | // -*-c++-*-// vim: set ft=cpp:/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying   file LICENSE.rst 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 the 'enum class' type with unsigned base type is supported. Moreover,// all definitions must be specified without a value.//// The methods offered by 'enum_set' are close as possible to the 'std::set'// container as well as the methods from 'std::bitset'.//// 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 or can be set explicitly as template parameter://// enum class Example : unsigned { A, B, C, D };// using ExampleSet = enum_set<Example, 4>;//// To facilitate the usage of the enum_set, operators '+' and '|' can be used// as alternate to the 'initializer_list':////  auto set1 = Example::A | Example::B | Example::C;//  auto set2 = Example::A + Example::B;//  set2.set(Example::C | Example::D);//namespace cm {template <typename EnumSet>class enum_set_iterator{public:  enum_set_iterator() = default;  enum_set_iterator(enum_set_iterator const& 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,  std::size_t Size =    std::numeric_limits<typename std::underlying_type<Enum>::type>::digits,  typename cm::enable_if_t<    cm::is_scoped_enum<Enum>::value &&      std::is_unsigned<typename std::underlying_type<Enum>::type>::value,    int> = 0>class enum_set{public:  static constexpr std::size_t set_size = Size;  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 = Enum const*;  using const_pointer = Enum const*;  using iterator = enum_set_iterator<enum_set>;  using const_iterator = enum_set_iterator<enum_set const>;  using reverse_iterator = std::reverse_iterator<iterator>;  using const_reverse_iterator = std::reverse_iterator<const_iterator>;  constexpr enum_set() noexcept {}  enum_set(key_type e) { this->insert(e); }  enum_set(enum_set const& other) noexcept { this->insert(other); }  template <typename E,            typename cm::enable_if_t<std::is_same<Enum, E>::value, int> = 0>  enum_set(enum_set<E> const& other) noexcept  {    static_assert(Size < enum_set<E>::set_size, "Incompatible sizes");    this->insert(other.cbegin(), other.cend());  }  enum_set(std::initializer_list<value_type> list) { this->insert(list); }  enum_set& operator=(key_type e)  {    this->Set.reset();    this->insert(e);    return *this;  }  enum_set& operator=(enum_set const& 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  // set all elements  enum_set& set()  {    this->Set.set();    return *this;  }  enum_set& set(key_type e)  {    this->insert(e);    return *this;  }  enum_set& set(enum_set const& other) noexcept  {    this->insert(other);    return *this;  }  enum_set& set(std::initializer_list<value_type> list)  {    this->insert(list);    return *this;  }  // alternate syntax for bit set  enum_set& operator+=(key_type e) { return this->set(e); }  enum_set& operator+=(enum_set const& other) noexcept  {    return this->set(other);  }  enum_set& operator+=(std::initializer_list<value_type> list)  {    return this->set(list);  }  // alternate syntax for bit set  enum_set& operator|=(key_type e) { return this->set(e); }  enum_set& operator|=(enum_set const& other) noexcept  {    return this->set(other);  }  enum_set& operator|=(std::initializer_list<value_type> list)  {    return this->set(list);  }  // reset all elements  void clear() noexcept { this->Set.reset(); }  enum_set& reset()  {    this->Set.reset();    return *this;  }  enum_set& reset(key_type e)  {    this->erase(e);    return *this;  }  enum_set& reset(enum_set const& other) noexcept  {    this->erase(other);    return *this;  }  enum_set& reset(std::initializer_list<value_type> list)  {    this->erase(list);    return *this;  }  // alternate syntax for bit reset  enum_set& operator-=(key_type e) { return this->reset(e); }  enum_set& operator-=(enum_set const& other) noexcept  {    return this->reset(other);  }  enum_set& operator-=(std::initializer_list<value_type> list)  {    return this->reset(list);  }  // toggle the specified enum  enum_set& flip(key_type e)  {    this->Set.flip(static_cast<size_type>(e));    return *this;  }  // toggle all the enums stored in the other enum_set  enum_set& flip(enum_set const& other) noexcept  {    this->Set ^= other.Set;    return *this;  }  // toggle all the enums specified in the list  enum_set& flip(std::initializer_list<value_type> list)  {    for (auto e : list) {      this->Set.flip(static_cast<size_type>(e));    }    return *this;  }  // alternate syntax for bit toggle  enum_set& operator^=(key_type key) { return this->flip(key); }  // toggle all the enums stored in the other enum_set  enum_set& operator^=(enum_set const& other) noexcept  {    return this->flip(other);  }  // toggle all the enums specified in the list  enum_set& operator^=(std::initializer_list<value_type> list)  {    return this->flip(list);  }  std::pair<iterator, bool> insert(key_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(enum_set const& 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(enum_set const& 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;  }  // 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();  }  // Checks  bool contains(key_type e) const  {    return this->Set.test(static_cast<size_type>(e));  }  bool all() const { return this->Set.all(); }  bool any() const { return this->Set.any(); }  bool none() const { return this->Set.none(); }  // alternate syntax to none()  bool operator!() const { return this->Set.none(); }  bool all_of(enum_set const& set) const  {    auto result = set;    result.Set &= this->Set;    return result == set;  }  bool any_of(enum_set const& set) const  {    auto result = set;    result.Set &= this->Set;    return result.any();  }  bool none_of(enum_set const& set) const  {    auto result = set;    result.Set &= this->Set;    return result.none();  }private:  template <typename E, std::size_t S>  friend inline bool operator==(enum_set<E, S> const& lhs,                                enum_set<E, S> const& rhs) noexcept;  template <typename E, std::size_t S, typename Predicate>  friend inline void erase_if(enum_set<E, S>& set, Predicate pred);  friend class enum_set_iterator<enum_set>;  friend class enum_set_iterator<enum_set const>;  bool test(size_type pos) const { return this->Set.test(pos); }  std::bitset<Size> Set;};// non-member functions for enum_settemplate <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator+(enum_set<Enum, Size> const& lhs,                                      Enum rhs){  return enum_set<Enum, Size>{ lhs } += rhs;}template <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator+(enum_set<Enum, Size> const& lhs,                                      enum_set<Enum, Size> const& rhs) noexcept{  return enum_set<Enum, Size>{ lhs } += rhs;}template <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator+(enum_set<Enum, Size> const& lhs,                                      std::initializer_list<Enum> const rhs){  return enum_set<Enum, Size>{ lhs } += rhs;}template <typename Enum, std::size_t Size>inline cm::enum_set<Enum, Size> operator|(cm::enum_set<Enum, Size> const& lhs,                                          Enum rhs){  return enum_set<Enum, Size>{ lhs } |= rhs;}template <typename Enum, std::size_t Size>inline cm::enum_set<Enum, Size> operator|(Enum lhs,                                          cm::enum_set<Enum, Size> const& rhs){  return enum_set<Enum, Size>{ lhs } |= rhs;}template <typename Enum, std::size_t Size>inline cm::enum_set<Enum, Size> operator|(cm::enum_set<Enum, Size> const& lhs,                                          cm::enum_set<Enum, Size> const& rhs){  return enum_set<Enum, Size>{ lhs } |= rhs;}template <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator-(enum_set<Enum, Size> const& lhs,                                      Enum rhs){  return enum_set<Enum, Size>{ lhs } -= rhs;}template <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator-(enum_set<Enum, Size> const& lhs,                                      enum_set<Enum, Size> const& rhs) noexcept{  return enum_set<Enum, Size>{ lhs } -= rhs;}template <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator-(enum_set<Enum, Size> const& lhs,                                      std::initializer_list<Enum> const rhs){  return enum_set<Enum, Size>{ lhs } -= rhs;}template <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator^(enum_set<Enum, Size> const& lhs,                                      Enum rhs){  return enum_set<Enum, Size>{ lhs } ^= rhs;}template <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator^(enum_set<Enum, Size> const& lhs,                                      enum_set<Enum, Size> const& rhs) noexcept{  return enum_set<Enum, Size>{ lhs } ^= rhs;}template <typename Enum, std::size_t Size>inline enum_set<Enum, Size> operator^(enum_set<Enum, Size> const& lhs,                                      std::initializer_list<Enum> const rhs){  return enum_set<Enum, Size>{ lhs } ^= rhs;}template <typename Enum, std::size_t Size>inline bool operator==(enum_set<Enum, Size> const& lhs,                       enum_set<Enum, Size> const& rhs) noexcept{  return lhs.Set == rhs.Set;}template <typename Enum, std::size_t Size>inline bool operator!=(enum_set<Enum, Size> const& lhs,                       enum_set<Enum, Size> const& rhs) noexcept{  return !(lhs == rhs);}template <typename Enum, std::size_t Size>inline void erase(enum_set<Enum, Size>& set, Enum value){  set.erase(value);}template <typename Enum, std::size_t Size, typename Predicate>inline void erase_if(enum_set<Enum, Size>& 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//// WARNING: the following two operators rely on the enum_set_traits<Enum>// struct definition.// The macro CM_ENUM_SET_TRAITS(EnumSet) can be used to define this structure.//// Notes:// When CM_ENUM_SET_TRAITS is used, the following restrictions applies://   * Due to language constraints, the enum_set_traits specialization must//     occur outside of any namespace or function definition.//   * Only one enum_set instantiation is supported per enum class type.//template <typename Enum>struct cm_enum_set_traits{};namespace cm {template <typename Enum, typename = cm::void_t<>>struct is_enum_set : std::false_type{};template <typename Enum>struct is_enum_set<Enum, cm::void_t<typename cm_enum_set_traits<Enum>::type>>  : std::true_type{};}#if defined(__SUNPRO_CC) && defined(__sparc)// Oracle DeveloperStudio C++ compiler on Solaris/Sparc crash on the following// template declarations, so declare explicitly the operators.// Helper macro to define the enum_set_traits struct specialization.#  define CM_ENUM_SET_TRAITS(E)                                               \    template <>                                                               \    struct cm_enum_set_traits<E::value_type>                                  \    {                                                                         \      using type = E;                                                         \      using value_type = E::value_type;                                       \    };                                                                        \                                                                              \    inline E operator+(E::value_type lhs, E::value_type rhs)                  \    {                                                                         \      return { lhs, rhs };                                                    \    }                                                                         \                                                                              \    inline E operator|(E::value_type lhs, E::value_type rhs)                  \    {                                                                         \      return { lhs, rhs };                                                    \    }#else// Helper macro to define the enum_set_traits struct specialization.#  define CM_ENUM_SET_TRAITS(E)                                               \    template <>                                                               \    struct cm_enum_set_traits<E::value_type>                                  \    {                                                                         \      using type = E;                                                         \      using value_type = E::value_type;                                       \    };template <typename Enum,          typename cm::enable_if_t<cm::is_enum_set<Enum>::value, int> = 0>inline typename cm_enum_set_traits<Enum>::type operator+(Enum lhs, Enum rhs){  return { lhs, rhs };}// Alternate syntaxtemplate <typename Enum,          typename cm::enable_if_t<cm::is_enum_set<Enum>::value, int> = 0>inline typename cm_enum_set_traits<Enum>::type operator|(Enum lhs, Enum rhs){  return { lhs, rhs };}#endif
 |