Gazebo Common

API Reference

5.7.0
gz/common/FlagSet.hh
Go to the documentation of this file.
1 /*
2  * MIT License
3  *
4  * Copyright (c) 2019 Arnaud Kapp (Xaqq), Barry Revzin, Mart Sõmermaa
5  * Copyright (c) 2020 Martin Pecka
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 #ifndef GZ_COMMON_FLAGSET_HH
26 #define GZ_COMMON_FLAGSET_HH
27 
28 // FlagSet is a type-safe class for using enums as flags in C++14 with an
29 // underlying std::bitset.
30 // See https://github.com/mrts/flag-set-cpp
31 // Licence: MIT
32 
33 #include <bitset>
34 #include <iostream>
35 #include <cassert>
36 #include <string>
37 
38 namespace gz::common
39 {
40 
58 template<typename T, T LastElement = T::_, bool ExcludeLast = true>
59 class FlagSet
60 {
62  public: FlagSet() = default;
63 
69  // cppcheck-suppress noExplicitConstructor
70  public: FlagSet(const T& _val)
71  {
72  flags.set(static_cast<UnderlyingType>(_val));
73  }
74 
77  public: explicit FlagSet(const std::initializer_list<T>& _list)
78  {
79  for (const auto& val : _list)
80  {
81  flags.set(static_cast<UnderlyingType>(val));
82  }
83  }
84 
85  // Binary operations.
86 
91  public: FlagSet& operator&=(const T& _val) noexcept
92  {
93  bool tmp = flags.test(static_cast<UnderlyingType>(_val));
94  flags.reset();
95  flags.set(static_cast<UnderlyingType>(_val), tmp);
96  return *this;
97  }
98 
102  public: FlagSet& operator&=(const FlagSet& _o) noexcept
103  {
104  flags &= _o.flags;
105  return *this;
106  }
107 
111  public: FlagSet& operator|=(const T& _val) noexcept
112  {
113  flags.set(static_cast<UnderlyingType>(_val));
114  return *this;
115  }
116 
120  public: FlagSet& operator|=(const FlagSet& _o) noexcept
121  {
122  flags |= _o.flags;
123  return *this;
124  }
125 
131  public: FlagSet operator&(const T& _val) const
132  {
133  FlagSet ret(*this);
134  ret &= _val;
135 
136  assert(ret.flags.count() <= 1);
137  return ret;
138  }
139 
143  public: FlagSet operator&(const FlagSet& _val) const
144  {
145  FlagSet ret(*this);
146  ret.flags &= _val.flags;
147 
148  return ret;
149  }
150 
155  public: FlagSet operator|(const T& _val) const
156  {
157  FlagSet ret(*this);
158  ret |= _val;
159 
160  assert(ret.flags.count() >= 1);
161  return ret;
162  }
163 
167  public: FlagSet operator|(const FlagSet& _val) const
168  {
169  FlagSet ret(*this);
170  ret.flags |= _val.flags;
171 
172  return ret;
173  }
174 
177  public: FlagSet operator~() const
178  {
179  FlagSet cp(*this);
180  cp.flags.flip();
181 
182  return cp;
183  }
184 
187  public: explicit operator bool() const
188  {
189  return flags.any();
190  }
191 
192  // Methods from std::bitset.
193 
197  public: bool operator==(const FlagSet& _o) const
198  {
199  return flags == _o.flags;
200  }
201 
205  public: bool operator!=(const FlagSet& _o) const
206  {
207  return !(*this == _o);
208  }
209 
214  public: std::size_t Size() const
215  {
216  return flags.size();
217  }
218 
222  public: std::size_t Count() const
223  {
224  return flags.count();
225  }
226 
229  public: FlagSet& Set()
230  {
231  flags.set();
232  return *this;
233  }
234 
237  public: FlagSet& Reset()
238  {
239  flags.reset();
240  return *this;
241  }
242 
245  public: FlagSet& Flip()
246  {
247  flags.flip();
248  return *this;
249  }
250 
255  public: FlagSet& Set(const T& _val, bool _value = true)
256  {
257  flags.set(static_cast<UnderlyingType>(_val), _value);
258  return *this;
259  }
260 
264  public: FlagSet& Reset(const T& _val)
265  {
266  flags.reset(static_cast<UnderlyingType>(_val));
267  return *this;
268  }
269 
273  public: FlagSet& Flip(const T& _val)
274  {
275  flags.flip(static_cast<UnderlyingType>(_val));
276  return *this;
277  }
278 
281  public: bool Any() const
282  {
283  return flags.any();
284  }
285 
288  public: bool All() const
289  {
290  return flags.all();
291  }
292 
295  public: bool None() const
296  {
297  return flags.none();
298  }
299 
301  public: static FlagSet AllSet()
302  {
303  return FlagSet().Set();
304  }
305 
307  public: static FlagSet NoneSet()
308  {
309  return FlagSet();
310  }
311 
316  public: constexpr bool operator[](const T& _val) const
317  {
318  return flags[static_cast<size_t>(static_cast<UnderlyingType>(_val))];
319  }
320 
323  public: std::string String() const
324  {
325  return flags.to_string();
326  }
327 
332  public: friend std::ostream& operator<<(std::ostream& _stream,
333  const FlagSet& _self)
334  {
335  return _stream << _self.flags;
336  }
337 
340  public: size_t Hash() const
341  {
342  return std::hash<decltype(this->flags)>{}(this->flags);
343  }
344 
346  private: using UnderlyingType = std::underlying_type_t<T>;
347 
349  public: static constexpr size_t numElements = static_cast<size_t>(
350  static_cast<UnderlyingType>(LastElement) +
351  static_cast<UnderlyingType>(1 - ExcludeLast));
352 
354  private: std::bitset<numElements> flags;
355 };
356 
357 template<typename T, typename = void>
359 {
360 };
361 
362 template<typename T>
363 struct IsEnumThatContainsSentinel<T, decltype(static_cast<void>(T::_))>
364  : std::is_enum<T>
365 {
366 };
367 
368 }
369 
370 // Operator that combines two enumeration values into a FlagSet only if the
371 // enumeration contains the sentinel `_`.
372 template<typename T>
373 std::enable_if_t<
376 >
377 operator|(const T& _lhs, const T& _rhs)
378 {
380  fs |= _lhs;
381  fs |= _rhs;
382 
383  return fs;
384 }
385 
386 namespace std
387 {
388 template<typename T, T LastElement, bool ExcludeLast>
389 struct hash<gz::common::FlagSet<T, LastElement, ExcludeLast>>
390 {
393  const noexcept
394  {
395  return _s.Hash();
396  }
397 };
398 }
399 
400 #endif