summaryrefslogtreecommitdiff
path: root/source/enum_set.h
blob: 95cfc497e996119a9154f21c0ddbdf126b016b11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright (c) 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef SOURCE_ENUM_SET_H_
#define SOURCE_ENUM_SET_H_

#include <cstdint>
#include <functional>
#include <memory>
#include <set>
#include <utility>

#include "latest_version_spirv_header.h"

namespace spvtools {

// A set of values of a 32-bit enum type.
// It is fast and compact for the common case, where enum values
// are at most 63.  But it can represent enums with larger values,
// as may appear in extensions.
template <typename EnumType>
class EnumSet {
 private:
  // The ForEach method will call the functor on enum values in
  // enum value order (lowest to highest).  To make that easier, use
  // an ordered set for the overflow values.
  using OverflowSetType = std::set<uint32_t>;

 public:
  // Construct an empty set.
  EnumSet() {}
  // Construct an set with just the given enum value.
  explicit EnumSet(EnumType c) { Add(c); }
  // Construct an set from an initializer list of enum values.
  EnumSet(std::initializer_list<EnumType> cs) {
    for (auto c : cs) Add(c);
  }
  EnumSet(uint32_t count, const EnumType* ptr) {
    for (uint32_t i = 0; i < count; ++i) Add(ptr[i]);
  }
  // Copy constructor.
  EnumSet(const EnumSet& other) { *this = other; }
  // Move constructor.  The moved-from set is emptied.
  EnumSet(EnumSet&& other) {
    mask_ = other.mask_;
    overflow_ = std::move(other.overflow_);
    other.mask_ = 0;
    other.overflow_.reset(nullptr);
  }
  // Assignment operator.
  EnumSet& operator=(const EnumSet& other) {
    if (&other != this) {
      mask_ = other.mask_;
      overflow_.reset(other.overflow_ ? new OverflowSetType(*other.overflow_)
                                      : nullptr);
    }
    return *this;
  }

  // Adds the given enum value to the set.  This has no effect if the
  // enum value is already in the set.
  void Add(EnumType c) { AddWord(ToWord(c)); }

  // Returns true if this enum value is in the set.
  bool Contains(EnumType c) const { return ContainsWord(ToWord(c)); }

  // Applies f to each enum in the set, in order from smallest enum
  // value to largest.
  void ForEach(std::function<void(EnumType)> f) const {
    for (uint32_t i = 0; i < 64; ++i) {
      if (mask_ & AsMask(i)) f(static_cast<EnumType>(i));
    }
    if (overflow_) {
      for (uint32_t c : *overflow_) f(static_cast<EnumType>(c));
    }
  }

  // Returns true if the set is empty.
  bool IsEmpty() const {
    if (mask_) return false;
    if (overflow_ && !overflow_->empty()) return false;
    return true;
  }

  // Returns true if the set contains ANY of the elements of |in_set|,
  // or if |in_set| is empty.
  bool HasAnyOf(const EnumSet<EnumType>& in_set) const {
    if (in_set.IsEmpty()) return true;

    if (mask_ & in_set.mask_) return true;

    if (!overflow_ || !in_set.overflow_) return false;

    for (uint32_t item : *in_set.overflow_) {
      if (overflow_->find(item) != overflow_->end()) return true;
    }

    return false;
  }

 private:
  // Adds the given enum value (as a 32-bit word) to the set.  This has no
  // effect if the enum value is already in the set.
  void AddWord(uint32_t word) {
    if (auto new_bits = AsMask(word)) {
      mask_ |= new_bits;
    } else {
      Overflow().insert(word);
    }
  }

  // Returns true if the enum represented as a 32-bit word is in the set.
  bool ContainsWord(uint32_t word) const {
    // We shouldn't call Overflow() since this is a const method.
    if (auto bits = AsMask(word)) {
      return (mask_ & bits) != 0;
    } else if (auto overflow = overflow_.get()) {
      return overflow->find(word) != overflow->end();
    }
    // The word is large, but the set doesn't have large members, so
    // it doesn't have an overflow set.
    return false;
  }

  // Returns the enum value as a uint32_t.
  uint32_t ToWord(EnumType value) const {
    static_assert(sizeof(EnumType) <= sizeof(uint32_t),
                  "EnumType must statically castable to uint32_t");
    return static_cast<uint32_t>(value);
  }

  // Determines whether the given enum value can be represented
  // as a bit in a uint64_t mask. If so, then returns that mask bit.
  // Otherwise, returns 0.
  uint64_t AsMask(uint32_t word) const {
    if (word > 63) return 0;
    return uint64_t(1) << word;
  }

  // Ensures that overflow_set_ references a set.  A new empty set is
  // allocated if one doesn't exist yet.  Returns overflow_set_.
  OverflowSetType& Overflow() {
    if (overflow_.get() == nullptr) {
      overflow_.reset(new OverflowSetType);
    }
    return *overflow_;
  }

  // Enums with values up to 63 are stored as bits in this mask.
  uint64_t mask_ = 0;
  // Enums with values larger than 63 are stored in this set.
  // This set should normally be empty or very small.
  std::unique_ptr<OverflowSetType> overflow_ = {};
};

// A set of SpvCapability, optimized for small capability values.
using CapabilitySet = EnumSet<SpvCapability>;

}  // namespace spvtools

#endif  // SOURCE_ENUM_SET_H_