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