blob: 90fb59a158f59b29571952ca35e68d742b1295a0 [file] [log] [blame]
David Neto909d7f92016-08-31 14:35:58 -04001// Copyright (c) 2016 Google Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and/or associated documentation files (the
5// "Materials"), to deal in the Materials without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Materials, and to
8// permit persons to whom the Materials are furnished to do so, subject to
9// the following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Materials.
13//
14// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
15// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
16// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
17// https://www.khronos.org/registry/
18//
19// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
26
27#ifndef LIBSPIRV_ENUM_SET_H
28#define LIBSPIRV_ENUM_SET_H
29
30#include <cstdint>
31#include <functional>
32#include <memory>
33#include <set>
34#include <utility>
35
36#include "spirv/1.1/spirv.h"
37
38namespace libspirv {
39
40// A set of values of a 32-bit enum type.
41// It is fast and compact for the common case, where enum values
42// are at most 63. But it can represent enums with larger values,
43// as may appear in extensions.
44template <typename EnumType>
45class EnumSet {
46 private:
47 // The ForEach method will call the functor on enum values in
48 // enum value order (lowest to highest). To make that easier, use
49 // an ordered set for the overflow values.
50 using OverflowSetType = std::set<uint32_t>;
51
52 public:
53 // Construct an empty set.
54 EnumSet() = default;
55 // Construct an set with just the given enum value.
56 explicit EnumSet(EnumType c) { Add(c); }
57 // Construct an set from an initializer list of enum values.
58 EnumSet(std::initializer_list<EnumType> cs) {
59 for (auto c : cs) Add(c);
60 }
61 // Copy constructor.
62 EnumSet(const EnumSet& other) { *this = other; }
63 // Move constructor. The moved-from set is emptied.
64 EnumSet(EnumSet&& other) {
65 mask_ = other.mask_;
66 overflow_ = std::move(other.overflow_);
67 other.mask_ = 0;
68 other.overflow_.reset(nullptr);
69 }
70 // Assignment operator.
71 EnumSet& operator=(const EnumSet& other) {
72 if (&other != this) {
73 mask_ = other.mask_;
74 overflow_.reset(other.overflow_ ? new OverflowSetType(*other.overflow_)
75 : nullptr);
76 }
77 return *this;
78 }
79
80 // Adds the given enum value to the set. This has no effect if the
81 // enum value is already in the set.
82 void Add(EnumType c) { Add(ToWord(c)); }
83 // Adds the given enum value (as a 32-bit word) to the set. This has no
84 // effect if the enum value is already in the set.
85 void Add(uint32_t word) {
86 if (auto new_bits = AsMask(word)) {
87 mask_ |= new_bits;
88 } else {
89 Overflow().insert(word);
90 }
91 }
92
93 // Returns true if this enum value is in the set.
94 bool Contains(EnumType c) const { return Contains(ToWord(c)); }
95 // Returns true if the enum represented as a 32-bit word is in the set.
96 bool Contains(uint32_t word) const {
97 // We shouldn't call Overflow() since this is a const method.
98 if (auto bits = AsMask(word)) {
99 return mask_ & bits;
100 } else if (auto overflow = overflow_.get()) {
101 return overflow->find(word) != overflow->end();
102 }
103 // The word is large, but the set doesn't have large members, so
104 // it doesn't have an overflow set.
105 return false;
106 }
107
108 // Applies f to each enum in the set, in order from smallest enum
109 // value to largest.
110 void ForEach(std::function<void(EnumType)> f) const {
111 for (uint32_t i = 0; i < 64; ++i) {
112 if (mask_ & AsMask(i)) f(static_cast<EnumType>(i));
113 }
114 if (overflow_) {
115 for (uint32_t c : *overflow_) f(static_cast<EnumType>(c));
116 }
117 }
118
119 private:
120 // Returns the enum value as a uint32_t.
121 uint32_t ToWord(EnumType value) const {
122 static_assert(sizeof(EnumType) <= sizeof(uint32_t),
123 "EnumType must statically castable to uint32_t");
124 return static_cast<uint32_t>(value);
125 }
126
127 // Determines whether the given enum value can be represented
128 // as a bit in a uint64_t mask. If so, then returns that mask bit.
129 // Otherwise, returns 0.
130 uint64_t AsMask(uint32_t word) const {
131 if (word > 63) return 0;
132 return uint64_t(1) << word;
133 }
134
135 // Ensures that overflow_set_ references a set. A new empty set is
136 // allocated if one doesn't exist yet. Returns overflow_set_.
137 OverflowSetType& Overflow() {
138 if (overflow_.get() == nullptr) {
139 overflow_.reset(new OverflowSetType);
140 }
141 return *overflow_;
142 }
143
144 // Enums with values up to 63 are stored as bits in this mask.
145 uint64_t mask_ = 0;
146 // Enums with values larger than 63 are stored in this set.
147 // This set should normally be empty or very small.
148 std::unique_ptr<OverflowSetType> overflow_ = {};
149};
150
151// A set of SpvCapability, optimized for small capability values.
152using CapabilitySet = EnumSet<SpvCapability>;
153
154} // namespace libspirv
155
156#endif // LIBSPIRV_ENUM_SET_H