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

341 lines
7.6 KiB
C++

#pragma once
#include "tl/detail/prologue.h"
#include <numeric>
#include <tl/string.h>
#include <cstdint>
#include <type_traits>
namespace tl
{
template <typename enumT>
class flag_set
{
public:
typedef enumT enum_type;
typedef std::underlying_type_t<enumT> store_type;
store_type combine();
store_type combine(enumT head);
template<typename... Ts>
store_type combine(enumT head, Ts... tail);
template<typename ... Types>
flag_set(Types... args);
// Value constructor.
//Only enabled if the storage_type and enum_type are different (i.e. one is an enum and the other is a primitive type)
explicit flag_set(store_type value);
template<class String>
String get_as() const;
flag_set& set();
flag_set& set(enum_type flag, bool val = true);
flag_set& reset();
flag_set& reset(enum_type flag);
flag_set& flip();
flag_set& flip(enum_type flag);
size_t count() const;
static size_t size_in_bits();
bool test(enum_type flag) const;
template <typename Enum, typename...Enums>
bool test_all(Enum first, Enums... remaining) const;
template <typename Enum, typename...Enums>
bool test_any(Enum first, Enums... remaining) const;
bool any() const;
bool none() const;
store_type value() const;
flag_set<enum_type>(const flag_set<enum_type>& other);
flag_set<enum_type>& operator=(const flag_set<enum_type>& other);
bool operator==(const flag_set<enum_type>& other) const;
bool operator!=(const flag_set<enum_type>& other) const;
flag_set<enum_type>& operator|=(const flag_set<enum_type>& other);
flag_set<enum_type>& operator&=(const flag_set<enum_type>& other);
flag_set<enum_type>& operator^=(const flag_set<enum_type>& other);
flag_set<enum_type>& operator|=(const enum_type& other);
flag_set<enum_type>& operator&=(const enum_type& other);
flag_set<enum_type>& operator^=(const enum_type& other);
flag_set<enum_type> operator~() const;
private:
store_type flags_;
};
template<typename enumT>
flag_set<enumT> operator&(const flag_set<enumT>& lhs, const flag_set<enumT>& rhs);
template<typename enumT>
flag_set<enumT> operator|(const flag_set<enumT>& lhs, const flag_set<enumT>& rhs);
template<typename enumT>
flag_set<enumT> operator^(const flag_set<enumT>& lhs, const flag_set<enumT>& rhs);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace tl
{
template <typename enumT>
typename flag_set<enumT>::store_type flag_set<enumT>::combine()
{
return flag_set<enumT>::store_type(0);
}
template <typename enumT>
auto flag_set<enumT>::combine(enumT head) -> store_type
{
return flag_set<enumT>::store_type(head);
}
template <typename enumT>
template <typename... Ts>
auto flag_set<enumT>::combine(enumT head, Ts... tail) -> store_type
{
return static_cast<store_type>(head) | combine(std::forward<Ts>(tail)...);
}
template <typename enumT>
template <typename... Types>
flag_set<enumT>::flag_set(Types... args)
: flags_(combine(std::forward<Types>(args)...))
{
}
template <typename enumT>
flag_set<enumT>::flag_set(store_type value)
: flags_(value)
{
}
template <typename enumT>
template <typename String>
String flag_set<enumT>::get_as() const
{
eastl::string str(size_in_bits(), '0');
for (size_t x = 0; x < size_in_bits(); ++x)
str[size_in_bits() - x - 1] = (flags_ & (1 << x) ? '1' : '0');
return String(str);
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::set()
{
flags_ = ~store_type(0);
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::set(enum_type flag, bool val)
{
flags_ = (val ? (flags_ | static_cast<store_type>(flag)) : (flags_ & ~static_cast<store_type>(flag)));
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::reset()
{
flags_ = store_type(0);
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::reset(enumT flag)
{
flags_ &= ~static_cast<store_type>(flag);
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::flip()
{
flags_ = ~flags_;
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::flip(enum_type flag)
{
flags_ ^= static_cast<store_type>(flag);
return *this;
}
template <typename enumT>
size_t flag_set<enumT>::count() const
{
// http://www-graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
store_type bits = 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_set<enumT>::size_in_bits()
{
return sizeof(store_type) * 8;
}
template <typename enumT>
bool flag_set<enumT>::test(enum_type flag) const
{
return (flags_ & static_cast<store_type>(flag)) == static_cast<store_type>(flag);
}
template <typename enumT>
template <typename Enum, typename...Enums>
bool flag_set<enumT>::test_all(Enum first, Enums... remaining) const
{
store_type expected = flag_set(first, remaining...).value();
return (flags_ & expected) == expected;
}
template <typename enumT>
template <typename Enum, typename...Enums>
bool flag_set<enumT>::test_any(Enum first, Enums... remaining) const
{
return (flags_ & flag_set(first, remaining...).value()) != 0;
}
template <typename enumT>
bool flag_set<enumT>::any() const
{
return flags_ > 0;
}
template <typename enumT>
bool flag_set<enumT>::none() const
{
return flags_ == 0;
}
template <typename enumT>
typename flag_set<enumT>::store_type flag_set<enumT>::value() const
{
return flags_;
}
template <typename enumT>
flag_set<enumT>::flag_set(const flag_set<enumT>& other)
: flags_(other.flags_)
{ }
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::operator=(const flag_set<enumT>& other)
{
flags_ = other.flags_;
return *this;
}
template <typename enumT>
bool flag_set<enumT>::operator==(const flag_set<enumT>& other) const
{
return flags_ == other.flags_;
}
template <typename enumT>
bool flag_set<enumT>::operator!=(const flag_set<enumT>& other) const
{
return !operator==(other);
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::operator|=(const flag_set<enumT>& other)
{
flags_ |= other.flags_;
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::operator&=(const flag_set<enumT>& other)
{
flags_ &= other.flags_;
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::operator^=(const flag_set<enumT>& other)
{
flags_ ^= other.flags_;
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::operator|=(const enumT& other)
{
flags_ |= other;
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::operator&=(const enumT& other)
{
flags_ &= other;
return *this;
}
template <typename enumT>
flag_set<enumT>& flag_set<enumT>::operator^=(const enumT& other)
{
flags_ ^= other;
return *this;
}
template <typename enumT>
flag_set<enumT> flag_set<enumT>::operator~() const
{
flag_set<enumT> ret;
ret.flags_ = ~flags_;
return ret;
}
template<typename enumT>
flag_set<enumT> operator&(const flag_set<enumT>& lhs, const flag_set<enumT>& rhs)
{
//MBR: on VisualStudio 2015 uint8 & uint8 -> uint32, thus difering from enum store type
return flag_set<enumT>(static_cast<typename flag_set<enumT>::store_type>(lhs.value() & rhs.value()));
}
template<typename enumT>
flag_set<enumT> operator|(const flag_set<enumT>& lhs, const flag_set<enumT>& rhs)
{
return flag_set<enumT>(lhs.value() | rhs.value());
}
template<typename enumT>
flag_set<enumT> operator^(const flag_set<enumT>& lhs, const flag_set<enumT>& rhs)
{
return flag_set<enumT>(lhs.value() ^ rhs.value());
}
}