341 lines
7.6 KiB
C++
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());
|
|
}
|
|
|
|
}
|