11#ifndef O2_FRAMEWORK_FLAGS_H_
12#define O2_FRAMEWORK_FLAGS_H_
19#include <source_location>
28#include <initializer_list>
42namespace details::enum_flags
48 requires std::is_enum_v<E>;
49 requires std::is_unsigned_v<std::underlying_type_t<E>>;
50 requires std::same_as<E, std::decay_t<E>>;
57template <EnumFlagHelper E>
59 using U = std::underlying_type_t<E>;
64 return std::is_enum_v<E> && !std::is_convertible_v<E, std::underlying_type_t<E>>;
69 static consteval const char*
tpeek() noexcept
71 return std::source_location::current().function_name();
75 static constexpr std::string_view
tpeek_v{tpeek<e>()};
79 std::tuple<std::string_view, char, std::string_view, char>>({
81 {
"e = ",
']',
"(anonymous namespace)",
'('},
82 {
"T = ",
']',
"(anonymous namespace)",
'('},
84 {
"e = ",
';',
"<unnamed>",
'<'},
85 {
"T = ",
']',
"{anonymous}",
'{'},
99 template <SVal v, SType t>
102 return std::get<static_cast<size_t>(
v)>(
CSpecifics[
static_cast<size_t>(t)]);
115 constexpr auto tp{tpeek_v<e>.rfind(getSpec<SVal::Start, SType::Enum_t>())};
116 if constexpr (tp == std::string_view::npos) {
120 else if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] ==
'(') {
121 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size() + 1] ==
'(') {
124 if constexpr (tpeek_v<e>.find(getSpec<SVal::AnonStr, SType::Enum_t>(), tp + getSpec<SVal::Start, SType::Enum_t>().size()) != std::string_view::npos) {
127 }
else if constexpr (tpeek_v<e>.find_first_of(getSpec<SVal::End, SType::Enum_t>(), tp + getSpec<SVal::Start, SType::Enum_t>().size()) != std::string_view::npos) {
133 else if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] !=
'(' && tpeek_v<e>.find_first_of(getSpec<SVal::End, SType::Enum_t>(), tp + getSpec<SVal::Start, SType::Enum_t>().
size()) != std::string_view::npos) {
143 template <
size_t... I>
144 static constexpr auto getValues(std::index_sequence<I...> )
noexcept
146 constexpr std::array<bool,
sizeof...(I)> valid{isValid<static_cast<E>(
MinScan + I)>()...};
147 constexpr auto count{std::count_if(valid.cbegin(), valid.cend(), [](
bool v)
noexcept { return v; })};
148 static_assert(
count > 0,
"EnumFlag requires at least one enum value. Check that your enum has consecutive values starting from 0.");
149 static_assert(
count <=
MaxUnderScan,
"Too many enum values for underlying type. Consider using a larger underlying type or fewer enum values.");
150 std::array<E, count>
values{};
151 for (
size_t idx{},
n{};
n <
count; ++idx) {
158 static constexpr auto Values{
getValues(std::make_index_sequence<MaxScan - MinScan - MarginScan>())};
164 static_assert(Max_u_v < std::numeric_limits<U>::digits,
"Max Bit is beyond allow range defered from underlying type");
169 if (
width >= std::numeric_limits<UMax>::digits) {
170 return std::numeric_limits<UMax>::max();
179 constexpr auto tp{tpeek_v<e>.rfind(getSpec<SVal::Start, SType::Enum_t>())};
180 if constexpr (tp == std::string_view::npos) {
183 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
185 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size() + 1] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
189 if (
constexpr auto lstr{tpeek_v<e>.substr(tp + getSpec<SVal::Start, SType::Enum_t>().
size())}; lstr.find(getSpec<SVal::AnonStr, SType::Enum_t>()) != std::string_view::npos) {
190 if constexpr (
constexpr auto lc{lstr.find_first_of(getSpec<SVal::End, SType::Enum_t>())}; lc != std::string_view::npos) {
191 return lstr.substr(getSpec<SVal::AnonStr, SType::Enum_t>().size() + 2, lc - (getSpec<SVal::AnonStr, SType::Enum_t>().size() + 2));
195 constexpr std::string_view
result{tpeek_v<e>.substr(tp + getSpec<SVal::Start, SType::Enum_t>().size())};
196 if constexpr (
constexpr auto lc{
result.find_first_of(getSpec<SVal::End, SType::Enum_t>())}; lc != std::string_view::npos) {
197 return result.substr(0, lc);
205 if (
const auto lc{s.find_last_of(
':')}; lc != std::string_view::npos) {
206 return s.substr(lc + 1);
211 static constexpr std::string_view
findScope(std::string_view s)
213 const auto pos1 = s.rfind(
"::");
214 if (pos1 == std::string_view::npos) {
217 const auto pos2 = s.rfind(
"::", pos1 - 1);
218 if (pos2 == std::string_view::npos) {
219 return s.substr(0, pos1);
221 return s.substr(pos2 + 2, pos1 - pos2 - 2);
227 template <
bool with_scope,
size_t... I>
228 static constexpr auto getNames(std::index_sequence<I...> )
230 if constexpr (with_scope) {
231 return std::array<std::string_view,
sizeof...(I)>{getNameValue<Values[I]>...};
237 static constexpr auto Names{getNames<false>(std::make_index_sequence<
count()>())};
244 for (
size_t i{0};
i <
count(); ++
i) {
253 static constexpr std::string_view
toString() noexcept
255 return getNameValue<e>();
260 for (
size_t i{0};
i <
count(); ++
i) {
269 static constexpr unsigned char toLower(
const unsigned char c)
noexcept
271 return (
c >=
'A' &&
c <=
'Z') ? (
c -
'A' +
'a') :
c;
275 static constexpr bool isIEqual(
const unsigned char a,
const unsigned char b)
noexcept
281 static constexpr bool isIEqual(std::string_view
s1, std::string_view s2)
noexcept
283 if (
s1.size() != s2.size()) {
286 for (
size_t i{0};
i <
s1.size(); ++
i) {
294 static constexpr std::string_view
None{
"none"};
298 for (
size_t i{0};
i <
count(); ++
i) {
306 static constexpr std::string_view
All{
"all"};
310 for (
size_t i{0};
i <
count(); ++
i) {
359 using U = std::underlying_type_t<E>;
363 constexpr auto to_underlying(E e)
const noexcept
365 return static_cast<U
>(e);
369 constexpr auto to_bit(E e)
const noexcept
371 return U(1) << to_underlying(e);
388 std::for_each(
flags.begin(),
flags.end(), [
this](
const E
f)
noexcept { mBits |= to_bit(f); });
416 void set(
const std::string& s =
"",
int base = 2)
419 const U prev = mBits;
426 }
catch (
const std::exception& e) {
432 [[nodiscard]]
constexpr auto value() const noexcept
444 template <
typename T>
445 requires std::is_same_v<T, E>
452 template <
typename T>
453 requires std::is_same_v<T, E>
454 [[nodiscard]]
constexpr bool test(T t)
const noexcept
456 return (mBits & to_bit(t)) !=
None;
460 template <
typename...
Ts>
467 template <
typename T>
468 requires std::is_same_v<T, E>
469 constexpr void set(T t)
noexcept
475 template <
typename T>
476 requires std::is_same_v<T, E>
483 [[nodiscard]]
constexpr bool any() const noexcept
485 return mBits !=
None;
489 [[nodiscard]]
constexpr bool all() const noexcept
497 std::ostringstream oss;
498 oss << std::bitset<H::count()>(mBits);
503 [[nodiscard]] std::string
pstring(
bool withNewline =
false)
const
505 std::ostringstream oss;
522 for (
size_t a{2 +
i}; --
a != 0U;) {
535 [[nodiscard]]
constexpr explicit operator bool() const noexcept
541 template <
typename T>
542 requires std::is_same_v<T, E>
543 [[nodiscard]]
constexpr bool operator[](
const T t)
const noexcept
551 return mBits == o.mBits;
557 return mBits != o.mBits;
567 template <
typename T>
568 requires std::is_same_v<T, E>
576 template <
typename T>
577 requires std::is_same_v<T, E>
585 template <
typename T>
586 requires std::is_same_v<T, E>
631 template <
typename...
Ts>
638 template <
typename...
Ts>
655 throw std::out_of_range(
"Values exceeds enum range.");
657 mBits =
static_cast<U
>(
v);
661 [[nodiscard]]
constexpr size_t count() const noexcept
663 return std::popcount(mBits);
686 void setImpl(
const std::string& s,
int base = 2)
688 if (std::all_of(s.begin(), s.end(), [](
unsigned char c) { return std::isdigit(c); })) {
690 if (!std::all_of(s.begin(), s.end(), [](
char c) { return c ==
'0' || c ==
'1'; })) {
691 throw std::invalid_argument(
"Invalid binary string.");
694 typename H::UMax v = std::stoul(s,
nullptr, base);
696 throw std::out_of_range(
"Values exceeds enum range.");
698 mBits =
static_cast<U
>(
v);
699 }
else if (std::all_of(
s.begin(),
s.end(), [](
unsigned char c) { return std::isalnum(c) != 0 || c ==
'|' || c ==
' ' || c ==
':' || c ==
',' || c ==
';'; })) {
701 std::transform(cs.begin(), cs.end(), cs.begin(), [](
unsigned char c) { return std::tolower(c); });
709 std::string::size_type
pos =
s.find_first_of(
",|;");
710 if (
pos != std::string::npos) {
713 for (
const auto& tok : Str::
tokenize(
s, token)) {
717 throw std::invalid_argument(tok +
" is not a valid enum value!");
722 throw std::invalid_argument(
"Cannot parse string!");
730 os <<
f.pstring(
true);
Classs to aggregate and manage enum-based on-off flags.
constexpr bool all_of(Ts... flags) const noexcept
constexpr EnumFlags operator|(const EnumFlags &o) const noexcept
constexpr EnumFlags & operator=(const EnumFlags &o)=default
constexpr bool operator[](const T t) const noexcept
constexpr bool operator==(const EnumFlags &o) const noexcept
constexpr void reset(T t)
std::string serialize() const
constexpr EnumFlags operator&(T t) const noexcept
constexpr size_t count() const noexcept
constexpr EnumFlags(std::initializer_list< E > flags) noexcept
constexpr bool operator!=(const EnumFlags &o) const noexcept
constexpr EnumFlags()=default
constexpr EnumFlags & operator|=(T t) noexcept
constexpr bool any() const noexcept
constexpr EnumFlags union_with(const EnumFlags &o) const noexcept
static constexpr auto getValues() noexcept
constexpr auto value() const noexcept
constexpr void reset() noexcept
constexpr EnumFlags(const EnumFlags &)=default
constexpr EnumFlags operator~() const noexcept
constexpr EnumFlags operator^(const EnumFlags &o) const noexcept
constexpr EnumFlags & operator=(EnumFlags &&o)=default
constexpr ~EnumFlags()=default
constexpr EnumFlags intersection_with(const EnumFlags &o) const noexcept
void deserialize(const std::string &data)
constexpr void toggle(T t) noexcept
constexpr bool all() const noexcept
constexpr EnumFlags(EnumFlags &&)=default
void set(const std::string &s="", int base=2)
constexpr EnumFlags & operator&=(T t) noexcept
constexpr bool none_of(Ts... flags) const noexcept
constexpr EnumFlags operator&(const EnumFlags &o) const noexcept
std::string string() const
static constexpr auto getNames() noexcept
constexpr EnumFlags & operator^=(const EnumFlags &o) noexcept
std::string pstring(bool withNewline=false) const
constexpr bool contains(const EnumFlags &other) const noexcept
constexpr bool test(Ts... flags) const noexcept
constexpr bool test(T t) const noexcept
constexpr void set(T t) noexcept
constexpr EnumFlags & operator|=(const EnumFlags &o) noexcept
EnumFlags(const std::string &str)
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLboolean GLboolean GLboolean b
GLenum GLsizei GLsizei GLint * values
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
GLboolean GLboolean GLboolean GLboolean a
const std::vector< std::string > tokenize(const std::string_view input, const std::string_view pattern)
std::ostream & operator<<(std::ostream &os, const EnumFlags< E > &f)
std::string to_string(gsl::span< T, Size > span)
FIXME: do not use data model tables.
Marks an empty item in the context.
static constexpr std::string_view findScope(std::string_view s)
static constexpr auto Min_u_v
static constexpr bool hasNone() noexcept
static constexpr std::string_view None
static constexpr UMax makeMaxRep(size_t min, size_t max)
static constexpr auto NamesScoped
static constexpr auto Max_u_v
static constexpr auto CSpecifics
static constexpr auto getLongestName() noexcept
static constexpr auto Min_v
static constexpr bool isIEqual(const unsigned char a, const unsigned char b) noexcept
static constexpr auto count() noexcept
std::underlying_type_t< E > U
static constexpr size_t MarginScan
static constexpr auto NamesLongest
static constexpr auto MaxRep
static constexpr auto Names
static constexpr std::string_view All
static constexpr bool isIEqual(std::string_view s1, std::string_view s2) noexcept
static constexpr size_t MinScan
static consteval const char * tpeek() noexcept
static constexpr auto getNames(std::index_sequence< I... >)
static constexpr std::string_view tpeek_v
static constexpr bool hasAll() noexcept
static constexpr std::string_view getName()
static constexpr bool isValid() noexcept
static constexpr size_t MaxScan
static constexpr auto Max_v
static constexpr unsigned char toLower(const unsigned char c) noexcept
static constexpr auto getValues(std::index_sequence< I... >) noexcept
static constexpr auto Values
static constexpr auto Scope
static constexpr std::string_view removeScope(std::string_view s)
static constexpr std::optional< E > fromString(std::string_view str) noexcept
static constexpr bool isScoped() noexcept
static constexpr bool isContinuous() noexcept
static constexpr size_t MaxUnderScan
static constexpr std::string_view toString() noexcept
static constexpr auto getNameValue
static constexpr auto getSpec() noexcept
VectorOfTObjectPtrs other