open62541pp 0.16.0
C++ wrapper of open62541
Loading...
Searching...
No Matches
bitmask.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <type_traits>
4
5namespace opcua {
6
7/**
8 * \addtogroup BitmaskAbstraction Bitmask abstraction
9 * @{
10 */
11
12/**
13 * Function template to define an enum (class) as a bitmask and allow bitwise operations.
14 * The function must be overloaded for a specific enum type to return `std::true_type`.
15 *
16 * This is an additional opt-in mechanism to specializations of the IsBitmaskEnum trait and can also
17 * be used in other namespaces.
18 */
19template <typename T>
20constexpr std::false_type isBitmaskEnum(T);
21
22/**
23 * Trait to define an enum (class) as a bitmask and allow bitwise operations.
24 *
25 * @code{.cpp}
26 * // define enum (class)
27 * enum class Access {
28 * Read = 1 << 0,
29 * Write = 1 << 1,
30 * };
31 *
32 * // allow bitwise operations
33 * // 1. with template specialization of IsBitmaskEnum trait
34 * template <>
35 * struct IsBitmaskEnum<Access> : std::true_type {};
36 * // 2. with overload of function isBitmaskEnum
37 * constexpr std::true_type isBitmaskEnum(Access);
38 *
39 * // use bitwise operations
40 * Access mask = Access::Read | Access::Write;
41 * @endcode
42 */
43template <typename T>
44struct IsBitmaskEnum : std::is_same<decltype(isBitmaskEnum(std::declval<T>())), std::true_type> {};
45
46/* -------------------------------------- Bitwise operators ------------------------------------- */
47
48// NOLINTBEGIN(clang-analyzer-optin.core.EnumCastOutOfRange)
49
50/// @relates IsBitmaskEnum
51template <typename T>
52constexpr typename std::enable_if_t<IsBitmaskEnum<T>::value, T> operator&(T lhs, T rhs) noexcept {
53 using U = typename std::underlying_type_t<T>;
54 return static_cast<T>(static_cast<U>(lhs) & static_cast<U>(rhs));
55}
56
57/// @relates IsBitmaskEnum
58template <typename T>
59constexpr typename std::enable_if_t<IsBitmaskEnum<T>::value, T> operator|(T lhs, T rhs) noexcept {
60 using U = typename std::underlying_type_t<T>;
61 return static_cast<T>(static_cast<U>(lhs) | static_cast<U>(rhs));
62}
63
64/// @relates IsBitmaskEnum
65template <typename T>
66constexpr typename std::enable_if_t<IsBitmaskEnum<T>::value, T> operator^(T lhs, T rhs) noexcept {
67 using U = typename std::underlying_type_t<T>;
68 return static_cast<T>(static_cast<U>(lhs) ^ static_cast<U>(rhs));
69}
70
71/// @relates IsBitmaskEnum
72template <typename T>
73constexpr typename std::enable_if_t<IsBitmaskEnum<T>::value, T> operator~(T rhs) noexcept {
74 using U = typename std::underlying_type_t<T>;
75 return static_cast<T>(~static_cast<U>(rhs));
76}
77
78/* -------------------------------- Bitwise assignment operators -------------------------------- */
79
80/// @relates IsBitmaskEnum
81template <typename T>
82constexpr typename std::enable_if_t<IsBitmaskEnum<T>::value, T> operator|=(T& lhs, T rhs) noexcept {
83 using U = typename std::underlying_type_t<T>;
84 lhs = static_cast<T>(static_cast<U>(lhs) | static_cast<U>(rhs));
85 return lhs;
86}
87
88/// @relates IsBitmaskEnum
89template <typename T>
90constexpr typename std::enable_if_t<IsBitmaskEnum<T>::value, T> operator&=(T& lhs, T rhs) noexcept {
91 using U = typename std::underlying_type_t<T>;
92 lhs = static_cast<T>(static_cast<U>(lhs) & static_cast<U>(rhs));
93 return lhs;
94}
95
96/// @relates IsBitmaskEnum
97template <typename T>
98constexpr typename std::enable_if_t<IsBitmaskEnum<T>::value, T> operator^=(T& lhs, T rhs) noexcept {
99 using U = typename std::underlying_type_t<T>;
100 lhs = static_cast<T>(static_cast<U>(lhs) ^ static_cast<U>(rhs));
101 return lhs;
102}
103
104// NOLINTEND(clang-analyzer-optin.core.EnumCastOutOfRange)
105
106/* ---------------------------------------- Bitmask class --------------------------------------- */
107
108/**
109 * Bitmask using (scoped) enums.
110 * Zero-cost abstraction to specify bitmasks with enums/ints or enum classes.
111 *
112 * @code{.cpp}
113 * // construct with scoped enums
114 * Bitmask<NodeClass> mask = NodeClass::Variable | NodeClass::Object;
115 * // construct with unscoped enums or ints
116 * Bitmask<NodeClass> mask = UA_NODECLASS_VARIABLE | UA_NODECLASS_OBJECT;
117 * @endcode
118 *
119 * @tparam T Enumeration type
120 *
121 * @see https://www.strikerx3.dev/cpp/2019/02/27/typesafe-enum-class-bitmasks-in-cpp.html
122 * @see https://andreasfertig.blog/2024/01/cpp20-concepts-applied/
123 */
124template <typename T>
125class Bitmask {
126public:
127 static_assert(std::is_enum_v<T>);
128 static_assert(IsBitmaskEnum<T>::value);
129
130 using Underlying = std::underlying_type_t<T>;
131
132 /// Create an empty bitmask.
133 constexpr Bitmask() noexcept = default;
134
135 /// Create a bitmask from the enumeration type.
136 constexpr Bitmask(T mask) noexcept // NOLINT(hicpp-explicit-conversions)
137 : mask_(toUnderlying(mask)) {}
138
139 /// Create a bitmask from the underlying type.
140 constexpr Bitmask(Underlying mask) noexcept // NOLINT(hicpp-explicit-conversions)
141 : mask_(mask) {}
142
143 /// Conversion to the enum type.
144 constexpr explicit operator T() const noexcept {
145 return static_cast<T>(mask_);
146 }
147
148 /// Conversion to the underlying type.
149 constexpr explicit operator Underlying() const noexcept { // NOLINT(abc)
150 return mask_;
151 }
152
153 /// Get the bitmask as the underlying type (integer).
154 constexpr Underlying get() const noexcept {
155 return mask_;
156 }
157
158 /// Set all bits.
159 constexpr Bitmask& set() noexcept {
160 mask_ = ~empty;
161 return *this;
162 }
163
164 /// Set specified bits.
165 constexpr Bitmask& set(T mask) noexcept {
166 mask_ |= toUnderlying(mask);
167 return *this;
168 }
169
170 /// Reset all bits.
171 constexpr Bitmask& reset() noexcept {
172 mask_ = empty;
173 return *this;
174 }
175
176 /// Reset specified bits.
177 constexpr Bitmask& reset(T mask) noexcept {
178 mask_ &= ~toUnderlying(mask);
179 return *this;
180 }
181
182 /// Flip all bits.
183 constexpr Bitmask& flip() noexcept {
184 mask_ = ~mask_;
185 return *this;
186 }
187
188 /// Check if all bits are set.
189 constexpr bool all() const noexcept {
190 return Underlying(~mask_) == empty;
191 }
192
193 /// Check if all of the specified bits are set.
194 constexpr bool allOf(T mask) const noexcept {
195 return (mask_ & toUnderlying(mask)) == toUnderlying(mask);
196 }
197
198 /// Check if any bits are set.
199 constexpr bool any() const noexcept {
200 return mask_ != empty;
201 }
202
203 /// Check if any of the specified bits are set.
204 constexpr bool anyOf(T mask) const noexcept {
205 return (mask_ & toUnderlying(mask)) != empty;
206 }
207
208 /// Check if none bits are set.
209 constexpr bool none() const noexcept {
210 return mask_ == empty;
211 }
212
213 /// Check if none of the specified bits are set.
214 constexpr bool noneOf(T mask) const noexcept {
215 return (mask_ & toUnderlying(mask)) == empty;
216 }
217
218private:
219 static constexpr Underlying toUnderlying(T mask) noexcept {
220 return static_cast<Underlying>(mask);
221 }
222
223 static constexpr Underlying empty{};
224 Underlying mask_{};
225};
226
227/// @relates Bitmask
228template <typename T, typename U>
229constexpr bool operator==(Bitmask<T> lhs, U rhs) noexcept {
230 return lhs.get() == Bitmask<T>(rhs).get();
231}
232
233/// @relates Bitmask
234template <typename T, typename U>
235constexpr bool operator!=(Bitmask<T> lhs, U rhs) noexcept {
236 return lhs.get() != Bitmask<T>(rhs).get();
237}
238
239/// @relates Bitmask
240template <typename T, typename U>
241constexpr bool operator==(U lhs, Bitmask<T> rhs) noexcept {
242 return Bitmask<T>(lhs).get() == rhs.get();
243}
244
245/// @relates Bitmask
246template <typename T, typename U>
247constexpr bool operator!=(U lhs, Bitmask<T> rhs) noexcept {
248 return Bitmask<T>(lhs).get() != rhs.get();
249}
250
251/**
252 * @}
253 */
254
255} // namespace opcua
Bitmask using (scoped) enums.
Definition bitmask.hpp:125
std::underlying_type_t< T > Underlying
Definition bitmask.hpp:130
constexpr bool allOf(T mask) const noexcept
Check if all of the specified bits are set.
Definition bitmask.hpp:194
constexpr Bitmask & reset(T mask) noexcept
Reset specified bits.
Definition bitmask.hpp:177
constexpr bool noneOf(T mask) const noexcept
Check if none of the specified bits are set.
Definition bitmask.hpp:214
constexpr bool all() const noexcept
Check if all bits are set.
Definition bitmask.hpp:189
constexpr Bitmask(Underlying mask) noexcept
Create a bitmask from the underlying type.
Definition bitmask.hpp:140
constexpr Bitmask & set(T mask) noexcept
Set specified bits.
Definition bitmask.hpp:165
constexpr bool any() const noexcept
Check if any bits are set.
Definition bitmask.hpp:199
constexpr Bitmask & reset() noexcept
Reset all bits.
Definition bitmask.hpp:171
constexpr Bitmask & flip() noexcept
Flip all bits.
Definition bitmask.hpp:183
constexpr bool none() const noexcept
Check if none bits are set.
Definition bitmask.hpp:209
constexpr Bitmask() noexcept=default
Create an empty bitmask.
constexpr Bitmask & set() noexcept
Set all bits.
Definition bitmask.hpp:159
constexpr bool anyOf(T mask) const noexcept
Check if any of the specified bits are set.
Definition bitmask.hpp:204
constexpr Underlying get() const noexcept
Get the bitmask as the underlying type (integer).
Definition bitmask.hpp:154
constexpr bool operator!=(Bitmask< T > lhs, U rhs) noexcept
Definition bitmask.hpp:235
constexpr std::enable_if_t< IsBitmaskEnum< T >::value, T > operator&=(T &lhs, T rhs) noexcept
Definition bitmask.hpp:90
constexpr std::enable_if_t< IsBitmaskEnum< T >::value, T > operator|(T lhs, T rhs) noexcept
Definition bitmask.hpp:59
constexpr std::enable_if_t< IsBitmaskEnum< T >::value, T > operator~(T rhs) noexcept
Definition bitmask.hpp:73
constexpr bool operator==(U lhs, Bitmask< T > rhs) noexcept
Definition bitmask.hpp:241
constexpr std::enable_if_t< IsBitmaskEnum< T >::value, T > operator|=(T &lhs, T rhs) noexcept
Definition bitmask.hpp:82
constexpr std::false_type isBitmaskEnum(T)
Function template to define an enum (class) as a bitmask and allow bitwise operations.
constexpr std::enable_if_t< IsBitmaskEnum< T >::value, T > operator&(T lhs, T rhs) noexcept
Definition bitmask.hpp:52
constexpr bool operator!=(U lhs, Bitmask< T > rhs) noexcept
Definition bitmask.hpp:247
constexpr std::enable_if_t< IsBitmaskEnum< T >::value, T > operator^(T lhs, T rhs) noexcept
Definition bitmask.hpp:66
constexpr std::enable_if_t< IsBitmaskEnum< T >::value, T > operator^=(T &lhs, T rhs) noexcept
Definition bitmask.hpp:98
constexpr bool operator==(Bitmask< T > lhs, U rhs) noexcept
Definition bitmask.hpp:229
Trait to define an enum (class) as a bitmask and allow bitwise operations.
Definition bitmask.hpp:44
Exposes the possibilities of a client to write the attributes of the node In contrast to the write mask