Chromium Code Reviews| Index: chrome/browser/sync/util/enum_set.h |
| diff --git a/chrome/browser/sync/util/enum_set.h b/chrome/browser/sync/util/enum_set.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4cad4275598cc41933e529d9bb7df3792a3bb74a |
| --- /dev/null |
| +++ b/chrome/browser/sync/util/enum_set.h |
| @@ -0,0 +1,242 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#ifndef CHROME_BROWSER_SYNC_UTIL_ENUM_SET_H_ |
| +#define CHROME_BROWSER_SYNC_UTIL_ENUM_SET_H_ |
| +#pragma once |
| + |
| +#include <bitset> |
| +#include <cstddef> |
| +#include <string> |
| + |
| +#include "base/basictypes.h" |
| +#include "base/compiler_specific.h" |
| +#include "base/logging.h" |
| + |
| +namespace browser_sync { |
| + |
| +// An EnumSet is a set that can hold enum values between a min and a |
| +// max value (inclusive of both). It's essentially a wrapper around |
| +// std::bitset<> with stronger type enforcement, more descriptive |
| +// member function names, and an iterator interface. |
| +// |
| +// If you're working with enums with a small number of possible values |
| +// (say, fewer than 64), you can efficiently pass around an EnumSet |
| +// for that enum around by value. |
| + |
| +template <typename E, E MinEnumValue, E MaxEnumValue> |
| +class EnumSet { |
| + public: |
| + typedef E EnumType; |
| + static const E kMinValue = MinEnumValue; |
| + static const E kMaxValue = MaxEnumValue; |
| + static const size_t kValueCount = kMaxValue - kMinValue + 1; |
| + COMPILE_ASSERT(kMinValue < kMaxValue, |
| + min_value_must_be_less_than_max_value); |
| + |
| + private: |
| + // Declaration needed by Iterator. |
| + typedef std::bitset<kValueCount> EnumBitSet; |
| + |
| + public: |
| + // Iterator is a forward-only read-only iterator for EnumSet. Its |
| + // interface is deliberately distinct from an STL iterator as its |
| + // semantics are substantially different. |
| + // |
| + // Example usage: |
| + // |
| + // for (EnumSet<...>::Iterator it = enums.First(); it.Good(); it.Inc()) { |
| + // Process(it.Get()); |
| + // } |
| + // |
| + // There are no guarantees as to what will happen if you modify an |
| + // EnumSet while traversing it with an iterator. |
| + class Iterator { |
| + public: |
| + // A default-constructed iterator can't do anything except check |
| + // Good(). You need to call First() on an EnumSet to get a usable |
| + // iterator. |
| + Iterator() : enums_(NULL), i_(kValueCount) {} |
| + ~Iterator() {} |
| + |
| + // Copy constructor and assignment welcome. |
| + |
| + // Returns true iff the iterator points to an EnumSet and it |
| + // hasn't yet traversed the EnumSet entirely. |
| + bool Good() const { |
| + return enums_ && i_ < kValueCount && enums_->test(i_); |
| + } |
| + |
| + // Returns the value the iterator currently points to. Good() |
| + // must hold. |
| + E Get() const { |
| + CHECK(Good()); |
| + return FromIndex(i_); |
| + } |
| + |
| + // Moves the iterator to the next value in the EnumSet. Good() |
| + // must hold. Takes linear time. |
| + void Inc() { |
| + CHECK(Good()); |
| + i_ = FindNext(i_ + 1); |
| + } |
| + |
| + private: |
| + friend Iterator EnumSet::First() const; |
| + |
| + explicit Iterator(const EnumBitSet& enums) |
| + : enums_(&enums), i_(FindNext(0)) {} |
| + |
| + size_t FindNext(size_t i) { |
| + while ((i < kValueCount) && !enums_->test(i)) { |
| + ++i; |
| + } |
| + return i; |
| + } |
| + |
| + const EnumBitSet* enums_; |
| + size_t i_; |
| + }; |
| + |
| + // You can construct an EnumSet with 0, 1, 2, or 3 initial values. |
| + |
| + EnumSet() {} |
| + |
| + explicit EnumSet(E value) { |
| + Put(value); |
| + } |
| + |
| + EnumSet(E value1, E value2) { |
| + Put(value1); |
| + Put(value2); |
| + } |
| + |
| + EnumSet(E value1, E value2, E value3) { |
| + Put(value1); |
| + Put(value2); |
| + Put(value3); |
| + } |
| + |
| + // Returns an EnumSet with all possible values. |
| + static EnumSet All() { |
| + EnumBitSet enums; |
| + enums.set(); |
| + return EnumSet(enums); |
| + } |
| + |
| + ~EnumSet() {} |
| + |
| + // Copy constructor and assignment welcome. |
| + |
| + // Set operations. Put, Retain, and Remove are basically |
| + // self-mutating versions of Union, Intersect, and Difference. |
| + |
| + // Adds the given value to our set. |
| + void Put(E value) { |
| + enums_.set(ToIndex(value)); |
| + } |
| + |
| + // Adds all values in the given set to our set. |
| + void PutAll(EnumSet other) { |
| + enums_ |= other.enums_; |
| + } |
| + |
| + // There's no real need for a Retain(E) member function. |
| + |
| + // Removes all values not in the given set from our set. |
| + void RetainAll(EnumSet other) { |
| + enums_ &= other.enums_; |
| + } |
| + |
| + // Removes the given value from our set. |
| + void Remove(E value) { |
| + enums_.reset(ToIndex(value)); |
| + } |
| + |
| + // Removes all values in the given set from our set. |
| + void RemoveAll(EnumSet other) { |
| + enums_ &= ~other.enums_; |
| + } |
| + |
| + // Removes all values from our set. |
| + void Clear() { |
| + enums_.reset(); |
| + } |
| + |
| + // Returns true iff the given value is a member of our set. |
| + bool Has(E value) const { |
| + return enums_.test(ToIndex(value)); |
| + } |
| + |
| + // Returns true iff the given set is a subset of our set. |
| + bool HasAll(EnumSet other) const { |
| + return (enums_ & other.enums_) == other.enums_; |
| + } |
| + |
| + // Returns true iff our set and the given set contain exactly the |
| + // same values. |
| + bool Equals(const EnumSet& other) const { |
| + return enums_ == other.enums_; |
| + } |
| + |
| + // Returns true iff our set is empty. |
| + bool Empty() const { |
| + return !enums_.any(); |
| + } |
| + |
| + // Returns how many values our set has. |
| + size_t Size() const { |
| + return enums_.count(); |
| + } |
| + |
| + // The usual set operations. |
| + |
| + EnumSet Union(EnumSet other) const WARN_UNUSED_RESULT { |
|
Nicolas Zea
2011/12/05 22:39:23
Although it can't be used as such, these methods s
|
| + return EnumSet(enums_ | other.enums_); |
| + } |
| + |
| + EnumSet Intersect(EnumSet other) const WARN_UNUSED_RESULT { |
| + return EnumSet(enums_ & other.enums_); |
| + } |
| + |
| + EnumSet Difference(EnumSet other) const WARN_UNUSED_RESULT { |
| + return EnumSet(enums_ & ~other.enums_); |
| + } |
| + |
| + // Returns an iterator pointing to the first element (if any). |
| + Iterator First() const { |
| + return Iterator(enums_); |
| + } |
| + |
| + private: |
| + explicit EnumSet(EnumBitSet enums) : enums_(enums) {} |
| + |
| + // Converts a value to/from an index into |enums_|. |
| + |
| + static size_t ToIndex(E value) { |
| + DCHECK_GE(value, MinEnumValue); |
| + DCHECK_LE(value, MaxEnumValue); |
| + return value - MinEnumValue; |
| + } |
| + |
| + static E FromIndex(size_t i) { |
| + DCHECK_LT(i, kValueCount); |
| + return static_cast<E>(MinEnumValue + i); |
| + } |
| + |
| + EnumBitSet enums_; |
| +}; |
| + |
| +template <typename E, E MinEnumValue, E MaxEnumValue> |
| +const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMinValue; |
| + |
| +template <typename E, E MinEnumValue, E MaxEnumValue> |
| +const E EnumSet<E, MinEnumValue, MaxEnumValue>::kMaxValue; |
| + |
| +template <typename E, E MinEnumValue, E MaxEnumValue> |
| +const size_t EnumSet<E, MinEnumValue, MaxEnumValue>::kValueCount; |
| + |
| +} // namespace browser_sync |
| + |
| +#endif // CHROME_BROWSER_SYNC_UTIL_ENUM_SET_H_ |