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