deaddev-bitmask 1.0.1
C++ bitmask library
Loading...
Searching...
No Matches
bitmask.hpp
1
2// //
3// MIT License //
4// //
5// Copyright (c) 2025 DeadDev //
6// //
7// Permission is hereby granted, free of charge, to any person obtaining a copy //
8// of this software and associated documentation files (the "Software"), to deal //
9// in the Software without restriction, including without limitation the rights //
10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //
11// copies of the Software, and to permit persons to whom the Software is //
12// furnished to do so, subject to the following conditions: //
13// //
14// The above copyright notice and this permission notice shall be included in all //
15// copies or substantial portions of the Software. //
16// //
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //
20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //
22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE //
23// SOFTWARE. //
24// //
26
37#ifndef DEADDEV_BITMASK_HPP
38#define DEADDEV_BITMASK_HPP
39#pragma once
40#include <climits>
41#include <type_traits>
42#include <cstddef>
43
44#ifndef DEADDEV_CONSTEVAL
45#if __cplusplus >= 202002L
46#define DEADDEV_CONSTEVAL consteval
47#else
48#define DEADDEV_CONSTEVAL constexpr
49#endif
50#endif
51
52#ifndef DEADDEV_NODISCARD
53#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
54#define DEADDEV_NODISCARD [[nodiscard]]
55#else
56#define DEADDEV_NODISCARD
57#endif
58#endif
59
63namespace deaddev {
64
68namespace details {
69
70#ifdef __cpp_lib_is_scoped_enum
76template <typename T> constexpr bool is_scoped_enum_v = ::std::is_scoped_enum_v<T>;
77#elif defined(__has_builtin) && __has_builtin(__is_scoped_enum)
78
84template <typename T> constexpr bool is_scoped_enum_v = __is_scoped_enum(T);
85#else
91template <typename T>
92constexpr bool is_scoped_enum_v =
93 ::std::is_enum<T>::value &&
94 !::std::is_convertible<T, typename ::std::underlying_type<T>::type>::value;
95#endif
96
103 static constexpr bool enable = false;
106 static constexpr size_t all_flags = 0xFFFFFFFFFFFFFFFF;
107};
108
116template <typename T>
117DEADDEV_CONSTEVAL auto combine_flags(::std::underlying_type_t<T> &result, T value)
118 -> void {
119 result |= static_cast<::std::underlying_type_t<T>>(value);
120}
121
122#if __cplusplus < 201703L
130template <typename T>
131DEADDEV_CONSTEVAL auto calculate_all_flags_cpp_before_17(T val) -> T {
132 return static_cast<T>(val);
133}
143template <typename T, typename... Args>
144DEADDEV_CONSTEVAL auto calculate_all_flags_cpp_before_17(T arg, Args... args) -> T {
145 return static_cast<T>(static_cast<typename ::std::underlying_type<T>::type>(arg) |
146 static_cast<typename ::std::underlying_type<T>::type>(
148}
149#else
150template <typename T, typename... Args>
151DEADDEV_CONSTEVAL auto calculate_all_flags_cpp_17(Args... args) -> T {
152 ::std::underlying_type_t<T> result{0};
153 (::deaddev::details::combine_flags(result, args), ...);
154 return static_cast<T>(result);
155}
156#endif
157
166template <typename T, typename... Args>
167DEADDEV_CONSTEVAL auto calculate_all_flags(Args... args) -> T {
168#if __cplusplus < 201703L
170#else
171 return calculate_all_flags_cpp_17<T>(args...);
172#endif
173}
180template <typename T> DEADDEV_CONSTEVAL auto calculate_all_flags() -> T {
181 return static_cast<T>((1ull << ((sizeof(T) * CHAR_BIT) - 1)) - 1); // patched
182}
183
191template <typename T, T AllFlags> struct bitmask_traits {
193 static constexpr bool enable = true;
195 static constexpr T all_flags = AllFlags;
196};
197
206
212template <typename T>
214 : decltype(adl_bitmask_operations_check(::std::declval<T &>())){};
215
222template <typename T,
223 typename = typename ::std::enable_if<::std::is_enum<T>::value>::type>
224constexpr bool is_bitmask_v =
225#ifdef DEADDEV_ENABLE_BITMASKS_FOR_SCOPED_ENUMS
227#endif
229
236template <typename T,
237 typename = typename ::std::enable_if<::std::is_enum<T>::value>::type>
240
241} // namespace details
242
250template <typename T,
251 typename = typename ::std::enable_if<::deaddev::details::is_bitmask_v<T>>::type>
252class bitmask {
253
254public:
256 using mask_type = ::std::underlying_type_t<T>;
258 using enum_type = T;
260 constexpr bitmask() noexcept = default;
262 constexpr bitmask(const bitmask &) noexcept = default;
264 constexpr bitmask(bitmask &&) noexcept = default;
266 constexpr bitmask &operator=(const bitmask &) noexcept = default;
268 constexpr bitmask &operator=(bitmask &&) noexcept = default;
273 constexpr bitmask(enum_type value) noexcept : mask_(static_cast<mask_type>(value)) {}
278 explicit constexpr bitmask(mask_type value) noexcept : mask_(value) {}
279
285 DEADDEV_NODISCARD explicit constexpr operator enum_type() const noexcept {
286 return static_cast<enum_type>(mask_);
287 }
293 DEADDEV_NODISCARD explicit constexpr operator mask_type() const noexcept {
294 return mask_;
295 }
296
301 DEADDEV_NODISCARD DEADDEV_CONSTEVAL static bitmask all_flags() noexcept {
303 }
304
306 DEADDEV_NODISCARD constexpr bool operator==(mask_type mask) const noexcept {
307 return mask_ == mask;
308 }
310 DEADDEV_NODISCARD constexpr bool operator!=(mask_type mask) const noexcept {
311 return mask_ != mask;
312 }
314 DEADDEV_NODISCARD constexpr bool operator<=(mask_type mask) const noexcept {
315 return mask_ <= mask;
316 }
318 DEADDEV_NODISCARD constexpr bool operator>=(mask_type mask) const noexcept {
319 return mask_ >= mask;
320 }
322 DEADDEV_NODISCARD constexpr bool operator<(mask_type mask) const noexcept {
323 return mask_ < mask;
324 }
326 DEADDEV_NODISCARD constexpr bool operator>(mask_type mask) const noexcept {
327 return mask_ > mask;
328 }
330 DEADDEV_NODISCARD constexpr bool operator==(bitmask other) const noexcept {
331 return mask_ == other.mask_;
332 }
334 DEADDEV_NODISCARD constexpr bool operator!=(bitmask other) const noexcept {
335 return mask_ != other.mask_;
336 }
338 DEADDEV_NODISCARD constexpr bool operator<=(bitmask other) const noexcept {
339 return mask_ <= other.mask_;
340 }
342 DEADDEV_NODISCARD constexpr bool operator>=(bitmask other) const noexcept {
343 return mask_ >= other.mask_;
344 }
346 DEADDEV_NODISCARD constexpr bool operator<(bitmask other) const noexcept {
347 return mask_ < other.mask_;
348 }
350 DEADDEV_NODISCARD constexpr bool operator>(bitmask other) const noexcept {
351 return mask_ > other.mask_;
352 }
353
355 DEADDEV_NODISCARD constexpr bitmask operator~() const noexcept {
356 return bitmask(static_cast<mask_type>(mask_ ^ all_flags().mask_));
357 }
358
360 DEADDEV_NODISCARD constexpr bitmask operator^(bitmask other) const noexcept {
361 return bitmask(mask_ ^ other.mask_);
362 }
363
365 DEADDEV_NODISCARD constexpr bitmask operator|(bitmask other) const noexcept {
366 return bitmask(mask_ | other.mask_);
367 }
368
370 DEADDEV_NODISCARD constexpr bitmask operator&(bitmask other) const noexcept {
371 return bitmask(mask_ & other.mask_);
372 }
373
375 constexpr bitmask &operator^=(bitmask other) noexcept {
376 mask_ ^= other.mask_;
377 return *this;
378 }
379
381 constexpr bitmask &operator|=(bitmask other) noexcept {
382 mask_ |= other.mask_;
383 return *this;
384 }
385
387 constexpr bitmask &operator&=(bitmask other) noexcept {
388 mask_ &= other.mask_;
389 return *this;
390 }
391
393 DEADDEV_NODISCARD constexpr bitmask operator^(enum_type other) const noexcept {
394 return bitmask(mask_ ^ static_cast<mask_type>(other));
395 }
396
398 DEADDEV_NODISCARD constexpr bitmask operator|(enum_type other) const noexcept {
399 return bitmask(mask_ | static_cast<mask_type>(other));
400 }
401
403 DEADDEV_NODISCARD constexpr bitmask operator&(enum_type other) const noexcept {
404 return bitmask(mask_ & static_cast<mask_type>(other));
405 }
406
408 constexpr bitmask &operator^=(enum_type other) noexcept {
409 mask_ ^= static_cast<mask_type>(other);
410 return *this;
411 }
412
414 constexpr bitmask &operator|=(enum_type other) noexcept {
415 mask_ |= static_cast<mask_type>(other);
416 return *this;
417 }
418
420 constexpr bitmask &operator&=(enum_type other) noexcept {
421 mask_ &= static_cast<mask_type>(other);
422 return *this;
423 }
424
433 DEADDEV_NODISCARD constexpr bool is_set(enum_type flag) const noexcept {
434 return (mask_ & static_cast<mask_type>(flag)) == static_cast<mask_type>(flag);
435 }
436
445 DEADDEV_NODISCARD constexpr bool is_set(bitmask other) const noexcept {
446 return (mask_ & other.mask_) == other.mask_;
447 }
448
455 constexpr bitmask &set(enum_type flag) noexcept { return *this |= flag; }
456
463 constexpr bitmask &set(bitmask other) noexcept { return *this |= other.mask_; }
464
471 constexpr bitmask &remove(enum_type flag) noexcept { return *this ^= flag; }
472
479 constexpr bitmask &remove(bitmask other) noexcept { return *this ^= other.mask_; }
480
481private:
483 mask_type mask_{};
484};
485
486} // namespace deaddev
487
488// Out of namespace because of ADL
489
490template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
491DEADDEV_NODISCARD constexpr bool operator==(T left, deaddev::bitmask<T> right) noexcept {
492 return right == left; // reversed order
493}
494template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
495DEADDEV_NODISCARD constexpr bool operator!=(T left, deaddev::bitmask<T> right) noexcept {
496 return right != left; // reversed order
497}
498template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
499DEADDEV_NODISCARD constexpr bool operator>=(T left, deaddev::bitmask<T> right) noexcept {
500 return right <= left; // reversed order
501}
502template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
503DEADDEV_NODISCARD constexpr bool operator<=(T left, deaddev::bitmask<T> right) noexcept {
504 return right >= left; // reversed order
505}
506template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
507DEADDEV_NODISCARD constexpr bool operator<(T left, deaddev::bitmask<T> right) noexcept {
508 return right > left; // reversed order
509}
510template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
511DEADDEV_NODISCARD constexpr bool operator>(T left, deaddev::bitmask<T> right) noexcept {
512 return right < left; // reversed order
513}
514template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
515DEADDEV_NODISCARD constexpr bool operator==(typename std::underlying_type<T>::type left,
516 deaddev::bitmask<T> right) noexcept {
517 return right == left; // reversed order
518}
519template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
520DEADDEV_NODISCARD constexpr bool operator!=(typename std::underlying_type<T>::type left,
521 deaddev::bitmask<T> right) noexcept {
522 return right != left; // reversed order
523}
524template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
525DEADDEV_NODISCARD constexpr bool operator>=(typename std::underlying_type<T>::type left,
526 deaddev::bitmask<T> right) noexcept {
527 return right <= left; // reversed order
528}
529template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
530DEADDEV_NODISCARD constexpr bool operator<=(typename std::underlying_type<T>::type left,
531 deaddev::bitmask<T> right) noexcept {
532 return right >= left; // reversed order
533}
534template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
535DEADDEV_NODISCARD constexpr bool operator<(typename std::underlying_type<T>::type left,
536 deaddev::bitmask<T> right) noexcept {
537 return right > left; // reversed order
538}
539template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
540DEADDEV_NODISCARD constexpr bool operator>(typename std::underlying_type<T>::type left,
541 deaddev::bitmask<T> right) noexcept {
542 return right < left; // reversed order
543}
544
545template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
546DEADDEV_NODISCARD constexpr deaddev::bitmask<T> operator~(T flag) noexcept {
547 return ~deaddev::bitmask<T>(flag);
548}
549
550template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
551DEADDEV_NODISCARD constexpr deaddev::bitmask<T> operator^(T left, T right) noexcept {
552 return deaddev::bitmask<T>(left) ^ right;
553}
554
555template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
556DEADDEV_NODISCARD constexpr deaddev::bitmask<T> operator|(T left, T right) noexcept {
557 return deaddev::bitmask<T>(left) | right;
558}
559
560template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
561DEADDEV_NODISCARD constexpr deaddev::bitmask<T> operator&(T left, T right) noexcept {
562 return deaddev::bitmask<T>(left) & right;
563}
564
565template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
566DEADDEV_NODISCARD constexpr deaddev::bitmask<T> operator^(T left, ::deaddev::bitmask<T> right) noexcept {
567 return right ^ left;
568}
569
570template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
571DEADDEV_NODISCARD constexpr deaddev::bitmask<T> operator|(T left, ::deaddev::bitmask<T> right) noexcept {
572 return right | left;
573}
574
575template <typename T, typename = ::std::enable_if<::deaddev::details::is_bitmask_v<T>>>
576DEADDEV_NODISCARD constexpr deaddev::bitmask<T> operator&(T left, ::deaddev::bitmask<T> right) noexcept {
577 return right & left;
578}
579
587#define DEADDEV_ENABLE_BITMASK(T, ...) \
588 auto adl_bitmask_operations_check(T &) -> ::deaddev::details::bitmask_traits< \
589 T, ::deaddev::details::calculate_all_flags<T>(__VA_ARGS__)>;
590
599#define DEADDEV_ENABLE_BITMASK_EXTERNAL(T, ...) \
600 template <> \
601 struct ::deaddev::details::bitmask_operations_check_traits<T> \
602 : ::deaddev::details::bitmask_traits< \
603 T, ::deaddev::details::calculate_all_flags<T>(__VA_ARGS__)> {};
604
605#endif // DEADDEV_BITMASK_HPP
Bitmask class type.
Definition bitmask.hpp:252
DEADDEV_NODISCARD constexpr bool operator!=(mask_type mask) const noexcept
comparison operator
Definition bitmask.hpp:310
constexpr bitmask & remove(enum_type flag) noexcept
Combine bit mask with an enum value.
Definition bitmask.hpp:471
constexpr bitmask(mask_type value) noexcept
mask from integral type assignment operator
Definition bitmask.hpp:278
::std::underlying_type_t< T > mask_type
underlying type of enum
Definition bitmask.hpp:256
constexpr bitmask & remove(bitmask other) noexcept
Combine bit mask with an enum value.
Definition bitmask.hpp:479
DEADDEV_NODISCARD constexpr bitmask operator&(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:370
DEADDEV_NODISCARD constexpr bool operator<(mask_type mask) const noexcept
comparison operator
Definition bitmask.hpp:322
constexpr bitmask & set(bitmask other) noexcept
Combine bit mask with an enum value.
Definition bitmask.hpp:463
DEADDEV_NODISCARD constexpr bool operator<=(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:338
constexpr bitmask & operator&=(enum_type other) noexcept
comparison operator
Definition bitmask.hpp:420
DEADDEV_NODISCARD constexpr bitmask operator^(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:360
DEADDEV_NODISCARD constexpr bool operator!=(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:334
DEADDEV_NODISCARD constexpr bitmask operator|(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:365
DEADDEV_NODISCARD constexpr bitmask operator&(enum_type other) const noexcept
comparison operator
Definition bitmask.hpp:403
DEADDEV_NODISCARD constexpr bool operator>=(mask_type mask) const noexcept
comparison operator
Definition bitmask.hpp:318
constexpr bitmask & operator^=(bitmask other) noexcept
comparison operator
Definition bitmask.hpp:375
DEADDEV_NODISCARD constexpr bool operator>(mask_type mask) const noexcept
comparison operator
Definition bitmask.hpp:326
constexpr bitmask & operator|=(enum_type other) noexcept
comparison operator
Definition bitmask.hpp:414
DEADDEV_NODISCARD constexpr bool operator>(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:350
DEADDEV_NODISCARD constexpr bitmask operator|(enum_type other) const noexcept
comparison operator
Definition bitmask.hpp:398
DEADDEV_NODISCARD constexpr bool operator<=(mask_type mask) const noexcept
comparison operator
Definition bitmask.hpp:314
DEADDEV_NODISCARD constexpr bool is_set(enum_type flag) const noexcept
Checks if an enum value is in the mask.
Definition bitmask.hpp:433
constexpr bitmask & operator^=(enum_type other) noexcept
comparison operator
Definition bitmask.hpp:408
DEADDEV_NODISCARD static DEADDEV_CONSTEVAL bitmask all_flags() noexcept
returns bitmask with all flags set
Definition bitmask.hpp:301
constexpr bitmask & set(enum_type flag) noexcept
Combine bit mask with an enum value.
Definition bitmask.hpp:455
DEADDEV_NODISCARD constexpr bool operator==(mask_type mask) const noexcept
comparison operator
Definition bitmask.hpp:306
DEADDEV_NODISCARD constexpr bool operator>=(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:342
constexpr bitmask & operator&=(bitmask other) noexcept
comparison operator
Definition bitmask.hpp:387
DEADDEV_NODISCARD constexpr bool is_set(bitmask other) const noexcept
Checks if all flags from other bit mask is set in this bit mask.
Definition bitmask.hpp:445
DEADDEV_NODISCARD constexpr bool operator<(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:346
DEADDEV_NODISCARD constexpr bitmask operator~() const noexcept
comparison operator
Definition bitmask.hpp:355
DEADDEV_NODISCARD constexpr bool operator==(bitmask other) const noexcept
comparison operator
Definition bitmask.hpp:330
constexpr bitmask & operator|=(bitmask other) noexcept
comparison operator
Definition bitmask.hpp:381
T enum_type
original enum
Definition bitmask.hpp:258
DEADDEV_NODISCARD constexpr bitmask operator^(enum_type other) const noexcept
comparison operator
Definition bitmask.hpp:393
constexpr bitmask() noexcept=default
default constructor
constexpr T bitmask_all_flags_v
All flags combined.
Definition bitmask.hpp:238
DEADDEV_CONSTEVAL auto combine_flags(::std::underlying_type_t< T > &result, T value) -> void
Flag combination routine.
Definition bitmask.hpp:117
constexpr bool is_bitmask_v
Is T a bitmask type.
Definition bitmask.hpp:224
auto adl_bitmask_operations_check(...) -> ::deaddev::details::empty_bitmask_traits
noop
DEADDEV_CONSTEVAL auto calculate_all_flags() -> T
returns all flags
Definition bitmask.hpp:180
constexpr bool is_scoped_enum_v
c++14 compatible std::is_scoped_enum
Definition bitmask.hpp:92
DEADDEV_CONSTEVAL auto calculate_all_flags_cpp_before_17(T val) -> T
sentinel recursion overload for all flags calculation
Definition bitmask.hpp:131
it's me :)
Definition bitmask.hpp:63
trait implementation
Definition bitmask.hpp:214
used for deaddev::details::is_bitmask_v<T> and deaddev::details::bitmask_all_flags_v<T>
Definition bitmask.hpp:191
static constexpr bool enable
for sfinae checks
Definition bitmask.hpp:193
static constexpr T all_flags
for better negation
Definition bitmask.hpp:195
default value
Definition bitmask.hpp:101
static constexpr size_t all_flags
Definition bitmask.hpp:106
static constexpr bool enable
for sfinae type checks
Definition bitmask.hpp:103