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>>;
58template <EnumFlagHelper E>
60 using U = std::underlying_type_t<E>;
62 static_assert(std::numeric_limits<U>::digits <= std::numeric_limits<UMax>::digits,
"Underlying type has more digits than max supported digits");
66 return std::is_enum_v<E> && !std::is_convertible_v<E, std::underlying_type_t<E>>;
71 static consteval const char*
tpeek() noexcept
73 return std::source_location::current().function_name();
77 static constexpr std::string_view
tpeek_v{tpeek<e>()};
81 std::tuple<std::string_view, char, std::string_view, char>>({
83 {
"e = ",
']',
"(anonymous namespace)",
'('},
84 {
"T = ",
']',
"(anonymous namespace)",
'('},
86 {
"e = ",
';',
"<unnamed>",
'<'},
87 {
"T = ",
']',
"{anonymous}",
'{'},
101 template <SVal v, SType t>
104 return std::get<static_cast<size_t>(
v)>(
CSpecifics[
static_cast<size_t>(t)]);
117 constexpr auto tp{tpeek_v<e>.rfind(getSpec<SVal::Start, SType::Enum_t>())};
118 if constexpr (tp == std::string_view::npos) {
122 else if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] ==
'(') {
123 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size() + 1] ==
'(') {
126 if constexpr (tpeek_v<e>.find(getSpec<SVal::AnonStr, SType::Enum_t>(), tp + getSpec<SVal::Start, SType::Enum_t>().size()) != std::string_view::npos) {
129 }
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) {
134 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) {
138#error Unsupported compiler
145 template <
size_t... I>
146 static constexpr auto getValues(std::index_sequence<I...> )
noexcept
148 constexpr std::array<bool,
sizeof...(I)> valid{isValid<static_cast<E>(
MinScan + I)>()...};
149 constexpr auto count{std::count_if(valid.cbegin(), valid.cend(), [](
bool v)
noexcept { return v; })};
150 static_assert(
count > 0,
"EnumFlag requires at least one enum value. Check that your enum has consecutive values starting from 0.");
151 static_assert(
count <=
MaxUnderScan,
"Too many enum values for underlying type. Consider using a larger underlying type or fewer enum values.");
152 std::array<E, count>
values{};
153 for (
size_t idx{},
n{};
n <
count; ++idx) {
160 static constexpr auto Values{
getValues(std::make_index_sequence<MaxScan - MinScan - MarginScan>())};
166 static_assert(Max_u_v < std::numeric_limits<U>::digits,
"Max Bit is beyond allow range deferred from underlying type");
171 if (
width >= std::numeric_limits<UMax>::digits) {
172 return std::numeric_limits<UMax>::max();
181 constexpr auto tp{tpeek_v<e>.rfind(getSpec<SVal::Start, SType::Enum_t>())};
182 if constexpr (tp == std::string_view::npos) {
185 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
187 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size() + 1] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
191 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) {
192 if constexpr (
constexpr auto lc{lstr.find_first_of(getSpec<SVal::End, SType::Enum_t>())}; lc != std::string_view::npos) {
193 return lstr.substr(getSpec<SVal::AnonStr, SType::Enum_t>().size() + 2, lc - (getSpec<SVal::AnonStr, SType::Enum_t>().size() + 2));
197 constexpr std::string_view
result{tpeek_v<e>.substr(tp + getSpec<SVal::Start, SType::Enum_t>().size())};
198 if constexpr (
constexpr auto lc{
result.find_first_of(getSpec<SVal::End, SType::Enum_t>())}; lc != std::string_view::npos) {
199 return result.substr(0, lc);
207 if (
const auto lc{s.find_last_of(
':')}; lc != std::string_view::npos) {
208 return s.substr(lc + 1);
213 static constexpr std::string_view
findScope(std::string_view s)
215 const auto pos1 = s.rfind(
"::");
216 if (pos1 == std::string_view::npos) {
219 const auto pos2 = s.rfind(
"::", pos1 - 1);
220 if (pos2 == std::string_view::npos) {
221 return s.substr(0, pos1);
223 return s.substr(pos2 + 2, pos1 - pos2 - 2);
229 template <
bool with_scope,
size_t... I>
230 static constexpr auto getNames(std::index_sequence<I...> )
232 if constexpr (with_scope) {
233 return std::array<std::string_view,
sizeof...(I)>{getNameValue<Values[I]>...};
239 static constexpr auto Names{getNames<false>(std::make_index_sequence<
count()>())};
246 for (
size_t i{0};
i <
count(); ++
i) {
255 static constexpr std::string_view
toString() noexcept
257 return getNameValue<e>();
262 for (
size_t i{0};
i <
count(); ++
i) {
271 static constexpr unsigned char toLower(
const unsigned char c)
noexcept
273 return (
c >=
'A' &&
c <=
'Z') ? (
c -
'A' +
'a') :
c;
277 static constexpr bool isIEqual(
const unsigned char a,
const unsigned char b)
noexcept
283 static constexpr bool isIEqual(std::string_view
s1, std::string_view s2)
noexcept
285 if (
s1.size() != s2.size()) {
288 for (
size_t i{0};
i <
s1.size(); ++
i) {
296 static constexpr std::string_view
None{
"none"};
300 for (
size_t i{0};
i <
count(); ++
i) {
308 static constexpr std::string_view
All{
"all"};
312 for (
size_t i{0};
i <
count(); ++
i) {
360 static constexpr int DefaultBase{2};
362 using U = std::underlying_type_t<E>;
366 constexpr auto to_underlying(E e)
const noexcept
368 return static_cast<U
>(e);
372 constexpr auto to_bit(E e)
const noexcept
374 return U(1) << to_underlying(e);
391 std::for_each(
flags.begin(),
flags.end(), [
this](
const E
f)
noexcept { mBits |= to_bit(f); });
420 void set(
const std::string& s,
int base = DefaultBase)
426 const U prev = mBits;
430 }
catch (
const std::exception& e) {
436 [[nodiscard]]
constexpr auto value() const noexcept
448 template <std::same_as<E> T>
455 template <std::same_as<E> T>
456 [[nodiscard]]
constexpr bool test(T t)
const noexcept
458 return (mBits & to_bit(t)) !=
None;
462 template <std::same_as<E>... Ts>
469 template <std::same_as<E> T>
470 constexpr void set(T t)
noexcept
476 template <std::same_as<E>... Ts>
483 template <std::same_as<E> T>
490 [[nodiscard]]
constexpr bool any() const noexcept
492 return mBits !=
None;
496 [[nodiscard]]
constexpr bool all() const noexcept
504 std::ostringstream oss;
505 oss << std::bitset<H::count()>(mBits);
510 [[nodiscard]] std::string
pstring(
bool withNewline =
false)
const
512 std::ostringstream oss;
529 for (
size_t a{2 +
i}; --
a != 0U;) {
542 [[nodiscard]]
constexpr explicit operator bool() const noexcept
548 template <std::same_as<E> T>
549 [[nodiscard]]
constexpr bool operator[](
const T t)
const noexcept
557 return mBits == o.mBits;
563 return mBits != o.mBits;
573 template <std::same_as<E> T>
581 template <std::same_as<E> T>
589 template <std::same_as<E> T>
634 template <
typename...
Ts>
641 template <
typename...
Ts>
658 throw std::out_of_range(
"Values exceeds enum range.");
660 mBits =
static_cast<U
>(
v);
664 [[nodiscard]]
constexpr size_t count() const noexcept
666 return std::popcount(mBits);
689 void setImpl(
const std::string& s,
int base = 2)
692 auto isValidForBase = [](
unsigned char c,
int base) ->
bool {
694 return c ==
'0' ||
c ==
'1';
697 return std::isdigit(
c);
700 return std::isdigit(
c) || (
c >=
'a' &&
c <=
'f') || (
c >=
'A' &&
c <=
'F');
707 std::string_view hex_str{
s};
709 if (
s.size() >= 2 &&
s[0] ==
'0' && (
s[1] ==
'x' ||
s[1] ==
'X')) {
710 hex_str.remove_prefix(2);
712 if (hex_str.empty()) {
713 throw std::invalid_argument(
"Empty hexadecimal string.");
715 if (!std::all_of(hex_str.begin(), hex_str.end(), [&](
unsigned char c) { return isValidForBase(c, 16); })) {
716 throw std::invalid_argument(
"Invalid hexadecimal string.");
718 typename H::UMax v = std::stoul(std::string(hex_str),
nullptr, 16);
720 throw std::out_of_range(
"Value exceeds enum range.");
722 mBits =
static_cast<U
>(
v);
727 if (std::all_of(
s.begin(),
s.end(), [](
unsigned char c) { return std::isdigit(c); })) {
730 if (!std::all_of(
s.begin(),
s.end(), [&](
unsigned char c) { return isValidForBase(c, 2); })) {
731 throw std::invalid_argument(
"Invalid binary string.");
734 typename H::UMax v = std::stoul(std::string(s),
nullptr, base);
736 throw std::out_of_range(
"Value exceeds enum range.");
738 mBits =
static_cast<U
>(
v);
741 else if (std::all_of(
s.begin(),
s.end(), [](
unsigned char c) { return std::isalnum(c) != 0 || c ==
'|' || c ==
' ' || c ==
':' || c ==
',' || c ==
';'; })) {
743 std::transform(cs.begin(), cs.end(), cs.begin(), [](
unsigned char c) { return std::tolower(c); });
752 size_t pipePos =
s.find(
'|');
753 size_t commaPos =
s.find(
',');
754 size_t semiPos =
s.find(
';');
757 int delimiterCount = (pipePos != std::string_view::npos ? 1 : 0) +
758 (commaPos != std::string_view::npos ? 1 : 0) +
759 (semiPos !=
std::string_view::npos ? 1 : 0);
761 if (delimiterCount > 1) {
762 throw std::invalid_argument(
"Mixed delimiters not allowed!");
765 if (pipePos != std::string_view::npos) {
767 }
else if (commaPos != std::string_view::npos) {
769 }
else if (semiPos != std::string_view::npos) {
777 throw std::invalid_argument(tok +
" is not a valid enum value!");
782 throw std::invalid_argument(
"Cannot parse string!");
790 os <<
f.pstring(
true);
Class 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 EnumFlags &o) const noexcept
std::string serialize() const
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 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
constexpr EnumFlags & operator|=(T t) noexcept
constexpr void reset(T t)
void deserialize(const std::string &data)
void set(const std::string &s, int base=DefaultBase)
constexpr bool all() const noexcept
constexpr EnumFlags(EnumFlags &&)=default
constexpr void set(Ts... flags) noexcept
constexpr bool test(T t) const noexcept
constexpr bool none_of(Ts... flags) const noexcept
constexpr EnumFlags operator&(const EnumFlags &o) const noexcept
constexpr EnumFlags operator&(T t) const noexcept
std::string string() const
static constexpr auto getNames() noexcept
constexpr EnumFlags & operator^=(const EnumFlags &o) noexcept
constexpr void set(T t) noexcept
constexpr EnumFlags & operator&=(T t) noexcept
std::string pstring(bool withNewline=false) const
constexpr bool contains(const EnumFlags &other) const noexcept
constexpr bool test(Ts... flags) const noexcept
constexpr void toggle(T t) noexcept
constexpr EnumFlags & operator|=(const EnumFlags &o) noexcept
constexpr bool operator[](const T t) const noexcept
EnumFlags(const std::string &str, int base=DefaultBase)
GLsizei const GLchar *const * string
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)
Defining DataPointCompositeObject explicitly as copiable.
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