Files
TL/include/tl/flag_set2.h
jeanlemotan 8297b0b45f First
2024-07-02 18:06:33 +02:00

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()));
}
}