Skip to content

Commit 3f05a14

Browse files
committed
feat(core): add BitFlags
1 parent de9303f commit 3f05a14

File tree

7 files changed

+388
-6
lines changed

7 files changed

+388
-6
lines changed

libs/core/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ target_sources(
6363
include/quite/value/generic_value_class.hpp
6464
include/quite/value/object_query.hpp
6565
include/quite/injectors/mouse_injector.hpp
66+
include/quite/core/bit.hpp
67+
include/quite/core/bit_flags.hpp
68+
include/quite/core/bit_flags_fmt.hpp
6669
FILE_SET export_config
6770
TYPE HEADERS
6871
BASE_DIRS ${CMAKE_CURRENT_BINARY_DIR}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-FileCopyrightText: 2025 Mathis Logemann <[email protected]>
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
#pragma once
6+
#include <concepts>
7+
8+
namespace quite
9+
{
10+
template <std::integral T = unsigned int>
11+
constexpr T bit(std::size_t position)
12+
{
13+
return static_cast<T>(1) << position;
14+
}
15+
} // namespace quite
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// SPDX-FileCopyrightText: 2025 Mathis Logemann <[email protected]>
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
#pragma once
6+
#include <initializer_list>
7+
#include <type_traits>
8+
namespace quite
9+
{
10+
template <typename T>
11+
class BitFlags
12+
{
13+
using underlying_t = std::underlying_type_t<T>;
14+
15+
public:
16+
constexpr BitFlags()
17+
: flags_(static_cast<underlying_t>(0))
18+
{}
19+
20+
constexpr explicit BitFlags(T v)
21+
: flags_(to_underlying(v))
22+
{}
23+
24+
constexpr BitFlags(std::initializer_list<T> vs)
25+
: BitFlags()
26+
{
27+
for (T v : vs)
28+
{
29+
flags_ |= to_underlying(v);
30+
}
31+
}
32+
33+
constexpr bool is_set(T v) const
34+
{
35+
return (flags_ & to_underlying(v)) == to_underlying(v);
36+
}
37+
38+
constexpr void set(T v)
39+
{
40+
flags_ |= to_underlying(v);
41+
}
42+
43+
constexpr void unset(T v)
44+
{
45+
flags_ &= ~to_underlying(v);
46+
}
47+
48+
constexpr void clear()
49+
{
50+
flags_ = static_cast<underlying_t>(0);
51+
}
52+
53+
constexpr operator bool() const
54+
{
55+
return flags_ != static_cast<underlying_t>(0);
56+
}
57+
58+
friend constexpr BitFlags operator|(BitFlags lhs, T rhs)
59+
{
60+
return BitFlags(lhs.flags_ | to_underlying(rhs));
61+
}
62+
63+
friend constexpr BitFlags operator|(BitFlags lhs, BitFlags rhs)
64+
{
65+
return BitFlags(lhs.flags_ | rhs.flags_);
66+
}
67+
68+
friend constexpr BitFlags operator&(BitFlags lhs, T rhs)
69+
{
70+
return BitFlags(lhs.flags_ & to_underlying(rhs));
71+
}
72+
73+
friend constexpr BitFlags operator&(BitFlags lhs, BitFlags rhs)
74+
{
75+
return BitFlags(lhs.flags_ & rhs.flags_);
76+
}
77+
78+
friend constexpr BitFlags operator^(BitFlags lhs, T rhs)
79+
{
80+
return BitFlags(lhs.flags_ ^ to_underlying(rhs));
81+
}
82+
83+
friend constexpr BitFlags operator^(BitFlags lhs, BitFlags rhs)
84+
{
85+
return BitFlags(lhs.flags_ ^ rhs.flags_);
86+
}
87+
88+
friend constexpr BitFlags &operator|=(BitFlags &lhs, T rhs)
89+
{
90+
lhs.flags_ |= to_underlying(rhs);
91+
return lhs;
92+
}
93+
friend constexpr BitFlags &operator|=(BitFlags &lhs, BitFlags rhs)
94+
{
95+
lhs.flags_ |= rhs.flags_;
96+
return lhs;
97+
}
98+
friend constexpr BitFlags &operator&=(BitFlags &lhs, T rhs)
99+
{
100+
lhs.flags_ &= to_underlying(rhs);
101+
return lhs;
102+
}
103+
friend constexpr BitFlags &operator&=(BitFlags &lhs, BitFlags rhs)
104+
{
105+
lhs.flags_ &= rhs.flags_;
106+
return lhs;
107+
}
108+
friend constexpr BitFlags &operator^=(BitFlags &lhs, T rhs)
109+
{
110+
lhs.flags_ ^= to_underlying(rhs);
111+
return lhs;
112+
}
113+
friend constexpr BitFlags &operator^=(BitFlags &lhs, BitFlags rhs)
114+
{
115+
lhs.flags_ ^= rhs.flags_;
116+
return lhs;
117+
}
118+
119+
friend constexpr BitFlags operator~(const BitFlags &bf)
120+
{
121+
return BitFlags(~bf.flags_);
122+
}
123+
124+
friend constexpr bool operator==(const BitFlags &lhs, const BitFlags &rhs)
125+
{
126+
return lhs.flags_ == rhs.flags_;
127+
}
128+
129+
friend constexpr bool operator!=(const BitFlags &lhs, const BitFlags &rhs)
130+
{
131+
return lhs.flags_ != rhs.flags_;
132+
}
133+
134+
// Construct BitFlags from raw values.
135+
static constexpr BitFlags from_raw(underlying_t flags)
136+
{
137+
return BitFlags(flags);
138+
}
139+
140+
// Retrieve the raw underlying flags.
141+
constexpr underlying_t to_raw() const
142+
{
143+
return flags_;
144+
}
145+
146+
private:
147+
constexpr explicit BitFlags(underlying_t flags)
148+
: flags_(flags)
149+
{}
150+
static constexpr underlying_t to_underlying(T v)
151+
{
152+
return static_cast<underlying_t>(v);
153+
}
154+
underlying_t flags_;
155+
};
156+
} // namespace quite
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-FileCopyrightText: 2025 Mathis Logemann <[email protected]>
2+
//
3+
// SPDX-License-Identifier: MIT
4+
5+
#pragma once
6+
#include <format>
7+
#include "quite/core/bit_flags.hpp"
8+
9+
template <typename T>
10+
struct std::formatter<quite::BitFlags<T>>
11+
{
12+
constexpr auto parse(std::format_parse_context &ctx)
13+
{
14+
return ctx.begin();
15+
}
16+
17+
auto format(const quite::BitFlags<T> &bf, std::format_context &ctx) const
18+
{
19+
using underlying_t = std::underlying_type_t<T>;
20+
constexpr size_t kNumBits = sizeof(underlying_t) * 8;
21+
auto val = bf.to_raw();
22+
23+
// Format as binary string
24+
std::string binary;
25+
binary.reserve(kNumBits);
26+
for (size_t i = 0; i < kNumBits; ++i)
27+
{
28+
binary = ((val & 1) ? '1' : '0') + binary;
29+
val >>= 1;
30+
}
31+
32+
return std::format_to(ctx.out(), "{}", binary);
33+
}
34+
};

libs/core/include/quite/keyboard.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
// SPDX-License-Identifier: MIT
44

55
#pragma once
6+
#include "quite/core/bit.hpp"
7+
68
namespace quite
79
{
810
enum class KeyboardModifier
911
{
10-
none,
11-
shift,
12-
control,
13-
alt,
14-
meta,
12+
none = 0,
13+
shift = bit(0),
14+
control = bit(1),
15+
alt = bit(2),
16+
meta = bit(3),
1517
};
1618
} // namespace quite

libs/core/test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ add_sanitizers(core_test)
77
target_link_libraries(core_test PRIVATE quite::core Boost::ut)
88
add_test(NAME core_test COMMAND core_test)
99

10-
target_sources(core_test PRIVATE test_error.cpp)
10+
target_sources(core_test PRIVATE test_error.cpp test_bit_flags.cpp)

0 commit comments

Comments
 (0)