Refactor CapabilitySet into templated class EnumSet

This commit is contained in:
David Neto 2016-08-31 14:35:58 -04:00
parent 2ce67252c8
commit 909d7f9bf5
12 changed files with 171 additions and 134 deletions

View File

@ -129,8 +129,8 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/util/hex_float.h
${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.h
${CMAKE_CURRENT_SOURCE_DIR}/binary.h
${CMAKE_CURRENT_SOURCE_DIR}/capability_set.h
${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.h
${CMAKE_CURRENT_SOURCE_DIR}/enum_set.h
${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.h
${CMAKE_CURRENT_SOURCE_DIR}/instruction.h
${CMAKE_CURRENT_SOURCE_DIR}/macro.h
@ -149,7 +149,6 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.cpp
${CMAKE_CURRENT_SOURCE_DIR}/binary.cpp
${CMAKE_CURRENT_SOURCE_DIR}/capability_set.cpp
${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.cpp
${CMAKE_CURRENT_SOURCE_DIR}/disassemble.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp

View File

@ -1,119 +0,0 @@
// Copyright (c) 2016 Google Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef LIBSPIRV_CAPABILITY_SET_H
#define LIBSPIRV_CAPABILITY_SET_H
#include <cstdint>
#include <functional>
#include <memory>
#include <set>
#include <utility>
#include "spirv/1.1/spirv.h"
namespace libspirv {
// A set of values of type SpvCapability.
// It is fast and compact for the common case, where capability values
// are at most 63. But it can represent capabilities with larger values,
// as may appear in extensions.
class CapabilitySet {
private:
// The ForEach method will call the functor on capabilities 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.
CapabilitySet() = default;
// Construct an set with just the given capability.
explicit CapabilitySet(SpvCapability c) { Add(c); }
// Construct an set from an initializer list of capabilities.
CapabilitySet(std::initializer_list<SpvCapability> cs) {
for (auto c : cs) Add(c);
}
// Copy constructor.
CapabilitySet(const CapabilitySet& other) { *this = other; }
// Move constructor. The moved-from set is emptied.
CapabilitySet(CapabilitySet&& other) {
mask_ = other.mask_;
overflow_ = std::move(other.overflow_);
other.mask_ = 0;
other.overflow_.reset(nullptr);
}
// Assignment operator.
CapabilitySet& operator=(const CapabilitySet& other) {
if (&other != this) {
mask_ = other.mask_;
overflow_.reset(other.overflow_ ? new OverflowSetType(*other.overflow_)
: nullptr);
}
return *this;
}
// Adds the given capability to the set. This has no effect if the
// capability is already in the set.
void Add(SpvCapability c) { Add(static_cast<uint32_t>(c)); }
// Adds the given capability (as a 32-bit word) to the set. This has no
// effect if the capability is already in the set.
void Add(uint32_t);
// Returns true if this capability is in the set.
bool Contains(SpvCapability c) const {
return Contains(static_cast<uint32_t>(c));
}
// Returns true if the capability represented as a 32-bit word is in the set.
bool Contains(uint32_t word) const;
// Applies f to each capability in the set, in order from smallest enum
// value to largest.
void ForEach(std::function<void(SpvCapability)> f) const;
private:
// Returns true if the set has capabilities with value greater than 63.
bool HasOverflow() { return overflow_ != nullptr; }
// 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_;
}
// Capabilities with values up to 63 are stored as bits in this mask.
uint64_t mask_ = 0;
// Capabilities with values larger than 63 are stored in this set.
// This set should normally be empty or very small.
std::unique_ptr<OverflowSetType> overflow_ = {};
};
} // namespace libspirv
#endif // LIBSPIRV_CAPABILITY_SET_H

View File

@ -24,13 +24,13 @@
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include "capability_set.h"
#include "enum_set.h"
#include "spirv/1.1/spirv.hpp"
namespace {
// Determines whether the given capability can be represented
// 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) {
@ -41,7 +41,8 @@ uint64_t AsMask(uint32_t word) {
namespace libspirv {
void CapabilitySet::Add(uint32_t word) {
template<typename EnumType>
void EnumSet<EnumType>::Add(uint32_t word) {
if (auto new_bits = AsMask(word)) {
mask_ |= new_bits;
} else {
@ -49,7 +50,8 @@ void CapabilitySet::Add(uint32_t word) {
}
}
bool CapabilitySet::Contains(uint32_t word) const {
template<typename EnumType>
bool EnumSet<EnumType>::Contains(uint32_t word) const {
// We shouldn't call Overflow() since this is a const method.
if (auto bits = AsMask(word)) {
return mask_ & bits;

156
source/enum_set.h Normal file
View File

@ -0,0 +1,156 @@
// Copyright (c) 2016 Google Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef LIBSPIRV_ENUM_SET_H
#define LIBSPIRV_ENUM_SET_H
#include <cstdint>
#include <functional>
#include <memory>
#include <set>
#include <utility>
#include "spirv/1.1/spirv.h"
namespace libspirv {
// 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() = default;
// 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);
}
// 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) { Add(ToWord(c)); }
// 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 Add(uint32_t word) {
if (auto new_bits = AsMask(word)) {
mask_ |= new_bits;
} else {
Overflow().insert(word);
}
}
// Returns true if this enum value is in the set.
bool Contains(EnumType c) const { return Contains(ToWord(c)); }
// Returns true if the enum represented as a 32-bit word is in the set.
bool Contains(uint32_t word) const {
// We shouldn't call Overflow() since this is a const method.
if (auto bits = AsMask(word)) {
return mask_ & bits;
} 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;
}
// 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));
}
}
private:
// 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 libspirv
#endif // LIBSPIRV_ENUM_SET_H

View File

@ -29,7 +29,7 @@
#include "spirv/1.1/spirv.h"
#include "capability_set.h"
#include "enum_set.h"
#include "spirv-tools/libspirv.h"
typedef struct spv_opcode_desc_t {

View File

@ -34,8 +34,8 @@
#include <vector>
#include "assembly_grammar.h"
#include "capability_set.h"
#include "diagnostic.h"
#include "enum_set.h"
#include "spirv-tools/libspirv.h"
#include "spirv/1.1/spirv.h"
#include "spirv_definition.h"

View File

@ -33,8 +33,8 @@
#include <sstream>
#include <string>
#include "capability_set.h"
#include "diagnostic.h"
#include "enum_set.h"
#include "opcode.h"
#include "operand.h"
#include "spirv_definition.h"

View File

@ -24,11 +24,10 @@
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include "capability_set.h"
#include <vector>
#include "gmock/gmock.h"
#include "enum_set.h"
#include "UnitSPIRV.h"
namespace {

View File

@ -26,7 +26,7 @@
#include "UnitSPIRV.h"
#include "capability_set.h"
#include "enum_set.h"
namespace {

View File

@ -30,7 +30,7 @@
#include "gmock/gmock.h"
#include "capability_set.h"
#include "enum_set.h"
#include "UnitSPIRV.h"
namespace {

View File

@ -34,7 +34,7 @@
#include "source/assembly_grammar.h"
#include "source/binary.h"
#include "source/capability_set.h"
#include "source/enum_set.h"
#include "source/diagnostic.h"
#include "source/opcode.h"
#include "source/spirv_endian.h"

View File

@ -34,7 +34,7 @@
#include "gtest/gtest.h"
#include "spirv/1.1/spirv.h"
#include "capability_set.h"
#include "enum_set.h"
#include "val/Construct.h"
#include "val/Function.h"
#include "validate.h"