Use enum classes and OptionSets for PaintPhase and PaintBehavior
[WebKit-https.git] / Source / WTF / wtf / OptionSet.h
1 /*
2  * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include <initializer_list>
29 #include <iterator>
30 #include <type_traits>
31 #include <wtf/Assertions.h>
32 #include <wtf/MathExtras.h>
33
34 namespace WTF {
35
36 // OptionSet is a class that represents a set of enumerators in a space-efficient manner. The enumerators
37 // must be powers of two greater than 0. This class is useful as a replacement for passing a bitmask of
38 // enumerators around.
39 template<typename T> class OptionSet {
40     static_assert(std::is_enum<T>::value, "T is not an enum type");
41     typedef typename std::make_unsigned<typename std::underlying_type<T>::type>::type StorageType;
42
43 public:
44     template<typename StorageType> class Iterator {
45     public:
46         // Isolate the rightmost set bit.
47         T operator*() const { return static_cast<T>(m_value & -m_value); }
48
49         // Iterates from smallest to largest enum value by turning off the rightmost set bit.
50         Iterator& operator++()
51         {
52             m_value &= m_value - 1;
53             return *this;
54         }
55
56         Iterator& operator++(int) = delete;
57
58         bool operator==(const Iterator& other) const { return m_value == other.m_value; }
59         bool operator!=(const Iterator& other) const { return m_value != other.m_value; }
60
61     private:
62         Iterator(StorageType value) : m_value(value) { }
63         friend OptionSet;
64
65         StorageType m_value;
66     };
67     using iterator = Iterator<StorageType>;
68
69     static constexpr OptionSet fromRaw(StorageType storageType)
70     {
71         return OptionSet(static_cast<T>(storageType), FromRawValue);
72     }
73
74     constexpr OptionSet() = default;
75
76 #if ASSERT_DISABLED
77     constexpr OptionSet(T t)
78         : m_storage(static_cast<StorageType>(t))
79     {
80     }
81
82     constexpr OptionSet(std::initializer_list<T> initializerList)
83     {
84         for (auto& option : initializerList)
85             m_storage |= static_cast<StorageType>(option);
86     }
87 #else
88     OptionSet(T t)
89         : m_storage(static_cast<StorageType>(t))
90     {
91         ASSERT_WITH_MESSAGE(!m_storage || hasOneBitSet(static_cast<StorageType>(t)), "Enumerator is not a zero or a positive power of two.");
92     }
93
94     OptionSet(std::initializer_list<T> initializerList)
95     {
96         for (auto& option : initializerList) {
97             ASSERT_WITH_MESSAGE(hasOneBitSet(static_cast<StorageType>(option)), "Enumerator is not a positive power of two.");
98             m_storage |= static_cast<StorageType>(option);
99         }
100     }
101 #endif
102
103     constexpr StorageType toRaw() const { return m_storage; }
104
105     constexpr bool isEmpty() const { return !m_storage; }
106
107     constexpr iterator begin() const { return m_storage; }
108     constexpr iterator end() const { return 0; }
109
110     constexpr explicit operator bool() { return !isEmpty(); }
111
112     constexpr bool contains(OptionSet optionSet) const
113     {
114         return m_storage & optionSet.m_storage;
115     }
116
117     constexpr friend bool operator==(OptionSet lhs, OptionSet rhs)
118     {
119         return lhs.m_storage == rhs.m_storage;
120     }
121
122     constexpr friend bool operator!=(OptionSet lhs, OptionSet rhs)
123     {
124         return lhs.m_storage != rhs.m_storage;
125     }
126
127     friend OptionSet& operator|=(OptionSet& lhs, OptionSet rhs)
128     {
129         lhs.m_storage |= rhs.m_storage;
130         return lhs;
131     }
132
133     friend OptionSet& operator-=(OptionSet& lhs, OptionSet rhs)
134     {
135         lhs.m_storage &= ~rhs.m_storage;
136         return lhs;
137     }
138
139     constexpr friend OptionSet operator|(OptionSet lhs, OptionSet rhs)
140     {
141         return fromRaw(lhs.m_storage | rhs.m_storage);
142     }
143
144     constexpr friend OptionSet operator&(OptionSet lhs, OptionSet rhs)
145     {
146         return fromRaw(lhs.m_storage & rhs.m_storage);
147     }
148
149     constexpr friend OptionSet operator-(OptionSet lhs, OptionSet rhs)
150     {
151         return fromRaw(lhs.m_storage & ~rhs.m_storage);
152     }
153
154 private:
155     enum InitializationTag { FromRawValue };
156     constexpr OptionSet(T t, InitializationTag)
157         : m_storage(static_cast<StorageType>(t))
158     {
159     }
160     StorageType m_storage { 0 };
161 };
162
163 }
164
165 using WTF::OptionSet;