open62541pp 0.17.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
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
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 * Bitmask enums are defined by specializing the IsBitmaskEnum trait.
120 *
121 * @tparam T Enumeration type
122 *
123 * @see https://www.strikerx3.dev/cpp/2019/02/27/typesafe-enum-class-bitmasks-in-cpp.html
124 * @see https://andreasfertig.blog/2024/01/cpp20-concepts-applied/
125 */
126template <typename T>
127class Bitmask {
128public:
129 static_assert(std::is_enum_v<T>);
130 static_assert(IsBitmaskEnum<T>::value);
131
132 using Underlying = std::underlying_type_t<T>;
133
134 /// Create an empty bitmask.
135 constexpr Bitmask() noexcept = default;
136
137 /// Create a bitmask from the enumeration type.
138 constexpr Bitmask(T mask) noexcept // NOLINT(hicpp-explicit-conversions)
139 : mask_(toUnderlying(mask)) {}
140
141 /// Create a bitmask from the underlying type.
142 constexpr Bitmask(Underlying mask) noexcept // NOLINT(hicpp-explicit-conversions)
143 : mask_(mask) {}
144
145 /// Conversion to the enum type.
146 constexpr explicit operator T() const noexcept {
147 return static_cast<T>(mask_);
148 }
149
150 /// Conversion to the underlying type.
151 constexpr explicit operator Underlying() const noexcept { // NOLINT(abc)
152 return mask_;
153 }
154
155 /// Get the bitmask as the underlying type (integer).
156 constexpr Underlying get() const noexcept {
157 return mask_;
158 }
159
160 /// Set all bits.
161 constexpr Bitmask& set() noexcept {
162 mask_ = ~empty;
163 return *this;
164 }
165
166 /// Set specified bits.
167 constexpr Bitmask& set(T mask) noexcept {
168 mask_ |= toUnderlying(mask);
169 return *this;
170 }
171
172 /// Reset all bits.
173 constexpr Bitmask& reset() noexcept {
174 mask_ = empty;
175 return *this;
176 }
177
178 /// Reset specified bits.
179 constexpr Bitmask& reset(T mask) noexcept {
180 mask_ &= ~toUnderlying(mask);
181 return *this;
182 }
183
184 /// Flip all bits.
185 constexpr Bitmask& flip() noexcept {
186 mask_ = ~mask_;
187 return *this;
188 }
189
190 /// Check if all bits are set.
191 constexpr bool all() const noexcept {
192 return Underlying(~mask_) == empty;
193 }
194
195 /// Check if all of the specified bits are set.
196 constexpr bool allOf(T mask) const noexcept {
197 return (mask_ & toUnderlying(mask)) == toUnderlying(mask);
198 }
199
200 /// Check if any bits are set.
201 constexpr bool any() const noexcept {
202 return mask_ != empty;
203 }
204
205 /// Check if any of the specified bits are set.
206 constexpr bool anyOf(T mask) const noexcept {
207 return (mask_ & toUnderlying(mask)) != empty;
208 }
209
210 /// Check if none bits are set.
211 constexpr bool none() const noexcept {
212 return mask_ == empty;
213 }
214
215 /// Check if none of the specified bits are set.
216 constexpr bool noneOf(T mask) const noexcept {
217 return (mask_ & toUnderlying(mask)) == empty;
218 }
219
220private:
221 static constexpr Underlying toUnderlying(T mask) noexcept {
222 return static_cast<Underlying>(mask);
223 }
224
225 static constexpr Underlying empty{};
226 Underlying mask_{};
227};
228
229/// @relates Bitmask
230template <typename T, typename U>
231constexpr bool operator==(Bitmask<T> lhs, U rhs) noexcept {
232 return lhs.get() == Bitmask<T>(rhs).get();
233}
234
235/// @relates Bitmask
236template <typename T, typename U>
237constexpr bool operator!=(Bitmask<T> lhs, U rhs) noexcept {
238 return lhs.get() != Bitmask<T>(rhs).get();
239}
240
241/// @relates Bitmask
242template <typename T, typename U>
243constexpr bool operator==(U lhs, Bitmask<T> rhs) noexcept {
244 return Bitmask<T>(lhs).get() == rhs.get();
245}
246
247/// @relates Bitmask
248template <typename T, typename U>
249constexpr bool operator!=(U lhs, Bitmask<T> rhs) noexcept {
250 return Bitmask<T>(lhs).get() != rhs.get();
251}
252
253/**
254 * @}
255 */
256
257} // namespace opcua
Bitmask using (scoped) enums.
Definition bitmask.hpp:127
std::underlying_type_t< T > Underlying
Definition bitmask.hpp:132
constexpr bool allOf(T mask) const noexcept
Check if all of the specified bits are set.
Definition bitmask.hpp:196
constexpr Bitmask & reset(T mask) noexcept
Reset specified bits.
Definition bitmask.hpp:179
constexpr bool noneOf(T mask) const noexcept
Check if none of the specified bits are set.
Definition bitmask.hpp:216
constexpr bool all() const noexcept
Check if all bits are set.
Definition bitmask.hpp:191
constexpr Bitmask(Underlying mask) noexcept
Create a bitmask from the underlying type.
Definition bitmask.hpp:142
constexpr Bitmask & set(T mask) noexcept
Set specified bits.
Definition bitmask.hpp:167
constexpr bool any() const noexcept
Check if any bits are set.
Definition bitmask.hpp:201
constexpr Bitmask & reset() noexcept
Reset all bits.
Definition bitmask.hpp:173
constexpr Bitmask & flip() noexcept
Flip all bits.
Definition bitmask.hpp:185
constexpr bool none() const noexcept
Check if none bits are set.
Definition bitmask.hpp:211
constexpr Bitmask() noexcept=default
Create an empty bitmask.
constexpr Bitmask & set() noexcept
Set all bits.
Definition bitmask.hpp:161
constexpr bool anyOf(T mask) const noexcept
Check if any of the specified bits are set.
Definition bitmask.hpp:206
constexpr Underlying get() const noexcept
Get the bitmask as the underlying type (integer).
Definition bitmask.hpp:156
constexpr bool operator!=(Bitmask< T > lhs, U rhs) noexcept
Definition bitmask.hpp:237
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:243
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:249
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:231
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