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(Flags<Enum>);
74 constexpr explicit AtomicFlags(Enum);
75 constexpr AtomicFlags(std::initializer_list<Enum>);
76
77 explicit operator bool() const;
78 /*implicit*/ operator Flags<Enum>() const;
79 Flags<Enum> Load(std::memory_order = std::memory_order_seq_cst) const;
80
81 AtomicFlags& operator=(Flags<Enum>);
82 AtomicFlags& Store(Flags<Enum>, std::memory_order = std::memory_order_seq_cst);
83 Flags<Enum> Exchange(Flags<Enum>);
84
85 AtomicFlags& operator|=(Flags<Enum>);
86 AtomicFlags& operator&=(Flags<Enum>);
87 AtomicFlags& Clear(Flags<Enum>);
88 Flags<Enum> FetchOr(Flags<Enum>, std::memory_order = std::memory_order_seq_cst);
89 Flags<Enum> FetchAnd(Flags<Enum>, std::memory_order = std::memory_order_seq_cst);
90 Flags<Enum> FetchClear(Flags<Enum>, std::memory_order = std::memory_order_seq_cst);
91 bool CompareExchangeWeak(
92 Flags<Enum>& expected,
93 Flags<Enum> desired,
94 std::memory_order order = std::memory_order_seq_cst
95 );
96 bool CompareExchangeStrong(
97 Flags<Enum>& expected,
98 Flags<Enum> desired,
99 std::memory_order order = std::memory_order_seq_cst
100 );
101 bool CompareExchangeWeak(
102 Flags<Enum>& expected,
103 Flags<Enum> desired,
104 std::memory_order success,
105 std::memory_order failure
106 );
107 bool CompareExchangeStrong(
108 Flags<Enum>& expected,
109 Flags<Enum> desired,
110 std::memory_order success,
111 std::memory_order failure
112 );
113
114 Flags<Enum> operator|(Flags<Enum>) const;
115 Flags<Enum> operator&(Flags<Enum>) const;
116
117 bool operator==(Flags<Enum>) const;
118 bool operator!=(Flags<Enum>) const;
119
120 ValueType GetValue();
121
122private:
123 std::atomic<ValueType> value_;
124};
125
126template <typename Enum>
127Flags<Enum> operator|(Enum, const AtomicFlags<Enum>&);
128
129template <typename Enum>
130Flags<Enum> operator&(Enum, const AtomicFlags<Enum>&);
131
132template <typename Enum>
133bool operator==(Enum, const AtomicFlags<Enum>&);
134
135template <typename Enum>
136bool operator!=(Enum, const AtomicFlags<Enum>&);
137
138template <typename Enum>
139constexpr Flags<Enum>::Flags(Enum value) noexcept : value_(static_cast<ValueType>(value)) {}
140
141template <typename Enum>
142constexpr Flags<Enum>::Flags(std::initializer_list<Enum> values) noexcept : Flags() {
143 for (Enum value : values) {
144 *this |= value;
145 }
146}
147
148template <typename Enum>
149constexpr Flags<Enum>::operator bool() const {
150 return !!value_;
151}
152
153template <typename Enum>
154constexpr Flags<Enum>& Flags<Enum>::operator|=(Flags rhs) {
155 value_ |= rhs.value_;
156 return *this;
157}
158
159template <typename Enum>
160constexpr Flags<Enum>& Flags<Enum>::operator&=(Flags rhs) {
161 value_ &= rhs.value_;
162 return *this;
163}
164
165template <typename Enum>
166constexpr Flags<Enum>& Flags<Enum>::Clear(Flags flags) {
167 value_ &= ~flags.value_;
168 return *this;
169}
170
171template <typename Enum>
172constexpr Flags<Enum> Flags<Enum>::operator|(Flags rhs) const {
173 return Flags(*this) |= rhs;
174}
175
176template <typename Enum>
177constexpr Flags<Enum> Flags<Enum>::operator&(Flags rhs) const {
178 return Flags(*this) &= rhs;
179}
180
181template <typename Enum>
182constexpr bool Flags<Enum>::operator==(Flags rhs) const {
183 return value_ == rhs.value_;
184}
185
186template <typename Enum>
187constexpr bool Flags<Enum>::operator!=(Flags rhs) const {
188 return !(*this == rhs);
189}
190
191template <typename Enum>
192constexpr typename Flags<Enum>::ValueType Flags<Enum>::GetValue() const {
193 return this->value_;
194}
195
196template <typename Enum>
197constexpr void Flags<Enum>::SetValue(typename Flags<Enum>::ValueType value) {
198 this->value_ = value;
199}
200
201template <typename Enum>
202constexpr Flags<Enum> operator|(Enum lhs, Flags<Enum> rhs) {
203 return rhs |= lhs;
204}
205
206template <typename Enum>
207constexpr Flags<Enum> operator&(Enum lhs, Flags<Enum> rhs) {
208 return rhs &= lhs;
209}
210
211template <typename Enum>
212constexpr bool operator==(Enum lhs, Flags<Enum> rhs) {
213 return rhs == Flags<Enum>{lhs};
214}
215
216template <typename Enum>
217constexpr bool operator!=(Enum lhs, Flags<Enum> rhs) {
218 return rhs != Flags<Enum>{lhs};
219}
220
221template <typename Enum>
222constexpr AtomicFlags<Enum>::AtomicFlags(Flags<Enum> flags)
223 : value_(flags.GetValue())
224{}
225
226template <typename Enum>
227constexpr AtomicFlags<Enum>::AtomicFlags(Enum value)
228 : AtomicFlags(Flags<Enum>(value))
229{}
230
231template <typename Enum>
232constexpr AtomicFlags<Enum>::AtomicFlags(std::initializer_list<Enum> values)
233 : AtomicFlags(Flags<Enum>(values))
234{}
235
236template <typename Enum>
237AtomicFlags<Enum>::operator bool() const {
238 return !!value_;
239}
240
241template <typename Enum>
242AtomicFlags<Enum>::operator Flags<Enum>() const {
243 return Load();
244}
245
246template <typename Enum>
247Flags<Enum> AtomicFlags<Enum>::Load(std::memory_order order) const {
248 return static_cast<Enum>(value_.load(order));
249}
250
251template <typename Enum>
252AtomicFlags<Enum>& AtomicFlags<Enum>::operator=(Flags<Enum> rhs) {
253 Store(rhs);
254 return *this;
255}
256
257template <typename Enum>
258AtomicFlags<Enum>& AtomicFlags<Enum>::Store(Flags<Enum> rhs, std::memory_order order) {
259 value_.store(rhs.value_, order);
260 return *this;
261}
262
263template <typename Enum>
264Flags<Enum> AtomicFlags<Enum>::Exchange(Flags<Enum> flags) {
265 return static_cast<Enum>(value_.exchange(flags.value_));
266}
267
268template <typename Enum>
269AtomicFlags<Enum>& AtomicFlags<Enum>::operator|=(Flags<Enum> rhs) {
270 FetchOr(rhs);
271 return *this;
272}
273
274template <typename Enum>
275AtomicFlags<Enum>& AtomicFlags<Enum>::operator&=(Flags<Enum> rhs) {
276 FetchAnd(rhs);
277 return *this;
278}
279
280template <typename Enum>
281AtomicFlags<Enum>& AtomicFlags<Enum>::Clear(Flags<Enum> flags) {
282 FetchClear(flags);
283 return *this;
284}
285
286template <typename Enum>
287Flags<Enum> AtomicFlags<Enum>::FetchOr(Flags<Enum> rhs, std::memory_order memory_order) {
288 return static_cast<Enum>(value_.fetch_or(rhs.value_, memory_order));
289}
290
291template <typename Enum>
292Flags<Enum> AtomicFlags<Enum>::FetchAnd(Flags<Enum> rhs, std::memory_order memory_order) {
293 return static_cast<Enum>(value_.fetch_and(rhs.value_, memory_order));
294}
295
296template <typename Enum>
297Flags<Enum> AtomicFlags<Enum>::FetchClear(Flags<Enum> flags, std::memory_order memory_order) {
298 return static_cast<Enum>(value_.fetch_and(~flags.value_, memory_order));
299}
300
301template <typename Enum>
302bool AtomicFlags<Enum>::CompareExchangeWeak(Flags<Enum>& expected, Flags<Enum> desired, std::memory_order order) {
303 auto expected_int = expected.GetValue();
304 const bool result = value_.compare_exchange_weak(expected_int, desired.GetValue(), order);
305 expected = Enum{expected_int};
306 return result;
307}
308
309template <typename Enum>
310bool AtomicFlags<Enum>::CompareExchangeStrong(Flags<Enum>& expected, Flags<Enum> desired, std::memory_order order) {
311 auto expected_int = expected.GetValue();
312 const bool result = value_.compare_exchange_strong(expected_int, desired.GetValue(), order);
313 expected = Enum{expected_int};
314 return result;
315}
316
317template <typename Enum>
318bool AtomicFlags<Enum>::CompareExchangeWeak(
319 Flags<Enum>& expected,
320 Flags<Enum> desired,
321 std::memory_order success,
322 std::memory_order failure
323) {
324 auto expected_int = expected.GetValue();
325 const bool result = value_.compare_exchange_weak(expected_int, desired.GetValue(), success, failure);
326 expected = Enum{expected_int};
327 return result;
328}
329
330template <typename Enum>
331bool AtomicFlags<Enum>::CompareExchangeStrong(
332 Flags<Enum>& expected,
333 Flags<Enum> desired,
334 std::memory_order success,
335 std::memory_order failure
336) {
337 auto expected_int = expected.GetValue();
338 const bool result = value_.compare_exchange_strong(expected_int, desired.GetValue(), success, failure);
339 expected = Enum{expected_int};
340 return result;
341}
342
343template <typename Enum>
344Flags<Enum> AtomicFlags<Enum>::operator|(Flags<Enum> rhs) const {
345 return Flags<Enum>{*this} |= rhs;
346}
347
348template <typename Enum>
349Flags<Enum> AtomicFlags<Enum>::operator&(Flags<Enum> rhs) const {
350 return Flags<Enum>{*this} &= rhs;
351}
352
353template <typename Enum>
354bool AtomicFlags<Enum>::operator==(Flags<Enum> rhs) const {
355 return value_ == rhs.value_;
356}
357
358template <typename Enum>
359bool AtomicFlags<Enum>::operator!=(Flags<Enum> rhs) const {
360 return !(*this == rhs);
361}
362
363template <typename Enum>
364typename AtomicFlags<Enum>::ValueType AtomicFlags<Enum>::GetValue() {
365 return this->value_.load();
366}
367
368template <typename Enum>
369Flags<Enum> operator|(Enum lhs, const AtomicFlags<Enum>& rhs) {
370 return rhs | lhs;
371}
372
373template <typename Enum>
374Flags<Enum> operator&(Enum lhs, const AtomicFlags<Enum>& rhs) {
375 return rhs & lhs;
376}
377
378template <typename Enum>
379bool operator==(Enum lhs, const AtomicFlags<Enum>& rhs) {
380 return rhs == Flags<Enum>{lhs};
381}
382
383template <typename Enum>
384bool operator!=(Enum lhs, const AtomicFlags<Enum>& rhs) {
385 return rhs != Flags<Enum>{lhs};
386}
387
388} // namespace utils
389
390USERVER_NAMESPACE_END