357 lines
8.7 KiB
C++
357 lines
8.7 KiB
C++
#pragma once
|
|
|
|
#include "tl/detail/prologue.h"
|
|
#include <numeric>
|
|
#include <EASTL/string.h>
|
|
#include <cstdint>
|
|
#include <compare>
|
|
#include <type_traits>
|
|
|
|
namespace tl
|
|
{
|
|
namespace detail
|
|
{
|
|
template<typename T, bool v>
|
|
struct enum_storage;
|
|
|
|
template<typename T>
|
|
struct enum_storage<T, true>
|
|
{
|
|
using type = std::underlying_type_t<T>;
|
|
};
|
|
|
|
template<typename T>
|
|
struct enum_storage<T, false>
|
|
{
|
|
using type = T;
|
|
};
|
|
}
|
|
|
|
template <typename enumT>
|
|
class flag_set2
|
|
{
|
|
public:
|
|
using enum_type = enumT;
|
|
using store_type = typename detail::enum_storage<enumT, std::is_enum_v<enumT>>::type;
|
|
|
|
store_type combine() noexcept;
|
|
store_type combine(enumT head) noexcept;
|
|
template<typename... Ts>
|
|
store_type combine(enumT head, Ts... tail) noexcept;
|
|
|
|
static flag_set2<enumT> from_raw(store_type) noexcept;
|
|
|
|
template<typename ... Types>
|
|
flag_set2(Types... args) noexcept;
|
|
|
|
template<class String>
|
|
String get_as() const noexcept;
|
|
|
|
flag_set2& set() noexcept;
|
|
|
|
flag_set2& set(enum_type flag, bool val = true) noexcept;
|
|
|
|
flag_set2& reset() noexcept;
|
|
|
|
flag_set2& reset(enum_type flag) noexcept;
|
|
|
|
flag_set2& flip() noexcept;
|
|
|
|
flag_set2& flip(enum_type flag) noexcept;
|
|
|
|
size_t count() const noexcept;
|
|
|
|
static size_t size_in_bits() noexcept;
|
|
|
|
bool test(enum_type flag) const noexcept;
|
|
|
|
template <typename Enum, typename...Enums>
|
|
bool test_all(Enum first, Enums... remaining) const noexcept;
|
|
|
|
template <typename Enum, typename...Enums>
|
|
bool test_any(Enum first, Enums... remaining) const noexcept;
|
|
|
|
bool any() const noexcept;
|
|
|
|
bool none() const noexcept;
|
|
|
|
store_type value() const noexcept;
|
|
|
|
flag_set2<enum_type>(const flag_set2<enum_type>& other) noexcept;
|
|
flag_set2<enum_type>& operator=(const flag_set2<enum_type>& other) noexcept;
|
|
|
|
bool operator==(const flag_set2<enum_type>& other) const noexcept;
|
|
bool operator!=(const flag_set2<enum_type>& other) const noexcept;
|
|
auto operator<=>(const flag_set2<enum_type>& other) const noexcept = default;
|
|
|
|
flag_set2<enum_type>& operator|=(const flag_set2<enum_type>& other) noexcept;
|
|
flag_set2<enum_type>& operator&=(const flag_set2<enum_type>& other) noexcept;
|
|
flag_set2<enum_type>& operator^=(const flag_set2<enum_type>& other) noexcept;
|
|
flag_set2<enum_type>& operator|=(const enum_type& other) noexcept;
|
|
flag_set2<enum_type>& operator&=(const enum_type& other) noexcept;
|
|
flag_set2<enum_type>& operator^=(const enum_type& other) noexcept;
|
|
|
|
flag_set2<enum_type> operator~() const noexcept;
|
|
|
|
private:
|
|
store_type m_flags;
|
|
};
|
|
|
|
template<typename enumT>
|
|
flag_set2<enumT> operator&(const flag_set2<enumT>& lhs, const flag_set2<enumT>& rhs) noexcept;
|
|
|
|
template<typename enumT>
|
|
flag_set2<enumT> operator|(const flag_set2<enumT>& lhs, const flag_set2<enumT>& rhs) noexcept;
|
|
|
|
template<typename enumT>
|
|
flag_set2<enumT> operator^(const flag_set2<enumT>& lhs, const flag_set2<enumT>& rhs) noexcept;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace tl
|
|
{
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT> flag_set2<enumT>::from_raw(store_type raw) noexcept
|
|
{
|
|
flag_set2<enumT> flags;
|
|
flags.m_flags = raw;
|
|
return flags;
|
|
}
|
|
|
|
template <typename enumT>
|
|
typename flag_set2<enumT>::store_type flag_set2<enumT>::combine() noexcept
|
|
{
|
|
return flag_set2<enumT>::store_type(0);
|
|
}
|
|
|
|
template <typename enumT>
|
|
auto flag_set2<enumT>::combine(enumT head) noexcept -> store_type
|
|
{
|
|
return (1 << flag_set2<enumT>::store_type(head));
|
|
}
|
|
|
|
template <typename enumT>
|
|
template <typename... Ts>
|
|
auto flag_set2<enumT>::combine(enumT head, Ts... tail) noexcept -> store_type
|
|
{
|
|
return (1 << static_cast<store_type>(head)) | combine(std::forward<Ts>(tail)...);
|
|
}
|
|
|
|
template <typename enumT>
|
|
template <typename... Types>
|
|
flag_set2<enumT>::flag_set2(Types... args) noexcept
|
|
: m_flags(combine(std::forward<Types>(args)...))
|
|
{
|
|
}
|
|
|
|
template <typename enumT>
|
|
template <typename String>
|
|
String flag_set2<enumT>::get_as() const noexcept
|
|
{
|
|
eastl::string str(size_in_bits(), '0');
|
|
for (size_t x = 0; x < size_in_bits(); ++x)
|
|
str[size_in_bits() - x - 1] = (m_flags & (1 << x) ? '1' : '0');
|
|
|
|
return String(str);
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::set() noexcept
|
|
{
|
|
m_flags = ~store_type(0);
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::set(enum_type flag, bool val) noexcept
|
|
{
|
|
m_flags = (val ? (m_flags | (1 << static_cast<store_type>(flag))) : (m_flags & ~(1 << static_cast<store_type>(flag))));
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::reset() noexcept
|
|
{
|
|
m_flags = store_type(0);
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::reset(enumT flag) noexcept
|
|
{
|
|
m_flags &= ~(1 << static_cast<store_type>(flag));
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::flip() noexcept
|
|
{
|
|
m_flags = ~m_flags;
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::flip(enum_type flag) noexcept
|
|
{
|
|
m_flags ^= (1 << static_cast<store_type>(flag));
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
size_t flag_set2<enumT>::count() const noexcept
|
|
{
|
|
// http://www-graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
|
|
|
|
store_type bits = m_flags;
|
|
size_t total = 0;
|
|
for (; bits != 0; ++total)
|
|
{
|
|
bits &= bits - 1; // clear the least significant bit set
|
|
}
|
|
return total;
|
|
}
|
|
|
|
template <typename enumT>
|
|
size_t flag_set2<enumT>::size_in_bits() noexcept
|
|
{
|
|
return sizeof(store_type) * 8;
|
|
}
|
|
|
|
template <typename enumT>
|
|
bool flag_set2<enumT>::test(enum_type flag) const noexcept
|
|
{
|
|
return (m_flags & (1u << static_cast<store_type>(flag))) == (1u << static_cast<store_type>(flag));
|
|
}
|
|
|
|
template <typename enumT>
|
|
template <typename Enum, typename...Enums>
|
|
bool flag_set2<enumT>::test_all(Enum first, Enums... remaining) const noexcept
|
|
{
|
|
store_type expected = flag_set2(first, remaining...).value();
|
|
return (m_flags & expected) == expected;
|
|
}
|
|
|
|
template <typename enumT>
|
|
template <typename Enum, typename...Enums>
|
|
bool flag_set2<enumT>::test_any(Enum first, Enums... remaining) const noexcept
|
|
{
|
|
return (m_flags & flag_set2(first, remaining...).value()) != 0;
|
|
}
|
|
|
|
template <typename enumT>
|
|
bool flag_set2<enumT>::any() const noexcept
|
|
{
|
|
return m_flags > 0;
|
|
}
|
|
|
|
template <typename enumT>
|
|
bool flag_set2<enumT>::none() const noexcept
|
|
{
|
|
return m_flags == 0;
|
|
}
|
|
|
|
template <typename enumT>
|
|
typename flag_set2<enumT>::store_type flag_set2<enumT>::value() const noexcept
|
|
{
|
|
return m_flags;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>::flag_set2(const flag_set2<enumT>& other) noexcept
|
|
: m_flags(other.m_flags)
|
|
{ }
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::operator=(const flag_set2<enumT>& other) noexcept
|
|
{
|
|
m_flags = other.m_flags;
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
bool flag_set2<enumT>::operator==(const flag_set2<enumT>& other) const noexcept
|
|
{
|
|
return m_flags == other.m_flags;
|
|
}
|
|
|
|
template <typename enumT>
|
|
bool flag_set2<enumT>::operator!=(const flag_set2<enumT>& other) const noexcept
|
|
{
|
|
return !operator==(other);
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::operator|=(const flag_set2<enumT>& other) noexcept
|
|
{
|
|
m_flags |= other.m_flags;
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::operator&=(const flag_set2<enumT>& other) noexcept
|
|
{
|
|
m_flags &= other.m_flags;
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::operator^=(const flag_set2<enumT>& other) noexcept
|
|
{
|
|
m_flags ^= other.m_flags;
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::operator|=(const enumT& other) noexcept
|
|
{
|
|
m_flags |= (1 << static_cast<store_type>(other));
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::operator&=(const enumT& other) noexcept
|
|
{
|
|
m_flags &= (1 << static_cast<store_type>(other));
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT>& flag_set2<enumT>::operator^=(const enumT& other) noexcept
|
|
{
|
|
m_flags ^= (1 << static_cast<store_type>(other));
|
|
return *this;
|
|
}
|
|
|
|
template <typename enumT>
|
|
flag_set2<enumT> flag_set2<enumT>::operator~() const noexcept
|
|
{
|
|
flag_set2<enumT> ret;
|
|
ret.m_flags = ~m_flags;
|
|
return ret;
|
|
}
|
|
|
|
template<typename enumT>
|
|
flag_set2<enumT> operator&(const flag_set2<enumT>& lhs, const flag_set2<enumT>& rhs) noexcept
|
|
{
|
|
return flag_set2<enumT>::from_raw((typename flag_set2<enumT>::store_type)(lhs.value() & rhs.value()));
|
|
}
|
|
|
|
template<typename enumT>
|
|
flag_set2<enumT> operator|(const flag_set2<enumT>& lhs, const flag_set2<enumT>& rhs) noexcept
|
|
{
|
|
return flag_set2<enumT>::from_raw((typename flag_set2<enumT>::store_type)(lhs.value() | rhs.value()));
|
|
}
|
|
|
|
template<typename enumT>
|
|
flag_set2<enumT> operator^(const flag_set2<enumT>& lhs, const flag_set2<enumT>& rhs) noexcept
|
|
{
|
|
return flag_set2<enumT>::from_raw((typename flag_set2<enumT>::store_type)(lhs.value() ^ rhs.value()));
|
|
}
|
|
|
|
}
|