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 {
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