|
| 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_ENUM_BIT_OPERATORS_H_ |
| 12 | +#define O2_FRAMEWORK_ENUM_BIT_OPERATORS_H_ |
| 13 | + |
| 14 | +#include <type_traits> |
| 15 | +#include <string> |
| 16 | +#include <sstream> |
| 17 | +#include <limits> |
| 18 | + |
| 19 | +namespace o2::flags |
| 20 | +{ |
| 21 | + |
| 22 | +template <typename E> |
| 23 | +concept EFlag = requires { |
| 24 | + requires std::is_enum_v<E>; |
| 25 | + requires std::is_unsigned_v<std::underlying_type_t<E>>; |
| 26 | + requires std::is_convertible_v<std::underlying_type_t<E>, size_t>; |
| 27 | +}; |
| 28 | + |
| 29 | +// Promote an enum to a functioning flag class. The underlying type is |
| 30 | +// the one behind the enum, when bitset becomes constexpr and we get |
| 31 | +// reflection one could changes this. |
| 32 | +template <EFlag E> |
| 33 | +class Flags |
| 34 | +{ |
| 35 | + using U = std::underlying_type_t<E>; |
| 36 | + U mBits{0}; |
| 37 | + |
| 38 | + constexpr auto to_underlying(E e) const noexcept |
| 39 | + { |
| 40 | + return static_cast<U>(e); |
| 41 | + } |
| 42 | + |
| 43 | + constexpr auto to_bit(E e) const noexcept |
| 44 | + { |
| 45 | + return U(1) << to_underlying(e); |
| 46 | + } |
| 47 | + |
| 48 | + public: |
| 49 | + constexpr explicit Flags() = default; |
| 50 | + constexpr explicit Flags(E e) : mBits(to_bit(e)) {} |
| 51 | + constexpr explicit Flags(const Flags&) = default; |
| 52 | + constexpr explicit Flags(U u) : mBits(u) {} |
| 53 | + constexpr explicit Flags(std::initializer_list<E> flags) noexcept |
| 54 | + { |
| 55 | + for (E flag : flags) { |
| 56 | + mBits |= to_bit(flag); |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + static constexpr U None{0}; |
| 61 | + static constexpr U All{std::numeric_limits<U>::max()}; |
| 62 | + |
| 63 | + void set(std::string& s, int base = 2) |
| 64 | + { |
| 65 | + if (base == 2) { // check of only 0 and 1 in string |
| 66 | + if (!std::all_of(s.begin(), s.end(), [](char c) { return c == '0' || c == '1'; })) { |
| 67 | + throw std::invalid_argument("Invalid binary string."); |
| 68 | + } |
| 69 | + } |
| 70 | + mBits = static_cast<U>(std::stoul(s, nullptr, base)); |
| 71 | + } |
| 72 | + |
| 73 | + constexpr auto value() const noexcept |
| 74 | + { |
| 75 | + return mBits; |
| 76 | + } |
| 77 | + |
| 78 | + constexpr void reset() noexcept |
| 79 | + { |
| 80 | + mBits = U(0); |
| 81 | + } |
| 82 | + |
| 83 | + template <typename T> |
| 84 | + requires std::is_same_v<T, E> |
| 85 | + constexpr void reset(T t) |
| 86 | + { |
| 87 | + mBits &= ~to_bit(t); |
| 88 | + } |
| 89 | + |
| 90 | + template <typename T> |
| 91 | + requires std::is_same_v<T, E> |
| 92 | + constexpr bool test(T t) const noexcept |
| 93 | + { |
| 94 | + return (mBits & to_bit(t)) != None; |
| 95 | + } |
| 96 | + |
| 97 | + constexpr bool any() const noexcept |
| 98 | + { |
| 99 | + return mBits != None; |
| 100 | + } |
| 101 | + |
| 102 | + std::string string() const |
| 103 | + { |
| 104 | + std::ostringstream oss; |
| 105 | + oss << std::bitset<std::numeric_limits<U>::digits>(mBits); |
| 106 | + return oss.str(); |
| 107 | + } |
| 108 | + |
| 109 | + constexpr explicit operator bool() const noexcept |
| 110 | + { |
| 111 | + return any(); |
| 112 | + } |
| 113 | + |
| 114 | + constexpr bool operator==(const Flags& o) const noexcept |
| 115 | + { |
| 116 | + return mBits == o.mBits; |
| 117 | + } |
| 118 | + |
| 119 | + constexpr bool operator!=(const Flags& o) const noexcept |
| 120 | + { |
| 121 | + return mBits != o.mBits; |
| 122 | + } |
| 123 | + |
| 124 | + constexpr Flags& operator=(const Flags& o) = default; |
| 125 | + |
| 126 | + template <typename T> |
| 127 | + requires std::is_same_v<T, E> |
| 128 | + constexpr Flags& operator|=(T t) noexcept |
| 129 | + { |
| 130 | + mBits |= to_bit(t); |
| 131 | + return *this; |
| 132 | + } |
| 133 | + |
| 134 | + template <typename T> |
| 135 | + requires std::is_same_v<T, E> |
| 136 | + constexpr Flags operator&=(T t) noexcept |
| 137 | + { |
| 138 | + mBits |= to_bit(t); |
| 139 | + return *this; |
| 140 | + } |
| 141 | + |
| 142 | + template <typename T> |
| 143 | + requires std::is_same_v<T, E> |
| 144 | + constexpr Flags operator&(T t) const noexcept |
| 145 | + { |
| 146 | + return Flags(mBits & to_bit(t)); |
| 147 | + } |
| 148 | + constexpr Flags operator~() const noexcept |
| 149 | + { |
| 150 | + return Flags(~mBits); |
| 151 | + } |
| 152 | + |
| 153 | + constexpr Flags operator|(const Flags& o) const noexcept |
| 154 | + { |
| 155 | + return Flags(mBits | o.mBits); |
| 156 | + } |
| 157 | + |
| 158 | + constexpr Flags& operator|=(const Flags& o) noexcept |
| 159 | + { |
| 160 | + mBits |= o.mBits; |
| 161 | + return *this; |
| 162 | + } |
| 163 | + |
| 164 | + template <typename... Ts> |
| 165 | + constexpr bool all_of(Ts... flags) const noexcept |
| 166 | + { |
| 167 | + return ((test(flags) && ...)); |
| 168 | + } |
| 169 | + |
| 170 | + template <typename... Ts> |
| 171 | + constexpr bool none_of(Ts... flags) const noexcept |
| 172 | + { |
| 173 | + return (!(test(flags) || ...)); |
| 174 | + } |
| 175 | +}; |
| 176 | + |
| 177 | +} // namespace o2::flags |
| 178 | + |
| 179 | +#endif |
0 commit comments