userver: userver/utils/flags.hpp Source File
Loading...
Searching...
No Matches
flags.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/flags.hpp
4/// @brief Types that provide flags interface to enums
5
6#include <atomic>
7#include <initializer_list>
8#include <type_traits>
9
10USERVER_NAMESPACE_BEGIN
11
12namespace utils {
13
14template <typename Enum>
15class AtomicFlags;
16
17/// @ingroup userver_universal userver_containers
18///
19/// @brief Wrapper to extend enum with flags interface
20template <typename Enum>
21class Flags final {
22public:
23 using ValueType = std::underlying_type_t<Enum>;
24
25 constexpr Flags() noexcept : Flags(Enum::kNone) {}
26 /*implicit*/ constexpr Flags(Enum) noexcept;
27 constexpr Flags(std::initializer_list<Enum>) noexcept;
28
29 constexpr explicit operator bool() const;
30
31 constexpr Flags& operator|=(Flags);
32 constexpr Flags& operator&=(Flags);
33 constexpr Flags& Clear(Flags);
34
35 constexpr Flags operator|(Flags) const;
36 constexpr Flags operator&(Flags) const;
37
38 constexpr bool operator==(Flags) const;
39 constexpr bool operator!=(Flags) const;
40
41 constexpr ValueType GetValue() const;
42 constexpr void SetValue(ValueType value);
43
44private:
45 friend class AtomicFlags<Enum>;
46
47 ValueType value_;
48};
49
50template <typename Enum>
51constexpr Flags<Enum> operator|(Enum, Flags<Enum>);
52
53template <typename Enum>
54constexpr Flags<Enum> operator&(Enum, Flags<Enum>);
55
56template <typename Enum>
57constexpr bool operator==(Enum, Flags<Enum>);
58
59template <typename Enum>
60constexpr bool operator!=(Enum, Flags<Enum>);
61
62/// @ingroup userver_universal userver_containers
63///
64/// @brief Wrapper to extend enum with atomic flags interface
65template <typename Enum>
66class AtomicFlags final {
67public:
68 using ValueType = std::underlying_type_t<Enum>;
69
70 constexpr AtomicFlags()
71 : AtomicFlags(Enum::kNone)
72 {}
73 constexpr explicit AtomicFlags(Enum);
74 constexpr AtomicFlags(std::initializer_list<Enum>);
75
76 explicit operator bool() const;
77 /*implicit*/ operator Flags<Enum>() const;
78 Flags<Enum> Load(std::memory_order = std::memory_order_seq_cst) const;
79
80 AtomicFlags& operator=(Flags<Enum>);
81 AtomicFlags& Store(Flags<Enum>, std::memory_order = std::memory_order_seq_cst);
82 Flags<Enum> Exchange(Flags<Enum>);
83
84 AtomicFlags& operator|=(Flags<Enum>);
85 AtomicFlags& operator&=(Flags<Enum>);
86 AtomicFlags& Clear(Flags<Enum>);
87 Flags<Enum> FetchOr(Flags<Enum>, std::memory_order = std::memory_order_seq_cst);
88 Flags<Enum> FetchAnd(Flags<Enum>, std::memory_order = std::memory_order_seq_cst);
89 Flags<Enum> FetchClear(Flags<Enum>, std::memory_order = std::memory_order_seq_cst);
90 bool CompareExchangeWeak(
91 Flags<Enum>& expected,
92 Flags<Enum> desired,
93 std::memory_order order = std::memory_order_seq_cst
94 );
95 bool CompareExchangeStrong(
96 Flags<Enum>& expected,
97 Flags<Enum> desired,
98 std::memory_order order = std::memory_order_seq_cst
99 );
100 bool CompareExchangeWeak(
101 Flags<Enum>& expected,
102 Flags<Enum> desired,
103 std::memory_order success,
104 std::memory_order failure
105 );
106 bool CompareExchangeStrong(
107 Flags<Enum>& expected,
108 Flags<Enum> desired,
109 std::memory_order success,
110 std::memory_order failure
111 );
112
113 Flags<Enum> operator|(Flags<Enum>) const;
114 Flags<Enum> operator&(Flags<Enum>) const;
115
116 bool operator==(Flags<Enum>) const;
117 bool operator!=(Flags<Enum>) const;
118
119 ValueType GetValue();
120
121private:
122 std::atomic<ValueType> value_;
123};
124
125template <typename Enum>
126Flags<Enum> operator|(Enum, const AtomicFlags<Enum>&);
127
128template <typename Enum>
129Flags<Enum> operator&(Enum, const AtomicFlags<Enum>&);
130
131template <typename Enum>
132bool operator==(Enum, const AtomicFlags<Enum>&);
133
134template <typename Enum>
135bool operator!=(Enum, const AtomicFlags<Enum>&);
136
137template <typename Enum>
138constexpr Flags<Enum>::Flags(Enum value) noexcept : value_(static_cast<ValueType>(value)) {}
139
140template <typename Enum>
141constexpr Flags<Enum>::Flags(std::initializer_list<Enum> values) noexcept : Flags() {
142 for (Enum value : values) {
143 *this |= value;
144 }
145}
146
147template <typename Enum>
148constexpr Flags<Enum>::operator bool() const {
149 return !!value_;
150}
151
152template <typename Enum>
153constexpr Flags<Enum>& Flags<Enum>::operator|=(Flags rhs) {
154 value_ |= rhs.value_;
155 return *this;
156}
157
158template <typename Enum>
159constexpr Flags<Enum>& Flags<Enum>::operator&=(Flags rhs) {
160 value_ &= rhs.value_;
161 return *this;
162}
163
164template <typename Enum>
165constexpr Flags<Enum>& Flags<Enum>::Clear(Flags flags) {
166 value_ &= ~flags.value_;
167 return *this;
168}
169
170template <typename Enum>
171constexpr Flags<Enum> Flags<Enum>::operator|(Flags rhs) const {
172 return Flags(*this) |= rhs;
173}
174
175template <typename Enum>
176constexpr Flags<Enum> Flags<Enum>::operator&(Flags rhs) const {
177 return Flags(*this) &= rhs;
178}
179
180template <typename Enum>
181constexpr bool Flags<Enum>::operator==(Flags rhs) const {
182 return value_ == rhs.value_;
183}
184
185template <typename Enum>
186constexpr bool Flags<Enum>::operator!=(Flags rhs) const {
187 return !(*this == rhs);
188}
189
190template <typename Enum>
191constexpr typename Flags<Enum>::ValueType Flags<Enum>::GetValue() const {
192 return this->value_;
193}
194
195template <typename Enum>
196constexpr void Flags<Enum>::SetValue(typename Flags<Enum>::ValueType value) {
197 this->value_ = value;
198}
199
200template <typename Enum>
201constexpr Flags<Enum> operator|(Enum lhs, Flags<Enum> rhs) {
202 return rhs |= lhs;
203}
204
205template <typename Enum>
206constexpr Flags<Enum> operator&(Enum lhs, Flags<Enum> rhs) {
207 return rhs &= lhs;
208}
209
210template <typename Enum>
211constexpr bool operator==(Enum lhs, Flags<Enum> rhs) {
212 return rhs == Flags<Enum>{lhs};
213}
214
215template <typename Enum>
216constexpr bool operator!=(Enum lhs, Flags<Enum> rhs) {
217 return rhs != Flags<Enum>{lhs};
218}
219
220template <typename Enum>
221constexpr AtomicFlags<Enum>::AtomicFlags(Enum value)
222 : value_(static_cast<ValueType>(value))
223{}
224
225template <typename Enum>
226constexpr AtomicFlags<Enum>::AtomicFlags(std::initializer_list<Enum> values)
227 : AtomicFlags(Enum(values))
228{}
229
230template <typename Enum>
231AtomicFlags<Enum>::operator bool() const {
232 return !!value_;
233}
234
235template <typename Enum>
236AtomicFlags<Enum>::operator Flags<Enum>() const {
237 return Load();
238}
239
240template <typename Enum>
241Flags<Enum> AtomicFlags<Enum>::Load(std::memory_order order) const {
242 return static_cast<Enum>(value_.load(order));
243}
244
245template <typename Enum>
246AtomicFlags<Enum>& AtomicFlags<Enum>::operator=(Flags<Enum> rhs) {
247 Store(rhs);
248 return *this;
249}
250
251template <typename Enum>
252AtomicFlags<Enum>& AtomicFlags<Enum>::Store(Flags<Enum> rhs, std::memory_order order) {
253 value_.store(rhs.value_, order);
254 return *this;
255}
256
257template <typename Enum>
258Flags<Enum> AtomicFlags<Enum>::Exchange(Flags<Enum> flags) {
259 return static_cast<Enum>(value_.exchange(flags.value_));
260}
261
262template <typename Enum>
263AtomicFlags<Enum>& AtomicFlags<Enum>::operator|=(Flags<Enum> rhs) {
264 FetchOr(rhs);
265 return *this;
266}
267
268template <typename Enum>
269AtomicFlags<Enum>& AtomicFlags<Enum>::operator&=(Flags<Enum> rhs) {
270 FetchAnd(rhs);
271 return *this;
272}
273
274template <typename Enum>
275AtomicFlags<Enum>& AtomicFlags<Enum>::Clear(Flags<Enum> flags) {
276 FetchClear(flags);
277 return *this;
278}
279
280template <typename Enum>
281Flags<Enum> AtomicFlags<Enum>::FetchOr(Flags<Enum> rhs, std::memory_order memory_order) {
282 return static_cast<Enum>(value_.fetch_or(rhs.value_, memory_order));
283}
284
285template <typename Enum>
286Flags<Enum> AtomicFlags<Enum>::FetchAnd(Flags<Enum> rhs, std::memory_order memory_order) {
287 return static_cast<Enum>(value_.fetch_and(rhs.value_, memory_order));
288}
289
290template <typename Enum>
291Flags<Enum> AtomicFlags<Enum>::FetchClear(Flags<Enum> flags, std::memory_order memory_order) {
292 return static_cast<Enum>(value_.fetch_and(~flags.value_, memory_order));
293}
294
295template <typename Enum>
296bool AtomicFlags<Enum>::CompareExchangeWeak(Flags<Enum>& expected, Flags<Enum> desired, std::memory_order order) {
297 auto expected_int = expected.GetValue();
298 const bool result = value_.compare_exchange_weak(expected_int, desired.GetValue(), order);
299 expected = Enum{expected_int};
300 return result;
301}
302
303template <typename Enum>
304bool AtomicFlags<Enum>::CompareExchangeStrong(Flags<Enum>& expected, Flags<Enum> desired, std::memory_order order) {
305 auto expected_int = expected.GetValue();
306 const bool result = value_.compare_exchange_strong(expected_int, desired.GetValue(), order);
307 expected = Enum{expected_int};
308 return result;
309}
310
311template <typename Enum>
312bool AtomicFlags<Enum>::CompareExchangeWeak(
313 Flags<Enum>& expected,
314 Flags<Enum> desired,
315 std::memory_order success,
316 std::memory_order failure
317) {
318 auto expected_int = expected.GetValue();
319 const bool result = value_.compare_exchange_weak(expected_int, desired.GetValue(), success, failure);
320 expected = Enum{expected_int};
321 return result;
322}
323
324template <typename Enum>
325bool AtomicFlags<Enum>::CompareExchangeStrong(
326 Flags<Enum>& expected,
327 Flags<Enum> desired,
328 std::memory_order success,
329 std::memory_order failure
330) {
331 auto expected_int = expected.GetValue();
332 const bool result = value_.compare_exchange_strong(expected_int, desired.GetValue(), success, failure);
333 expected = Enum{expected_int};
334 return result;
335}
336
337template <typename Enum>
338Flags<Enum> AtomicFlags<Enum>::operator|(Flags<Enum> rhs) const {
339 return Flags<Enum>{*this} |= rhs;
340}
341
342template <typename Enum>
343Flags<Enum> AtomicFlags<Enum>::operator&(Flags<Enum> rhs) const {
344 return Flags<Enum>{*this} &= rhs;
345}
346
347template <typename Enum>
348bool AtomicFlags<Enum>::operator==(Flags<Enum> rhs) const {
349 return value_ == rhs.value_;
350}
351
352template <typename Enum>
353bool AtomicFlags<Enum>::operator!=(Flags<Enum> rhs) const {
354 return !(*this == rhs);
355}
356
357template <typename Enum>
358typename AtomicFlags<Enum>::ValueType AtomicFlags<Enum>::GetValue() {
359 return this->value_.load();
360}
361
362template <typename Enum>
363Flags<Enum> operator|(Enum lhs, const AtomicFlags<Enum>& rhs) {
364 return rhs | lhs;
365}
366
367template <typename Enum>
368Flags<Enum> operator&(Enum lhs, const AtomicFlags<Enum>& rhs) {
369 return rhs & lhs;
370}
371
372template <typename Enum>
373bool operator==(Enum lhs, const AtomicFlags<Enum>& rhs) {
374 return rhs == Flags<Enum>{lhs};
375}
376
377template <typename Enum>
378bool operator!=(Enum lhs, const AtomicFlags<Enum>& rhs) {
379 return rhs != Flags<Enum>{lhs};
380}
381
382} // namespace utils
383
384USERVER_NAMESPACE_END