@@ -57,6 +57,7 @@ concept EnumFlagHelper = requires {
5757template <EnumFlagHelper E>
5858struct FlagsHelper final {
5959 using U = std::underlying_type_t <E>;
60+ using UMax = uint64_t ; // max represetable type
6061
6162 static constexpr bool isScoped () noexcept
6263 {
@@ -144,8 +145,8 @@ struct FlagsHelper final {
144145 {
145146 constexpr std::array<bool , sizeof ...(I)> valid{isValid<static_cast <E>(MinScan + I)>()...};
146147 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! " );
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. " );
149150 std::array<E, count> values{};
150151 for (size_t idx{}, n{}; n < count; ++idx) {
151152 if (valid[idx]) {
@@ -161,8 +162,16 @@ struct FlagsHelper final {
161162 static constexpr auto Min_u_v{static_cast <size_t >(Min_v)}; // Enum first entry as size_t
162163 static constexpr auto Max_u_v{static_cast <size_t >(Max_v)}; // Enum last entry as size_t
163164 static_assert (Max_u_v < std::numeric_limits<U>::digits, " Max Bit is beyond allow range defered from underlying type" );
164- static constexpr bool isContinuous () noexcept { return (Max_u_v - Min_u_v + 1 ) == count (); } // Is the enum continuous
165- static constexpr auto MaxRep{((1ULL << (static_cast <unsigned long long >(Max_u_v - Min_u_v) + 1ULL )) - 1ULL ) << Min_u_v}; // largest representable value
165+ static constexpr bool isContinuous () noexcept { return (Max_u_v - Min_u_v + 1 ) == count (); } // Is the enum continuous
166+ static constexpr UMax makeMaxRep (size_t min, size_t max)
167+ {
168+ const size_t width = max - min + 1 ;
169+ if (width >= std::numeric_limits<UMax>::digits) {
170+ return std::numeric_limits<UMax>::max ();
171+ }
172+ return ((UMax (1 ) << width) - 1 ) << min;
173+ }
174+ static constexpr auto MaxRep{makeMaxRep (Min_u_v, Max_u_v)}; // largest representable value
166175
167176 template <E e>
168177 static constexpr std::string_view getName ()
@@ -173,7 +182,7 @@ struct FlagsHelper final {
173182 }
174183 if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::Enum_t>().size ()] == getSpec<SVal::AnonStart, SType::Enum_t>()) {
175184#if defined __clang__
176- if constexpr (tpeek_v<e>[tp + getSpec<SVal::Start, SType::enum_t >().size () + 1 ] == 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>()) {
177186 return {};
178187 }
179188#endif
@@ -215,7 +224,7 @@ struct FlagsHelper final {
215224 template <E e>
216225 static constexpr auto getNameValue{getName<e>()};
217226
218- template <bool with_scope, std:: size_t ... I>
227+ template <bool with_scope, size_t ... I>
219228 static constexpr auto getNames (std::index_sequence<I...> /* unused*/ )
220229 {
221230 if constexpr (with_scope) {
@@ -248,7 +257,7 @@ struct FlagsHelper final {
248257
249258 static constexpr std::optional<E> fromString (std::string_view str) noexcept
250259 {
251- for (std:: size_t i{0 }; i < count (); ++i) {
260+ for (size_t i{0 }; i < count (); ++i) {
252261 if (Names[i] == str || NamesScoped[i] == str) {
253262 return Values[i];
254263 }
@@ -325,7 +334,7 @@ concept EnumFlag = requires {
325334/* *
326335 * \brief Classs to aggregate and manage enum-based on-off flags.
327336 *
328- * This class manages flags as bits in the underlying type of an enum, allowing
337+ * This class manages flags as bits in the underlying type of an enum (upto 64 bits) , allowing
329338 * manipulation via enum member names. It supports operations akin to std::bitset
330339 * but is fully constexpr and is ideal for aggregating multiple on-off booleans,
331340 * e.g., enabling/disabling algorithm features.
@@ -371,13 +380,18 @@ class EnumFlags
371380 constexpr EnumFlags (const EnumFlags&) = default;
372381 // Move constructor.
373382 constexpr EnumFlags (EnumFlags&&) = default;
374- // Constructor to initialize with the underlyiny type.
383+ // Constructor to initialize with the underlying type.
375384 constexpr explicit EnumFlags (U u) : mBits(u) {}
376385 // Initialize with a list of flags.
377386 constexpr EnumFlags (std::initializer_list<E> flags) noexcept
378387 {
379388 std::for_each (flags.begin (), flags.end (), [this ](const E f) noexcept { mBits |= to_bit (f); });
380389 }
390+ // Init from a string.
391+ EnumFlags (const std::string& str)
392+ {
393+ set (str);
394+ }
381395 // Destructor.
382396 constexpr ~EnumFlags () = default ;
383397
@@ -415,7 +429,7 @@ class EnumFlags
415429 }
416430 }
417431 // Returns the raw bitset value.
418- constexpr auto value () const noexcept
432+ [[nodiscard]] constexpr auto value () const noexcept
419433 {
420434 return mBits ;
421435 }
@@ -442,6 +456,13 @@ class EnumFlags
442456 return (mBits & to_bit (t)) != None;
443457 }
444458
459+ // Tests if all specified flags are set.
460+ template <typename ... Ts>
461+ [[nodiscard]] constexpr bool test (Ts... flags) const noexcept
462+ {
463+ return ((test (flags) && ...));
464+ }
465+
445466 // Sets a specific flag.
446467 template <typename T>
447468 requires std::is_same_v<T, E>
@@ -464,6 +485,12 @@ class EnumFlags
464485 return mBits != None;
465486 }
466487
488+ // Checks if all flags are set.
489+ [[nodiscard]] constexpr bool all () const noexcept
490+ {
491+ return mBits == All;
492+ }
493+
467494 // Returns the bitset as a binary string.
468495 [[nodiscard]] std::string string () const
469496 {
@@ -505,27 +532,27 @@ class EnumFlags
505532 }
506533
507534 // Checks if any flag is set (Boolean context).
508- constexpr explicit operator bool () const noexcept
535+ [[nodiscard]] constexpr explicit operator bool () const noexcept
509536 {
510537 return any ();
511538 }
512539
513540 // Check if given flag is set.
514541 template <typename T>
515542 requires std::is_same_v<T, E>
516- constexpr bool operator [](const T t) noexcept
543+ [[nodiscard]] constexpr bool operator [](const T t) const noexcept
517544 {
518545 return test (t);
519546 }
520547
521548 // Checks if two flag sets are equal.
522- constexpr bool operator ==(const EnumFlags& o) const noexcept
549+ [[nodiscard]] constexpr bool operator ==(const EnumFlags& o) const noexcept
523550 {
524551 return mBits == o.mBits ;
525552 }
526553
527554 // Checks if two flag sets are not equal.
528- constexpr bool operator !=(const EnumFlags& o) const noexcept
555+ [[nodiscard]] constexpr bool operator !=(const EnumFlags& o) const noexcept
529556 {
530557 return mBits != o.mBits ;
531558 }
@@ -584,7 +611,13 @@ class EnumFlags
584611 // Performs a bitwise XOR with another flag set.
585612 constexpr EnumFlags operator ^(const EnumFlags& o) const noexcept
586613 {
587- return Flags (mBits ^ o.mBits );
614+ return EnumFlags (mBits ^ o.mBits );
615+ }
616+
617+ // Performs a bitwise and with another flag set.
618+ constexpr EnumFlags operator &(const EnumFlags& o) const noexcept
619+ {
620+ return EnumFlags (mBits & o.mBits );
588621 }
589622
590623 // Performs a bitwise XOR assignment.
@@ -596,14 +629,14 @@ class EnumFlags
596629
597630 // Checks if all specified flags are set.
598631 template <typename ... Ts>
599- constexpr bool all_of (Ts... flags) const noexcept
632+ [[nodiscard]] constexpr bool all_of (Ts... flags) const noexcept
600633 {
601- return (( test (flags) && ...) );
634+ return test (flags...);
602635 }
603636
604637 // Checks if none of the specified flags are set.
605638 template <typename ... Ts>
606- constexpr bool none_of (Ts... flags) const noexcept
639+ [[nodiscard]] constexpr bool none_of (Ts... flags) const noexcept
607640 {
608641 return (!(test (flags) || ...));
609642 }
@@ -617,7 +650,7 @@ class EnumFlags
617650 // Deserializes a string into the flag set.
618651 void deserialize (const std::string& data)
619652 {
620- uint64_t v = std::stoul (data);
653+ typename H::UMax v = std::stoul (data);
621654 if (v > H::MaxRep) {
622655 throw std::out_of_range (" Values exceeds enum range." );
623656 }
@@ -627,35 +660,29 @@ class EnumFlags
627660 // Counts the number of set bits (active flags).
628661 [[nodiscard]] constexpr size_t count () const noexcept
629662 {
630- size_t c{0 };
631- for (size_t i{H::Min_u_v}; i < H::Max_u_v; ++i) {
632- if ((mBits & (U (1 ) << i)) != U (0 )) {
633- ++c;
634- }
635- }
636- return c;
663+ return std::popcount (mBits );
637664 }
638665
639666 // Returns the union of two flag sets.
640- constexpr EnumFlags union_with (const EnumFlags& o) const noexcept
667+ [[nodiscard]] constexpr EnumFlags union_with (const EnumFlags& o) const noexcept
641668 {
642669 return EnumFlags (mBits | o.mBits );
643670 }
644671
645672 // Returns the intersection of two flag sets.
646- constexpr EnumFlags intersection_with (const EnumFlags& o) const noexcept
673+ [[nodiscard]] constexpr EnumFlags intersection_with (const EnumFlags& o) const noexcept
647674 {
648675 return EnumFlags (mBits & o.mBits );
649676 }
650677
651678 // Checks if all flags in another Flags object are present in the current object.
652- constexpr bool contains (const EnumFlags& other) const noexcept
679+ [[nodiscard]] constexpr bool contains (const EnumFlags& other) const noexcept
653680 {
654681 return (mBits & other.mBits ) == other.mBits ;
655682 }
656683
657684 private:
658- // Set implemnetation , bits was zeroed before.
685+ // Set implementation , bits was zeroed before.
659686 void setImpl (const std::string& s, int base = 2 )
660687 {
661688 if (std::all_of (s.begin (), s.end (), [](unsigned char c) { return std::isdigit (c); })) {
@@ -664,20 +691,25 @@ class EnumFlags
664691 throw std::invalid_argument (" Invalid binary string." );
665692 }
666693 }
667- uint64_t v = std::stoul (s, nullptr , base);
694+ typename H::UMax v = std::stoul (s, nullptr , base);
668695 if (v > H::MaxRep) {
669696 throw std::out_of_range (" Values exceeds enum range." );
670697 }
671698 mBits = static_cast <U>(v);
672- } else if (std::all_of (s.begin (), s.end (), [](unsigned char c) { return std::isalnum (c) != 0 || c == ' |' || c == ' ' || c == ' :' || c == ' ,' ; })) {
699+ } else if (std::all_of (s.begin (), s.end (), [](unsigned char c) { return std::isalnum (c) != 0 || c == ' |' || c == ' ' || c == ' :' || c == ' ,' || c == ' ; ' ; })) {
673700 std::string cs{s};
674701 std::transform (cs.begin (), cs.end (), cs.begin (), [](unsigned char c) { return std::tolower (c); });
675702 if (cs == H::All) {
676703 mBits = All;
677704 } else if (cs == H::None) {
678705 mBits = None;
679706 } else {
680- char token = (s.find (' ,' ) != std::string::npos) ? ' ,' : ' |' ;
707+ // accept as delimiter ' ', '|', ';', ','
708+ char token = ' ' ;
709+ std::string::size_type pos = s.find_first_of (" ,|;" );
710+ if (pos != std::string::npos) {
711+ token = s[pos];
712+ }
681713 for (const auto & tok : Str::tokenize (s, token)) {
682714 if (auto e = H::fromString (tok)) {
683715 mBits |= to_bit (*e);
0 commit comments