#pragma once #include "tl/detail/prologue.h" #include #include #include #include namespace tl { template class flag_set { public: typedef enumT enum_type; typedef std::underlying_type_t store_type; store_type combine(); store_type combine(enumT head); template store_type combine(enumT head, Ts... tail); template 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 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 bool test_all(Enum first, Enums... remaining) const; template bool test_any(Enum first, Enums... remaining) const; bool any() const; bool none() const; store_type value() const; flag_set(const flag_set& other); flag_set& operator=(const flag_set& other); bool operator==(const flag_set& other) const; bool operator!=(const flag_set& other) const; flag_set& operator|=(const flag_set& other); flag_set& operator&=(const flag_set& other); flag_set& operator^=(const flag_set& other); flag_set& operator|=(const enum_type& other); flag_set& operator&=(const enum_type& other); flag_set& operator^=(const enum_type& other); flag_set operator~() const; private: store_type flags_; }; template flag_set operator&(const flag_set& lhs, const flag_set& rhs); template flag_set operator|(const flag_set& lhs, const flag_set& rhs); template flag_set operator^(const flag_set& lhs, const flag_set& rhs); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// namespace tl { template typename flag_set::store_type flag_set::combine() { return flag_set::store_type(0); } template auto flag_set::combine(enumT head) -> store_type { return flag_set::store_type(head); } template template auto flag_set::combine(enumT head, Ts... tail) -> store_type { return static_cast(head) | combine(std::forward(tail)...); } template template flag_set::flag_set(Types... args) : flags_(combine(std::forward(args)...)) { } template flag_set::flag_set(store_type value) : flags_(value) { } template template String flag_set::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 flag_set& flag_set::set() { flags_ = ~store_type(0); return *this; } template flag_set& flag_set::set(enum_type flag, bool val) { flags_ = (val ? (flags_ | static_cast(flag)) : (flags_ & ~static_cast(flag))); return *this; } template flag_set& flag_set::reset() { flags_ = store_type(0); return *this; } template flag_set& flag_set::reset(enumT flag) { flags_ &= ~static_cast(flag); return *this; } template flag_set& flag_set::flip() { flags_ = ~flags_; return *this; } template flag_set& flag_set::flip(enum_type flag) { flags_ ^= static_cast(flag); return *this; } template size_t flag_set::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 size_t flag_set::size_in_bits() { return sizeof(store_type) * 8; } template bool flag_set::test(enum_type flag) const { return (flags_ & static_cast(flag)) == static_cast(flag); } template template bool flag_set::test_all(Enum first, Enums... remaining) const { store_type expected = flag_set(first, remaining...).value(); return (flags_ & expected) == expected; } template template bool flag_set::test_any(Enum first, Enums... remaining) const { return (flags_ & flag_set(first, remaining...).value()) != 0; } template bool flag_set::any() const { return flags_ > 0; } template bool flag_set::none() const { return flags_ == 0; } template typename flag_set::store_type flag_set::value() const { return flags_; } template flag_set::flag_set(const flag_set& other) : flags_(other.flags_) { } template flag_set& flag_set::operator=(const flag_set& other) { flags_ = other.flags_; return *this; } template bool flag_set::operator==(const flag_set& other) const { return flags_ == other.flags_; } template bool flag_set::operator!=(const flag_set& other) const { return !operator==(other); } template flag_set& flag_set::operator|=(const flag_set& other) { flags_ |= other.flags_; return *this; } template flag_set& flag_set::operator&=(const flag_set& other) { flags_ &= other.flags_; return *this; } template flag_set& flag_set::operator^=(const flag_set& other) { flags_ ^= other.flags_; return *this; } template flag_set& flag_set::operator|=(const enumT& other) { flags_ |= other; return *this; } template flag_set& flag_set::operator&=(const enumT& other) { flags_ &= other; return *this; } template flag_set& flag_set::operator^=(const enumT& other) { flags_ ^= other; return *this; } template flag_set flag_set::operator~() const { flag_set ret; ret.flags_ = ~flags_; return ret; } template flag_set operator&(const flag_set& lhs, const flag_set& rhs) { //MBR: on VisualStudio 2015 uint8 & uint8 -> uint32, thus difering from enum store type return flag_set(static_cast::store_type>(lhs.value() & rhs.value())); } template flag_set operator|(const flag_set& lhs, const flag_set& rhs) { return flag_set(lhs.value() | rhs.value()); } template flag_set operator^(const flag_set& lhs, const flag_set& rhs) { return flag_set(lhs.value() ^ rhs.value()); } }