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>;
63 return std::is_enum_v<E> && !std::is_convertible_v<E, std::underlying_type_t<E>>;
68 static consteval const char*
tpeek() noexcept
70 return std::source_location::current().function_name();
74 static constexpr std::string_view
tpeek_v{tpeek<e>()};
78 std::tuple<std::string_view, char, std::string_view, char>>({
80 {
"e = ",
']',
"(anonymous namespace)",
'('},
81 {
"T = ",
']',
"(anonymous namespace)",
'('},
83 {
"e = ",
';',
"<unnamed>",
'<'},
84 {
"T = ",
']',
"{anonymous}",
'{'},
98 template <SVal v, SType t>
101 return std::get<static_cast<size_t>(
v)>(
CSpecifics[
static_cast<size_t>(t)]);
114 constexpr auto tp{tpeek_v<e>.rfind(getSpec<SVal::Start, SType::Enum_t>())};
115 if constexpr (tp == std::string_view::npos) {
119 else if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] ==
'(') {
120 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size() + 1] ==
'(') {
123 if constexpr (tpeek_v<e>.find(getSpec<SVal::AnonStr, SType::Enum_t>(), tp + getSpec<SVal::Start, SType::Enum_t>().size()) != std::string_view::npos) {
126 }
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) {
132 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) {
142 template <
size_t... I>
143 static constexpr auto getValues(std::index_sequence<I...> )
noexcept
145 constexpr std::array<bool,
sizeof...(I)> valid{isValid<static_cast<E>(
MinScan + I)>()...};
146 constexpr auto count{std::count_if(valid.cbegin(), valid.cend(), [](
bool v)
noexcept { return v; })};
147 static_assert(
count > 0,
"Requiring non-empty enum!");
148 static_assert(
count <=
MaxUnderScan,
"Underlying type of enum has less digits than given expected!");
149 std::array<E, count>
values{};
150 for (
size_t idx{},
n{};
n <
count; ++idx) {
157 static constexpr auto Values{
getValues(std::make_index_sequence<MaxScan - MinScan - MarginScan>())};
164 static constexpr uint64_t
MaxRep{(
Max_u_v >= 64) ? std::numeric_limits<uint64_t>::max() : (1ULL <<
Max_u_v) - 1};
169 constexpr auto tp{tpeek_v<e>.rfind(getSpec<SVal::Start, SType::Enum_t>())};
170 if constexpr (tp == std::string_view::npos) {
173 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
175 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::enum_t>().size() + 1] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
179 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) {
180 if constexpr (
constexpr auto lc{lstr.find_first_of(getSpec<SVal::End, SType::Enum_t>())}; lc != std::string_view::npos) {
181 return lstr.substr(getSpec<SVal::AnonStr, SType::Enum_t>().size() + 2, lc - (getSpec<SVal::AnonStr, SType::Enum_t>().size() + 2));
185 constexpr std::string_view
result{tpeek_v<e>.substr(tp + getSpec<SVal::Start, SType::Enum_t>().size())};
186 if constexpr (
constexpr auto lc{
result.find_first_of(getSpec<SVal::End, SType::Enum_t>())}; lc != std::string_view::npos) {
187 return result.substr(0, lc);
195 if (
const auto lc{s.find_last_of(
':')}; lc != std::string_view::npos) {
196 return s.substr(lc + 1);
201 static constexpr std::string_view
findScope(std::string_view s)
203 const auto pos1 = s.rfind(
"::");
204 if (pos1 == std::string_view::npos) {
207 const auto pos2 = s.rfind(
"::", pos1 - 1);
208 if (pos2 == std::string_view::npos) {
209 return s.substr(0, pos1);
211 return s.substr(pos2 + 2, pos1 - pos2 - 2);
217 template <
bool with_scope, std::size_t... I>
218 static constexpr auto getNames(std::index_sequence<I...> )
220 if constexpr (with_scope) {
221 return std::array<std::string_view,
sizeof...(I)>{getNameValue<Values[I]>...};
227 static constexpr auto Names{getNames<false>(std::make_index_sequence<
count()>())};
234 for (
size_t i{0};
i <
count(); ++
i) {
243 static constexpr std::string_view
toString() noexcept
245 return getNameValue<e>();
250 for (std::size_t
i{0};
i <
count(); ++
i) {
259 static constexpr unsigned char toLower(
const unsigned char c)
noexcept
261 return (
c >=
'A' &&
c <=
'Z') ? (
c -
'A' +
'a') :
c;
265 static constexpr bool isIEqual(
const unsigned char a,
const unsigned char b)
noexcept
271 static constexpr bool isIEqual(std::string_view
s1, std::string_view s2)
noexcept
273 if (
s1.size() != s2.size()) {
276 for (
size_t i{0};
i <
s1.size(); ++
i) {
284 static constexpr std::string_view
None{
"none"};
288 for (
size_t i{0};
i <
count(); ++
i) {
296 static constexpr std::string_view
All{
"all"};
300 for (
size_t i{0};
i <
count(); ++
i) {
349 using U = std::underlying_type_t<E>;
353 constexpr auto to_underlying(E e)
const noexcept
355 return static_cast<U
>(e);
359 constexpr auto to_bit(E e)
const noexcept
361 return U(1) << to_underlying(e);
378 std::for_each(
flags.begin(),
flags.end(), [
this](
const E
f)
noexcept { mBits |= to_bit(f); });
401 void set(
const std::string& s,
int base = 2)
404 const U prev = mBits;
408 }
catch (
const std::exception& e) {
414 constexpr auto value() const noexcept
426 template <
typename T>
427 requires std::is_same_v<T, E>
434 template <
typename T>
435 requires std::is_same_v<T, E>
436 [[nodiscard]]
constexpr bool test(T t)
const noexcept
438 return (mBits & to_bit(t)) !=
None;
442 template <
typename T>
443 requires std::is_same_v<T, E>
444 constexpr void set(T t)
noexcept
450 template <
typename T>
451 requires std::is_same_v<T, E>
458 [[nodiscard]]
constexpr bool any() const noexcept
460 return mBits !=
None;
466 std::ostringstream oss;
467 oss << std::bitset<H::count()>(mBits);
472 [[nodiscard]] std::string
pstring(
bool withNewline =
false)
const
474 std::ostringstream oss;
491 for (
size_t a{2 +
i}; --
a != 0U;) {
504 constexpr explicit operator bool() const noexcept
510 template <
typename T>
511 requires std::is_same_v<T, E>
520 return mBits ==
o.mBits;
526 return mBits !=
o.mBits;
536 template <
typename T>
537 requires std::is_same_v<T, E>
545 template <
typename T>
546 requires std::is_same_v<T, E>
554 template <
typename T>
555 requires std::is_same_v<T, E>
583 return Flags(mBits ^
o.mBits);
594 template <
typename...
Ts>
601 template <
typename...
Ts>
616 uint64_t
v = std::stoul(
data);
618 throw std::out_of_range(
"Values exceeds enum range.");
620 mBits =
static_cast<U
>(
v);
624 [[nodiscard]]
constexpr size_t count() const noexcept
628 if ((mBits & (U(1) <<
i)) != U(0)) {
655 void setImpl(
const std::string& s,
int base = 2)
657 if (std::all_of(s.begin(), s.end(), [](
unsigned char c) { return std::isdigit(c); })) {
659 if (!std::all_of(s.begin(), s.end(), [](
char c) { return c ==
'0' || c ==
'1'; })) {
660 throw std::invalid_argument(
"Invalid binary string.");
663 uint64_t
v = std::stoul(s,
nullptr, base);
665 throw std::out_of_range(
"Values exceeds enum range.");
667 mBits =
static_cast<U
>(
v);
668 }
else if (std::all_of(
s.begin(),
s.end(), [](
unsigned char c) { return std::isalnum(c) != 0 || c ==
'|' || c ==
' ' || c ==
':'; })) {
670 std::transform(cs.begin(), cs.end(), cs.begin(), [](
unsigned char c) { return std::tolower(c); });
676 for (
const auto& tok : Str::
tokenize(
s,
'|')) {
680 throw std::invalid_argument(tok +
" is not a valid enum value!");
685 throw std::invalid_argument(
"Cannot parse string!");
693 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) 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
void set(const std::string &s, int base=2)
constexpr EnumFlags(EnumFlags &&)=default
constexpr EnumFlags & operator&=(T t) noexcept
constexpr bool none_of(Ts... flags) 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(T t) const noexcept
constexpr void set(T t) noexcept
constexpr EnumFlags & operator|=(const EnumFlags &o) noexcept
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 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 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 uint64_t MaxRep
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