MySQL 9.1.0
Source Code Documentation
flags.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2021, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_STDX_FLAGS_INCLUDED
27#define MYSQL_HARNESS_STDX_FLAGS_INCLUDED
28
29#include <bit> // popcount
30#include <type_traits>
31
32#include "mysql/harness/stdx/type_traits.h" // is_scoped_enum_v
33
34namespace stdx {
35
36// tags a class as flags-class
37template <class E, class Enabler = void>
38struct is_flags : public std::false_type {};
39
40template <class E>
41inline constexpr bool is_flags_v = is_flags<E>::value;
42
43/**
44 * a type-safe flags type.
45 *
46 * # abstract
47 *
48 * Using flags in the in C++ isn't very ergonimic:
49 *
50 * 1. using plain C-enum's isn't typesafe
51 * 2. using std::bitset requires bit-positions to set/reset/test them
52 * 3. scoped-enums (enum class) doesn't have operaters
53 *
54 * For ease of use it should be possible to have a flags-type which
55 * allows the type-safe operations:
56 *
57 * - flags = flags & flag
58 * - flags &= flag
59 * - flags = flags | flag
60 * - flags |= flag
61 * - flags = flags ^ flag
62 * - flags ^= flag
63 * - flags = ~flag
64 *
65 * - flag | flag -> flags
66 * - flag & flag -> flags
67 * - flag ^ flag -> flags
68 *
69 * # example
70 *
71 * @code{.cpp}
72 * // underlying scoped-enum
73 * enum class somebits {
74 * bit0 = 1 << 0,
75 * bit1 = 1 << 1,
76 * };
77 *
78 * // activate stdx::flags support for the scoped-enum
79 * namespace stdx {
80 * template<>
81 * struct is_flags<somebits> : std::true_type {}
82 * }
83 *
84 * { // default-construct + assignment
85 * stdx::flags<somebits> someflags;
86 *
87 * someflags = somebits::bit0 | somebits::bit1;
88 *
89 * // get the underlying bitvalue.
90 * std::cerr << someflags.underlying_value() << "\n";
91 * }
92 *
93 * { // direct initialization from enum
94 * stdx::flags<somebits> someflags{somebits::bit0 | somebits::bit1};
95 * }
96 *
97 * { // testing if bit set
98 * stdx::flags<somebits> someflags{somebits::bit0 | somebits::bit1};
99 *
100 * if (someflags & somebits::bit1) {} // true
101 * }
102 *
103 * { // setting raw value
104 * stdx::flags<somebits> someflags;
105 * someflags.underlying_value(3);
106 *
107 * if (someflags & somebits::bit0) {} // true
108 * if (someflags & somebits::bit1) {} // true
109 * }
110 * @endcode
111 *
112 * @tparam E a scoped enum that is tagged with stdx::is_flags.
113 */
114template <class E>
115class flags {
116 public:
117 static_assert(stdx::is_scoped_enum_v<E>,
118 "flags<E>, E must be a scoped enum type");
119 static_assert(is_flags_v<E>,
120 "flags<E>, E must be declared as flags-type via:"
121 "namespace stdx { template<> struct is_flags<...> : "
122 "std::true_type {};} ");
123
124 //!< type of the wrapped enum.
125 using enum_type = std::decay_t<E>;
126 //!< underlying integer type of the enum_type.
127 using underlying_type = std::underlying_type_t<enum_type>;
128 //!< implementation type of the underlying type.
129 using impl_type = std::make_unsigned_t<underlying_type>;
130 using size_type = std::size_t;
131
132 /**
133 * default constructor.
134 *
135 * initializes underlying_value to 0 (no-bits-set).
136 */
137 constexpr flags() = default;
138
139 constexpr flags(const flags &other) = default; //!< copy constructor.
140 constexpr flags(flags &&other) = default; //!< move constructor
141 constexpr flags &operator=(const flags &other) =
142 default; //!< copy assignment
143 constexpr flags &operator=(flags &&other) = default; //!< move assignment
144
145 /**
146 * converting constructor from enum_type.
147 */
148 constexpr flags(enum_type v) : v_{static_cast<impl_type>(v)} {}
149
150 /**
151 * check if any bit is set.
152 *
153 * @retval true at least one bit is set.
154 * @retval false no bit is set.
155 */
156 constexpr operator bool() const noexcept { return v_ != 0; }
157
158 /**
159 * check if no bit is set.
160 *
161 * @retval true no bit is set.
162 * @retval false at least one bit is set.
163 */
164 constexpr bool operator!() const noexcept { return !v_; }
165
166 /**
167 * negation of all bits.
168 *
169 * ~flags -> flags.
170 */
171 constexpr flags operator~() const noexcept {
172 return flags{static_cast<impl_type>(~v_)};
173 }
174
175 /**
176 * bit-or.
177 *
178 * flags |= flags.
179 */
180 constexpr flags &operator|=(const flags &other) noexcept {
181 v_ |= other.v_;
182 return *this;
183 }
184
185 /**
186 * bit-and.
187 *
188 * flags &= flags.
189 */
190 constexpr flags &operator&=(const flags &other) noexcept {
191 v_ &= other.v_;
192 return *this;
193 }
194
195 /**
196 * bit-xor.
197 *
198 * flag ^= flag
199 */
200 constexpr flags &operator^=(const flags &other) noexcept {
201 v_ ^= other.v_;
202 return *this;
203 }
204
205 /**
206 * bit-and.
207 *
208 * flags & flags -> flags
209 */
210 friend constexpr flags operator&(flags a, flags b) noexcept {
211 return flags{static_cast<impl_type>(a.v_ & b.v_)};
212 }
213
214 /**
215 * bit-or.
216 *
217 * flags | flags -> flags
218 */
219 friend constexpr flags operator|(flags a, flags b) noexcept {
220 return flags{static_cast<impl_type>(a.v_ | b.v_)};
221 }
222
223 /**
224 * bit-xor.
225 *
226 * flags ^ flags -> flags
227 */
228 friend constexpr flags operator^(flags a, flags b) noexcept {
229 return flags{static_cast<impl_type>(a.v_ ^ b.v_)};
230 }
231
232 /**
233 * set underlying value.
234 *
235 * @param v underlying value to set.
236 */
237 constexpr void underlying_value(underlying_type v) noexcept { v_ = v; }
238
239 /**
240 * get underlying value.
241 *
242 * @return underlying value.
243 */
244 constexpr underlying_type underlying_value() const noexcept { return v_; }
245
246 /**
247 * count bits set to true.
248 *
249 * @sa size()
250 *
251 * @return bits set to true.
252 */
253 [[nodiscard]] constexpr size_type count() const noexcept {
254 return std::popcount(v_);
255 }
256
257 /**
258 * returns number of bits the flag-type can hold.
259 *
260 * @sa count()
261 *
262 * @returns number of bits the flag-type can hold.
263 */
264 [[nodiscard]] constexpr size_type size() const noexcept {
265 return 8 * sizeof(underlying_type);
266 }
267
268 /**
269 * reset all flags to 0.
270 */
271 constexpr void reset() { v_ = 0; }
272
273 private:
274 constexpr explicit flags(impl_type v) noexcept : v_{v} {}
275
277};
278
279} // namespace stdx
280
281/**
282 * bit-or.
283 *
284 * E | E -> flags<E>;
285 *
286 * @return a flags<E> of bit-or(e1, e2).
287 */
288template <class E>
289constexpr auto operator|(E e1, E e2) noexcept
290 -> std::enable_if_t<stdx::is_flags<E>::value, stdx::flags<E>> {
291 return stdx::flags<E>(e1) | e2;
292}
293
294/**
295 * bit-and.
296 *
297 * E & E -> flags<E>;
298 *
299 * @return a flags<E> of bit-and(e1, e2).
300 */
301template <class E>
302constexpr auto operator&(E e1, E e2) noexcept
303 -> std::enable_if_t<stdx::is_flags<E>::value, stdx::flags<E>> {
304 return stdx::flags<E>(e1) & e2;
305}
306
307/**
308 * bit-xor.
309 *
310 * E ^ E -> flags<E>;
311 *
312 * @return a flags<E> of bit-xor(e1, e2).
313 */
314template <class E>
315constexpr auto operator^(E e1, E e2) noexcept
316 -> std::enable_if_t<stdx::is_flags<E>::value, stdx::flags<E>> {
317 return stdx::flags<E>(e1) ^ e2;
318}
319
320#endif
a type-safe flags type.
Definition: flags.h:115
constexpr flags & operator&=(const flags &other) noexcept
bit-and.
Definition: flags.h:190
std::make_unsigned_t< underlying_type > impl_type
Definition: flags.h:129
constexpr size_type size() const noexcept
returns number of bits the flag-type can hold.
Definition: flags.h:264
constexpr flags & operator=(flags &&other)=default
move assignment
constexpr flags(const flags &other)=default
copy constructor.
constexpr void underlying_value(underlying_type v) noexcept
set underlying value.
Definition: flags.h:237
constexpr friend flags operator^(flags a, flags b) noexcept
bit-xor.
Definition: flags.h:228
constexpr flags & operator=(const flags &other)=default
copy assignment
constexpr flags(flags &&other)=default
move constructor
constexpr bool operator!() const noexcept
check if no bit is set.
Definition: flags.h:164
std::decay_t< E > enum_type
underlying integer type of the enum_type.
Definition: flags.h:126
impl_type v_
Definition: flags.h:276
constexpr void reset()
reset all flags to 0.
Definition: flags.h:271
constexpr flags(enum_type v)
converting constructor from enum_type.
Definition: flags.h:148
constexpr friend flags operator&(flags a, flags b) noexcept
bit-and.
Definition: flags.h:210
std::size_t size_type
Definition: flags.h:130
constexpr size_type count() const noexcept
count bits set to true.
Definition: flags.h:253
constexpr flags & operator^=(const flags &other) noexcept
bit-xor.
Definition: flags.h:200
constexpr flags()=default
default constructor.
constexpr underlying_type underlying_value() const noexcept
get underlying value.
Definition: flags.h:244
std::underlying_type_t< enum_type > underlying_type
implementation type of the underlying type.
Definition: flags.h:128
constexpr flags operator~() const noexcept
negation of all bits.
Definition: flags.h:171
constexpr flags(impl_type v) noexcept
Definition: flags.h:274
constexpr friend flags operator|(flags a, flags b) noexcept
bit-or.
Definition: flags.h:219
constexpr flags & operator|=(const flags &other) noexcept
bit-or.
Definition: flags.h:180
constexpr auto operator|(E e1, E e2) noexcept -> std::enable_if_t< stdx::is_flags< E >::value, stdx::flags< E > >
bit-or.
Definition: flags.h:289
constexpr auto operator^(E e1, E e2) noexcept -> std::enable_if_t< stdx::is_flags< E >::value, stdx::flags< E > >
bit-xor.
Definition: flags.h:315
constexpr auto operator&(E e1, E e2) noexcept -> std::enable_if_t< stdx::is_flags< E >::value, stdx::flags< E > >
bit-and.
Definition: flags.h:302
Definition: bit.h:32
constexpr bool is_flags_v
Definition: flags.h:41
Definition: flags.h:38