| Differences between
and this patch
- a/Source/WTF/ChangeLog +31 lines
Lines 1-5 a/Source/WTF/ChangeLog_sec1
1
2016-03-03  Daniel Bates  <dabates@apple.com>
1
2016-03-03  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
        <rdar://problem/24964187>
6
7
        Reviewed by NOBODY (OOPS!).
8
9
        Implements support for iterating over the enumerators in an OptionSet as well as
10
        determining if the set is empty.
11
12
        Iterating over an OptionSet is in Big Theta(N) where N is the number of items in
13
        the set. More precisely, it is in Big Theta(log M) where M is the bitmask represented
14
        by the bitwise OR-ing of all enumerators in the set.
15
16
        * wtf/OptionSet.h: Added comment to describe the purpose of this class and its invariant -
17
        the enumerators must be positive powers of two.
18
        (WTF::OptionSet::fromRaw): Instantiate using specialized private constructor to allow
19
        instantiation with a raw value of 0.
20
        (WTF::OptionSet::OptionSet): Specialized constructor that asserts that the specified value
21
        is a positive power of two. This variant is only compiled when assertions are enabled (i.e. !ASSERT_DISABLED).
22
        (WTF::OptionSet::isEmpty): Returns whether the set is empty.
23
        (WTF::OptionSet::begin): Returns an iterator to the enumerator with the smallest value in the set.
24
        (WTF::OptionSet::end): Returns an iterator that represents the end sentinel of the set.
25
        (WTF::OptionSetIterator::OptionSetIterator): Implements a forward iterator for the set.
26
        (WTF::OptionSetIterator::operator=): Added.
27
        (WTF::OptionSetIterator::operator*): Returns the enumerator pointed to by the iterator.
28
        (WTF::OptionSetIterator::operator++): Advance to the next smallest enumerator in the set.
29
        (WTF::OptionSetIterator::operator==): Returns whether the iterator is equal to the specified iterator.
30
        (WTF::OptionSetIterator::operator!=): Returns whether the iterator is not equal to the specified iterator.
31
32
2016-03-03  Daniel Bates  <dabates@apple.com>
33
3
        Add unit tests for WTF::OptionSet
34
        Add unit tests for WTF::OptionSet
4
        https://bugs.webkit.org/show_bug.cgi?id=154925
35
        https://bugs.webkit.org/show_bug.cgi?id=154925
5
        <rdar://problem/24964211>
36
        <rdar://problem/24964211>
- a/Source/WTF/wtf/OptionSet.h -2 / +62 lines
Lines 27-63 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() = default;
54
    constexpr OptionSet() = default;
45
55
56
#if ASSERT_DISABLED
46
    constexpr OptionSet(T t)
57
    constexpr OptionSet(T t)
47
        : m_storage(static_cast<StorageType>(t))
58
        : m_storage(static_cast<StorageType>(t))
48
    {
59
    {
49
    }
60
    }
61
#else
62
    OptionSet(T t)
63
        : m_storage(static_cast<StorageType>(t))
64
    {
65
        ASSERT_WITH_MESSAGE(hasOneBitSet(static_cast<StorageType>(t)), "Enumerator is not a positive power of two.");
66
    }
67
#endif
50
68
51
    // FIXME: Make this constexpr once we adopt C++14 as C++11 does not support for-loops
69
    // FIXME: Make this constexpr once we adopt C++14 as C++11 does not support for-loops
52
    // in a constexpr function.
70
    // in a constexpr function.
53
    OptionSet(std::initializer_list<T> initializerList)
71
    OptionSet(std::initializer_list<T> initializerList)
54
    {
72
    {
55
        for (auto& option : initializerList)
73
        for (auto& option : initializerList) {
74
            ASSERT_WITH_MESSAGE(hasOneBitSet(static_cast<StorageType>(option)), "Enumerator is not a positive power of two.");
56
            m_storage |= static_cast<StorageType>(option);
75
            m_storage |= static_cast<StorageType>(option);
76
        }
57
    }
77
    }
58
78
59
    constexpr StorageType toRaw() const { return m_storage; }
79
    constexpr StorageType toRaw() const { return m_storage; }
60
80
81
    constexpr bool isEmpty() const { return !m_storage; }
82
83
    constexpr iterator begin() const { return m_storage; }
84
    constexpr iterator end() const { return 0; }
85
61
    constexpr bool contains(OptionSet optionSet) const
86
    constexpr bool contains(OptionSet optionSet) const
62
    {
87
    {
63
        return m_storage & optionSet.m_storage;
88
        return m_storage & optionSet.m_storage;
Lines 71-79 public: a/Source/WTF/wtf/OptionSet.h_sec2
71
    }
96
    }
72
97
73
private:
98
private:
99
    enum InitializationTag { FromRawValue };
100
    constexpr OptionSet(T t, InitializationTag)
101
        : m_storage(static_cast<StorageType>(t))
102
    {
103
    }
74
    StorageType m_storage { 0 };
104
    StorageType m_storage { 0 };
75
};
105
};
76
106
107
template<typename T, typename StorageType> class OptionSetIterator {
108
public:
109
    OptionSetIterator(const StorageType value) : m_value(value) { }
110
    OptionSetIterator(const OptionSetIterator& other) : m_value(other.m_value) { }
111
112
    OptionSetIterator& operator=(const OptionSetIterator& other)
113
    {
114
        m_value = other.m_value;
115
        return *this;
116
    }
117
118
    // Isolate the rightmost set bit.
119
    T operator*() const { return static_cast<T>(m_value & -m_value); }
120
121
    // Iterates from smallest to largest enum value by turning off the rightmost set bit.
122
    OptionSetIterator& operator++()
123
    {
124
        m_value &= m_value - 1;
125
        return *this;
126
    }
127
128
    OptionSetIterator& operator++(int) = delete;
129
130
    bool operator==(const OptionSetIterator& other) const { return m_value == other.m_value; }
131
    bool operator!=(const OptionSetIterator& other) const { return m_value != other.m_value; }
132
133
private:
134
    StorageType m_value;
135
};
136
77
}
137
}
78
138
79
using WTF::OptionSet;
139
using WTF::OptionSet;
- a/Tools/ChangeLog +16 lines
Lines 1-5 a/Tools/ChangeLog_sec1
1
2016-03-03  Daniel Bates  <dabates@apple.com>
1
2016-03-03  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
        <rdar://problem/24964187>
6
7
        Reviewed by NOBODY (OOPS!).
8
9
        Add tests to ensure that we do not regression both iteration of an OptionSet and
10
        determining whether an OptionSet is empty.
11
12
        * TestWebKitAPI/PlatformUtilities.h:
13
        (TestWebKitAPI::Util::assertStrongEnum): Helper function to assert two strong enum type for equality.
14
        * TestWebKitAPI/Tests/WTF/OptionSet.cpp:
15
        (TestWebKitAPI::TEST):
16
17
2016-03-03  Daniel Bates  <dabates@apple.com>
18
3
        Add unit tests for WTF::OptionSet
19
        Add unit tests for WTF::OptionSet
4
        https://bugs.webkit.org/show_bug.cgi?id=154925
20
        https://bugs.webkit.org/show_bug.cgi?id=154925
5
        <rdar://problem/24964211>
21
        <rdar://problem/24964211>
- 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