1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef SYNC_INTERNAL_API_PUBLIC_BASE_ENUM_SET_H_
6 #define SYNC_INTERNAL_API_PUBLIC_BASE_ENUM_SET_H_
12 #include "base/basictypes.h"
13 #include "base/logging.h"
17 // Forward declarations needed for friend declarations.
18 template <typename E
, E MinEnumValue
, E MaxEnumValue
>
21 template <typename E
, E Min
, E Max
>
22 EnumSet
<E
, Min
, Max
> Union(EnumSet
<E
, Min
, Max
> set1
,
23 EnumSet
<E
, Min
, Max
> set2
);
25 template <typename E
, E Min
, E Max
>
26 EnumSet
<E
, Min
, Max
> Intersection(EnumSet
<E
, Min
, Max
> set1
,
27 EnumSet
<E
, Min
, Max
> set2
);
29 template <typename E
, E Min
, E Max
>
30 EnumSet
<E
, Min
, Max
> Difference(EnumSet
<E
, Min
, Max
> set1
,
31 EnumSet
<E
, Min
, Max
> set2
);
33 // An EnumSet is a set that can hold enum values between a min and a
34 // max value (inclusive of both). It's essentially a wrapper around
35 // std::bitset<> with stronger type enforcement, more descriptive
36 // member function names, and an iterator interface.
38 // If you're working with enums with a small number of possible values
39 // (say, fewer than 64), you can efficiently pass around an EnumSet
40 // for that enum around by value.
42 template <typename E
, E MinEnumValue
, E MaxEnumValue
>
46 static const E kMinValue
= MinEnumValue
;
47 static const E kMaxValue
= MaxEnumValue
;
48 static const size_t kValueCount
= kMaxValue
- kMinValue
+ 1;
49 static_assert(kMinValue
< kMaxValue
,
50 "min value must be less than max value");
53 // Declaration needed by Iterator.
54 typedef std::bitset
<kValueCount
> EnumBitSet
;
57 // Iterator is a forward-only read-only iterator for EnumSet. Its
58 // interface is deliberately distinct from an STL iterator as its
59 // semantics are substantially different.
63 // for (EnumSet<...>::Iterator it = enums.First(); it.Good(); it.Inc()) {
67 // The iterator must not be outlived by the set. In particular, the
68 // following is an error:
70 // EnumSet<...> SomeFn() { ... }
73 // for (EnumSet<...>::Iterator it = SomeFun().First(); ...
75 // Also, there are no guarantees as to what will happen if you
76 // modify an EnumSet while traversing it with an iterator.
79 // A default-constructed iterator can't do anything except check
80 // Good(). You need to call First() on an EnumSet to get a usable
82 Iterator() : enums_(NULL
), i_(kValueCount
) {}
85 // Copy constructor and assignment welcome.
87 // Returns true iff the iterator points to an EnumSet and it
88 // hasn't yet traversed the EnumSet entirely.
90 return enums_
&& i_
< kValueCount
&& enums_
->test(i_
);
93 // Returns the value the iterator currently points to. Good()
100 // Moves the iterator to the next value in the EnumSet. Good()
101 // must hold. Takes linear time.
104 i_
= FindNext(i_
+ 1);
108 friend Iterator
EnumSet::First() const;
110 explicit Iterator(const EnumBitSet
& enums
)
111 : enums_(&enums
), i_(FindNext(0)) {}
113 size_t FindNext(size_t i
) {
114 while ((i
< kValueCount
) && !enums_
->test(i
)) {
120 const EnumBitSet
* enums_
;
124 // You can construct an EnumSet with 0, 1, 2, or 3 initial values.
128 explicit EnumSet(E value
) {
132 EnumSet(E value1
, E value2
) {
137 EnumSet(E value1
, E value2
, E value3
) {
143 // Returns an EnumSet with all possible values.
144 static EnumSet
All() {
147 return EnumSet(enums
);
152 // Copy constructor and assignment welcome.
154 // Set operations. Put, Retain, and Remove are basically
155 // self-mutating versions of Union, Intersection, and Difference
158 // Adds the given value (which must be in range) to our set.
160 enums_
.set(ToIndex(value
));
163 // Adds all values in the given set to our set.
164 void PutAll(EnumSet other
) {
165 enums_
|= other
.enums_
;
168 // There's no real need for a Retain(E) member function.
170 // Removes all values not in the given set from our set.
171 void RetainAll(EnumSet other
) {
172 enums_
&= other
.enums_
;
175 // If the given value is in range, removes it from our set.
176 void Remove(E value
) {
177 if (InRange(value
)) {
178 enums_
.reset(ToIndex(value
));
182 // Removes all values in the given set from our set.
183 void RemoveAll(EnumSet other
) {
184 enums_
&= ~other
.enums_
;
187 // Removes all values from our set.
192 // Returns true iff the given value is in range and a member of our
194 bool Has(E value
) const {
195 return InRange(value
) && enums_
.test(ToIndex(value
));
198 // Returns true iff the given set is a subset of our set.
199 bool HasAll(EnumSet other
) const {
200 return (enums_
& other
.enums_
) == other
.enums_
;
203 // Returns true iff our set and the given set contain exactly the
205 bool Equals(const EnumSet
& other
) const {
206 return enums_
== other
.enums_
;
209 // Returns true iff our set is empty.
211 return !enums_
.any();
214 // Returns how many values our set has.
215 size_t Size() const {
216 return enums_
.count();
219 // Returns an iterator pointing to the first element (if any).
220 Iterator
First() const {
221 return Iterator(enums_
);
225 friend EnumSet Union
<E
, MinEnumValue
, MaxEnumValue
>(
226 EnumSet set1
, EnumSet set2
);
227 friend EnumSet Intersection
<E
, MinEnumValue
, MaxEnumValue
>(
228 EnumSet set1
, EnumSet set2
);
229 friend EnumSet Difference
<E
, MinEnumValue
, MaxEnumValue
>(
230 EnumSet set1
, EnumSet set2
);
232 explicit EnumSet(EnumBitSet enums
) : enums_(enums
) {}
234 static bool InRange(E value
) {
235 return (value
>= MinEnumValue
) && (value
<= MaxEnumValue
);
238 // Converts a value to/from an index into |enums_|.
240 static size_t ToIndex(E value
) {
241 DCHECK_GE(value
, MinEnumValue
);
242 DCHECK_LE(value
, MaxEnumValue
);
243 return value
- MinEnumValue
;
246 static E
FromIndex(size_t i
) {
247 DCHECK_LT(i
, kValueCount
);
248 return static_cast<E
>(MinEnumValue
+ i
);
254 template <typename E
, E MinEnumValue
, E MaxEnumValue
>
255 const E EnumSet
<E
, MinEnumValue
, MaxEnumValue
>::kMinValue
;
257 template <typename E
, E MinEnumValue
, E MaxEnumValue
>
258 const E EnumSet
<E
, MinEnumValue
, MaxEnumValue
>::kMaxValue
;
260 template <typename E
, E MinEnumValue
, E MaxEnumValue
>
261 const size_t EnumSet
<E
, MinEnumValue
, MaxEnumValue
>::kValueCount
;
263 // The usual set operations.
265 template <typename E
, E Min
, E Max
>
266 EnumSet
<E
, Min
, Max
> Union(EnumSet
<E
, Min
, Max
> set1
,
267 EnumSet
<E
, Min
, Max
> set2
) {
268 return EnumSet
<E
, Min
, Max
>(set1
.enums_
| set2
.enums_
);
271 template <typename E
, E Min
, E Max
>
272 EnumSet
<E
, Min
, Max
> Intersection(EnumSet
<E
, Min
, Max
> set1
,
273 EnumSet
<E
, Min
, Max
> set2
) {
274 return EnumSet
<E
, Min
, Max
>(set1
.enums_
& set2
.enums_
);
277 template <typename E
, E Min
, E Max
>
278 EnumSet
<E
, Min
, Max
> Difference(EnumSet
<E
, Min
, Max
> set1
,
279 EnumSet
<E
, Min
, Max
> set2
) {
280 return EnumSet
<E
, Min
, Max
>(set1
.enums_
& ~set2
.enums_
);
283 } // namespace syncer
285 #endif // SYNC_INTERNAL_API_PUBLIC_BASE_ENUM_SET_H_