OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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. |
| 4 |
| 5 #ifndef CHROME_BROWSER_SYNC_UTIL_ENUM_SET_H_ |
| 6 #define CHROME_BROWSER_SYNC_UTIL_ENUM_SET_H_ |
| 7 #pragma once |
| 8 |
| 9 #include <bitset> |
| 10 #include <cstddef> |
| 11 #include <string> |
| 12 |
| 13 #include "base/basictypes.h" |
| 14 #include "base/logging.h" |
| 15 |
| 16 namespace browser_sync { |
| 17 |
| 18 // Forward declarations needed for friend declarations. |
| 19 template <typename E, E MinEnumValue, E MaxEnumValue> |
| 20 class EnumSet; |
| 21 |
| 22 template <typename E, E Min, E Max> |
| 23 EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1, |
| 24 EnumSet<E, Min, Max> set2); |
| 25 |
| 26 template <typename E, E Min, E Max> |
| 27 EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1, |
| 28 EnumSet<E, Min, Max> set2); |
| 29 |
| 30 template <typename E, E Min, E Max> |
| 31 EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1, |
| 32 EnumSet<E, Min, Max> set2); |
| 33 |
| 34 // An EnumSet is a set that can hold enum values between a min and a |
| 35 // max value (inclusive of both). It's essentially a wrapper around |
| 36 // std::bitset<> with stronger type enforcement, more descriptive |
| 37 // member function names, and an iterator interface. |
| 38 // |
| 39 // If you're working with enums with a small number of possible values |
| 40 // (say, fewer than 64), you can efficiently pass around an EnumSet |
| 41 // for that enum around by value. |
| 42 |
| 43 template <typename E, E MinEnumValue, E MaxEnumValue> |
| 44 class EnumSet { |
| 45 public: |
| 46 typedef E EnumType; |
| 47 static const E kMinValue = MinEnumValue; |
| 48 static const E kMaxValue = MaxEnumValue; |
| 49 static const size_t kValueCount = kMaxValue - kMinValue + 1; |
| 50 COMPILE_ASSERT(kMinValue < kMaxValue, |
| 51 min_value_must_be_less_than_max_value); |
| 52 |
| 53 private: |
| 54 // Declaration needed by Iterator. |
| 55 typedef std::bitset<kValueCount> EnumBitSet; |
| 56 |
| 57 public: |
| 58 // Iterator is a forward-only read-only iterator for EnumSet. Its |
| 59 // interface is deliberately distinct from an STL iterator as its |
| 60 // semantics are substantially different. |
| 61 // |
| 62 // Example usage: |
| 63 // |
| 64 // for (EnumSet<...>::Iterator it = enums.First(); it.Good(); it.Inc()) { |
| 65 // Process(it.Get()); |
| 66 // } |
| 67 // |
| 68 // There are no guarantees as to what will happen if you modify an |
| 69 // EnumSet while traversing it with an iterator. |
| 70 class Iterator { |
| 71 public: |
| 72 // A default-constructed iterator can't do anything except check |
| 73 // Good(). You need to call First() on an EnumSet to get a usable |
| 74 // iterator. |
| 75 Iterator() : enums_(NULL), i_(kValueCount) {} |
| 76 ~Iterator() {} |
| 77 |
| 78 // Copy constructor and assignment welcome. |
| 79 |
| 80 // Returns true iff the iterator points to an EnumSet and it |
| 81 // hasn't yet traversed the EnumSet entirely. |
| 82 bool Good() const { |
| 83 return enums_ && i_ < kValueCount && enums_->test(i_); |
| 84 } |
| 85 |
| 86 // Returns the value the iterator currently points to. Good() |
| 87 // must hold. |
| 88 E Get() const { |
| 89 CHECK(Good()); |
| 90 return FromIndex(i_); |
| 91 } |
| 92 |
| 93 // Moves the iterator to the next value in the EnumSet. Good() |
| 94 // must hold. Takes linear time. |
| 95 void Inc() { |
| 96 CHECK(Good()); |
| 97 i_ = FindNext(i_ + 1); |
| 98 } |
| 99 |
| 100 private: |
| 101 friend Iterator EnumSet::First() const; |
| 102 |
| 103 explicit Iterator(const EnumBitSet& enums) |
| 104 : enums_(&enums), i_(FindNext(0)) {} |
| 105 |
| 106 size_t FindNext(size_t i) { |
| 107 while ((i < kValueCount) && !enums_->test(i)) { |
| 108 ++i; |
| 109 } |
| 110 return i; |
| 111 } |
| 112 |
| 113 const EnumBitSet* enums_; |
| 114 size_t i_; |
| 115 }; |
| 116 |
| 117 // You can construct an EnumSet with 0, 1, 2, or 3 initial values. |
| 118 |
| 119 EnumSet() {} |
| 120 |
| 121 explicit EnumSet(E value) { |
| 122 Put(value); |
| 123 } |
| 124 |
| 125 EnumSet(E value1, E value2) { |
| 126 Put(value1); |
| 127 Put(value2); |
| 128 } |
| 129 |
| 130 EnumSet(E value1, E value2, E value3) { |
| 131 Put(value1); |
| 132 Put(value2); |
| 133 Put(value3); |
| 134 } |
| 135 |
| 136 // Returns an EnumSet with all possible values. |
| 137 static EnumSet All() { |
| 138 EnumBitSet enums; |
| 139 enums.set(); |
| 140 return EnumSet(enums); |
| 141 } |
| 142 |
| 143 ~EnumSet() {} |
| 144 |
| 145 // Copy constructor and assignment welcome. |
| 146 |
| 147 // Set operations. Put, Retain, and Remove are basically |
| 148 // self-mutating versions of Union, Intersection, and Difference |
| 149 // (defined below). |
| 150 |
| 151 // Adds the given value to our set. |
| 152 void Put(E value) { |
| 153 enums_.set(ToIndex(value)); |
| 154 } |
| 155 |
| 156 // Adds all values in the given set to our set. |
| 157 void PutAll(EnumSet other) { |
| 158 enums_ |= other.enums_; |
| 159 } |
| 160 |
| 161 // There's no real need for a Retain(E) member function. |
| 162 |
| 163 // Removes all values not in the given set from our set. |
| 164 void RetainAll(EnumSet other) { |
| 165 enums_ &= other.enums_; |
| 166 } |
| 167 |
| 168 // Removes the given value from our set. |
| 169 void Remove(E value) { |
| 170 enums_.reset(ToIndex(value)); |
| 171 } |
| 172 |
| 173 // Removes all values in the given set from our set. |
| 174 void RemoveAll(EnumSet other) { |
| 175 enums_ &= ~other.enums_; |
| 176 } |
| 177 |
| 178 // Removes all values from our set. |
| 179 void Clear() { |
| 180 enums_.reset(); |
| 181 } |
| 182 |
| 183 // Returns true iff the given value is a member of our set. |
| 184 bool Has(E value) const { |
| 185 return enums_.test(ToIndex(value)); |
| 186 } |
| 187 |
| 188 // Returns true iff the given set is a subset of our set. |
| 189 bool HasAll(EnumSet other) const { |
| 190 return (enums_ & other.enums_) == other.enums_; |
| 191 } |
| 192 |
| 193 // Returns true iff our set and the given set contain exactly the |
| 194 // same values. |
| 195 bool Equals(const EnumSet& other) const { |
| 196 return enums_ == other.enums_; |
| 197 } |
| 198 |
| 199 // Returns true iff our set is empty. |
| 200 bool Empty() const { |
| 201 return !enums_.any(); |
| 202 } |
| 203 |
| 204 // Returns how many values our set has. |
| 205 size_t Size() const { |
| 206 return enums_.count(); |
| 207 } |
| 208 |
| 209 // Returns an iterator pointing to the first element (if any). |
| 210 Iterator First() const { |
| 211 return Iterator(enums_); |
| 212 } |
| 213 |
| 214 private: |
| 215 friend EnumSet Union<E, MinEnumValue, MaxEnumValue>( |
| 216 EnumSet set1, EnumSet set2); |
| 217 friend EnumSet Intersection<E, MinEnumValue, MaxEnumValue>( |
| 218 EnumSet set1, EnumSet set2); |
| 219 friend EnumSet Difference<E, MinEnumValue, MaxEnumValue>( |
| 220 EnumSet set1, EnumSet set2); |
| 221 |
| 222 explicit EnumSet(EnumBitSet enums) : enums_(enums) {} |
| 223 |
| 224 // Converts a value to/from an index into |enums_|. |
| 225 |
| 226 static size_t ToIndex(E value) { |
| 227 DCHECK_GE(value, MinEnumValue); |
| 228 DCHECK_LE(value, MaxEnumValue); |
| 229 return value - MinEnumValue; |
| 230 } |
| 231 |
| 232 static E FromIndex(size_t i) { |
| 233 DCHECK_LT(i, kValueCount); |
| 234 return static_cast<E>(MinEnumValue + i); |
| 235 } |
| 236 |
| 237 EnumBitSet enums_; |
| 238 }; |
| 239 |
| 240 template <typename E, E MinEnumValue, E MaxEnumValue> |
| 241 const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMinValue; |
| 242 |
| 243 template <typename E, E MinEnumValue, E MaxEnumValue> |
| 244 const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMaxValue; |
| 245 |
| 246 template <typename E, E MinEnumValue, E MaxEnumValue> |
| 247 const size_t EnumSet<E, MinEnumValue, MaxEnumValue>::kValueCount; |
| 248 |
| 249 // The usual set operations. |
| 250 |
| 251 template <typename E, E Min, E Max> |
| 252 EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1, |
| 253 EnumSet<E, Min, Max> set2) { |
| 254 return EnumSet<E, Min, Max>(set1.enums_ | set2.enums_); |
| 255 } |
| 256 |
| 257 template <typename E, E Min, E Max> |
| 258 EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1, |
| 259 EnumSet<E, Min, Max> set2) { |
| 260 return EnumSet<E, Min, Max>(set1.enums_ & set2.enums_); |
| 261 } |
| 262 |
| 263 template <typename E, E Min, E Max> |
| 264 EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1, |
| 265 EnumSet<E, Min, Max> set2) { |
| 266 return EnumSet<E, Min, Max>(set1.enums_ & ~set2.enums_); |
| 267 } |
| 268 |
| 269 } // namespace browser_sync |
| 270 |
| 271 #endif // CHROME_BROWSER_SYNC_UTIL_ENUM_SET_H_ |
OLD | NEW |