| Differences between
and this patch
- a/Source/WTF/ChangeLog +30 lines
Lines 1-5 a/Source/WTF/ChangeLog_sec1
1
2016-03-02  Daniel Bates  <dabates@apple.com>
1
2016-03-02  Daniel Bates  <dabates@apple.com>
2
2
3
        Support iterating over an OptionSet and checking if it is empty
4
        https://bugs.webkit.org/show_bug.cgi?id=154941
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Implements support for iterating over the enumerators in an OptionSet as well as
9
        determining if the set is empty.
10
11
        Iterating over an OptionSet is in Big Theta(N) where N is the number of items in
12
        the set. More precisely, it is in Big Theta(log M) where M is the bitmask represented
13
        by the bitwise OR-ing of all enumerators in the set.
14
15
        * wtf/OptionSet.h: Added comment to describe the purpose of this class and its invariant -
16
        the enumerators must be positive powers of two.
17
        (WTF::OptionSet::fromRaw): Instantiate using specialized private constructor to allow
18
        instantiation with a raw value of 0.
19
        (WTF::OptionSet::OptionSet): Specialized constructor that asserts that the specified value
20
        is a positive power of two. This variant is only compiled when assertions are enabled (i.e. !ASSERT_DISABLED).
21
        (WTF::OptionSet::isEmpty): Returns whether the set is empty.
22
        (WTF::OptionSet::begin): Returns an iterator to the enumerator with the smallest value in the set.
23
        (WTF::OptionSet::end): Returns an iterator that represents the end sentinel of the set.
24
        (WTF::OptionSetIterator::OptionSetIterator): Implements a forward iterator for the set.
25
        (WTF::OptionSetIterator::operator=): Added.
26
        (WTF::OptionSetIterator::operator*): Returns the enumerator pointed to by the iterator.
27
        (WTF::OptionSetIterator::operator++): Advance to the next smallest enumerator in the set. 
28
        (WTF::OptionSetIterator::operator==): Returns whether the iterator is equal to the specified iterator.
29
        (WTF::OptionSetIterator::operator!=): Returns whether the iterator is not equal to the specified iterator.
30
31
2016-03-02  Daniel Bates  <dabates@apple.com>
32
3
        Add unit tests for WTF::OptionSet
33
        Add unit tests for WTF::OptionSet
4
        https://bugs.webkit.org/show_bug.cgi?id=154925
34
        https://bugs.webkit.org/show_bug.cgi?id=154925
5
35
- a/Source/WTF/wtf/OptionSet.h -2 / +62 lines
Lines 27-44 a/Source/WTF/wtf/OptionSet.h_sec1
27
#define OptionSet_h
27
#define OptionSet_h
28
28
29
#include <initializer_list>
29
#include <initializer_list>
30
#include <iterator>
30
#include <type_traits>
31
#include <type_traits>
32
#include <wtf/Assertions.h>
33
#include <wtf/MathExtras.h>
31
34
32
namespace WTF {
35
namespace WTF {
33
36
37
template<typename T, typename StorageType> class OptionSetIterator;
38
39
// OptionSet is a class that represents a set of enumerators in a space-efficient manner. The enumerators
40
// must be powers of two greater than 0. This class is useful as a replacement for passing a bitmask of
41
// enumerators around.
34
template<typename T> class OptionSet {
42
template<typename T> class OptionSet {
35
    static_assert(std::is_enum<T>::value, "T is not an enum type");
43
    static_assert(std::is_enum<T>::value, "T is not an enum type");
36
    typedef typename std::make_unsigned<typename std::underlying_type<T>::type>::type StorageType;
44
    typedef typename std::make_unsigned<typename std::underlying_type<T>::type>::type StorageType;
37
45
38
public:
46
public:
47
    typedef OptionSetIterator<T, StorageType> iterator;
48
39
    static OptionSet fromRaw(StorageType storageType)
49
    static OptionSet fromRaw(StorageType storageType)
40
    {
50
    {
41
        return static_cast<T>(storageType);
51
        return OptionSet(static_cast<T>(storageType), OptionSet::FromRawValue);
42
    }
52
    }
43
53
44
    constexpr OptionSet()
54
    constexpr OptionSet()
Lines 46-67 public: a/Source/WTF/wtf/OptionSet.h_sec2
46
    {
56
    {
47
    }
57
    }
48
58
59
#if ASSERT_DISABLED
49
    constexpr OptionSet(T t)
60
    constexpr OptionSet(T t)
50
        : m_storage(static_cast<StorageType>(t))
61
        : m_storage(static_cast<StorageType>(t))
51
    {
62
    {
52
    }
63
    }
64
#else
65
    OptionSet(T t)
66
        : m_storage(static_cast<StorageType>(t))
67
    {
68
        ASSERT_WITH_MESSAGE(hasOneBitSet(static_cast<StorageType>(t)), "Enumerator is not a positive power of two.");
69
    }
70
#endif
53
71
54
    // FIXME: Make this constexpr once we adopt C++14 as C++11 does not support for-loops
72
    // FIXME: Make this constexpr once we adopt C++14 as C++11 does not support for-loops
55
    // in a constexpr function.
73
    // in a constexpr function.
56
    OptionSet(std::initializer_list<T> initializerList)
74
    OptionSet(std::initializer_list<T> initializerList)
57
        : m_storage(0)
75
        : m_storage(0)
58
    {
76
    {
59
        for (auto& option : initializerList)
77
        for (auto& option : initializerList) {
78
            ASSERT_WITH_MESSAGE(hasOneBitSet(static_cast<StorageType>(option)), "Enumerator is not a positive power of two.");
60
            m_storage |= static_cast<StorageType>(option);
79
            m_storage |= static_cast<StorageType>(option);
80
        }
61
    }
81
    }
62
82
63
    constexpr StorageType toRaw() const { return m_storage; }
83
    constexpr StorageType toRaw() const { return m_storage; }
64
84
85
    constexpr StorageType isEmpty() const { return !m_storage; }
86
87
    constexpr iterator begin() const { return m_storage; }
88
    constexpr iterator end() const { return 0; }
89
65
    constexpr bool contains(OptionSet optionSet) const
90
    constexpr bool contains(OptionSet optionSet) const
66
    {
91
    {
67
        return m_storage & optionSet.m_storage;
92
        return m_storage & optionSet.m_storage;
Lines 75-83 public: a/Source/WTF/wtf/OptionSet.h_sec3
75
    }
100
    }
76
101
77
private:
102
private:
103
    enum InitializationTag { FromRawValue };
104
    constexpr OptionSet(T t, InitializationTag)
105
        : m_storage(static_cast<StorageType>(t))
106
    {
107
    }
78
    StorageType m_storage;
108
    StorageType m_storage;
79
};
109
};
80
110
111
template<typename T, typename StorageType> class OptionSetIterator {
112
public:
113
    OptionSetIterator(const StorageType value) : m_value(value) { }
114
    OptionSetIterator(const OptionSetIterator& other) : m_value(other.m_value) { }
115
116
    OptionSetIterator& operator=(const OptionSetIterator& other)
117
    {
118
        m_value = other.m_value;
119
        return *this;
120
    }
121
122
    // Isolate the rightmost set bit.
123
    T operator*() const { return static_cast<T>(m_value & -m_value); }
124
125
    // Iterates from smallest to largest enum value by turning off the rightmost set bit.
126
    OptionSetIterator& operator++()
127
    {
128
        m_value &= m_value - 1;
129
        return *this;
130
    }
131
132
    OptionSetIterator& operator++(int) = delete;
133
134
    bool operator==(const OptionSetIterator& other) const { return m_value == other.m_value; }
135
    bool operator!=(const OptionSetIterator& other) const { return m_value != other.m_value; }
136
137
private:
138
    StorageType m_value;
139
};
140
81
}
141
}
82
142
83
using WTF::OptionSet;
143
using WTF::OptionSet;
- a/Tools/ChangeLog +15 lines
Lines 1-5 a/Tools/ChangeLog_sec1
1
2016-03-02  Daniel Bates  <dabates@apple.com>
1
2016-03-02  Daniel Bates  <dabates@apple.com>
2
2
3
        Support iterating over an OptionSet and checking if it is empty
4
        https://bugs.webkit.org/show_bug.cgi?id=154941
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Add tests to ensure that we do not regression both iteration of an OptionSet and
9
        determining whether an OptionSet is empty.
10
11
        * TestWebKitAPI/PlatformUtilities.h:
12
        (TestWebKitAPI::Util::assertStrongEnum): Helper function to assert two strong enum type for equality.
13
        * TestWebKitAPI/Tests/WTF/OptionSet.cpp:
14
        (TestWebKitAPI::TEST):
15
16
2016-03-02  Daniel Bates  <dabates@apple.com>
17
3
        Add unit tests for WTF::OptionSet
18
        Add unit tests for WTF::OptionSet
4
        https://bugs.webkit.org/show_bug.cgi?id=154925
19
        https://bugs.webkit.org/show_bug.cgi?id=154925
5
20
- a/Tools/TestWebKitAPI/PlatformUtilities.h +12 lines
Lines 75-80 static inline ::testing::AssertionResult assertWKStringEqual(const char* expecte a/Tools/TestWebKitAPI/PlatformUtilities.h_sec1
75
#define EXPECT_WK_STREQ(expected, actual) \
75
#define EXPECT_WK_STREQ(expected, actual) \
76
    EXPECT_PRED_FORMAT2(TestWebKitAPI::Util::assertWKStringEqual, expected, actual)
76
    EXPECT_PRED_FORMAT2(TestWebKitAPI::Util::assertWKStringEqual, expected, actual)
77
77
78
template<typename T>
79
static inline ::testing::AssertionResult assertStrongEnum(const char* expected_expression, const char* actual_expression, T expected, T actual)
80
{
81
    static_assert(std::is_enum<T>::value, "T is not an enum type");
82
    typedef typename std::underlying_type<T>::type UnderlyingStorageType;
83
    return ::testing::internal::CmpHelperEQ(expected_expression, actual_expression, static_cast<UnderlyingStorageType>(expected), static_cast<UnderlyingStorageType>(actual));
84
}
85
86
#define EXPECT_STRONG_ENUM_EQ(expected, actual) \
87
    EXPECT_PRED_FORMAT2(TestWebKitAPI::Util::assertStrongEnum, expected, actual)
88
89
78
#if WK_API_ENABLED
90
#if WK_API_ENABLED
79
extern NSString * const TestPlugInClassNameParameter;
91
extern NSString * const TestPlugInClassNameParameter;
80
#endif
92
#endif
- a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp +50 lines
Lines 24-29 a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp_sec1
24
 */
24
 */
25
25
26
#include "config.h"
26
#include "config.h"
27
#include "PlatformUtilities.h"
27
28
28
#include <wtf/OptionSet.h>
29
#include <wtf/OptionSet.h>
29
30
Lines 38-43 enum class ExampleFlags { a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp_sec2
38
TEST(WTF_OptionSet, EmptySet)
39
TEST(WTF_OptionSet, EmptySet)
39
{
40
{
40
    OptionSet<ExampleFlags> set;
41
    OptionSet<ExampleFlags> set;
42
    EXPECT_TRUE(set.isEmpty());
41
    EXPECT_FALSE(set.contains(ExampleFlags::A));
43
    EXPECT_FALSE(set.contains(ExampleFlags::A));
42
    EXPECT_FALSE(set.contains(ExampleFlags::B));
44
    EXPECT_FALSE(set.contains(ExampleFlags::B));
43
    EXPECT_FALSE(set.contains(ExampleFlags::C));
45
    EXPECT_FALSE(set.contains(ExampleFlags::C));
Lines 46-51 TEST(WTF_OptionSet, EmptySet) a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp_sec3
46
TEST(WTF_OptionSet, ContainsOneFlag)
48
TEST(WTF_OptionSet, ContainsOneFlag)
47
{
49
{
48
    OptionSet<ExampleFlags> set = ExampleFlags::A;
50
    OptionSet<ExampleFlags> set = ExampleFlags::A;
51
    EXPECT_FALSE(set.isEmpty());
49
    EXPECT_TRUE(set.contains(ExampleFlags::A));
52
    EXPECT_TRUE(set.contains(ExampleFlags::A));
50
    EXPECT_FALSE(set.contains(ExampleFlags::B));
53
    EXPECT_FALSE(set.contains(ExampleFlags::B));
51
    EXPECT_FALSE(set.contains(ExampleFlags::C));
54
    EXPECT_FALSE(set.contains(ExampleFlags::C));
Lines 54-59 TEST(WTF_OptionSet, ContainsOneFlag) a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp_sec4
54
TEST(WTF_OptionSet, ContainsTwoFlags)
57
TEST(WTF_OptionSet, ContainsTwoFlags)
55
{
58
{
56
    OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::B };
59
    OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::B };
60
    EXPECT_FALSE(set.isEmpty());
57
    EXPECT_TRUE(set.contains(ExampleFlags::A));
61
    EXPECT_TRUE(set.contains(ExampleFlags::A));
58
    EXPECT_TRUE(set.contains(ExampleFlags::B));
62
    EXPECT_TRUE(set.contains(ExampleFlags::B));
59
    EXPECT_FALSE(set.contains(ExampleFlags::C));
63
    EXPECT_FALSE(set.contains(ExampleFlags::C));
Lines 71-81 TEST(WTF_OptionSet, OperatorBitwiseOr) a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp_sec5
71
TEST(WTF_OptionSet, EmptyOptionSetToRawValueToOptionSet)
75
TEST(WTF_OptionSet, EmptyOptionSetToRawValueToOptionSet)
72
{
76
{
73
    OptionSet<ExampleFlags> set;
77
    OptionSet<ExampleFlags> set;
78
    EXPECT_TRUE(set.isEmpty());
74
    EXPECT_FALSE(set.contains(ExampleFlags::A));
79
    EXPECT_FALSE(set.contains(ExampleFlags::A));
75
    EXPECT_FALSE(set.contains(ExampleFlags::B));
80
    EXPECT_FALSE(set.contains(ExampleFlags::B));
76
    EXPECT_FALSE(set.contains(ExampleFlags::C));
81
    EXPECT_FALSE(set.contains(ExampleFlags::C));
77
82
78
    auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
83
    auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
84
    EXPECT_TRUE(set2.isEmpty());
79
    EXPECT_FALSE(set2.contains(ExampleFlags::A));
85
    EXPECT_FALSE(set2.contains(ExampleFlags::A));
80
    EXPECT_FALSE(set2.contains(ExampleFlags::B));
86
    EXPECT_FALSE(set2.contains(ExampleFlags::B));
81
    EXPECT_FALSE(set2.contains(ExampleFlags::C));
87
    EXPECT_FALSE(set2.contains(ExampleFlags::C));
Lines 84-94 TEST(WTF_OptionSet, EmptyOptionSetToRawValueToOptionSet) a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp_sec6
84
TEST(WTF_OptionSet, OptionSetThatContainsOneFlagToRawValueToOptionSet)
90
TEST(WTF_OptionSet, OptionSetThatContainsOneFlagToRawValueToOptionSet)
85
{
91
{
86
    OptionSet<ExampleFlags> set = ExampleFlags::A;
92
    OptionSet<ExampleFlags> set = ExampleFlags::A;
93
    EXPECT_FALSE(set.isEmpty());
87
    EXPECT_TRUE(set.contains(ExampleFlags::A));
94
    EXPECT_TRUE(set.contains(ExampleFlags::A));
88
    EXPECT_FALSE(set.contains(ExampleFlags::B));
95
    EXPECT_FALSE(set.contains(ExampleFlags::B));
89
    EXPECT_FALSE(set.contains(ExampleFlags::C));
96
    EXPECT_FALSE(set.contains(ExampleFlags::C));
90
97
91
    auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
98
    auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
99
    EXPECT_FALSE(set2.isEmpty());
92
    EXPECT_TRUE(set2.contains(ExampleFlags::A));
100
    EXPECT_TRUE(set2.contains(ExampleFlags::A));
93
    EXPECT_FALSE(set2.contains(ExampleFlags::B));
101
    EXPECT_FALSE(set2.contains(ExampleFlags::B));
94
    EXPECT_FALSE(set2.contains(ExampleFlags::C));
102
    EXPECT_FALSE(set2.contains(ExampleFlags::C));
Lines 97-110 TEST(WTF_OptionSet, OptionSetThatContainsOneFlagToRawValueToOptionSet) a/Tools/TestWebKitAPI/Tests/WTF/OptionSet.cpp_sec7
97
TEST(WTF_OptionSet, OptionSetThatContainsTwoFlagsToRawValueToOptionSet)
105
TEST(WTF_OptionSet, OptionSetThatContainsTwoFlagsToRawValueToOptionSet)
98
{
106
{
99
    OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::C };
107
    OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::C };
108
    EXPECT_FALSE(set.isEmpty());
100
    EXPECT_TRUE(set.contains(ExampleFlags::A));
109
    EXPECT_TRUE(set.contains(ExampleFlags::A));
101
    EXPECT_TRUE(set.contains(ExampleFlags::C));
110
    EXPECT_TRUE(set.contains(ExampleFlags::C));
102
    EXPECT_FALSE(set.contains(ExampleFlags::B));
111
    EXPECT_FALSE(set.contains(ExampleFlags::B));
103
112
104
    auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
113
    auto set2 = OptionSet<ExampleFlags>::fromRaw(set.toRaw());
114
    EXPECT_FALSE(set2.isEmpty());
105
    EXPECT_TRUE(set2.contains(ExampleFlags::A));
115
    EXPECT_TRUE(set2.contains(ExampleFlags::A));
106
    EXPECT_TRUE(set2.contains(ExampleFlags::C));
116
    EXPECT_TRUE(set2.contains(ExampleFlags::C));
107
    EXPECT_FALSE(set2.contains(ExampleFlags::B));
117
    EXPECT_FALSE(set2.contains(ExampleFlags::B));
108
}
118
}
109
119
120
TEST(WTF_OptionSet, TwoIteratorsIntoSameOptionSet)
121
{
122
    OptionSet<ExampleFlags> set { ExampleFlags::C, ExampleFlags::B };
123
    OptionSet<ExampleFlags>::iterator it1 = set.begin();
124
    OptionSet<ExampleFlags>::iterator it2 = it1;
125
    ++it1;
126
    EXPECT_STRONG_ENUM_EQ(ExampleFlags::C, *it1);
127
    EXPECT_STRONG_ENUM_EQ(ExampleFlags::B, *it2);
128
}
129
130
TEST(WTF_OptionSet, IterateOverOptionSetThatContainsTwoFlags)
131
{
132
    OptionSet<ExampleFlags> set { ExampleFlags::A, ExampleFlags::C };
133
    OptionSet<ExampleFlags>::iterator it = set.begin();
134
    OptionSet<ExampleFlags>::iterator end = set.end();
135
    EXPECT_TRUE(it != end);
136
    EXPECT_STRONG_ENUM_EQ(ExampleFlags::A, *it);
137
    ++it;
138
    EXPECT_STRONG_ENUM_EQ(ExampleFlags::C, *it);
139
    ++it;
140
    EXPECT_TRUE(it == end);
141
}
142
143
TEST(WTF_OptionSet, IterationOrderTheSameRegardlessOfInsertionOrder)
144
{
145
    OptionSet<ExampleFlags> set1 = ExampleFlags::C;
146
    set1 |= ExampleFlags::A;
147
148
    OptionSet<ExampleFlags> set2 = ExampleFlags::A;
149
    set2 |= ExampleFlags::C;
150
151
    OptionSet<ExampleFlags>::iterator it1 = set1.begin();
152
    OptionSet<ExampleFlags>::iterator it2 = set2.begin();
153
154
    EXPECT_TRUE(*it1 == *it2);
155
    ++it1;
156
    ++it2;
157
    EXPECT_TRUE(*it1 == *it2);
158
}
159
110
} // namespace TestWebKitAPI
160
} // namespace TestWebKitAPI

Return to Bug 154941