Project
Loading...
Searching...
No Matches
EnumFlags.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11#ifndef O2_FRAMEWORK_FLAGS_H_
12#define O2_FRAMEWORK_FLAGS_H_
13
14#include <algorithm>
15#include <array>
16#include <concepts>
17#include <exception>
18#include <ostream>
19#include <source_location>
20#include <stdexcept>
21#include <string_view>
22#include <tuple>
23#include <type_traits>
24#include <string>
25#include <sstream>
26#include <limits>
27#include <bit>
28#include <bitset>
29#include <initializer_list>
30#include <cstdint>
31#include <cstddef>
32#include <cctype>
33#include <utility>
34#include <optional>
35#include <iostream>
36#include <iomanip>
37
38#ifndef GPUCA_GPUCODE
40#endif
41
42namespace o2::utils
43{
44
45namespace details::enum_flags
46{
47
48// Require that an enum with an underlying unsigned type.
49template <typename E>
50concept EnumFlagHelper = requires {
51 requires std::is_enum_v<E>;
52 requires std::is_unsigned_v<std::underlying_type_t<E>>;
53 requires std::same_as<E, std::decay_t<E>>;
54};
55
56// Static constexpr only helper struct to implement modicum of enum reflection
57// functions and also check via concepts expected properties of the enum.
58// This is very much inspired by much more extensive libraries like magic_enum.
59// Inspiration by its c++20 version (https://github.com/fix8mt/conjure_enum).
60// NOTE: Cannot detect if bit values past the underlying type are defined.
61#ifndef GPUCA_GPUCODE
62template <EnumFlagHelper E>
63struct FlagsHelper final {
64 using U = std::underlying_type_t<E>;
65 using UMax = uint64_t; // max represetable type
66 static_assert(std::numeric_limits<U>::digits <= std::numeric_limits<UMax>::digits, "Underlying type has more digits than max supported digits");
67
68 static constexpr bool isScoped() noexcept
69 {
70 return std::is_enum_v<E> && !std::is_convertible_v<E, std::underlying_type_t<E>>;
71 }
72
73 // Return line at given position.
74 template <E e>
75 static consteval const char* tpeek() noexcept
76 {
77 return std::source_location::current().function_name();
78 }
79 // string_view value of function above
80 template <E e>
81 static constexpr std::string_view tpeek_v{tpeek<e>()};
82
83 // Compiler Specifics
84 static constexpr auto CSpecifics{std::to_array<
85 std::tuple<std::string_view, char, std::string_view, char>>({
86#if defined __clang__
87 {"e = ", ']', "(anonymous namespace)", '('},
88 {"T = ", ']', "(anonymous namespace)", '('},
89#else // assuming __GNUC__
90 {"e = ", ';', "<unnamed>", '<'},
91 {"T = ", ']', "{anonymous}", '{'},
92#endif
93 })};
94 enum class SVal : uint8_t { Start,
95 End,
96 AnonStr,
97 AnonStart };
98 enum class SType : uint8_t { Enum_t,
99 Type_t,
100 eT0,
101 eT1,
102 eT2,
103 eT3 };
104 // Extract a compiler specification.
105 template <SVal v, SType t>
106 static constexpr auto getSpec() noexcept
107 {
108 return std::get<static_cast<size_t>(v)>(CSpecifics[static_cast<size_t>(t)]);
109 }
110
111 // Range that is scanned by the compiler
112 static constexpr size_t MinScan{0};
113 static constexpr size_t MarginScan{1}; // Scan one past to check for overpopulation
114 static constexpr size_t MaxUnderScan{std::numeric_limits<U>::digits}; // Maximum digits the underlying type has
115 static constexpr size_t MaxScan{MaxUnderScan + MarginScan};
116
117 // Checks if a given 'location' contains an enum.
118 template <E e>
119 static constexpr bool isValid() noexcept
120 {
121 constexpr auto tp{tpeek_v<e>.rfind(getSpec<SVal::Start, SType::Enum_t>())};
122 if constexpr (tp == std::string_view::npos) {
123 return false;
124 }
125#if defined __clang__
126 else if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] == '(') {
127 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size() + 1] == '(') {
128 return false;
129 }
130 if constexpr (tpeek_v<e>.find(getSpec<SVal::AnonStr, SType::Enum_t>(), tp + getSpec<SVal::Start, SType::Enum_t>().size()) != std::string_view::npos) {
131 return true;
132 }
133 } 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 // check if this is an anonymous enum
135 return true;
136 }
137#elif __GNUC__
138 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) {
139 return true;
140 }
141#else
142#error Unsupported compiler
143#endif
144 return false;
145 }
146
147 // Extract which values are present in the enum by checking all values in
148 // the min-max-range above.
149 template <size_t... I>
150 static constexpr auto getValues(std::index_sequence<I...> /*unused*/) noexcept
151 {
152 constexpr std::array<bool, sizeof...(I)> valid{isValid<static_cast<E>(MinScan + I)>()...};
153 constexpr auto count{std::count_if(valid.cbegin(), valid.cend(), [](bool v) noexcept { return v; })};
154 static_assert(count > 0, "EnumFlag requires at least one enum value. Check that your enum has consecutive values starting from 0.");
155 static_assert(count <= MaxUnderScan, "Too many enum values for underlying type. Consider using a larger underlying type or fewer enum values.");
156 std::array<E, count> values{};
157 for (size_t idx{}, n{}; n < count; ++idx) {
158 if (valid[idx]) {
159 values[n++] = static_cast<E>(MinScan + idx);
160 }
161 }
162 return values;
163 }
164 static constexpr auto Values{getValues(std::make_index_sequence<MaxScan - MinScan - MarginScan>())}; // Enum Values
165 static constexpr auto count() noexcept { return Values.size(); } // Number of enum members
166 static constexpr auto Min_v{Values.front()}; // Enum first entry
167 static constexpr auto Max_v{Values.back()}; // Enum last entry
168 static constexpr auto Min_u_v{static_cast<size_t>(Min_v)}; // Enum first entry as size_t
169 static constexpr auto Max_u_v{static_cast<size_t>(Max_v)}; // Enum last entry as size_t
170 static_assert(Max_u_v < std::numeric_limits<U>::digits, "Max Bit is beyond allow range deferred from underlying type");
171 static constexpr bool isContinuous() noexcept { return (Max_u_v - Min_u_v + 1) == count(); } // Is the enum continuous
172 static constexpr UMax makeMaxRep(size_t min, size_t max)
173 {
174 const size_t width = max - min + 1;
175 if (width >= std::numeric_limits<UMax>::digits) {
176 return std::numeric_limits<UMax>::max();
177 }
178 return ((UMax(1) << width) - 1) << min;
179 }
180 static constexpr auto MaxRep{makeMaxRep(Min_u_v, Max_u_v)}; // largest representable value
181
182 template <E e>
183 static constexpr std::string_view getName()
184 {
185 constexpr auto tp{tpeek_v<e>.rfind(getSpec<SVal::Start, SType::Enum_t>())};
186 if constexpr (tp == std::string_view::npos) {
187 return {};
188 }
189 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size()] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
190#if defined __clang__
191 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size() + 1] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
192 return {};
193 }
194#endif
195 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) { // is anon
196 if constexpr (constexpr auto lc{lstr.find_first_of(getSpec<SVal::End, SType::Enum_t>())}; lc != std::string_view::npos) {
197 return lstr.substr(getSpec<SVal::AnonStr, SType::Enum_t>().size() + 2, lc - (getSpec<SVal::AnonStr, SType::Enum_t>().size() + 2));
198 }
199 }
200 }
201 constexpr std::string_view result{tpeek_v<e>.substr(tp + getSpec<SVal::Start, SType::Enum_t>().size())};
202 if constexpr (constexpr auto lc{result.find_first_of(getSpec<SVal::End, SType::Enum_t>())}; lc != std::string_view::npos) {
203 return result.substr(0, lc);
204 } else {
205 return {};
206 }
207 }
208
209 static constexpr std::string_view removeScope(std::string_view s)
210 {
211 if (const auto lc{s.find_last_of(':')}; lc != std::string_view::npos) {
212 return s.substr(lc + 1);
213 }
214 return s;
215 }
216
217 static constexpr std::string_view findScope(std::string_view s)
218 {
219 const auto pos1 = s.rfind("::");
220 if (pos1 == std::string_view::npos) {
221 return s;
222 }
223 const auto pos2 = s.rfind("::", pos1 - 1);
224 if (pos2 == std::string_view::npos) {
225 return s.substr(0, pos1);
226 }
227 return s.substr(pos2 + 2, pos1 - pos2 - 2);
228 }
229
230 template <E e>
231 static constexpr auto getNameValue{getName<e>()};
232
233 template <bool with_scope, size_t... I>
234 static constexpr auto getNames(std::index_sequence<I...> /*unused*/)
235 {
236 if constexpr (with_scope) {
237 return std::array<std::string_view, sizeof...(I)>{getNameValue<Values[I]>...};
238 } else {
239 return std::array<std::string_view, sizeof...(I)>{removeScope(getNameValue<Values[I]>)...};
240 }
241 }
242
243 static constexpr auto Names{getNames<false>(std::make_index_sequence<count()>())}; // Enum names without scope
244 static constexpr auto NamesScoped{getNames<true>(std::make_index_sequence<count()>())}; // Enum names with scope
245 static constexpr auto Scope{findScope(NamesScoped.front())}; // Enum scope
246
247 static constexpr auto getLongestName() noexcept
248 {
249 size_t max{0};
250 for (size_t i{0}; i < count(); ++i) {
251 max = std::max(max, Names[i].size());
252 }
253 return max;
254 }
255
256 static constexpr auto NamesLongest{getLongestName()}; // Size of longest name
257
258 template <E e>
259 static constexpr std::string_view toString() noexcept
260 {
261 return getNameValue<e>();
262 }
263
264 static constexpr std::optional<E> fromString(std::string_view str) noexcept
265 {
266 for (size_t i{0}; i < count(); ++i) {
267 if (isIEqual(Names[i], str) || isIEqual(NamesScoped[i], str)) {
268 return Values[i];
269 }
270 }
271 return std::nullopt;
272 }
273
274 // Convert char to lower.
275 static constexpr unsigned char toLower(const unsigned char c) noexcept
276 {
277 return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
278 }
279
280 // Are these chars equal (case-insensitive).
281 static constexpr bool isIEqual(const unsigned char a, const unsigned char b) noexcept
282 {
283 return toLower(a) == toLower(b);
284 }
285
286 // Case-insensitive comparison for string_view.
287 static constexpr bool isIEqual(std::string_view s1, std::string_view s2) noexcept
288 {
289 if (s1.size() != s2.size()) {
290 return false;
291 }
292 for (size_t i{0}; i < s1.size(); ++i) {
293 if (!isIEqual(s1[i], s2[i])) {
294 return false;
295 }
296 }
297 return true;
298 }
299
300 static constexpr std::string_view None{"none"};
301 static constexpr bool hasNone() noexcept
302 {
303 // check that enum does not contain member named 'none'
304 for (size_t i{0}; i < count(); ++i) {
305 if (isIEqual(Names[i], None)) {
306 return true;
307 }
308 }
309 return false;
310 }
311
312 static constexpr std::string_view All{"all"};
313 static constexpr bool hasAll() noexcept
314 {
315 // check that enum does not contain member named 'all'
316 for (size_t i{0}; i < count(); ++i) {
317 if (isIEqual(Names[i], All)) {
318 return true;
319 }
320 }
321 return false;
322 }
323};
324#endif
325
326} // namespace details::enum_flags
327
328// Require an enum to fullfil what one would except from a bitset.
329#ifndef GPUCA_GPUCODE
330template <typename E>
331concept EnumFlag = requires {
332 // range checks
333 requires details::enum_flags::FlagsHelper<E>::Min_u_v == 0; // the first bit should be at position 0
334 requires details::enum_flags::FlagsHelper<E>::Max_u_v < details::enum_flags::FlagsHelper<E>::count(); // the maximum is less than the total
335 requires details::enum_flags::FlagsHelper<E>::isContinuous(); // do not allow missing bits
336
337 // type checks
338 requires !details::enum_flags::FlagsHelper<E>::hasNone(); // added automatically
339 requires !details::enum_flags::FlagsHelper<E>::hasAll(); // added automatically
340};
341#else
342template <typename E>
344#endif
345
367template <EnumFlag E>
369{
370 static constexpr int DefaultBase{2};
371#ifndef GPUCA_GPUCODE
373#endif
374 using U = std::underlying_type_t<E>;
375 U mBits{0};
376
377 // Converts enum to its underlying type.
378 constexpr auto to_underlying(E e) const noexcept
379 {
380 return static_cast<U>(e);
381 }
382
383 // Returns the bit representation of a flag.
384 constexpr auto to_bit(E e) const noexcept
385 {
386 return U(1) << to_underlying(e);
387 }
388
389 public:
390 // Default constructor.
391 constexpr explicit EnumFlags() = default;
392 // Constructor to initialize with a single flag.
393 constexpr explicit EnumFlags(E e) : mBits(to_bit(e)) {}
394 // Copy constructor.
395 constexpr EnumFlags(const EnumFlags&) = default;
396 // Move constructor.
397 constexpr EnumFlags(EnumFlags&&) = default;
398 // Constructor to initialize with the underlying type.
399 constexpr explicit EnumFlags(U u) : mBits(u) {}
400 // Initialize with a list of flags.
401 constexpr EnumFlags(std::initializer_list<E> flags) noexcept
402 {
403 for (const E f : flags) {
404 mBits |= to_bit(f);
405 }
406 }
407#ifndef GPUCA_GPUCODE
408 // Init from a string.
409 //
410 explicit EnumFlags(const std::string& str, int base = DefaultBase)
411 {
412 set(str, base);
413 }
414#endif
415
416 static constexpr U None{0}; // Represents no flags set.
417#ifndef GPUCA_GPUCODE
418 static constexpr U All{H::MaxRep}; // Represents all flags set.
419
420 // Return list of all enum values
421 static constexpr auto getValues() noexcept
422 {
423 return H::Values;
424 }
425
426 // Return list of all enum Names
427 static constexpr auto getNames() noexcept
428 {
429 return H::Names;
430 }
431
432 // Sets flags from a string representation.
433 // This can be either from a number representation (binary or digits) or
434 // a concatenation of the enums members name e.g., 'Enum1|Enum2|...'
435 void set(const std::string& s, int base = DefaultBase)
436 {
437 if (s.empty()) { // no-op
438 return;
439 }
440 // on throw restore previous state and rethrow
441 const U prev = mBits;
442 reset();
443 try {
444 setImpl(s, base);
445 } catch (const std::exception& e) {
446 mBits = prev;
447 throw;
448 }
449 }
450#endif
451 // Returns the raw bitset value.
452 [[nodiscard]] constexpr auto value() const noexcept
453 {
454 return mBits;
455 }
456
457 // Resets all flags.
458 constexpr void reset() noexcept
459 {
460 mBits = U(0);
461 }
462
463 // Resets a specific flag.
464 template <std::same_as<E> T>
465 constexpr void reset(T t)
466 {
467 mBits &= ~to_bit(t);
468 }
469
470 // Tests if a specific flag is set.
471 template <std::same_as<E> T>
472 [[nodiscard]] constexpr bool test(T t) const noexcept
473 {
474 return (mBits & to_bit(t)) != None;
475 }
476
477 // Tests if all specified flags are set.
478 template <std::same_as<E>... Ts>
479 [[nodiscard]] constexpr bool test(Ts... flags) const noexcept
480 {
481 return ((test(flags) && ...));
482 }
483
484 // Sets a specific flag.
485 template <std::same_as<E> T>
486 constexpr void set(T t) noexcept
487 {
488 mBits |= to_bit(t);
489 }
490
491 // Sets multiple specific flags.
492 template <std::same_as<E>... Ts>
493 constexpr void set(Ts... flags) noexcept
494 {
495 (set(flags), ...);
496 }
497
498 // Toggles a specific flag.
499 template <std::same_as<E> T>
500 constexpr void toggle(T t) noexcept
501 {
502 mBits ^= to_bit(t);
503 }
504
505 // Checks if any flag is set.
506 [[nodiscard]] constexpr bool any() const noexcept
507 {
508 return mBits != None;
509 }
510
511 // Checks if all flags are set.
512#ifndef GPUCA_GPUCODE
513 [[nodiscard]] constexpr bool all() const noexcept
514 {
515 return mBits == All;
516 }
517
518 // Returns the bitset as a binary string.
519 [[nodiscard]] std::string string() const
520 {
521 std::ostringstream oss;
522 oss << std::bitset<H::count()>(mBits);
523 return oss.str();
524 }
525
526 // Returns the bitset as a pretty multiline binary string.
527 [[nodiscard]] std::string pstring(bool withNewline = false) const
528 {
529 std::ostringstream oss;
530 if (withNewline) {
531 oss << '\n';
532 }
533 oss << "0b";
534 const std::bitset<H::count()> bits(mBits);
535 oss << bits;
536 if constexpr (H::isScoped()) {
537 oss << " " << H::Scope;
538 }
539 oss << '\n';
540 for (size_t i = 0; i < H::count(); ++i) {
541 oss << " ";
542 for (size_t j = 0; j < H::count() - i - 1; ++j) {
543 oss << "┃";
544 }
545 oss << "┗";
546 for (size_t a{2 + i}; --a != 0U;) {
547 oss << "━";
548 }
549 oss << " " << std::setw(H::NamesLongest) << std::left
550 << H::Names[i] << " " << (bits[i] ? "[Active]" : "[Inactive]");
551 if (i != H::count() - 1) {
552 oss << "\n";
553 }
554 }
555 return oss.str();
556 }
557#endif
558
559 // Checks if any flag is set (Boolean context).
560 [[nodiscard]] constexpr explicit operator bool() const noexcept
561 {
562 return any();
563 }
564
565 // Check if given flag is set.
566 template <std::same_as<E> T>
567 [[nodiscard]] constexpr bool operator[](const T t) const noexcept
568 {
569 return test(t);
570 }
571
572 // Checks if two flag sets are equal.
573 [[nodiscard]] constexpr bool operator==(const EnumFlags& o) const noexcept
574 {
575 return mBits == o.mBits;
576 }
577
578 // Checks if two flag sets are not equal.
579 [[nodiscard]] constexpr bool operator!=(const EnumFlags& o) const noexcept
580 {
581 return mBits != o.mBits;
582 }
583
584 // Copy assignment operator
585 constexpr EnumFlags& operator=(const EnumFlags& o) = default;
586
587 // Move assignment operator
588 constexpr EnumFlags& operator=(EnumFlags&& o) = default;
589
590 // Performs a bitwise OR with a flag.
591 template <std::same_as<E> T>
592 constexpr EnumFlags& operator|=(T t) noexcept
593 {
594 mBits |= to_bit(t);
595 return *this;
596 }
597
598 // Performs a bitwise AND with a flag.
599 template <std::same_as<E> T>
600 constexpr EnumFlags& operator&=(T t) noexcept
601 {
602 mBits &= to_bit(t);
603 return *this;
604 }
605
606 // Returns a flag set with a bitwise AND.
607 template <std::same_as<E> T>
608 constexpr EnumFlags operator&(T t) const noexcept
609 {
610 return EnumFlags(mBits & to_bit(t));
611 }
612
613 // Returns a flag set with all bits inverted.
614 constexpr EnumFlags operator~() const noexcept
615 {
616 return EnumFlags(~mBits);
617 }
618
619 // Performs a bitwise OR with another flag set.
620 constexpr EnumFlags operator|(const EnumFlags& o) const noexcept
621 {
622 return EnumFlags(mBits | o.mBits);
623 }
624
625 // Performs a bitwise OR assignment.
626 constexpr EnumFlags& operator|=(const EnumFlags& o) noexcept
627 {
628 mBits |= o.mBits;
629 return *this;
630 }
631
632 // Performs a bitwise XOR with another flag set.
633 constexpr EnumFlags operator^(const EnumFlags& o) const noexcept
634 {
635 return EnumFlags(mBits ^ o.mBits);
636 }
637
638 // Performs a bitwise and with another flag set.
639 constexpr EnumFlags operator&(const EnumFlags& o) const noexcept
640 {
641 return EnumFlags(mBits & o.mBits);
642 }
643
644 // Performs a bitwise XOR assignment.
645 constexpr EnumFlags& operator^=(const EnumFlags& o) noexcept
646 {
647 mBits ^= o.mBits;
648 return *this;
649 }
650
651 // Checks if all specified flags are set.
652 template <typename... Ts>
653 [[nodiscard]] constexpr bool all_of(Ts... flags) const noexcept
654 {
655 return test(flags...);
656 }
657
658 // Checks if none of the specified flags are set.
659 template <typename... Ts>
660 [[nodiscard]] constexpr bool none_of(Ts... flags) const noexcept
661 {
662 return (!(test(flags) || ...));
663 }
664
665 // Serializes the flag set to a string.
666#ifndef GPUCA_GPUCODE
667 [[nodiscard]] std::string serialize() const
668 {
669 return std::to_string(mBits);
670 }
671
672 // Deserializes a string into the flag set.
673 void deserialize(const std::string& data)
674 {
675 typename H::UMax v = std::stoul(data);
676 if (v > H::MaxRep) {
677 throw std::out_of_range("Values exceeds enum range.");
678 }
679 mBits = static_cast<U>(v);
680 }
681#endif
682
683 // Counts the number of set bits (active flags).
684 [[nodiscard]] constexpr size_t count() const noexcept
685 {
686 return std::popcount(mBits);
687 }
688
689 // Returns the union of two flag sets.
690 [[nodiscard]] constexpr EnumFlags union_with(const EnumFlags& o) const noexcept
691 {
692 return EnumFlags(mBits | o.mBits);
693 }
694
695 // Returns the intersection of two flag sets.
696 [[nodiscard]] constexpr EnumFlags intersection_with(const EnumFlags& o) const noexcept
697 {
698 return EnumFlags(mBits & o.mBits);
699 }
700
701 // Checks if all flags in another Flags object are present in the current object.
702 [[nodiscard]] constexpr bool contains(const EnumFlags& other) const noexcept
703 {
704 return (mBits & other.mBits) == other.mBits;
705 }
706
707 private:
708 // Set implementation, bits was zeroed before.
709#ifndef GPUCA_GPUCODE
710 void setImpl(const std::string& s, int base = 2)
711 {
712 // Helper to check if character is valid for given base
713 auto isValidForBase = [](unsigned char c, int base) -> bool {
714 if (base == 2) {
715 return c == '0' || c == '1';
716 }
717 if (base == 10) {
718 return std::isdigit(c);
719 }
720 if (base == 16) {
721 return std::isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
722 }
723 return false;
724 };
725
726 // hex
727 if (base == 16) {
728 std::string_view hex_str{s};
729 // Strip optional 0x or 0X prefix
730 if (s.size() >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
731 hex_str.remove_prefix(2);
732 }
733 if (hex_str.empty()) {
734 throw std::invalid_argument("Empty hexadecimal string.");
735 }
736 if (!std::all_of(hex_str.begin(), hex_str.end(), [&](unsigned char c) { return isValidForBase(c, 16); })) {
737 throw std::invalid_argument("Invalid hexadecimal string.");
738 }
739 typename H::UMax v = std::stoul(std::string(hex_str), nullptr, 16);
740 if (v > H::MaxRep) {
741 throw std::out_of_range("Value exceeds enum range.");
742 }
743 mBits = static_cast<U>(v);
744 return;
745 }
746
747 // decimal and binary
748 if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isdigit(c); })) {
749 if (base == 2) {
750 // Binary: check only 0 and 1
751 if (!std::all_of(s.begin(), s.end(), [&](unsigned char c) { return isValidForBase(c, 2); })) {
752 throw std::invalid_argument("Invalid binary string.");
753 }
754 }
755 typename H::UMax v = std::stoul(std::string(s), nullptr, base);
756 if (v > H::MaxRep) {
757 throw std::out_of_range("Value exceeds enum range.");
758 }
759 mBits = static_cast<U>(v);
760 }
761 // enum name strings
762 else if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalnum(c) != 0 || c == '|' || c == ' ' || c == ':' || c == ',' || c == ';'; })) {
763 std::string cs{s};
764 std::transform(cs.begin(), cs.end(), cs.begin(), [](unsigned char c) { return std::tolower(c); });
765
766 if (cs == H::All) {
767 mBits = All;
768 } else if (cs == H::None) {
769 mBits = None;
770 } else {
771 // Detect delimiter and ensure only one type is used
772 char token = ' ';
773 size_t pipePos = s.find('|');
774 size_t commaPos = s.find(',');
775 size_t semiPos = s.find(';');
776
777 // Count how many different delimiters exist
778 int delimiterCount = (pipePos != std::string_view::npos ? 1 : 0) +
779 (commaPos != std::string_view::npos ? 1 : 0) +
780 (semiPos != std::string_view::npos ? 1 : 0);
781
782 if (delimiterCount > 1) {
783 throw std::invalid_argument("Mixed delimiters not allowed!");
784 }
785
786 if (pipePos != std::string_view::npos) {
787 token = '|';
788 } else if (commaPos != std::string_view::npos) {
789 token = ',';
790 } else if (semiPos != std::string_view::npos) {
791 token = ';';
792 }
793
794 for (const auto& tok : Str::tokenize(std::string(s), token)) {
795 if (auto e = H::fromString(tok)) {
796 mBits |= to_bit(*e);
797 } else {
798 throw std::invalid_argument(tok + " is not a valid enum value!");
799 }
800 }
801 }
802 } else {
803 throw std::invalid_argument("Cannot parse string!");
804 }
805 }
806#endif
807};
808
809#ifndef GPUCA_GPUCODE
810template <EnumFlag E>
811std::ostream& operator<<(std::ostream& os, const EnumFlags<E>& f)
812{
813 os << f.pstring(true);
814 return os;
815}
816#endif
817
818} // namespace o2::utils
819
820#endif
int32_t i
bool valid
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
Class to aggregate and manage enum-based on-off flags.
Definition EnumFlags.h:369
constexpr EnumFlags(E e)
Definition EnumFlags.h:393
constexpr bool all_of(Ts... flags) const noexcept
Definition EnumFlags.h:653
constexpr EnumFlags operator|(const EnumFlags &o) const noexcept
Definition EnumFlags.h:620
constexpr EnumFlags & operator=(const EnumFlags &o)=default
static constexpr U All
Definition EnumFlags.h:418
constexpr bool operator==(const EnumFlags &o) const noexcept
Definition EnumFlags.h:573
std::string serialize() const
Definition EnumFlags.h:667
constexpr size_t count() const noexcept
Definition EnumFlags.h:684
constexpr EnumFlags(std::initializer_list< E > flags) noexcept
Definition EnumFlags.h:401
constexpr bool operator!=(const EnumFlags &o) const noexcept
Definition EnumFlags.h:579
constexpr EnumFlags()=default
constexpr bool any() const noexcept
Definition EnumFlags.h:506
constexpr EnumFlags union_with(const EnumFlags &o) const noexcept
Definition EnumFlags.h:690
static constexpr auto getValues() noexcept
Definition EnumFlags.h:421
constexpr auto value() const noexcept
Definition EnumFlags.h:452
constexpr void reset() noexcept
Definition EnumFlags.h:458
constexpr EnumFlags(const EnumFlags &)=default
constexpr EnumFlags operator~() const noexcept
Definition EnumFlags.h:614
constexpr EnumFlags operator^(const EnumFlags &o) const noexcept
Definition EnumFlags.h:633
constexpr EnumFlags & operator=(EnumFlags &&o)=default
constexpr EnumFlags intersection_with(const EnumFlags &o) const noexcept
Definition EnumFlags.h:696
constexpr EnumFlags & operator|=(T t) noexcept
Definition EnumFlags.h:592
constexpr void reset(T t)
Definition EnumFlags.h:465
void deserialize(const std::string &data)
Definition EnumFlags.h:673
void set(const std::string &s, int base=DefaultBase)
Definition EnumFlags.h:435
static constexpr U None
Definition EnumFlags.h:416
constexpr bool all() const noexcept
Definition EnumFlags.h:513
constexpr EnumFlags(EnumFlags &&)=default
constexpr EnumFlags(U u)
Definition EnumFlags.h:399
constexpr void set(Ts... flags) noexcept
Definition EnumFlags.h:493
constexpr bool test(T t) const noexcept
Definition EnumFlags.h:472
constexpr bool none_of(Ts... flags) const noexcept
Definition EnumFlags.h:660
constexpr EnumFlags operator&(const EnumFlags &o) const noexcept
Definition EnumFlags.h:639
constexpr EnumFlags operator&(T t) const noexcept
Definition EnumFlags.h:608
std::string string() const
Definition EnumFlags.h:519
static constexpr auto getNames() noexcept
Definition EnumFlags.h:427
constexpr EnumFlags & operator^=(const EnumFlags &o) noexcept
Definition EnumFlags.h:645
constexpr void set(T t) noexcept
Definition EnumFlags.h:486
constexpr EnumFlags & operator&=(T t) noexcept
Definition EnumFlags.h:600
std::string pstring(bool withNewline=false) const
Definition EnumFlags.h:527
constexpr bool contains(const EnumFlags &other) const noexcept
Definition EnumFlags.h:702
constexpr bool test(Ts... flags) const noexcept
Definition EnumFlags.h:479
constexpr void toggle(T t) noexcept
Definition EnumFlags.h:500
constexpr EnumFlags & operator|=(const EnumFlags &o) noexcept
Definition EnumFlags.h:626
constexpr bool operator[](const T t) const noexcept
Definition EnumFlags.h:567
EnumFlags(const std::string &str, int base=DefaultBase)
Definition EnumFlags.h:410
GLsizei const GLchar *const * string
Definition glcorearb.h:809
GLdouble n
Definition glcorearb.h:1982
GLint GLsizei count
Definition glcorearb.h:399
GLuint64EXT * result
Definition glcorearb.h:5662
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition glcorearb.h:5034
GLint GLsizei width
Definition glcorearb.h:270
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLenum GLsizei GLsizei GLint * values
Definition glcorearb.h:1576
GLboolean * data
Definition glcorearb.h:298
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
Definition glcorearb.h:4150
GLbitfield flags
Definition glcorearb.h:1570
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
const std::vector< std::string > tokenize(const std::string_view input, const std::string_view pattern)
Definition Utils.cxx:40
std::ostream & operator<<(std::ostream &os, const EnumFlags< E > &f)
Definition EnumFlags.h:811
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
FIXME: do not use data model tables.
Marks an empty item in the context.
static constexpr std::string_view findScope(std::string_view s)
Definition EnumFlags.h:217
static constexpr bool hasNone() noexcept
Definition EnumFlags.h:301
static constexpr std::string_view None
Definition EnumFlags.h:300
static constexpr UMax makeMaxRep(size_t min, size_t max)
Definition EnumFlags.h:172
static constexpr auto getLongestName() noexcept
Definition EnumFlags.h:247
static constexpr bool isIEqual(const unsigned char a, const unsigned char b) noexcept
Definition EnumFlags.h:281
static constexpr auto count() noexcept
Definition EnumFlags.h:165
std::underlying_type_t< E > U
Definition EnumFlags.h:64
static constexpr std::string_view All
Definition EnumFlags.h:312
static constexpr bool isIEqual(std::string_view s1, std::string_view s2) noexcept
Definition EnumFlags.h:287
static consteval const char * tpeek() noexcept
Definition EnumFlags.h:75
static constexpr auto getNames(std::index_sequence< I... >)
Definition EnumFlags.h:234
static constexpr std::string_view tpeek_v
Definition EnumFlags.h:81
static constexpr bool hasAll() noexcept
Definition EnumFlags.h:313
static constexpr std::string_view getName()
Definition EnumFlags.h:183
static constexpr bool isValid() noexcept
Definition EnumFlags.h:119
static constexpr unsigned char toLower(const unsigned char c) noexcept
Definition EnumFlags.h:275
static constexpr auto getValues(std::index_sequence< I... >) noexcept
Definition EnumFlags.h:150
static constexpr std::string_view removeScope(std::string_view s)
Definition EnumFlags.h:209
static constexpr std::optional< E > fromString(std::string_view str) noexcept
Definition EnumFlags.h:264
static constexpr bool isScoped() noexcept
Definition EnumFlags.h:68
static constexpr bool isContinuous() noexcept
Definition EnumFlags.h:171
static constexpr std::string_view toString() noexcept
Definition EnumFlags.h:259
static constexpr auto getSpec() noexcept
Definition EnumFlags.h:106
constexpr size_t min
constexpr size_t max
VectorOfTObjectPtrs other
const std::string str