tint: Rework tint::Manager

Don't use dynamic casting in hashing and equality. These should be fast, and dynamic casting is expensive.

Add type::UniqueNode for things that need de-duplicating and bin the types on construction.

Replace some use of SFINAE with constexpr.

Also fixes a build failure for x86.

Bug: oss-fuzz:54184
Change-Id: Ic1b0708394f9f5703fc179a2c31ce18bd07e196c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/114760
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Ben Clayton 2022-12-16 15:31:19 +00:00 committed by Dawn LUCI CQ
parent 1438e82354
commit 7c3e9a6dd2
56 changed files with 237 additions and 212 deletions

View File

@ -583,6 +583,7 @@ libtint_source_set("libtint_core_all_src") {
"type/texture.h",
"type/type.h",
"type/u32.h",
"type/unique_node.h",
"type/vector.h",
"type/void.h",
"utils/bitcast.h",
@ -754,6 +755,8 @@ libtint_source_set("libtint_type_src") {
"type/type.h",
"type/u32.cc",
"type/u32.h",
"type/unique_node.cc",
"type/unique_node.h",
"type/vector.cc",
"type/vector.h",
"type/void.cc",

View File

@ -514,6 +514,8 @@ list(APPEND TINT_LIB_SRCS
type/type.h
type/u32.cc
type/u32.h
type/unique_node.cc
type/unique_node.h
type/vector.cc
type/vector.h
type/void.cc

View File

@ -539,35 +539,18 @@ class ProgramBuilder {
return constant_nodes_.Create<constant::Splat>(type, element, n);
}
/// Creates a new type::Type owned by the ProgramBuilder.
/// When the ProgramBuilder is destructed, owned ProgramBuilder and the
/// returned `Type` will also be destructed.
/// Types are unique (de-aliased), and so calling create() for the same `T`
/// and arguments will return the same pointer.
/// @param args the arguments to pass to the type constructor
/// @returns the de-aliased type pointer
/// Creates a new type::Node owned by the ProgramBuilder.
/// When the ProgramBuilder is destructed, owned ProgramBuilder and the returned node will also
/// be destructed. If T derives from type::UniqueNode, then the calling create() for the same
/// `T` and arguments will return the same pointer.
/// @param args the arguments to pass to the constructor
/// @returns the new, or existing node
template <typename T, typename... ARGS>
traits::EnableIfIsType<T, type::Type>* create(ARGS&&... args) {
traits::EnableIfIsType<T, type::Node>* create(ARGS&&... args) {
AssertNotMoved();
return types_.Get<T>(std::forward<ARGS>(args)...);
}
/// Creates a new type::ArrayCount owned by the ProgramBuilder.
/// When the ProgramBuilder is destructed, owned ProgramBuilder and the
/// returned `ArrayCount` will also be destructed.
/// ArrayCounts are unique (de-aliased), and so calling create() for the same `T`
/// and arguments will return the same pointer.
/// @param args the arguments to pass to the array count constructor
/// @returns the de-aliased array count pointer
template <typename T, typename... ARGS>
traits::EnableIf<traits::IsTypeOrDerived<T, type::ArrayCount> ||
traits::IsTypeOrDerived<T, type::StructMember>,
T>*
create(ARGS&&... args) {
AssertNotMoved();
return types_.GetNode<T>(std::forward<ARGS>(args)...);
}
/// Marks this builder as moved, preventing any further use of the builder.
void MarkAsMoved();

View File

@ -62,7 +62,7 @@ class Any final : public Castable<Any, type::Type> {
// Stub implementations for type::Type conformance.
size_t Hash() const override { return 0; }
bool Equals(const type::Type&) const override { return false; }
bool Equals(const type::UniqueNode&) const override { return false; }
std::string FriendlyName(const SymbolTable&) const override { return "<any>"; }
};

View File

@ -27,7 +27,7 @@ size_t NamedOverrideArrayCount::Hash() const {
return static_cast<size_t>(TypeInfo::Of<NamedOverrideArrayCount>().full_hashcode);
}
bool NamedOverrideArrayCount::Equals(const ArrayCount& other) const {
bool NamedOverrideArrayCount::Equals(const UniqueNode& other) const {
if (auto* v = other.As<NamedOverrideArrayCount>()) {
return variable == v->variable;
}
@ -45,7 +45,7 @@ size_t UnnamedOverrideArrayCount::Hash() const {
return static_cast<size_t>(TypeInfo::Of<UnnamedOverrideArrayCount>().full_hashcode);
}
bool UnnamedOverrideArrayCount::Equals(const ArrayCount& other) const {
bool UnnamedOverrideArrayCount::Equals(const UniqueNode& other) const {
if (auto* v = other.As<UnnamedOverrideArrayCount>()) {
return expr == v->expr;
}

View File

@ -39,9 +39,9 @@ class NamedOverrideArrayCount final : public Castable<NamedOverrideArrayCount, t
/// @returns a hash of the array count.
size_t Hash() const override;
/// @param t other array count
/// @returns true if this array count is equal to the given array count
bool Equals(const type::ArrayCount& t) const override;
/// @param other the other node
/// @returns true if this array count is equal @p other
bool Equals(const type::UniqueNode& other) const override;
/// @param symbols the symbol table
/// @returns the friendly name for this array count
@ -68,9 +68,9 @@ class UnnamedOverrideArrayCount final
/// @returns a hash of the array count.
size_t Hash() const override;
/// @param t other array count
/// @returns true if this array count is equal to the given array count
bool Equals(const type::ArrayCount& t) const override;
/// @param other the other node
/// @returns true if this array count is equal @p other
bool Equals(const type::UniqueNode& other) const override;
/// @param symbols the symbol table
/// @returns the friendly name for this array count

View File

@ -29,7 +29,7 @@ size_t AbstractFloat::Hash() const {
return utils::Hash(TypeInfo::Of<AbstractFloat>().full_hashcode);
}
bool AbstractFloat::Equals(const Type& other) const {
bool AbstractFloat::Equals(const UniqueNode& other) const {
return other.Is<AbstractFloat>();
}

View File

@ -37,7 +37,7 @@ class AbstractFloat final : public Castable<AbstractFloat, AbstractNumeric> {
/// @param other the other type to compare against
/// @returns true if this type is equal to the given type
bool Equals(const Type& other) const override;
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type when printed in diagnostics.

View File

@ -29,7 +29,7 @@ size_t AbstractInt::Hash() const {
return utils::Hash(TypeInfo::Of<AbstractInt>().full_hashcode);
}
bool AbstractInt::Equals(const Type& other) const {
bool AbstractInt::Equals(const UniqueNode& other) const {
return other.Is<AbstractInt>();
}

View File

@ -35,9 +35,9 @@ class AbstractInt final : public Castable<AbstractInt, AbstractNumeric> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type when printed in diagnostics.

View File

@ -72,7 +72,7 @@ size_t Array::Hash() const {
return utils::Hash(TypeInfo::Of<Array>().full_hashcode, count_, align_, size_, stride_);
}
bool Array::Equals(const Type& other) const {
bool Array::Equals(const UniqueNode& other) const {
if (auto* o = other.As<Array>()) {
// Note: implicit_stride is not part of the type_name string as this is
// derived from the element type

View File

@ -55,9 +55,9 @@ class Array final : public Castable<Array, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @return the array element type
Type const* ElemType() const { return element_; }

View File

@ -30,7 +30,7 @@ size_t ConstantArrayCount::Hash() const {
return static_cast<size_t>(TypeInfo::Of<ConstantArrayCount>().full_hashcode);
}
bool ConstantArrayCount::Equals(const ArrayCount& other) const {
bool ConstantArrayCount::Equals(const UniqueNode& other) const {
if (auto* v = other.As<ConstantArrayCount>()) {
return value == v->value;
}
@ -48,7 +48,7 @@ size_t RuntimeArrayCount::Hash() const {
return static_cast<size_t>(TypeInfo::Of<RuntimeArrayCount>().full_hashcode);
}
bool RuntimeArrayCount::Equals(const ArrayCount& other) const {
bool RuntimeArrayCount::Equals(const UniqueNode& other) const {
return other.Is<RuntimeArrayCount>();
}

View File

@ -19,22 +19,15 @@
#include <string>
#include "src/tint/symbol_table.h"
#include "src/tint/type/node.h"
#include "src/tint/type/unique_node.h"
namespace tint::type {
/// An array count
class ArrayCount : public Castable<ArrayCount, Node> {
class ArrayCount : public Castable<ArrayCount, UniqueNode> {
public:
~ArrayCount() override;
/// @returns a hash of the array count.
virtual size_t Hash() const = 0;
/// @param t other array count
/// @returns true if this array count is equal to the given array count
virtual bool Equals(const ArrayCount& t) const = 0;
/// @param symbols the symbol table
/// @returns the friendly name for this array count
virtual std::string FriendlyName(const SymbolTable& symbols) const = 0;
@ -59,9 +52,9 @@ class ConstantArrayCount final : public Castable<ConstantArrayCount, ArrayCount>
/// @returns a hash of the array count.
size_t Hash() const override;
/// @param t other array count
/// @returns true if this array count is equal to the given array count
bool Equals(const ArrayCount& t) const override;
/// @param other the other object
/// @returns true if this array count is equal to other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the symbol table
/// @returns the friendly name for this array count
@ -85,9 +78,9 @@ class RuntimeArrayCount final : public Castable<RuntimeArrayCount, ArrayCount> {
/// @returns a hash of the array count.
size_t Hash() const override;
/// @param t other array count
/// @returns true if this array count is equal to the given array count
bool Equals(const ArrayCount& t) const override;
/// @param other the other object
/// @returns true if this array count is equal to other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the symbol table
/// @returns the friendly name for this array count

View File

@ -35,7 +35,7 @@ size_t Atomic::Hash() const {
return utils::Hash(TypeInfo::Of<Atomic>().full_hashcode, subtype_);
}
bool Atomic::Equals(const type::Type& other) const {
bool Atomic::Equals(const type::UniqueNode& other) const {
if (auto* o = other.As<Atomic>()) {
return o->subtype_ == subtype_;
}

View File

@ -35,9 +35,9 @@ class Atomic final : public Castable<Atomic, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const type::Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const type::UniqueNode& other) const override;
/// @returns the atomic type
const type::Type* Type() const { return subtype_; }

View File

@ -35,7 +35,7 @@ size_t Bool::Hash() const {
return static_cast<size_t>(TypeInfo::Of<Bool>().full_hashcode);
}
bool Bool::Equals(const Type& other) const {
bool Bool::Equals(const UniqueNode& other) const {
return other.Is<Bool>();
}

View File

@ -39,9 +39,9 @@ class Bool final : public Castable<Bool, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be

View File

@ -40,7 +40,7 @@ size_t DepthMultisampledTexture::Hash() const {
return utils::Hash(TypeInfo::Of<DepthMultisampledTexture>().full_hashcode, dim());
}
bool DepthMultisampledTexture::Equals(const Type& other) const {
bool DepthMultisampledTexture::Equals(const UniqueNode& other) const {
if (auto* o = other.As<DepthMultisampledTexture>()) {
return o->dim() == dim();
}

View File

@ -34,9 +34,9 @@ class DepthMultisampledTexture final : public Castable<DepthMultisampledTexture,
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be

View File

@ -41,7 +41,7 @@ size_t DepthTexture::Hash() const {
return utils::Hash(TypeInfo::Of<DepthTexture>().full_hashcode, dim());
}
bool DepthTexture::Equals(const Type& other) const {
bool DepthTexture::Equals(const UniqueNode& other) const {
if (auto* o = other.As<DepthTexture>()) {
return o->dim() == dim();
}

View File

@ -34,9 +34,9 @@ class DepthTexture final : public Castable<DepthTexture, Texture> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be

View File

@ -30,7 +30,7 @@ size_t ExternalTexture::Hash() const {
return static_cast<size_t>(TypeInfo::Of<ExternalTexture>().full_hashcode);
}
bool ExternalTexture::Equals(const Type& other) const {
bool ExternalTexture::Equals(const UniqueNode& other) const {
return other.Is<ExternalTexture>();
}

View File

@ -34,9 +34,9 @@ class ExternalTexture final : public Castable<ExternalTexture, Texture> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be

View File

@ -35,7 +35,7 @@ size_t F16::Hash() const {
return static_cast<size_t>(TypeInfo::Of<F16>().full_hashcode);
}
bool F16::Equals(const Type& other) const {
bool F16::Equals(const UniqueNode& other) const {
return other.Is<F16>();
}

View File

@ -33,9 +33,9 @@ class F16 final : public Castable<F16, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be

View File

@ -35,7 +35,7 @@ size_t F32::Hash() const {
return static_cast<size_t>(TypeInfo::Of<F32>().full_hashcode);
}
bool F32::Equals(const Type& other) const {
bool F32::Equals(const UniqueNode& other) const {
return other.Is<F32>();
}

View File

@ -33,9 +33,9 @@ class F32 final : public Castable<F32, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be

View File

@ -35,7 +35,7 @@ size_t I32::Hash() const {
return static_cast<size_t>(TypeInfo::Of<I32>().full_hashcode);
}
bool I32::Equals(const Type& other) const {
bool I32::Equals(const UniqueNode& other) const {
return other.Is<I32>();
}

View File

@ -33,9 +33,9 @@ class I32 final : public Castable<I32, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be

View File

@ -15,15 +15,10 @@
#ifndef SRC_TINT_TYPE_MANAGER_H_
#define SRC_TINT_TYPE_MANAGER_H_
#include <functional>
#include <string>
#include <unordered_map>
#include <utility>
#include "src/tint/type/array_count.h"
#include "src/tint/type/node.h"
#include "src/tint/type/struct.h"
#include "src/tint/type/type.h"
#include "src/tint/utils/hash.h"
#include "src/tint/utils/unique_allocator.h"
namespace tint::type {
@ -60,19 +55,23 @@ class Manager final {
static Manager Wrap(const Manager& inner) {
Manager out;
out.types_.Wrap(inner.types_);
out.nodes_.Wrap(inner.nodes_);
out.unique_nodes_.Wrap(inner.unique_nodes_);
return out;
}
/// @param args the arguments used to construct the object.
/// @param args the arguments used to construct the type, unique node or node.
/// @return a pointer to an instance of `T` with the provided arguments.
/// If an existing instance of `T` has been constructed, then the same
/// pointer is returned.
template <typename TYPE,
typename _ = std::enable_if<traits::IsTypeOrDerived<TYPE, Type>>,
typename... ARGS>
TYPE* Get(ARGS&&... args) {
return types_.Get<TYPE>(std::forward<ARGS>(args)...);
/// If NODE derives from UniqueNode and an existing instance of `T` has been
/// constructed, then the same pointer is returned.
template <typename NODE, typename... ARGS>
NODE* Get(ARGS&&... args) {
if constexpr (traits::IsTypeOrDerived<NODE, Type>) {
return types_.Get<NODE>(std::forward<ARGS>(args)...);
} else if constexpr (traits::IsTypeOrDerived<NODE, UniqueNode>) {
return unique_nodes_.Get<NODE>(std::forward<ARGS>(args)...);
} else {
return nodes_.Create<NODE>(std::forward<ARGS>(args)...);
}
}
/// @param args the arguments used to create the temporary used for the search.
@ -85,68 +84,20 @@ class Manager final {
return types_.Find<TYPE>(std::forward<ARGS>(args)...);
}
/// @param args the arguments used to construct the object.
/// @return a pointer to an instance of `T` with the provided arguments.
/// If an existing instance of `T` has been constructed, then the same
/// pointer is returned.
template <typename TYPE,
typename _ = std::enable_if<traits::IsTypeOrDerived<TYPE, ArrayCount> ||
traits::IsTypeOrDerived<TYPE, StructMember>>,
typename... ARGS>
TYPE* GetNode(ARGS&&... args) {
return nodes_.Get<TYPE>(std::forward<ARGS>(args)...);
}
/// @returns an iterator to the beginning of the types
TypeIterator begin() const { return types_.begin(); }
/// @returns an iterator to the end of the types
TypeIterator end() const { return types_.end(); }
private:
/// Unique types owned by the manager
utils::UniqueAllocator<Type> types_;
utils::UniqueAllocator<Node> nodes_;
/// Unique nodes (excluding types) owned by the manager
utils::UniqueAllocator<UniqueNode> unique_nodes_;
/// Non-unique nodes owned by the manager
utils::BlockAllocator<Node> nodes_;
};
} // namespace tint::type
namespace std {
/// std::hash specialization for tint::type::Node
template <>
struct hash<tint::type::Node> {
/// @param type the type to obtain a hash from
/// @returns the hash of the type
size_t operator()(const tint::type::Node& type) const {
if (const auto* ac = type.As<tint::type::ArrayCount>()) {
return ac->Hash();
} else if (type.Is<tint::type::StructMember>()) {
return tint::TypeInfo::Of<tint::type::StructMember>().full_hashcode;
}
TINT_ASSERT(Type, false && "Unreachable");
return 0;
}
};
/// std::equal_to specialization for tint::type::Node
template <>
struct equal_to<tint::type::Node> {
/// @param a the first type to compare
/// @param b the second type to compare
/// @returns true if the two types are equal
bool operator()(const tint::type::Node& a, const tint::type::Node& b) const {
if (const auto* ac = a.As<tint::type::ArrayCount>()) {
if (const auto* bc = b.As<tint::type::ArrayCount>()) {
return ac->Equals(*bc);
}
return false;
} else if (a.Is<tint::type::StructMember>()) {
return &a == &b;
}
TINT_ASSERT(Type, false && "Unreachable");
return false;
}
};
} // namespace std
#endif // SRC_TINT_TYPE_MANAGER_H_

View File

@ -46,7 +46,7 @@ size_t Matrix::Hash() const {
return utils::Hash(TypeInfo::Of<Vector>().full_hashcode, rows_, columns_, column_type_);
}
bool Matrix::Equals(const Type& other) const {
bool Matrix::Equals(const UniqueNode& other) const {
if (auto* v = other.As<Matrix>()) {
return v->rows_ == rows_ && v->columns_ == columns_ && v->column_type_ == column_type_;
}

View File

@ -40,9 +40,9 @@ class Matrix final : public Castable<Matrix, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the type of the matrix
const Type* type() const { return subtype_; }

View File

@ -34,7 +34,7 @@ size_t MultisampledTexture::Hash() const {
return utils::Hash(TypeInfo::Of<MultisampledTexture>().full_hashcode, dim(), type_);
}
bool MultisampledTexture::Equals(const Type& other) const {
bool MultisampledTexture::Equals(const UniqueNode& other) const {
if (auto* o = other.As<MultisampledTexture>()) {
return o->dim() == dim() && o->type_ == type_;
}

View File

@ -35,9 +35,9 @@ class MultisampledTexture final : public Castable<MultisampledTexture, Texture>
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the subtype of the sampled texture
const Type* type() const { return type_; }

View File

@ -32,7 +32,7 @@ size_t Pointer::Hash() const {
return utils::Hash(TypeInfo::Of<Pointer>().full_hashcode, address_space_, subtype_, access_);
}
bool Pointer::Equals(const Type& other) const {
bool Pointer::Equals(const UniqueNode& other) const {
if (auto* o = other.As<Pointer>()) {
return o->address_space_ == address_space_ && o->subtype_ == subtype_ &&
o->access_ == access_;

View File

@ -39,9 +39,9 @@ class Pointer final : public Castable<Pointer, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the pointee type
const Type* StoreType() const { return subtype_; }

View File

@ -31,7 +31,7 @@ size_t Reference::Hash() const {
return utils::Hash(TypeInfo::Of<Reference>().full_hashcode, address_space_, subtype_, access_);
}
bool Reference::Equals(const Type& other) const {
bool Reference::Equals(const UniqueNode& other) const {
if (auto* o = other.As<Reference>()) {
return o->address_space_ == address_space_ && o->subtype_ == subtype_ &&
o->access_ == access_;

View File

@ -39,9 +39,9 @@ class Reference final : public Castable<Reference, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the pointee type
const Type* StoreType() const { return subtype_; }

View File

@ -34,7 +34,7 @@ size_t SampledTexture::Hash() const {
return utils::Hash(TypeInfo::Of<SampledTexture>().full_hashcode, dim(), type_);
}
bool SampledTexture::Equals(const Type& other) const {
bool SampledTexture::Equals(const UniqueNode& other) const {
if (auto* o = other.As<SampledTexture>()) {
return o->dim() == dim() && o->type_ == type_;
}

View File

@ -35,9 +35,9 @@ class SampledTexture final : public Castable<SampledTexture, Texture> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the subtype of the sampled texture
Type* type() const { return const_cast<Type*>(type_); }

View File

@ -31,7 +31,7 @@ size_t Sampler::Hash() const {
return utils::Hash(TypeInfo::Of<Sampler>().full_hashcode, kind_);
}
bool Sampler::Equals(const Type& other) const {
bool Sampler::Equals(const UniqueNode& other) const {
if (auto* o = other.As<Sampler>()) {
return o->kind_ == kind_;
}

View File

@ -35,9 +35,9 @@ class Sampler final : public Castable<Sampler, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the sampler type
ast::SamplerKind kind() const { return kind_; }

View File

@ -35,7 +35,7 @@ size_t StorageTexture::Hash() const {
return utils::Hash(TypeInfo::Of<StorageTexture>().full_hashcode, dim(), texel_format_, access_);
}
bool StorageTexture::Equals(const Type& other) const {
bool StorageTexture::Equals(const UniqueNode& other) const {
if (auto* o = other.As<StorageTexture>()) {
return o->dim() == dim() && o->texel_format_ == texel_format_ && o->access_ == access_;
}

View File

@ -48,9 +48,9 @@ class StorageTexture final : public Castable<StorageTexture, Texture> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the storage subtype
Type* type() const { return subtype_; }

View File

@ -70,7 +70,7 @@ size_t Struct::Hash() const {
return utils::Hash(TypeInfo::Of<Struct>().full_hashcode, name_);
}
bool Struct::Equals(const Type& other) const {
bool Struct::Equals(const UniqueNode& other) const {
if (auto* o = other.As<Struct>()) {
return o->name_ == name_;
}

View File

@ -68,9 +68,9 @@ class Struct : public Castable<Struct, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the source of the structure
tint::Source Source() const { return source_; }

View File

@ -18,7 +18,7 @@
#include <functional>
#include <string>
#include "src/tint/type/node.h"
#include "src/tint/type/unique_node.h"
#include "src/tint/utils/enum_set.h"
#include "src/tint/utils/vector.h"
@ -46,18 +46,12 @@ enum Flag {
using Flags = utils::EnumSet<Flag>;
/// Base class for a type in the system
class Type : public Castable<Type, Node> {
class Type : public Castable<Type, UniqueNode> {
public:
/// Move constructor
Type(Type&&);
~Type() override;
/// @returns a hash of the type.
virtual size_t Hash() const = 0;
/// @returns true if the this type is equal to the given type
virtual bool Equals(const Type&) const = 0;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be
/// declared in WGSL.

View File

@ -35,7 +35,7 @@ size_t U32::Hash() const {
return static_cast<size_t>(TypeInfo::Of<U32>().full_hashcode);
}
bool U32::Equals(const Type& other) const {
bool U32::Equals(const UniqueNode& other) const {
return other.Is<U32>();
}

View File

@ -33,9 +33,9 @@ class U32 final : public Castable<U32, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be

View File

@ -0,0 +1,27 @@
// Copyright 2022 The Tint Authors.
//
// 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.
#include "src/tint/type/unique_node.h"
TINT_INSTANTIATE_TYPEINFO(tint::type::UniqueNode);
namespace tint::type {
UniqueNode::UniqueNode() = default;
UniqueNode::UniqueNode(const UniqueNode&) = default;
UniqueNode::~UniqueNode() = default;
} // namespace tint::type

View File

@ -0,0 +1,72 @@
// Copyright 2022 The Tint Authors.
//
// 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 SRC_TINT_TYPE_UNIQUE_NODE_H_
#define SRC_TINT_TYPE_UNIQUE_NODE_H_
#include <functional>
#include "src/tint/type/node.h"
namespace tint::type {
/// UniqueNode is the base class for objects that are de-duplicated by the Manager.
/// Deduplication is achieved by comparing a temporary object to the set of existing objects, using
/// Hash() and Equals(). If an existing object is found, then the pointer to that object is
/// returned, otherwise a new object is constructed, added to the Manager's set and returned.
class UniqueNode : public Castable<UniqueNode, Node> {
public:
/// Constructor
UniqueNode();
/// Copy constructor
UniqueNode(const UniqueNode&);
/// Destructor
~UniqueNode() override;
/// @returns a hash of the node.
virtual size_t Hash() const = 0;
/// @param other the other node to compare this node against
/// @returns true if the this node is equal to @p other
virtual bool Equals(const UniqueNode& other) const = 0;
};
} // namespace tint::type
namespace std {
/// std::hash specialization for tint::type::UniqueNode
template <>
struct hash<tint::type::UniqueNode> {
/// @param node the unique node to obtain a hash from
/// @returns the hash of the node
size_t operator()(const tint::type::UniqueNode& node) const { return node.Hash(); }
};
/// std::equal_to specialization for tint::type::UniqueNode
template <>
struct equal_to<tint::type::UniqueNode> {
/// @param a the first unique node to compare
/// @param b the second unique node to compare
/// @returns true if the two nodes are equal
bool operator()(const tint::type::UniqueNode& a, const tint::type::UniqueNode& b) const {
return &a == &b || a.Equals(b);
}
};
} // namespace std
#endif // SRC_TINT_TYPE_UNIQUE_NODE_H_

View File

@ -41,7 +41,7 @@ size_t Vector::Hash() const {
return utils::Hash(TypeInfo::Of<Vector>().full_hashcode, width_, subtype_);
}
bool Vector::Equals(const Type& other) const {
bool Vector::Equals(const UniqueNode& other) const {
if (auto* v = other.As<Vector>()) {
return v->width_ == width_ && v->subtype_ == subtype_;
}

View File

@ -35,9 +35,9 @@ class Vector final : public Castable<Vector, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @returns the type of the vector elements
const Type* type() const { return subtype_; }

View File

@ -30,7 +30,7 @@ size_t Void::Hash() const {
return static_cast<size_t>(TypeInfo::Of<Void>().full_hashcode);
}
bool Void::Equals(const Type& other) const {
bool Void::Equals(const UniqueNode& other) const {
return other.Is<Void>();
}

View File

@ -33,9 +33,9 @@ class Void final : public Castable<Void, Type> {
/// @returns a hash of the type.
size_t Hash() const override;
/// @param other the other type to compare against
/// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override;
/// @param other the other node to compare against
/// @returns true if the this type is equal to @p other
bool Equals(const UniqueNode& other) const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be