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