Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions Common/Utils/include/CommonUtils/EnumFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <string>
#include <sstream>
#include <limits>
#include <bit>
#include <bitset>
#include <initializer_list>
#include <cstdint>
Expand All @@ -34,7 +35,15 @@
#include <iostream>
#include <iomanip>

#if !defined(__CUDACC__) && !defined(__HIPCC__)
#define O2_ENUMFLAGS_ENABLE_REFLECTION 1
#else
#define O2_ENUMFLAGS_ENABLE_REFLECTION 0
#endif

#if O2_ENUMFLAGS_ENABLE_REFLECTION
#include "CommonUtils/StringUtils.h"
#endif

namespace o2::utils
{
Expand All @@ -55,6 +64,7 @@ concept EnumFlagHelper = requires {
// This is very much inspired by much more extensive libraries like magic_enum.
// Inspiration by its c++20 version (https://github.com/fix8mt/conjure_enum).
// NOTE: Cannot detect if bit values past the underlying type are defined.
#if O2_ENUMFLAGS_ENABLE_REFLECTION
template <EnumFlagHelper E>
struct FlagsHelper final {
using U = std::underlying_type_t<E>;
Expand Down Expand Up @@ -317,10 +327,12 @@ struct FlagsHelper final {
return false;
}
};
#endif

} // namespace details::enum_flags

// Require an enum to fullfil what one would except from a bitset.
#if O2_ENUMFLAGS_ENABLE_REFLECTION
template <typename E>
concept EnumFlag = requires {
// range checks
Expand All @@ -332,6 +344,10 @@ concept EnumFlag = requires {
requires !details::enum_flags::FlagsHelper<E>::hasNone(); // added automatically
requires !details::enum_flags::FlagsHelper<E>::hasAll(); // added automatically
};
#else
template <typename E>
concept EnumFlag = details::enum_flags::EnumFlagHelper<E>;
#endif

/**
* \brief Class to aggregate and manage enum-based on-off flags.
Expand All @@ -358,7 +374,9 @@ template <EnumFlag E>
class EnumFlags
{
static constexpr int DefaultBase{2};
#if O2_ENUMFLAGS_ENABLE_REFLECTION
using H = details::enum_flags::FlagsHelper<E>;
#endif
using U = std::underlying_type_t<E>;
U mBits{0};

Expand Down Expand Up @@ -388,18 +406,21 @@ class EnumFlags
// Initialize with a list of flags.
constexpr EnumFlags(std::initializer_list<E> flags) noexcept
{
std::for_each(flags.begin(), flags.end(), [this](const E f) noexcept { mBits |= to_bit(f); });
for (const E f : flags) {
mBits |= to_bit(f);
}
}
#if O2_ENUMFLAGS_ENABLE_REFLECTION
// Init from a string.
//
explicit EnumFlags(const std::string& str, int base = DefaultBase)
{
set(str, base);
}
// Destructor.
constexpr ~EnumFlags() = default;
#endif

static constexpr U None{0}; // Represents no flags set.
static constexpr U None{0}; // Represents no flags set.
#if O2_ENUMFLAGS_ENABLE_REFLECTION
static constexpr U All{H::MaxRep}; // Represents all flags set.

// Return list of all enum values
Expand Down Expand Up @@ -432,6 +453,7 @@ class EnumFlags
throw;
}
}
#endif
// Returns the raw bitset value.
[[nodiscard]] constexpr auto value() const noexcept
{
Expand Down Expand Up @@ -493,6 +515,7 @@ class EnumFlags
}

// Checks if all flags are set.
#if O2_ENUMFLAGS_ENABLE_REFLECTION
[[nodiscard]] constexpr bool all() const noexcept
{
return mBits == All;
Expand Down Expand Up @@ -537,6 +560,7 @@ class EnumFlags
}
return oss.str();
}
#endif

// Checks if any flag is set (Boolean context).
[[nodiscard]] constexpr explicit operator bool() const noexcept
Expand Down Expand Up @@ -645,6 +669,7 @@ class EnumFlags
}

// Serializes the flag set to a string.
#if O2_ENUMFLAGS_ENABLE_REFLECTION
[[nodiscard]] std::string serialize() const
{
return std::to_string(mBits);
Expand All @@ -659,6 +684,7 @@ class EnumFlags
}
mBits = static_cast<U>(v);
}
#endif

// Counts the number of set bits (active flags).
[[nodiscard]] constexpr size_t count() const noexcept
Expand Down Expand Up @@ -686,6 +712,7 @@ class EnumFlags

private:
// Set implementation, bits was zeroed before.
#if O2_ENUMFLAGS_ENABLE_REFLECTION
void setImpl(const std::string& s, int base = 2)
{
// Helper to check if character is valid for given base
Expand Down Expand Up @@ -782,15 +809,20 @@ class EnumFlags
throw std::invalid_argument("Cannot parse string!");
}
}
#endif
};

#if O2_ENUMFLAGS_ENABLE_REFLECTION
template <EnumFlag E>
std::ostream& operator<<(std::ostream& os, const EnumFlags<E>& f)
{
os << f.pstring(true);
return os;
}
#endif

} // namespace o2::utils

#undef O2_ENUMFLAGS_ENABLE_REFLECTION

#endif