#pragma once #include "tl/detail/prologue.h" #include #include #include #include #include namespace tl { namespace detail { template struct enum_storage; template struct enum_storage { using type = std::underlying_type_t; }; template struct enum_storage { using type = T; }; } template class flag_set2 { public: using enum_type = enumT; using store_type = typename detail::enum_storage>::type; store_type combine() noexcept; store_type combine(enumT head) noexcept; template store_type combine(enumT head, Ts... tail) noexcept; static flag_set2 from_raw(store_type) noexcept; template flag_set2(Types... args) noexcept; template 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 bool test_all(Enum first, Enums... remaining) const noexcept; template bool test_any(Enum first, Enums... remaining) const noexcept; bool any() const noexcept; bool none() const noexcept; store_type value() const noexcept; flag_set2(const flag_set2& other) noexcept; flag_set2& operator=(const flag_set2& other) noexcept; bool operator==(const flag_set2& other) const noexcept; bool operator!=(const flag_set2& other) const noexcept; auto operator<=>(const flag_set2& other) const noexcept = default; flag_set2& operator|=(const flag_set2& other) noexcept; flag_set2& operator&=(const flag_set2& other) noexcept; flag_set2& operator^=(const flag_set2& other) noexcept; flag_set2& operator|=(const enum_type& other) noexcept; flag_set2& operator&=(const enum_type& other) noexcept; flag_set2& operator^=(const enum_type& other) noexcept; flag_set2 operator~() const noexcept; private: store_type m_flags; }; template flag_set2 operator&(const flag_set2& lhs, const flag_set2& rhs) noexcept; template flag_set2 operator|(const flag_set2& lhs, const flag_set2& rhs) noexcept; template flag_set2 operator^(const flag_set2& lhs, const flag_set2& rhs) noexcept; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// namespace tl { template flag_set2 flag_set2::from_raw(store_type raw) noexcept { flag_set2 flags; flags.m_flags = raw; return flags; } template typename flag_set2::store_type flag_set2::combine() noexcept { return flag_set2::store_type(0); } template auto flag_set2::combine(enumT head) noexcept -> store_type { return (1 << flag_set2::store_type(head)); } template template auto flag_set2::combine(enumT head, Ts... tail) noexcept -> store_type { return (1 << static_cast(head)) | combine(std::forward(tail)...); } template template flag_set2::flag_set2(Types... args) noexcept : m_flags(combine(std::forward(args)...)) { } template template String flag_set2::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 flag_set2& flag_set2::set() noexcept { m_flags = ~store_type(0); return *this; } template flag_set2& flag_set2::set(enum_type flag, bool val) noexcept { m_flags = (val ? (m_flags | (1 << static_cast(flag))) : (m_flags & ~(1 << static_cast(flag)))); return *this; } template flag_set2& flag_set2::reset() noexcept { m_flags = store_type(0); return *this; } template flag_set2& flag_set2::reset(enumT flag) noexcept { m_flags &= ~(1 << static_cast(flag)); return *this; } template flag_set2& flag_set2::flip() noexcept { m_flags = ~m_flags; return *this; } template flag_set2& flag_set2::flip(enum_type flag) noexcept { m_flags ^= (1 << static_cast(flag)); return *this; } template size_t flag_set2::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 size_t flag_set2::size_in_bits() noexcept { return sizeof(store_type) * 8; } template bool flag_set2::test(enum_type flag) const noexcept { return (m_flags & (1u << static_cast(flag))) == (1u << static_cast(flag)); } template template bool flag_set2::test_all(Enum first, Enums... remaining) const noexcept { store_type expected = flag_set2(first, remaining...).value(); return (m_flags & expected) == expected; } template template bool flag_set2::test_any(Enum first, Enums... remaining) const noexcept { return (m_flags & flag_set2(first, remaining...).value()) != 0; } template bool flag_set2::any() const noexcept { return m_flags > 0; } template bool flag_set2::none() const noexcept { return m_flags == 0; } template typename flag_set2::store_type flag_set2::value() const noexcept { return m_flags; } template flag_set2::flag_set2(const flag_set2& other) noexcept : m_flags(other.m_flags) { } template flag_set2& flag_set2::operator=(const flag_set2& other) noexcept { m_flags = other.m_flags; return *this; } template bool flag_set2::operator==(const flag_set2& other) const noexcept { return m_flags == other.m_flags; } template bool flag_set2::operator!=(const flag_set2& other) const noexcept { return !operator==(other); } template flag_set2& flag_set2::operator|=(const flag_set2& other) noexcept { m_flags |= other.m_flags; return *this; } template flag_set2& flag_set2::operator&=(const flag_set2& other) noexcept { m_flags &= other.m_flags; return *this; } template flag_set2& flag_set2::operator^=(const flag_set2& other) noexcept { m_flags ^= other.m_flags; return *this; } template flag_set2& flag_set2::operator|=(const enumT& other) noexcept { m_flags |= (1 << static_cast(other)); return *this; } template flag_set2& flag_set2::operator&=(const enumT& other) noexcept { m_flags &= (1 << static_cast(other)); return *this; } template flag_set2& flag_set2::operator^=(const enumT& other) noexcept { m_flags ^= (1 << static_cast(other)); return *this; } template flag_set2 flag_set2::operator~() const noexcept { flag_set2 ret; ret.m_flags = ~m_flags; return ret; } template flag_set2 operator&(const flag_set2& lhs, const flag_set2& rhs) noexcept { return flag_set2::from_raw((typename flag_set2::store_type)(lhs.value() & rhs.value())); } template flag_set2 operator|(const flag_set2& lhs, const flag_set2& rhs) noexcept { return flag_set2::from_raw((typename flag_set2::store_type)(lhs.value() | rhs.value())); } template flag_set2 operator^(const flag_set2& lhs, const flag_set2& rhs) noexcept { return flag_set2::from_raw((typename flag_set2::store_type)(lhs.value() ^ rhs.value())); } }