stlab-enum-ops 1.0.0
Type-safe operators for enums
Loading...
Searching...
No Matches
enum_ops.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6/**************************************************************************************************/
7
8#ifndef STLAB_ENUM_OPS_HPP
9#define STLAB_ENUM_OPS_HPP
10
11/**************************************************************************************************/
12
13#include <type_traits>
14
15/**************************************************************************************************/
16
21
62
63/**************************************************************************************************/
64
66namespace stlab {
67
68/**************************************************************************************************/
69
72auto stlab_enable_bitmask_enum(...) -> std::false_type;
75auto stlab_enable_arithmetic_enum(...) -> std::false_type;
76
77/**************************************************************************************************/
78
80namespace implementation {
81
82/**************************************************************************************************/
83
84template <class T>
85using has_enabled_bitmask_t = decltype(stlab_enable_bitmask_enum(std::declval<T>()));
86
87template <class T>
88constexpr bool has_enabled_bitmask = has_enabled_bitmask_t<T>::value;
89
90template <class T>
91using has_enabled_arithmetic_t = decltype(stlab_enable_arithmetic_enum(std::declval<T>()));
92
93template <class T>
94constexpr bool has_enabled_arithmetic = has_enabled_arithmetic_t<T>::value;
95
96template <class T, class U>
97using enable_if_bitmask_or_arithmetic =
98 std::enable_if_t<std::disjunction_v<stlab::implementation::has_enabled_bitmask_t<T>,
99 stlab::implementation::has_enabled_arithmetic_t<T>>,
100 U>;
101
102template <class, bool>
103struct safe_underlying_type;
104
105template <class T>
106struct safe_underlying_type<T, true> {
107 using type = std::underlying_type_t<T>;
108};
109
110template <class T>
111struct safe_underlying_type<T, false> {
112 using type = void;
113};
114
115template <class T>
116using safe_underlying_type_t = typename safe_underlying_type<T, std::is_enum<T>::value>::type;
117
118template <class U, class T>
119using is_convertible_to_underlying =
120 std::is_convertible<U, stlab::implementation::safe_underlying_type_t<T>>;
121
122/**************************************************************************************************/
123
124} // namespace implementation
125
126/**************************************************************************************************/
127
128} // namespace stlab
129
130/**************************************************************************************************/
131
132template <class T>
134constexpr auto operator&(T lhs, T rhs)
135 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
136 using underlying = std::underlying_type_t<T>;
137 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
138 return static_cast<T>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
139}
140
141template <class T>
143constexpr auto operator~(T a)
144 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
145 using underlying = std::underlying_type_t<T>;
146 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
147 return static_cast<T>(~static_cast<underlying>(a));
148}
149
150template <class T>
152constexpr auto operator|(T lhs, T rhs)
153 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
154 using underlying = std::underlying_type_t<T>;
155 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
156 return static_cast<T>(static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
157}
158
159template <class T>
161constexpr auto operator^(T lhs, T rhs)
162 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
163 using underlying = std::underlying_type_t<T>;
164 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
165 return static_cast<T>(static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs));
166}
167
168template <class T>
170constexpr auto operator<<(T lhs, std::size_t rhs)
171 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
172 using underlying = std::make_unsigned_t<std::underlying_type_t<T>>;
173 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
174 return static_cast<T>(static_cast<underlying>(lhs) << static_cast<underlying>(rhs));
175}
176
177template <class T>
179constexpr auto operator>>(T lhs, std::size_t rhs)
180 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T> {
181 using underlying = std::make_unsigned_t<std::underlying_type_t<T>>;
182 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
183 return static_cast<T>(static_cast<underlying>(lhs) >> static_cast<underlying>(rhs));
184}
185
186template <class T>
188constexpr auto operator^=(T& lhs, T rhs)
189 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
190 return lhs = lhs ^ rhs;
191}
192
193template <class T>
195constexpr auto operator&=(T& lhs, T rhs)
196 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
197 return lhs = lhs & rhs;
198}
199
200template <class T>
202constexpr auto operator|=(T& lhs, T rhs)
203 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
204 return lhs = lhs | rhs;
205}
206
207template <class T>
209constexpr auto operator<<=(T& lhs, std::size_t rhs)
210 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
211 return lhs = lhs << rhs;
212}
213
214template <class T>
216constexpr auto operator>>=(T& lhs, std::size_t rhs)
217 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T>, T&> {
218 return lhs = lhs >> rhs;
219}
220
221template <class T, class U>
223constexpr auto operator-(T lhs, U rhs)
224 -> std::enable_if_t<stlab::implementation::has_enabled_bitmask<T> &&
225 stlab::implementation::is_convertible_to_underlying<U, T>::value,
226 T> {
227 using underlying = std::underlying_type_t<T>;
228 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
229 return static_cast<T>(static_cast<underlying>(lhs) - static_cast<underlying>(rhs));
230}
231
232/**************************************************************************************************/
233
234template <class T>
236constexpr auto operator+(T a)
237 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
238 using underlying = std::underlying_type_t<T>;
239 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
240 return static_cast<T>(+static_cast<underlying>(a));
241}
242
243template <class T>
245constexpr auto operator-(T a)
246 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
247 using underlying = std::underlying_type_t<T>;
248 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
249 return static_cast<T>(-static_cast<underlying>(a));
250}
251
252template <class T>
254constexpr auto operator+(T lhs, T rhs)
255 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
256 using underlying = std::underlying_type_t<T>;
257 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
258 return static_cast<T>(static_cast<underlying>(lhs) + static_cast<underlying>(rhs));
259}
260
261template <class T>
263constexpr auto operator-(T lhs, T rhs)
264 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
265 using underlying = std::underlying_type_t<T>;
266 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
267 return static_cast<T>(static_cast<underlying>(lhs) - static_cast<underlying>(rhs));
268}
269
270template <class T, class U>
272constexpr auto operator*(T lhs, U rhs)
273 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
274 stlab::implementation::is_convertible_to_underlying<U, T>::value,
275 T> {
276 using underlying = std::underlying_type_t<T>;
277 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
278 return static_cast<T>(static_cast<underlying>(lhs) * rhs);
279}
280
281template <class U, class T>
283constexpr auto operator*(U lhs, T rhs)
284 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
285 stlab::implementation::is_convertible_to_underlying<U, T>::value,
286 T> {
287 using underlying = std::underlying_type_t<T>;
288 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
289 return static_cast<T>(lhs * static_cast<underlying>(rhs));
290}
291
292template <class T, class U>
294constexpr auto operator/(T lhs, U rhs)
295 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
296 stlab::implementation::is_convertible_to_underlying<U, T>::value,
297 T> {
298 using underlying = std::underlying_type_t<T>;
299 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
300 return static_cast<T>(static_cast<underlying>(lhs) / rhs);
301}
302
303template <class T, class U>
305constexpr auto operator%(T lhs, U rhs)
306 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
307 stlab::implementation::is_convertible_to_underlying<U, T>::value,
308 T> {
309 using underlying = std::underlying_type_t<T>;
310 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
311 return static_cast<T>(static_cast<underlying>(lhs) % rhs);
312}
313
314template <class T>
316constexpr auto operator+=(T& lhs, T rhs)
317 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> {
318 return lhs = lhs + rhs;
319}
320
321template <class T>
323constexpr auto operator-=(T& lhs, T rhs)
324 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> {
325 return lhs = lhs - rhs;
326}
327
328template <class T, class U>
330constexpr auto operator*=(T& lhs, U rhs)
331 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
332 stlab::implementation::is_convertible_to_underlying<U, T>::value,
333 T&> {
334 return lhs = lhs * rhs;
335}
336
337template <class T, class U>
339constexpr auto operator/=(T& lhs, U rhs)
340 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
341 stlab::implementation::is_convertible_to_underlying<U, T>::value,
342 T&> {
343 return lhs = lhs / rhs;
344}
345
346template <class T, class U>
348constexpr auto operator%=(T& lhs, U rhs)
349 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T> &&
350 stlab::implementation::is_convertible_to_underlying<U, T>::value,
351 T&> {
352 return lhs = lhs % rhs;
353}
354
355template <class T>
357constexpr auto operator++(T& lhs)
358 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> {
359 return lhs += static_cast<T>(1);
360}
361
362template <class T>
364constexpr auto operator++(T& lhs, int)
365 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
366 T result = lhs;
367 lhs += static_cast<T>(1);
368 return result;
369}
370
371template <class T>
373constexpr auto operator--(T& lhs)
374 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T&> {
375 return lhs -= static_cast<T>(1);
376}
377
378template <class T>
380constexpr auto operator--(T& lhs, int)
381 -> std::enable_if_t<stlab::implementation::has_enabled_arithmetic<T>, T> {
382 T result = lhs;
383 lhs -= static_cast<T>(1);
384 return result;
385}
386
387/**************************************************************************************************/
388
389template <class T>
391constexpr auto operator==(T lhs, std::nullptr_t)
392 -> std::enable_if_t<(stlab::implementation::has_enabled_bitmask<T> ||
393 stlab::implementation::has_enabled_arithmetic<T>) &&
394 !stlab::implementation::is_convertible_to_underlying<T, T>::value,
395 bool> {
396 return !lhs;
397}
398
399template <class T>
401constexpr auto operator==(std::nullptr_t, T rhs)
402 -> std::enable_if_t<(stlab::implementation::has_enabled_bitmask<T> ||
403 stlab::implementation::has_enabled_arithmetic<T>) &&
404 !stlab::implementation::is_convertible_to_underlying<T, T>::value,
405 bool> {
406 return !rhs;
407}
408
409template <class T>
411constexpr auto operator!=(T lhs, std::nullptr_t rhs)
412 -> std::enable_if_t<(stlab::implementation::has_enabled_bitmask<T> ||
413 stlab::implementation::has_enabled_arithmetic<T>) &&
414 !stlab::implementation::is_convertible_to_underlying<T, T>::value,
415 bool> {
416 return !(lhs == rhs);
417}
418
419template <class T>
421constexpr auto operator!=(std::nullptr_t lhs, T rhs)
422 -> std::enable_if_t<(stlab::implementation::has_enabled_bitmask<T> ||
423 stlab::implementation::has_enabled_arithmetic<T>) &&
424 !stlab::implementation::is_convertible_to_underlying<T, T>::value,
425 bool> {
426 return !(lhs == rhs);
427}
428
429template <class T>
431constexpr auto operator!(T lhs) -> stlab::implementation::enable_if_bitmask_or_arithmetic<T, bool> {
432 return !static_cast<bool>(lhs);
433}
434
435/**************************************************************************************************/
436
437#endif
438
439/**************************************************************************************************/
constexpr auto operator/=(T &lhs, U rhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T > &&stlab::implementation::is_convertible_to_underlying< U, T >::value, T & >
Division assignment by a value convertible to the enum's underlying type.
Definition enum_ops.hpp:339
constexpr auto operator==(T lhs, std::nullptr_t) -> std::enable_if_t<(stlab::implementation::has_enabled_bitmask< T >||stlab::implementation::has_enabled_arithmetic< T >) &&!stlab::implementation::is_convertible_to_underlying< T, T >::value, bool >
Equality with nullptr for bitmask or arithmetic scoped enums; true when the value is zero.
Definition enum_ops.hpp:391
constexpr auto operator|=(T &lhs, T rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T & >
OR-assign for bitmask-enabled enums.
Definition enum_ops.hpp:202
constexpr auto operator/(T lhs, U rhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T > &&stlab::implementation::is_convertible_to_underlying< U, T >::value, T >
Division by a value convertible to the enum's underlying type.
Definition enum_ops.hpp:294
constexpr auto operator+(T a) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T >, T >
Unary plus for arithmetic-enabled enums.
Definition enum_ops.hpp:236
constexpr auto operator<<=(T &lhs, std::size_t rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T & >
Left shift-assign for bitmask-enabled enums.
Definition enum_ops.hpp:209
constexpr auto operator-=(T &lhs, T rhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T >, T & >
Subtraction assignment for arithmetic-enabled enums.
Definition enum_ops.hpp:323
constexpr auto operator^=(T &lhs, T rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T & >
XOR-assign for bitmask-enabled enums.
Definition enum_ops.hpp:188
constexpr auto operator>>=(T &lhs, std::size_t rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T & >
Right shift-assign for bitmask-enabled enums.
Definition enum_ops.hpp:216
constexpr auto operator>>(T lhs, std::size_t rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T >
Right shift for bitmask-enabled enums.
Definition enum_ops.hpp:179
constexpr auto operator!=(T lhs, std::nullptr_t rhs) -> std::enable_if_t<(stlab::implementation::has_enabled_bitmask< T >||stlab::implementation::has_enabled_arithmetic< T >) &&!stlab::implementation::is_convertible_to_underlying< T, T >::value, bool >
Inequality with nullptr for bitmask or arithmetic scoped enums.
Definition enum_ops.hpp:411
constexpr auto operator*(T lhs, U rhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T > &&stlab::implementation::is_convertible_to_underlying< U, T >::value, T >
Multiplication by a value convertible to the enum's underlying type.
Definition enum_ops.hpp:272
constexpr auto operator!(T lhs) -> stlab::implementation::enable_if_bitmask_or_arithmetic< T, bool >
Logical NOT for bitmask or arithmetic enums; true when the value converts to false.
Definition enum_ops.hpp:431
constexpr auto operator+=(T &lhs, T rhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T >, T & >
Addition assignment for arithmetic-enabled enums.
Definition enum_ops.hpp:316
constexpr auto operator<<(T lhs, std::size_t rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T >
Left shift for bitmask-enabled enums.
Definition enum_ops.hpp:170
constexpr auto operator++(T &lhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T >, T & >
Prefix increment for arithmetic-enabled enums.
Definition enum_ops.hpp:357
constexpr auto operator^(T lhs, T rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T >
Bitwise XOR for bitmask-enabled enums.
Definition enum_ops.hpp:161
constexpr auto operator%(T lhs, U rhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T > &&stlab::implementation::is_convertible_to_underlying< U, T >::value, T >
Modulo by a value convertible to the enum's underlying type.
Definition enum_ops.hpp:305
constexpr auto operator&=(T &lhs, T rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T & >
AND-assign for bitmask-enabled enums.
Definition enum_ops.hpp:195
constexpr auto operator*=(T &lhs, U rhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T > &&stlab::implementation::is_convertible_to_underlying< U, T >::value, T & >
Multiplication assignment by a value convertible to the enum's underlying type.
Definition enum_ops.hpp:330
constexpr auto operator-(T lhs, U rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T > &&stlab::implementation::is_convertible_to_underlying< U, T >::value, T >
Subtracts a value convertible to the underlying type from a bitmask-enabled enum.
Definition enum_ops.hpp:223
constexpr auto operator--(T &lhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T >, T & >
Prefix decrement for arithmetic-enabled enums.
Definition enum_ops.hpp:373
constexpr auto operator%=(T &lhs, U rhs) -> std::enable_if_t< stlab::implementation::has_enabled_arithmetic< T > &&stlab::implementation::is_convertible_to_underlying< U, T >::value, T & >
Modulo assignment by a value convertible to the enum's underlying type.
Definition enum_ops.hpp:348
constexpr auto operator&(T lhs, T rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T >
Bitwise AND for bitmask-enabled enums; returns the same enum type.
Definition enum_ops.hpp:134
constexpr auto operator|(T lhs, T rhs) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T >
Bitwise OR for bitmask-enabled enums.
Definition enum_ops.hpp:152
constexpr auto operator~(T a) -> std::enable_if_t< stlab::implementation::has_enabled_bitmask< T >, T >
Bitwise NOT for bitmask-enabled enums; returns the same enum type.
Definition enum_ops.hpp:143
The stlab namespace.
Definition enum_ops.hpp:66
auto stlab_enable_arithmetic_enum(...) -> std::false_type
auto stlab_enable_bitmask_enum(...) -> std::false_type