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