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
34namespace 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.
39template<typename T> class OptionSet {
40 WTF_MAKE_FAST_ALLOCATED;
41 static_assert(std::is_enum<T>::value, "T is not an enum type");
42 typedef typename std::make_unsigned<typename std::underlying_type<T>::type>::type StorageType;
43
44public:
45 template<typename StorageType> class Iterator {
46 WTF_MAKE_FAST_ALLOCATED;
47 public:
48 // Isolate the rightmost set bit.
49 T operator*() const { return static_cast<T>(m_value & -m_value); }
50
51 // Iterates from smallest to largest enum value by turning off the rightmost set bit.
52 Iterator& operator++()
53 {
54 m_value &= m_value - 1;
55 return *this;
56 }
57
58 Iterator& operator++(int) = delete;
59
60 bool operator==(const Iterator& other) const { return m_value == other.m_value; }
61 bool operator!=(const Iterator& other) const { return m_value != other.m_value; }
62
63 private:
64 Iterator(StorageType value) : m_value(value) { }
65 friend OptionSet;
66
67 StorageType m_value;
68 };
69 using iterator = Iterator<StorageType>;
70
71 static constexpr OptionSet fromRaw(StorageType storageType)
72 {
73 return OptionSet(static_cast<T>(storageType), FromRawValue);
74 }
75
76 constexpr OptionSet() = default;
77
78 constexpr OptionSet(T t)
79 : m_storage(static_cast<StorageType>(t))
80 {
81 ASSERT_WITH_MESSAGE(!m_storage || hasOneBitSet(m_storage), "Enumerator is not a zero or a positive power of two.");
82 }
83
84 constexpr OptionSet(std::initializer_list<T> initializerList)
85 {
86 for (auto& option : initializerList) {
87 ASSERT_WITH_MESSAGE(hasOneBitSet(static_cast<StorageType>(option)), "Enumerator is not a positive power of two.");
88 m_storage |= static_cast<StorageType>(option);
89 }
90 }
91
92 constexpr StorageType toRaw() const { return m_storage; }
93
94 constexpr bool isEmpty() const { return !m_storage; }
95
96 constexpr iterator begin() const { return m_storage; }
97 constexpr iterator end() const { return 0; }
98
99 constexpr explicit operator bool() { return !isEmpty(); }
100
101 constexpr bool contains(T option) const
102 {
103 return containsAny(option);
104 }
105
106 constexpr bool containsAny(OptionSet optionSet) const
107 {
108 return !!(*this & optionSet);
109 }
110
111 constexpr bool containsAll(OptionSet optionSet) const
112 {
113 return (*this & optionSet) == optionSet;
114 }
115
116 constexpr void add(OptionSet optionSet)
117 {
118 m_storage |= optionSet.m_storage;
119 }
120
121 constexpr void remove(OptionSet optionSet)
122 {
123 m_storage &= ~optionSet.m_storage;
124 }
125
126 constexpr friend bool operator==(OptionSet lhs, OptionSet rhs)
127 {
128 return lhs.m_storage == rhs.m_storage;
129 }
130
131 constexpr friend bool operator!=(OptionSet lhs, OptionSet rhs)
132 {
133 return lhs.m_storage != rhs.m_storage;
134 }
135
136 constexpr friend OptionSet operator|(OptionSet lhs, OptionSet rhs)
137 {
138 return fromRaw(lhs.m_storage | rhs.m_storage);
139 }
140
141 constexpr friend OptionSet operator&(OptionSet lhs, OptionSet rhs)
142 {
143 return fromRaw(lhs.m_storage & rhs.m_storage);
144 }
145
146 constexpr friend OptionSet operator-(OptionSet lhs, OptionSet rhs)
147 {
148 return fromRaw(lhs.m_storage & ~rhs.m_storage);
149 }
150
151 constexpr friend OptionSet operator^(OptionSet lhs, OptionSet rhs)
152 {
153 return fromRaw(lhs.m_storage ^ rhs.m_storage);
154 }
155
156private:
157 enum InitializationTag { FromRawValue };
158 constexpr OptionSet(T t, InitializationTag)
159 : m_storage(static_cast<StorageType>(t))
160 {
161 }
162 StorageType m_storage { 0 };
163};
164
165}
166
167using WTF::OptionSet;
168