mirror of
https://github.com/Kitware/CMake.git
synced 2025-05-09 06:42:18 +08:00

``` git grep -lz 'Copyright.txt or https://cmake.org/licensing ' | while IFS= read -r -d $'\0' f ; do sed -i '/Copyright.txt or https:\/\/cmake.org\/licensing / { s/Copyright.txt/LICENSE.rst/ }' "$f" ; done ```
640 lines
18 KiB
C++
640 lines
18 KiB
C++
// -*-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 = default;
|
|
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_set
|
|
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 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 syntax
|
|
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 };
|
|
}
|
|
#endif
|