Commit 26a5a1b9 authored by akalin@chromium.org's avatar akalin@chromium.org

[Sync] Add new EnumSet class representing a set of enum values

This will eventually replace ModelType{Bit,}Set.

BUG=79970
TEST=


Review URL: http://codereview.chromium.org/8772073

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113147 0039d316-1c4b-4281-b951-d872f2087c98
parent 0de37001
// 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/logging.h"
namespace browser_sync {
// Forward declarations needed for friend declarations.
template <typename E, E MinEnumValue, E MaxEnumValue>
class EnumSet;
template <typename E, E Min, E Max>
EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2);
template <typename E, E Min, E Max>
EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2);
template <typename E, E Min, E Max>
EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2);
// 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, Intersection, and Difference
// (defined below).
// 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();
}
// Returns an iterator pointing to the first element (if any).
Iterator First() const {
return Iterator(enums_);
}
private:
friend EnumSet Union<E, MinEnumValue, MaxEnumValue>(
EnumSet set1, EnumSet set2);
friend EnumSet Intersection<E, MinEnumValue, MaxEnumValue>(
EnumSet set1, EnumSet set2);
friend EnumSet Difference<E, MinEnumValue, MaxEnumValue>(
EnumSet set1, EnumSet set2);
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;
// The usual set operations.
template <typename E, E Min, E Max>
EnumSet<E, Min, Max> Union(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2) {
return EnumSet<E, Min, Max>(set1.enums_ | set2.enums_);
}
template <typename E, E Min, E Max>
EnumSet<E, Min, Max> Intersection(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2) {
return EnumSet<E, Min, Max>(set1.enums_ & set2.enums_);
}
template <typename E, E Min, E Max>
EnumSet<E, Min, Max> Difference(EnumSet<E, Min, Max> set1,
EnumSet<E, Min, Max> set2) {
return EnumSet<E, Min, Max>(set1.enums_ & ~set2.enums_);
}
} // namespace browser_sync
#endif // CHROME_BROWSER_SYNC_UTIL_ENUM_SET_H_
// 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.
#include "chrome/browser/sync/util/enum_set.h"
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace browser_sync {
namespace {
enum TestEnum {
TEST_0,
TEST_MIN = TEST_0,
TEST_1,
TEST_2,
TEST_3,
TEST_4,
TEST_MAX = TEST_4,
};
typedef EnumSet<TestEnum, TEST_MIN, TEST_MAX> TestEnumSet;
class EnumSetTest : public ::testing::Test {};
TEST_F(EnumSetTest, ClassConstants) {
TestEnumSet enums;
EXPECT_EQ(TEST_MIN, TestEnumSet::kMinValue);
EXPECT_EQ(TEST_MAX, TestEnumSet::kMaxValue);
EXPECT_EQ(static_cast<size_t>(5), TestEnumSet::kValueCount);
}
TEST_F(EnumSetTest, DefaultConstructor) {
const TestEnumSet enums;
EXPECT_TRUE(enums.Empty());
EXPECT_EQ(static_cast<size_t>(0), enums.Size());
EXPECT_FALSE(enums.Has(TEST_0));
EXPECT_FALSE(enums.Has(TEST_1));
EXPECT_FALSE(enums.Has(TEST_2));
EXPECT_FALSE(enums.Has(TEST_3));
EXPECT_FALSE(enums.Has(TEST_4));
}
TEST_F(EnumSetTest, OneArgConstructor) {
const TestEnumSet enums(TEST_3);
EXPECT_FALSE(enums.Empty());
EXPECT_EQ(static_cast<size_t>(1), enums.Size());
EXPECT_FALSE(enums.Has(TEST_0));
EXPECT_FALSE(enums.Has(TEST_1));
EXPECT_FALSE(enums.Has(TEST_2));
EXPECT_TRUE(enums.Has(TEST_3));
EXPECT_FALSE(enums.Has(TEST_4));
}
TEST_F(EnumSetTest, TwoArgConstructor) {
const TestEnumSet enums(TEST_3, TEST_1);
EXPECT_FALSE(enums.Empty());
EXPECT_EQ(static_cast<size_t>(2), enums.Size());
EXPECT_FALSE(enums.Has(TEST_0));
EXPECT_TRUE(enums.Has(TEST_1));
EXPECT_FALSE(enums.Has(TEST_2));
EXPECT_TRUE(enums.Has(TEST_3));
EXPECT_FALSE(enums.Has(TEST_4));
}
TEST_F(EnumSetTest, ThreeArgConstructor) {
const TestEnumSet enums(TEST_3, TEST_1, TEST_0);
EXPECT_FALSE(enums.Empty());
EXPECT_EQ(static_cast<size_t>(3), enums.Size());
EXPECT_TRUE(enums.Has(TEST_0));
EXPECT_TRUE(enums.Has(TEST_1));
EXPECT_FALSE(enums.Has(TEST_2));
EXPECT_TRUE(enums.Has(TEST_3));
EXPECT_FALSE(enums.Has(TEST_4));
}
TEST_F(EnumSetTest, All) {
const TestEnumSet enums(TestEnumSet::All());
EXPECT_FALSE(enums.Empty());
EXPECT_EQ(static_cast<size_t>(5), enums.Size());
EXPECT_TRUE(enums.Has(TEST_0));
EXPECT_TRUE(enums.Has(TEST_1));
EXPECT_TRUE(enums.Has(TEST_2));
EXPECT_TRUE(enums.Has(TEST_3));
EXPECT_TRUE(enums.Has(TEST_4));
}
TEST_F(EnumSetTest, Put) {
TestEnumSet enums(TEST_3);
enums.Put(TEST_2);
EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3)));
enums.Put(TEST_4);
EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4)));
}
TEST_F(EnumSetTest, PutAll) {
TestEnumSet enums(TEST_3, TEST_4);
enums.PutAll(TestEnumSet(TEST_2, TEST_3));
EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4)));
}
TEST_F(EnumSetTest, RetainAll) {
TestEnumSet enums(TEST_3, TEST_4);
enums.RetainAll(TestEnumSet(TEST_2, TEST_3));
EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_3)));
}
TEST_F(EnumSetTest, Remove) {
TestEnumSet enums(TEST_3, TEST_4);
enums.Remove(TEST_2);
EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_3, TEST_4)));
enums.Remove(TEST_3);
EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_4)));
enums.Remove(TEST_4);
EXPECT_TRUE(enums.Empty());
}
TEST_F(EnumSetTest, RemoveAll) {
TestEnumSet enums(TEST_3, TEST_4);
enums.RemoveAll(TestEnumSet(TEST_2, TEST_3));
EXPECT_TRUE(enums.Equals(TestEnumSet(TEST_4)));
}
TEST_F(EnumSetTest, Clear) {
TestEnumSet enums(TEST_3, TEST_4);
enums.Clear();
EXPECT_TRUE(enums.Empty());
}
TEST_F(EnumSetTest, Has) {
const TestEnumSet enums(TEST_3, TEST_4);
EXPECT_FALSE(enums.Has(TEST_1));
EXPECT_FALSE(enums.Has(TEST_2));
EXPECT_TRUE(enums.Has(TEST_3));
EXPECT_TRUE(enums.Has(TEST_4));
}
TEST_F(EnumSetTest, HasAll) {
const TestEnumSet enums1(TEST_3, TEST_4);
const TestEnumSet enums2(TEST_2, TEST_3);
const TestEnumSet enums3 = Union(enums1, enums2);
EXPECT_TRUE(enums1.HasAll(enums1));
EXPECT_FALSE(enums1.HasAll(enums2));
EXPECT_FALSE(enums1.HasAll(enums3));
EXPECT_FALSE(enums2.HasAll(enums1));
EXPECT_TRUE(enums2.HasAll(enums2));
EXPECT_FALSE(enums2.HasAll(enums3));
EXPECT_TRUE(enums3.HasAll(enums1));
EXPECT_TRUE(enums3.HasAll(enums2));
EXPECT_TRUE(enums3.HasAll(enums3));
}
TEST_F(EnumSetTest, Iterators) {
const TestEnumSet enums1(TEST_3, TEST_4);
TestEnumSet enums2;
for (TestEnumSet::Iterator it = enums1.First(); it.Good(); it.Inc()) {
enums2.Put(it.Get());
}
EXPECT_TRUE(enums1.Equals(enums2));
}
TEST_F(EnumSetTest, Union) {
const TestEnumSet enums1(TEST_3, TEST_4);
const TestEnumSet enums2(TEST_2, TEST_3);
const TestEnumSet enums3 = Union(enums1, enums2);
EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_2, TEST_3, TEST_4)));
}
TEST_F(EnumSetTest, Intersection) {
const TestEnumSet enums1(TEST_3, TEST_4);
const TestEnumSet enums2(TEST_2, TEST_3);
const TestEnumSet enums3 = Intersection(enums1, enums2);
EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_3)));
}
TEST_F(EnumSetTest, Difference) {
const TestEnumSet enums1(TEST_3, TEST_4);
const TestEnumSet enums2(TEST_2, TEST_3);
const TestEnumSet enums3 = Difference(enums1, enums2);
EXPECT_TRUE(enums3.Equals(TestEnumSet(TEST_4)));
}
} // namespace
} // namespace browser_sync
......@@ -466,6 +466,7 @@
'browser/sync/syncable/transaction_observer.h',
'browser/sync/util/cryptographer.cc',
'browser/sync/util/cryptographer.h',
'browser/sync/util/enum_set.h',
'browser/sync/util/extensions_activity_monitor.cc',
'browser/sync/util/extensions_activity_monitor.h',
'browser/sync/util/get_session_name_task.cc',
......
......@@ -3302,6 +3302,7 @@
'browser/sync/test/engine/test_syncable_utils.h',
'browser/sync/test/sessions/test_scoped_session_event_listener.h',
'browser/sync/util/data_encryption_unittest.cc',
'browser/sync/util/enum_set_unittest.cc',
'browser/sync/util/extensions_activity_monitor_unittest.cc',
'browser/sync/util/protobuf_unittest.cc',
'browser/sync/util/immutable_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment