Skip to content

Commit 88dcc79

Browse files
committed
Add bitmask
1 parent c983072 commit 88dcc79

3 files changed

Lines changed: 66 additions & 0 deletions

File tree

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,53 @@ int main() {
778778
}
779779
```
780780

781+
### Bitmask
782+
783+
The `Bitmask` utility provides a type-safe, convenient way to work with flag enums. It uses a CRTP pattern so derived bitmask types preserve their concrete type when performing bitwise operations (so `a | b` returns the derived bitmask type, not the base class).
784+
785+
Key points:
786+
787+
- Uses `enum class` underlying values safely via `Type::ToUnderlying`.
788+
- Operators `|`, `&`, `^`, and `~` return the derived bitmask type (CRTP).
789+
- Provides helpers `Add`, `Remove`, `Has`, `Any`, `None`, and `Value()`.
790+
791+
#### Example
792+
793+
```cpp
794+
#include <StormByte/bitmask.hxx>
795+
#include <iostream>
796+
797+
using namespace StormByte;
798+
799+
enum class MyFlags : uint8_t {
800+
FlagA = 0x01,
801+
FlagB = 0x02,
802+
FlagC = 0x04
803+
};
804+
805+
class MyBitmask: public Bitmask<MyBitmask, MyFlags> {
806+
public:
807+
using Bitmask<MyBitmask, MyFlags>::Bitmask;
808+
};
809+
810+
int main() {
811+
MyBitmask a(MyFlags::FlagA);
812+
MyBitmask b(MyFlags::FlagB);
813+
814+
MyBitmask c = a | b; // returns MyBitmask
815+
816+
if (c.Value() == (MyFlags::FlagA | MyFlags::FlagB)) {
817+
std::cout << "Flags A and B set\n";
818+
}
819+
820+
c |= MyBitmask(MyFlags::FlagC);
821+
c.Remove(MyFlags::FlagB);
822+
823+
std::cout << "Final value: " << static_cast<int>(Type::ToUnderlying(c.Value())) << std::endl;
824+
return 0;
825+
}
826+
```
827+
781828
### Type Traits
782829

783830
StormByte provides several custom type traits for compile-time type inspection, particularly useful for template metaprogramming and serialization.

lib/public/StormByte/type_traits.hxx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,21 @@ namespace StormByte {
207207
template<typename E>
208208
concept Enum = std::is_enum_v<std::remove_cv_t<E>>;
209209

210+
/**
211+
* @brief Concept to check if a type is an unsigned enumeration.
212+
* @tparam E Type to check.
213+
*
214+
* A type satisfies UnsignedEnum if it is an enumeration with an unsigned underlying type.
215+
* @code
216+
* template<Type::UnsignedEnum E>
217+
* void process(E value) { ... }
218+
* @endcode
219+
*/
220+
template<typename E>
221+
concept UnsignedEnum =
222+
Enum<E> &&
223+
std::is_unsigned_v<std::underlying_type_t<std::remove_cv_t<E>>>;
224+
210225
/**
211226
* @brief Concept to check if a type is a scoped enumeration (enum class).
212227
* @tparam E Type to check.

test/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ option(ENABLE_TEST "Enable Unit Tests" OFF)
22
if(ENABLE_TEST AND NOT STORMBYTE_AS_DEPENDENCY)
33
enable_testing()
44

5+
add_executable(BitmaskTests bitmask_test.cxx)
6+
target_link_libraries(BitmaskTests StormByte)
7+
add_test(NAME BitmaskTests COMMAND BitmaskTests)
8+
59
add_executable(IterableTests iterable_test.cxx)
610
target_link_libraries(IterableTests StormByte)
711
add_test(NAME IterableTests COMMAND IterableTests)

0 commit comments

Comments
 (0)