xref: /aosp_15_r20/external/cronet/base/containers/enum_set.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_CONTAINERS_ENUM_SET_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_ENUM_SET_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <bitset>
9*6777b538SAndroid Build Coastguard Worker #include <cstddef>
10*6777b538SAndroid Build Coastguard Worker #include <initializer_list>
11*6777b538SAndroid Build Coastguard Worker #include <string>
12*6777b538SAndroid Build Coastguard Worker #include <type_traits>
13*6777b538SAndroid Build Coastguard Worker #include <utility>
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
18*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker namespace base {
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker // Forward declarations needed for friend declarations.
23*6777b538SAndroid Build Coastguard Worker template <typename E, E MinEnumValue, E MaxEnumValue>
24*6777b538SAndroid Build Coastguard Worker class EnumSet;
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker template <typename E, E Min, E Max>
27*6777b538SAndroid Build Coastguard Worker constexpr EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1,
28*6777b538SAndroid Build Coastguard Worker                                      EnumSet<E, Min, Max> set2);
29*6777b538SAndroid Build Coastguard Worker 
30*6777b538SAndroid Build Coastguard Worker template <typename E, E Min, E Max>
31*6777b538SAndroid Build Coastguard Worker constexpr EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1,
32*6777b538SAndroid Build Coastguard Worker                                             EnumSet<E, Min, Max> set2);
33*6777b538SAndroid Build Coastguard Worker 
34*6777b538SAndroid Build Coastguard Worker template <typename E, E Min, E Max>
35*6777b538SAndroid Build Coastguard Worker constexpr EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1,
36*6777b538SAndroid Build Coastguard Worker                                           EnumSet<E, Min, Max> set2);
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker // An EnumSet is a set that can hold enum values between a min and a
39*6777b538SAndroid Build Coastguard Worker // max value (inclusive of both).  It's essentially a wrapper around
40*6777b538SAndroid Build Coastguard Worker // std::bitset<> with stronger type enforcement, more descriptive
41*6777b538SAndroid Build Coastguard Worker // member function names, and an iterator interface.
42*6777b538SAndroid Build Coastguard Worker //
43*6777b538SAndroid Build Coastguard Worker // If you're working with enums with a small number of possible values
44*6777b538SAndroid Build Coastguard Worker // (say, fewer than 64), you can efficiently pass around an EnumSet
45*6777b538SAndroid Build Coastguard Worker // for that enum around by value.
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker template <typename E, E MinEnumValue, E MaxEnumValue>
48*6777b538SAndroid Build Coastguard Worker class EnumSet {
49*6777b538SAndroid Build Coastguard Worker  private:
50*6777b538SAndroid Build Coastguard Worker   static_assert(
51*6777b538SAndroid Build Coastguard Worker       std::is_enum_v<E>,
52*6777b538SAndroid Build Coastguard Worker       "First template parameter of EnumSet must be an enumeration type");
53*6777b538SAndroid Build Coastguard Worker   using enum_underlying_type = std::underlying_type_t<E>;
54*6777b538SAndroid Build Coastguard Worker 
InRange(E value)55*6777b538SAndroid Build Coastguard Worker   static constexpr bool InRange(E value) {
56*6777b538SAndroid Build Coastguard Worker     return (value >= MinEnumValue) && (value <= MaxEnumValue);
57*6777b538SAndroid Build Coastguard Worker   }
58*6777b538SAndroid Build Coastguard Worker 
GetUnderlyingValue(E value)59*6777b538SAndroid Build Coastguard Worker   static constexpr enum_underlying_type GetUnderlyingValue(E value) {
60*6777b538SAndroid Build Coastguard Worker     return static_cast<enum_underlying_type>(value);
61*6777b538SAndroid Build Coastguard Worker   }
62*6777b538SAndroid Build Coastguard Worker 
63*6777b538SAndroid Build Coastguard Worker  public:
64*6777b538SAndroid Build Coastguard Worker   using EnumType = E;
65*6777b538SAndroid Build Coastguard Worker   static const E kMinValue = MinEnumValue;
66*6777b538SAndroid Build Coastguard Worker   static const E kMaxValue = MaxEnumValue;
67*6777b538SAndroid Build Coastguard Worker   static const size_t kValueCount =
68*6777b538SAndroid Build Coastguard Worker       GetUnderlyingValue(kMaxValue) - GetUnderlyingValue(kMinValue) + 1;
69*6777b538SAndroid Build Coastguard Worker 
70*6777b538SAndroid Build Coastguard Worker   static_assert(kMinValue <= kMaxValue,
71*6777b538SAndroid Build Coastguard Worker                 "min value must be no greater than max value");
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker  private:
74*6777b538SAndroid Build Coastguard Worker   // Declaration needed by Iterator.
75*6777b538SAndroid Build Coastguard Worker   using EnumBitSet = std::bitset<kValueCount>;
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker  public:
78*6777b538SAndroid Build Coastguard Worker   // Iterator is a forward-only read-only iterator for EnumSet. It follows the
79*6777b538SAndroid Build Coastguard Worker   // common STL input iterator interface (like std::unordered_set).
80*6777b538SAndroid Build Coastguard Worker   //
81*6777b538SAndroid Build Coastguard Worker   // Example usage, using a range-based for loop:
82*6777b538SAndroid Build Coastguard Worker   //
83*6777b538SAndroid Build Coastguard Worker   // EnumSet<SomeType> enums;
84*6777b538SAndroid Build Coastguard Worker   // for (SomeType val : enums) {
85*6777b538SAndroid Build Coastguard Worker   //   Process(val);
86*6777b538SAndroid Build Coastguard Worker   // }
87*6777b538SAndroid Build Coastguard Worker   //
88*6777b538SAndroid Build Coastguard Worker   // Or using an explicit iterator (not recommended):
89*6777b538SAndroid Build Coastguard Worker   //
90*6777b538SAndroid Build Coastguard Worker   // for (EnumSet<...>::Iterator it = enums.begin(); it != enums.end(); it++) {
91*6777b538SAndroid Build Coastguard Worker   //   Process(*it);
92*6777b538SAndroid Build Coastguard Worker   // }
93*6777b538SAndroid Build Coastguard Worker   //
94*6777b538SAndroid Build Coastguard Worker   // The iterator must not be outlived by the set. In particular, the following
95*6777b538SAndroid Build Coastguard Worker   // is an error:
96*6777b538SAndroid Build Coastguard Worker   //
97*6777b538SAndroid Build Coastguard Worker   // EnumSet<...> SomeFn() { ... }
98*6777b538SAndroid Build Coastguard Worker   //
99*6777b538SAndroid Build Coastguard Worker   // /* ERROR */
100*6777b538SAndroid Build Coastguard Worker   // for (EnumSet<...>::Iterator it = SomeFun().begin(); ...
101*6777b538SAndroid Build Coastguard Worker   //
102*6777b538SAndroid Build Coastguard Worker   // Also, there are no guarantees as to what will happen if you
103*6777b538SAndroid Build Coastguard Worker   // modify an EnumSet while traversing it with an iterator.
104*6777b538SAndroid Build Coastguard Worker   class Iterator {
105*6777b538SAndroid Build Coastguard Worker    public:
106*6777b538SAndroid Build Coastguard Worker     using value_type = EnumType;
107*6777b538SAndroid Build Coastguard Worker     using size_type = size_t;
108*6777b538SAndroid Build Coastguard Worker     using difference_type = ptrdiff_t;
109*6777b538SAndroid Build Coastguard Worker     using pointer = EnumType*;
110*6777b538SAndroid Build Coastguard Worker     using reference = EnumType&;
111*6777b538SAndroid Build Coastguard Worker     using iterator_category = std::forward_iterator_tag;
112*6777b538SAndroid Build Coastguard Worker 
Iterator()113*6777b538SAndroid Build Coastguard Worker     Iterator() : enums_(nullptr), i_(kValueCount) {}
114*6777b538SAndroid Build Coastguard Worker     ~Iterator() = default;
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker     friend bool operator==(const Iterator& lhs, const Iterator& rhs) {
117*6777b538SAndroid Build Coastguard Worker       return lhs.i_ == rhs.i_;
118*6777b538SAndroid Build Coastguard Worker     }
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker     value_type operator*() const {
121*6777b538SAndroid Build Coastguard Worker       DCHECK(Good());
122*6777b538SAndroid Build Coastguard Worker       return FromIndex(i_);
123*6777b538SAndroid Build Coastguard Worker     }
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker     Iterator& operator++() {
126*6777b538SAndroid Build Coastguard Worker       DCHECK(Good());
127*6777b538SAndroid Build Coastguard Worker       // If there are no more set elements in the bitset, this will result in an
128*6777b538SAndroid Build Coastguard Worker       // index equal to kValueCount, which is equivalent to EnumSet.end().
129*6777b538SAndroid Build Coastguard Worker       i_ = FindNext(i_ + 1);
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker       return *this;
132*6777b538SAndroid Build Coastguard Worker     }
133*6777b538SAndroid Build Coastguard Worker 
134*6777b538SAndroid Build Coastguard Worker     Iterator operator++(int) {
135*6777b538SAndroid Build Coastguard Worker       DCHECK(Good());
136*6777b538SAndroid Build Coastguard Worker       Iterator old(*this);
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker       // If there are no more set elements in the bitset, this will result in an
139*6777b538SAndroid Build Coastguard Worker       // index equal to kValueCount, which is equivalent to EnumSet.end().
140*6777b538SAndroid Build Coastguard Worker       i_ = FindNext(i_ + 1);
141*6777b538SAndroid Build Coastguard Worker 
142*6777b538SAndroid Build Coastguard Worker       return std::move(old);
143*6777b538SAndroid Build Coastguard Worker     }
144*6777b538SAndroid Build Coastguard Worker 
145*6777b538SAndroid Build Coastguard Worker    private:
146*6777b538SAndroid Build Coastguard Worker     friend Iterator EnumSet::begin() const;
147*6777b538SAndroid Build Coastguard Worker 
Iterator(const EnumBitSet & enums)148*6777b538SAndroid Build Coastguard Worker     explicit Iterator(const EnumBitSet& enums)
149*6777b538SAndroid Build Coastguard Worker         : enums_(&enums), i_(FindNext(0)) {}
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker     // Returns true iff the iterator points to an EnumSet and it
152*6777b538SAndroid Build Coastguard Worker     // hasn't yet traversed the EnumSet entirely.
Good()153*6777b538SAndroid Build Coastguard Worker     bool Good() const { return enums_ && i_ < kValueCount && enums_->test(i_); }
154*6777b538SAndroid Build Coastguard Worker 
FindNext(size_t i)155*6777b538SAndroid Build Coastguard Worker     size_t FindNext(size_t i) {
156*6777b538SAndroid Build Coastguard Worker       while ((i < kValueCount) && !enums_->test(i)) {
157*6777b538SAndroid Build Coastguard Worker         ++i;
158*6777b538SAndroid Build Coastguard Worker       }
159*6777b538SAndroid Build Coastguard Worker       return i;
160*6777b538SAndroid Build Coastguard Worker     }
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker     const raw_ptr<const EnumBitSet> enums_;
163*6777b538SAndroid Build Coastguard Worker     size_t i_;
164*6777b538SAndroid Build Coastguard Worker   };
165*6777b538SAndroid Build Coastguard Worker 
166*6777b538SAndroid Build Coastguard Worker   EnumSet() = default;
167*6777b538SAndroid Build Coastguard Worker 
168*6777b538SAndroid Build Coastguard Worker   ~EnumSet() = default;
169*6777b538SAndroid Build Coastguard Worker 
EnumSet(std::initializer_list<E> values)170*6777b538SAndroid Build Coastguard Worker   constexpr EnumSet(std::initializer_list<E> values) {
171*6777b538SAndroid Build Coastguard Worker     if (std::is_constant_evaluated()) {
172*6777b538SAndroid Build Coastguard Worker       enums_ = bitstring(values);
173*6777b538SAndroid Build Coastguard Worker     } else {
174*6777b538SAndroid Build Coastguard Worker       for (E value : values) {
175*6777b538SAndroid Build Coastguard Worker         Put(value);
176*6777b538SAndroid Build Coastguard Worker       }
177*6777b538SAndroid Build Coastguard Worker     }
178*6777b538SAndroid Build Coastguard Worker   }
179*6777b538SAndroid Build Coastguard Worker 
180*6777b538SAndroid Build Coastguard Worker   // Returns an EnumSet with all values between kMinValue and kMaxValue, which
181*6777b538SAndroid Build Coastguard Worker   // also contains undefined enum values if the enum in question has gaps
182*6777b538SAndroid Build Coastguard Worker   // between kMinValue and kMaxValue.
All()183*6777b538SAndroid Build Coastguard Worker   static constexpr EnumSet All() {
184*6777b538SAndroid Build Coastguard Worker     if (std::is_constant_evaluated()) {
185*6777b538SAndroid Build Coastguard Worker       if (kValueCount == 0) {
186*6777b538SAndroid Build Coastguard Worker         return EnumSet();
187*6777b538SAndroid Build Coastguard Worker       }
188*6777b538SAndroid Build Coastguard Worker       // Since `1 << kValueCount` may trigger shift-count-overflow warning if
189*6777b538SAndroid Build Coastguard Worker       // the `kValueCount` is 64, instead of returning `(1 << kValueCount) - 1`,
190*6777b538SAndroid Build Coastguard Worker       // the bitmask will be constructed from two parts: the most significant
191*6777b538SAndroid Build Coastguard Worker       // bits and the remaining.
192*6777b538SAndroid Build Coastguard Worker       uint64_t mask = 1ULL << (kValueCount - 1);
193*6777b538SAndroid Build Coastguard Worker       return EnumSet(EnumBitSet(mask - 1 + mask));
194*6777b538SAndroid Build Coastguard Worker     } else {
195*6777b538SAndroid Build Coastguard Worker       // When `kValueCount` is greater than 64, we can't use the constexpr path,
196*6777b538SAndroid Build Coastguard Worker       // and we will build an `EnumSet` value by value.
197*6777b538SAndroid Build Coastguard Worker       EnumSet enum_set;
198*6777b538SAndroid Build Coastguard Worker       for (size_t value = 0; value < kValueCount; ++value) {
199*6777b538SAndroid Build Coastguard Worker         enum_set.Put(FromIndex(value));
200*6777b538SAndroid Build Coastguard Worker       }
201*6777b538SAndroid Build Coastguard Worker       return enum_set;
202*6777b538SAndroid Build Coastguard Worker     }
203*6777b538SAndroid Build Coastguard Worker   }
204*6777b538SAndroid Build Coastguard Worker 
205*6777b538SAndroid Build Coastguard Worker   // Returns an EnumSet with all the values from start to end, inclusive.
FromRange(E start,E end)206*6777b538SAndroid Build Coastguard Worker   static constexpr EnumSet FromRange(E start, E end) {
207*6777b538SAndroid Build Coastguard Worker     CHECK_LE(start, end);
208*6777b538SAndroid Build Coastguard Worker     return EnumSet(EnumBitSet(
209*6777b538SAndroid Build Coastguard Worker         ((single_val_bitstring(end)) - (single_val_bitstring(start))) |
210*6777b538SAndroid Build Coastguard Worker         (single_val_bitstring(end))));
211*6777b538SAndroid Build Coastguard Worker   }
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker   // Copy constructor and assignment welcome.
214*6777b538SAndroid Build Coastguard Worker 
215*6777b538SAndroid Build Coastguard Worker   // Bitmask operations.
216*6777b538SAndroid Build Coastguard Worker   //
217*6777b538SAndroid Build Coastguard Worker   // This bitmask is 0-based and the value of the Nth bit depends on whether
218*6777b538SAndroid Build Coastguard Worker   // the set contains an enum element of integer value N.
219*6777b538SAndroid Build Coastguard Worker   //
220*6777b538SAndroid Build Coastguard Worker   // These may only be used if Min >= 0 and Max < 64.
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   // Returns an EnumSet constructed from |bitmask|.
FromEnumBitmask(const uint64_t bitmask)223*6777b538SAndroid Build Coastguard Worker   static constexpr EnumSet FromEnumBitmask(const uint64_t bitmask) {
224*6777b538SAndroid Build Coastguard Worker     static_assert(GetUnderlyingValue(kMaxValue) < 64,
225*6777b538SAndroid Build Coastguard Worker                   "The highest enum value must be < 64 for FromEnumBitmask ");
226*6777b538SAndroid Build Coastguard Worker     static_assert(GetUnderlyingValue(kMinValue) >= 0,
227*6777b538SAndroid Build Coastguard Worker                   "The lowest enum value must be >= 0 for FromEnumBitmask ");
228*6777b538SAndroid Build Coastguard Worker     return EnumSet(EnumBitSet(bitmask >> GetUnderlyingValue(kMinValue)));
229*6777b538SAndroid Build Coastguard Worker   }
230*6777b538SAndroid Build Coastguard Worker   // Returns a bitmask for the EnumSet.
ToEnumBitmask()231*6777b538SAndroid Build Coastguard Worker   uint64_t ToEnumBitmask() const {
232*6777b538SAndroid Build Coastguard Worker     static_assert(GetUnderlyingValue(kMaxValue) < 64,
233*6777b538SAndroid Build Coastguard Worker                   "The highest enum value must be < 64 for ToEnumBitmask ");
234*6777b538SAndroid Build Coastguard Worker     static_assert(GetUnderlyingValue(kMinValue) >= 0,
235*6777b538SAndroid Build Coastguard Worker                   "The lowest enum value must be >= 0 for FromEnumBitmask ");
236*6777b538SAndroid Build Coastguard Worker     return enums_.to_ullong() << GetUnderlyingValue(kMinValue);
237*6777b538SAndroid Build Coastguard Worker   }
238*6777b538SAndroid Build Coastguard Worker 
239*6777b538SAndroid Build Coastguard Worker   // Set operations.  Put, Retain, and Remove are basically
240*6777b538SAndroid Build Coastguard Worker   // self-mutating versions of Union, Intersection, and Difference
241*6777b538SAndroid Build Coastguard Worker   // (defined below).
242*6777b538SAndroid Build Coastguard Worker 
243*6777b538SAndroid Build Coastguard Worker   // Adds the given value (which must be in range) to our set.
Put(E value)244*6777b538SAndroid Build Coastguard Worker   void Put(E value) { enums_.set(ToIndex(value)); }
245*6777b538SAndroid Build Coastguard Worker 
246*6777b538SAndroid Build Coastguard Worker   // Adds all values in the given set to our set.
PutAll(EnumSet other)247*6777b538SAndroid Build Coastguard Worker   void PutAll(EnumSet other) { enums_ |= other.enums_; }
248*6777b538SAndroid Build Coastguard Worker 
249*6777b538SAndroid Build Coastguard Worker   // Adds all values in the given range to our set, inclusive.
PutRange(E start,E end)250*6777b538SAndroid Build Coastguard Worker   void PutRange(E start, E end) {
251*6777b538SAndroid Build Coastguard Worker     CHECK_LE(start, end);
252*6777b538SAndroid Build Coastguard Worker     size_t endIndexInclusive = ToIndex(end);
253*6777b538SAndroid Build Coastguard Worker     for (size_t current = ToIndex(start); current <= endIndexInclusive;
254*6777b538SAndroid Build Coastguard Worker          ++current) {
255*6777b538SAndroid Build Coastguard Worker       enums_.set(current);
256*6777b538SAndroid Build Coastguard Worker     }
257*6777b538SAndroid Build Coastguard Worker   }
258*6777b538SAndroid Build Coastguard Worker 
259*6777b538SAndroid Build Coastguard Worker   // There's no real need for a Retain(E) member function.
260*6777b538SAndroid Build Coastguard Worker 
261*6777b538SAndroid Build Coastguard Worker   // Removes all values not in the given set from our set.
RetainAll(EnumSet other)262*6777b538SAndroid Build Coastguard Worker   void RetainAll(EnumSet other) { enums_ &= other.enums_; }
263*6777b538SAndroid Build Coastguard Worker 
264*6777b538SAndroid Build Coastguard Worker   // If the given value is in range, removes it from our set.
Remove(E value)265*6777b538SAndroid Build Coastguard Worker   void Remove(E value) {
266*6777b538SAndroid Build Coastguard Worker     if (InRange(value)) {
267*6777b538SAndroid Build Coastguard Worker       enums_.reset(ToIndex(value));
268*6777b538SAndroid Build Coastguard Worker     }
269*6777b538SAndroid Build Coastguard Worker   }
270*6777b538SAndroid Build Coastguard Worker 
271*6777b538SAndroid Build Coastguard Worker   // Removes all values in the given set from our set.
RemoveAll(EnumSet other)272*6777b538SAndroid Build Coastguard Worker   void RemoveAll(EnumSet other) { enums_ &= ~other.enums_; }
273*6777b538SAndroid Build Coastguard Worker 
274*6777b538SAndroid Build Coastguard Worker   // Removes all values from our set.
Clear()275*6777b538SAndroid Build Coastguard Worker   void Clear() { enums_.reset(); }
276*6777b538SAndroid Build Coastguard Worker 
277*6777b538SAndroid Build Coastguard Worker   // Conditionally puts or removes `value`, based on `should_be_present`.
PutOrRemove(E value,bool should_be_present)278*6777b538SAndroid Build Coastguard Worker   void PutOrRemove(E value, bool should_be_present) {
279*6777b538SAndroid Build Coastguard Worker     if (should_be_present) {
280*6777b538SAndroid Build Coastguard Worker       Put(value);
281*6777b538SAndroid Build Coastguard Worker     } else {
282*6777b538SAndroid Build Coastguard Worker       Remove(value);
283*6777b538SAndroid Build Coastguard Worker     }
284*6777b538SAndroid Build Coastguard Worker   }
285*6777b538SAndroid Build Coastguard Worker 
286*6777b538SAndroid Build Coastguard Worker   // Returns true iff the given value is in range and a member of our set.
Has(E value)287*6777b538SAndroid Build Coastguard Worker   constexpr bool Has(E value) const {
288*6777b538SAndroid Build Coastguard Worker     return InRange(value) && enums_[ToIndex(value)];
289*6777b538SAndroid Build Coastguard Worker   }
290*6777b538SAndroid Build Coastguard Worker 
291*6777b538SAndroid Build Coastguard Worker   // Returns true iff the given set is a subset of our set.
HasAll(EnumSet other)292*6777b538SAndroid Build Coastguard Worker   bool HasAll(EnumSet other) const {
293*6777b538SAndroid Build Coastguard Worker     return (enums_ & other.enums_) == other.enums_;
294*6777b538SAndroid Build Coastguard Worker   }
295*6777b538SAndroid Build Coastguard Worker 
296*6777b538SAndroid Build Coastguard Worker   // Returns true if the given set contains any value of our set.
HasAny(EnumSet other)297*6777b538SAndroid Build Coastguard Worker   bool HasAny(EnumSet other) const {
298*6777b538SAndroid Build Coastguard Worker     return (enums_ & other.enums_).count() > 0;
299*6777b538SAndroid Build Coastguard Worker   }
300*6777b538SAndroid Build Coastguard Worker 
301*6777b538SAndroid Build Coastguard Worker   // Returns true iff our set is empty.
empty()302*6777b538SAndroid Build Coastguard Worker   bool empty() const { return !enums_.any(); }
303*6777b538SAndroid Build Coastguard Worker 
304*6777b538SAndroid Build Coastguard Worker   // Returns how many values our set has.
size()305*6777b538SAndroid Build Coastguard Worker   size_t size() const { return enums_.count(); }
306*6777b538SAndroid Build Coastguard Worker 
307*6777b538SAndroid Build Coastguard Worker   // Returns an iterator pointing to the first element (if any).
begin()308*6777b538SAndroid Build Coastguard Worker   Iterator begin() const { return Iterator(enums_); }
309*6777b538SAndroid Build Coastguard Worker 
310*6777b538SAndroid Build Coastguard Worker   // Returns an iterator that does not point to any element, but to the position
311*6777b538SAndroid Build Coastguard Worker   // that follows the last element in the set.
end()312*6777b538SAndroid Build Coastguard Worker   Iterator end() const { return Iterator(); }
313*6777b538SAndroid Build Coastguard Worker 
314*6777b538SAndroid Build Coastguard Worker   // Returns true iff our set and the given set contain exactly the same values.
315*6777b538SAndroid Build Coastguard Worker   friend bool operator==(const EnumSet&, const EnumSet&) = default;
316*6777b538SAndroid Build Coastguard Worker 
ToString()317*6777b538SAndroid Build Coastguard Worker   std::string ToString() const { return enums_.to_string(); }
318*6777b538SAndroid Build Coastguard Worker 
319*6777b538SAndroid Build Coastguard Worker  private:
320*6777b538SAndroid Build Coastguard Worker   friend constexpr EnumSet Union<E, MinEnumValue, MaxEnumValue>(EnumSet set1,
321*6777b538SAndroid Build Coastguard Worker                                                                 EnumSet set2);
322*6777b538SAndroid Build Coastguard Worker   friend constexpr EnumSet Intersection<E, MinEnumValue, MaxEnumValue>(
323*6777b538SAndroid Build Coastguard Worker       EnumSet set1,
324*6777b538SAndroid Build Coastguard Worker       EnumSet set2);
325*6777b538SAndroid Build Coastguard Worker   friend constexpr EnumSet Difference<E, MinEnumValue, MaxEnumValue>(
326*6777b538SAndroid Build Coastguard Worker       EnumSet set1,
327*6777b538SAndroid Build Coastguard Worker       EnumSet set2);
328*6777b538SAndroid Build Coastguard Worker 
bitstring(const std::initializer_list<E> & values)329*6777b538SAndroid Build Coastguard Worker   static constexpr uint64_t bitstring(const std::initializer_list<E>& values) {
330*6777b538SAndroid Build Coastguard Worker     uint64_t result = 0;
331*6777b538SAndroid Build Coastguard Worker     for (E value : values) {
332*6777b538SAndroid Build Coastguard Worker       result |= single_val_bitstring(value);
333*6777b538SAndroid Build Coastguard Worker     }
334*6777b538SAndroid Build Coastguard Worker     return result;
335*6777b538SAndroid Build Coastguard Worker   }
336*6777b538SAndroid Build Coastguard Worker 
single_val_bitstring(E val)337*6777b538SAndroid Build Coastguard Worker   static constexpr uint64_t single_val_bitstring(E val) {
338*6777b538SAndroid Build Coastguard Worker     const uint64_t bitstring = 1;
339*6777b538SAndroid Build Coastguard Worker     const size_t shift_amount = ToIndex(val);
340*6777b538SAndroid Build Coastguard Worker     CHECK_LT(shift_amount, sizeof(bitstring) * 8);
341*6777b538SAndroid Build Coastguard Worker     return bitstring << shift_amount;
342*6777b538SAndroid Build Coastguard Worker   }
343*6777b538SAndroid Build Coastguard Worker 
344*6777b538SAndroid Build Coastguard Worker   // A bitset can't be constexpr constructed if it has size > 64, since the
345*6777b538SAndroid Build Coastguard Worker   // constexpr constructor uses a uint64_t. If your EnumSet has > 64 values, you
346*6777b538SAndroid Build Coastguard Worker   // can safely remove the constepxr qualifiers from this file, at the cost of
347*6777b538SAndroid Build Coastguard Worker   // some minor optimizations.
EnumSet(EnumBitSet enums)348*6777b538SAndroid Build Coastguard Worker   explicit constexpr EnumSet(EnumBitSet enums) : enums_(enums) {
349*6777b538SAndroid Build Coastguard Worker     if (std::is_constant_evaluated()) {
350*6777b538SAndroid Build Coastguard Worker       CHECK(kValueCount <= 64)
351*6777b538SAndroid Build Coastguard Worker           << "Max number of enum values is 64 for constexpr constructor";
352*6777b538SAndroid Build Coastguard Worker     }
353*6777b538SAndroid Build Coastguard Worker   }
354*6777b538SAndroid Build Coastguard Worker 
355*6777b538SAndroid Build Coastguard Worker   // Converts a value to/from an index into |enums_|.
ToIndex(E value)356*6777b538SAndroid Build Coastguard Worker   static constexpr size_t ToIndex(E value) {
357*6777b538SAndroid Build Coastguard Worker     CHECK(InRange(value));
358*6777b538SAndroid Build Coastguard Worker     return static_cast<size_t>(GetUnderlyingValue(value)) -
359*6777b538SAndroid Build Coastguard Worker            static_cast<size_t>(GetUnderlyingValue(MinEnumValue));
360*6777b538SAndroid Build Coastguard Worker   }
361*6777b538SAndroid Build Coastguard Worker 
FromIndex(size_t i)362*6777b538SAndroid Build Coastguard Worker   static E FromIndex(size_t i) {
363*6777b538SAndroid Build Coastguard Worker     DCHECK_LT(i, kValueCount);
364*6777b538SAndroid Build Coastguard Worker     return static_cast<E>(GetUnderlyingValue(MinEnumValue) + i);
365*6777b538SAndroid Build Coastguard Worker   }
366*6777b538SAndroid Build Coastguard Worker 
367*6777b538SAndroid Build Coastguard Worker   EnumBitSet enums_;
368*6777b538SAndroid Build Coastguard Worker };
369*6777b538SAndroid Build Coastguard Worker 
370*6777b538SAndroid Build Coastguard Worker template <typename E, E MinEnumValue, E MaxEnumValue>
371*6777b538SAndroid Build Coastguard Worker const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMinValue;
372*6777b538SAndroid Build Coastguard Worker 
373*6777b538SAndroid Build Coastguard Worker template <typename E, E MinEnumValue, E MaxEnumValue>
374*6777b538SAndroid Build Coastguard Worker const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMaxValue;
375*6777b538SAndroid Build Coastguard Worker 
376*6777b538SAndroid Build Coastguard Worker template <typename E, E MinEnumValue, E MaxEnumValue>
377*6777b538SAndroid Build Coastguard Worker const size_t EnumSet<E, MinEnumValue, MaxEnumValue>::kValueCount;
378*6777b538SAndroid Build Coastguard Worker 
379*6777b538SAndroid Build Coastguard Worker // The usual set operations.
380*6777b538SAndroid Build Coastguard Worker 
381*6777b538SAndroid Build Coastguard Worker template <typename E, E Min, E Max>
Union(EnumSet<E,Min,Max> set1,EnumSet<E,Min,Max> set2)382*6777b538SAndroid Build Coastguard Worker constexpr EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1,
383*6777b538SAndroid Build Coastguard Worker                                      EnumSet<E, Min, Max> set2) {
384*6777b538SAndroid Build Coastguard Worker   return EnumSet<E, Min, Max>(set1.enums_ | set2.enums_);
385*6777b538SAndroid Build Coastguard Worker }
386*6777b538SAndroid Build Coastguard Worker 
387*6777b538SAndroid Build Coastguard Worker template <typename E, E Min, E Max>
Intersection(EnumSet<E,Min,Max> set1,EnumSet<E,Min,Max> set2)388*6777b538SAndroid Build Coastguard Worker constexpr EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1,
389*6777b538SAndroid Build Coastguard Worker                                             EnumSet<E, Min, Max> set2) {
390*6777b538SAndroid Build Coastguard Worker   return EnumSet<E, Min, Max>(set1.enums_ & set2.enums_);
391*6777b538SAndroid Build Coastguard Worker }
392*6777b538SAndroid Build Coastguard Worker 
393*6777b538SAndroid Build Coastguard Worker template <typename E, E Min, E Max>
Difference(EnumSet<E,Min,Max> set1,EnumSet<E,Min,Max> set2)394*6777b538SAndroid Build Coastguard Worker constexpr EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1,
395*6777b538SAndroid Build Coastguard Worker                                           EnumSet<E, Min, Max> set2) {
396*6777b538SAndroid Build Coastguard Worker   return EnumSet<E, Min, Max>(set1.enums_ & ~set2.enums_);
397*6777b538SAndroid Build Coastguard Worker }
398*6777b538SAndroid Build Coastguard Worker 
399*6777b538SAndroid Build Coastguard Worker }  // namespace base
400*6777b538SAndroid Build Coastguard Worker 
401*6777b538SAndroid Build Coastguard Worker #endif  // BASE_CONTAINERS_ENUM_SET_H_
402