diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 87eb8521c8..484c6f9ba3 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -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", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index ee350f167f..ee7c17c9b3 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -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 diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index 597463c582..5396cdd0c5 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h @@ -539,35 +539,18 @@ class ProgramBuilder { return constant_nodes_.Create(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 - traits::EnableIfIsType* create(ARGS&&... args) { + traits::EnableIfIsType* create(ARGS&&... args) { AssertNotMoved(); return types_.Get(std::forward(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 - traits::EnableIf || - traits::IsTypeOrDerived, - T>* - create(ARGS&&... args) { - AssertNotMoved(); - return types_.GetNode(std::forward(args)...); - } - /// Marks this builder as moved, preventing any further use of the builder. void MarkAsMoved(); diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc index e6fd3df988..a8d3f478fb 100644 --- a/src/tint/resolver/intrinsic_table.cc +++ b/src/tint/resolver/intrinsic_table.cc @@ -62,7 +62,7 @@ class Any final : public Castable { // 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 ""; } }; diff --git a/src/tint/sem/array_count.cc b/src/tint/sem/array_count.cc index 08719adb99..1999877454 100644 --- a/src/tint/sem/array_count.cc +++ b/src/tint/sem/array_count.cc @@ -27,7 +27,7 @@ size_t NamedOverrideArrayCount::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool NamedOverrideArrayCount::Equals(const ArrayCount& other) const { +bool NamedOverrideArrayCount::Equals(const UniqueNode& other) const { if (auto* v = other.As()) { return variable == v->variable; } @@ -45,7 +45,7 @@ size_t UnnamedOverrideArrayCount::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool UnnamedOverrideArrayCount::Equals(const ArrayCount& other) const { +bool UnnamedOverrideArrayCount::Equals(const UniqueNode& other) const { if (auto* v = other.As()) { return expr == v->expr; } diff --git a/src/tint/sem/array_count.h b/src/tint/sem/array_count.h index d948106493..b30ab38aad 100644 --- a/src/tint/sem/array_count.h +++ b/src/tint/sem/array_count.h @@ -39,9 +39,9 @@ class NamedOverrideArrayCount final : public Castable().full_hashcode); } -bool AbstractFloat::Equals(const Type& other) const { +bool AbstractFloat::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/abstract_float.h b/src/tint/type/abstract_float.h index 69c12be181..d45ec73450 100644 --- a/src/tint/type/abstract_float.h +++ b/src/tint/type/abstract_float.h @@ -37,7 +37,7 @@ class AbstractFloat final : public Castable { /// @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. diff --git a/src/tint/type/abstract_int.cc b/src/tint/type/abstract_int.cc index dffaab03a2..439c291ba2 100644 --- a/src/tint/type/abstract_int.cc +++ b/src/tint/type/abstract_int.cc @@ -29,7 +29,7 @@ size_t AbstractInt::Hash() const { return utils::Hash(TypeInfo::Of().full_hashcode); } -bool AbstractInt::Equals(const Type& other) const { +bool AbstractInt::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/abstract_int.h b/src/tint/type/abstract_int.h index 7c7f287128..98d878ffc3 100644 --- a/src/tint/type/abstract_int.h +++ b/src/tint/type/abstract_int.h @@ -35,9 +35,9 @@ class AbstractInt final : public Castable { /// @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. diff --git a/src/tint/type/array.cc b/src/tint/type/array.cc index ad903fa014..28f41d39f8 100644 --- a/src/tint/type/array.cc +++ b/src/tint/type/array.cc @@ -72,7 +72,7 @@ size_t Array::Hash() const { return utils::Hash(TypeInfo::Of().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()) { // Note: implicit_stride is not part of the type_name string as this is // derived from the element type diff --git a/src/tint/type/array.h b/src/tint/type/array.h index 52fb8a81db..e77d2d99fc 100644 --- a/src/tint/type/array.h +++ b/src/tint/type/array.h @@ -55,9 +55,9 @@ class Array final : public Castable { /// @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_; } diff --git a/src/tint/type/array_count.cc b/src/tint/type/array_count.cc index f97e94fd05..9c6d4f6503 100644 --- a/src/tint/type/array_count.cc +++ b/src/tint/type/array_count.cc @@ -30,7 +30,7 @@ size_t ConstantArrayCount::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool ConstantArrayCount::Equals(const ArrayCount& other) const { +bool ConstantArrayCount::Equals(const UniqueNode& other) const { if (auto* v = other.As()) { return value == v->value; } @@ -48,7 +48,7 @@ size_t RuntimeArrayCount::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool RuntimeArrayCount::Equals(const ArrayCount& other) const { +bool RuntimeArrayCount::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/array_count.h b/src/tint/type/array_count.h index 76c1588307..c3e59cbc1f 100644 --- a/src/tint/type/array_count.h +++ b/src/tint/type/array_count.h @@ -19,22 +19,15 @@ #include #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 { +class ArrayCount : public Castable { 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 /// @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 { /// @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 diff --git a/src/tint/type/atomic.cc b/src/tint/type/atomic.cc index e8508743b2..5070dd9ae1 100644 --- a/src/tint/type/atomic.cc +++ b/src/tint/type/atomic.cc @@ -35,7 +35,7 @@ size_t Atomic::Hash() const { return utils::Hash(TypeInfo::Of().full_hashcode, subtype_); } -bool Atomic::Equals(const type::Type& other) const { +bool Atomic::Equals(const type::UniqueNode& other) const { if (auto* o = other.As()) { return o->subtype_ == subtype_; } diff --git a/src/tint/type/atomic.h b/src/tint/type/atomic.h index c05227407f..fefc791177 100644 --- a/src/tint/type/atomic.h +++ b/src/tint/type/atomic.h @@ -35,9 +35,9 @@ class Atomic final : public Castable { /// @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_; } diff --git a/src/tint/type/bool.cc b/src/tint/type/bool.cc index a76228dc92..8c80c522d4 100644 --- a/src/tint/type/bool.cc +++ b/src/tint/type/bool.cc @@ -35,7 +35,7 @@ size_t Bool::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool Bool::Equals(const Type& other) const { +bool Bool::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/bool.h b/src/tint/type/bool.h index 19ad8c1bd2..b14ec0a729 100644 --- a/src/tint/type/bool.h +++ b/src/tint/type/bool.h @@ -39,9 +39,9 @@ class Bool final : public Castable { /// @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 diff --git a/src/tint/type/depth_multisampled_texture.cc b/src/tint/type/depth_multisampled_texture.cc index b6a8704957..271544c720 100644 --- a/src/tint/type/depth_multisampled_texture.cc +++ b/src/tint/type/depth_multisampled_texture.cc @@ -40,7 +40,7 @@ size_t DepthMultisampledTexture::Hash() const { return utils::Hash(TypeInfo::Of().full_hashcode, dim()); } -bool DepthMultisampledTexture::Equals(const Type& other) const { +bool DepthMultisampledTexture::Equals(const UniqueNode& other) const { if (auto* o = other.As()) { return o->dim() == dim(); } diff --git a/src/tint/type/depth_multisampled_texture.h b/src/tint/type/depth_multisampled_texture.h index c39a7bf9d4..b54f5061af 100644 --- a/src/tint/type/depth_multisampled_texture.h +++ b/src/tint/type/depth_multisampled_texture.h @@ -34,9 +34,9 @@ class DepthMultisampledTexture final : public Castable().full_hashcode, dim()); } -bool DepthTexture::Equals(const Type& other) const { +bool DepthTexture::Equals(const UniqueNode& other) const { if (auto* o = other.As()) { return o->dim() == dim(); } diff --git a/src/tint/type/depth_texture.h b/src/tint/type/depth_texture.h index afa39f4a8f..db687c5d73 100644 --- a/src/tint/type/depth_texture.h +++ b/src/tint/type/depth_texture.h @@ -34,9 +34,9 @@ class DepthTexture final : public Castable { /// @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 diff --git a/src/tint/type/external_texture.cc b/src/tint/type/external_texture.cc index ac7e676ba6..298f6b5008 100644 --- a/src/tint/type/external_texture.cc +++ b/src/tint/type/external_texture.cc @@ -30,7 +30,7 @@ size_t ExternalTexture::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool ExternalTexture::Equals(const Type& other) const { +bool ExternalTexture::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/external_texture.h b/src/tint/type/external_texture.h index 9c443c0943..3afe9f643d 100644 --- a/src/tint/type/external_texture.h +++ b/src/tint/type/external_texture.h @@ -34,9 +34,9 @@ class ExternalTexture final : public Castable { /// @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 diff --git a/src/tint/type/f16.cc b/src/tint/type/f16.cc index 4243cb8942..0cea348b8f 100644 --- a/src/tint/type/f16.cc +++ b/src/tint/type/f16.cc @@ -35,7 +35,7 @@ size_t F16::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool F16::Equals(const Type& other) const { +bool F16::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/f16.h b/src/tint/type/f16.h index c4c3d1fa2b..71071e0df3 100644 --- a/src/tint/type/f16.h +++ b/src/tint/type/f16.h @@ -33,9 +33,9 @@ class F16 final : public Castable { /// @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 diff --git a/src/tint/type/f32.cc b/src/tint/type/f32.cc index ea86008b9f..5c7013996d 100644 --- a/src/tint/type/f32.cc +++ b/src/tint/type/f32.cc @@ -35,7 +35,7 @@ size_t F32::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool F32::Equals(const Type& other) const { +bool F32::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/f32.h b/src/tint/type/f32.h index 57aa560f8e..962beec117 100644 --- a/src/tint/type/f32.h +++ b/src/tint/type/f32.h @@ -33,9 +33,9 @@ class F32 final : public Castable { /// @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 diff --git a/src/tint/type/i32.cc b/src/tint/type/i32.cc index fb3d258b4a..80d7d8ee7b 100644 --- a/src/tint/type/i32.cc +++ b/src/tint/type/i32.cc @@ -35,7 +35,7 @@ size_t I32::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool I32::Equals(const Type& other) const { +bool I32::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/i32.h b/src/tint/type/i32.h index 9073daa13a..6cf9befacd 100644 --- a/src/tint/type/i32.h +++ b/src/tint/type/i32.h @@ -33,9 +33,9 @@ class I32 final : public Castable { /// @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 diff --git a/src/tint/type/manager.h b/src/tint/type/manager.h index 0515b1432a..59a8cf5e1f 100644 --- a/src/tint/type/manager.h +++ b/src/tint/type/manager.h @@ -15,15 +15,10 @@ #ifndef SRC_TINT_TYPE_MANAGER_H_ #define SRC_TINT_TYPE_MANAGER_H_ -#include -#include -#include #include -#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... ARGS> - TYPE* Get(ARGS&&... args) { - return types_.Get(std::forward(args)...); + /// If NODE derives from UniqueNode and an existing instance of `T` has been + /// constructed, then the same pointer is returned. + template + NODE* Get(ARGS&&... args) { + if constexpr (traits::IsTypeOrDerived) { + return types_.Get(std::forward(args)...); + } else if constexpr (traits::IsTypeOrDerived) { + return unique_nodes_.Get(std::forward(args)...); + } else { + return nodes_.Create(std::forward(args)...); + } } /// @param args the arguments used to create the temporary used for the search. @@ -85,68 +84,20 @@ class Manager final { return types_.Find(std::forward(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 || - traits::IsTypeOrDerived>, - typename... ARGS> - TYPE* GetNode(ARGS&&... args) { - return nodes_.Get(std::forward(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 types_; - utils::UniqueAllocator nodes_; + /// Unique nodes (excluding types) owned by the manager + utils::UniqueAllocator unique_nodes_; + /// Non-unique nodes owned by the manager + utils::BlockAllocator nodes_; }; } // namespace tint::type -namespace std { - -/// std::hash specialization for tint::type::Node -template <> -struct hash { - /// @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()) { - return ac->Hash(); - } else if (type.Is()) { - return tint::TypeInfo::Of().full_hashcode; - } - TINT_ASSERT(Type, false && "Unreachable"); - return 0; - } -}; - -/// std::equal_to specialization for tint::type::Node -template <> -struct equal_to { - /// @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()) { - if (const auto* bc = b.As()) { - return ac->Equals(*bc); - } - return false; - } else if (a.Is()) { - return &a == &b; - } - TINT_ASSERT(Type, false && "Unreachable"); - return false; - } -}; - -} // namespace std - #endif // SRC_TINT_TYPE_MANAGER_H_ diff --git a/src/tint/type/matrix.cc b/src/tint/type/matrix.cc index 063ac88a61..db5380a624 100644 --- a/src/tint/type/matrix.cc +++ b/src/tint/type/matrix.cc @@ -46,7 +46,7 @@ size_t Matrix::Hash() const { return utils::Hash(TypeInfo::Of().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()) { return v->rows_ == rows_ && v->columns_ == columns_ && v->column_type_ == column_type_; } diff --git a/src/tint/type/matrix.h b/src/tint/type/matrix.h index 3191f95677..c4df065aa4 100644 --- a/src/tint/type/matrix.h +++ b/src/tint/type/matrix.h @@ -40,9 +40,9 @@ class Matrix final : public Castable { /// @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_; } diff --git a/src/tint/type/multisampled_texture.cc b/src/tint/type/multisampled_texture.cc index e1d2ed795a..ab1356a381 100644 --- a/src/tint/type/multisampled_texture.cc +++ b/src/tint/type/multisampled_texture.cc @@ -34,7 +34,7 @@ size_t MultisampledTexture::Hash() const { return utils::Hash(TypeInfo::Of().full_hashcode, dim(), type_); } -bool MultisampledTexture::Equals(const Type& other) const { +bool MultisampledTexture::Equals(const UniqueNode& other) const { if (auto* o = other.As()) { return o->dim() == dim() && o->type_ == type_; } diff --git a/src/tint/type/multisampled_texture.h b/src/tint/type/multisampled_texture.h index 421b2946ab..410ecf42b3 100644 --- a/src/tint/type/multisampled_texture.h +++ b/src/tint/type/multisampled_texture.h @@ -35,9 +35,9 @@ class MultisampledTexture final : public Castable /// @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_; } diff --git a/src/tint/type/pointer.cc b/src/tint/type/pointer.cc index c59170cf55..00c3d225f7 100644 --- a/src/tint/type/pointer.cc +++ b/src/tint/type/pointer.cc @@ -32,7 +32,7 @@ size_t Pointer::Hash() const { return utils::Hash(TypeInfo::Of().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()) { return o->address_space_ == address_space_ && o->subtype_ == subtype_ && o->access_ == access_; diff --git a/src/tint/type/pointer.h b/src/tint/type/pointer.h index a7703e458e..c7a7ef8034 100644 --- a/src/tint/type/pointer.h +++ b/src/tint/type/pointer.h @@ -39,9 +39,9 @@ class Pointer final : public Castable { /// @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_; } diff --git a/src/tint/type/reference.cc b/src/tint/type/reference.cc index 0541f84fc2..a825bb7914 100644 --- a/src/tint/type/reference.cc +++ b/src/tint/type/reference.cc @@ -31,7 +31,7 @@ size_t Reference::Hash() const { return utils::Hash(TypeInfo::Of().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()) { return o->address_space_ == address_space_ && o->subtype_ == subtype_ && o->access_ == access_; diff --git a/src/tint/type/reference.h b/src/tint/type/reference.h index ebf307cc43..848c95d441 100644 --- a/src/tint/type/reference.h +++ b/src/tint/type/reference.h @@ -39,9 +39,9 @@ class Reference final : public Castable { /// @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_; } diff --git a/src/tint/type/sampled_texture.cc b/src/tint/type/sampled_texture.cc index 2a708e544e..b723d3afd6 100644 --- a/src/tint/type/sampled_texture.cc +++ b/src/tint/type/sampled_texture.cc @@ -34,7 +34,7 @@ size_t SampledTexture::Hash() const { return utils::Hash(TypeInfo::Of().full_hashcode, dim(), type_); } -bool SampledTexture::Equals(const Type& other) const { +bool SampledTexture::Equals(const UniqueNode& other) const { if (auto* o = other.As()) { return o->dim() == dim() && o->type_ == type_; } diff --git a/src/tint/type/sampled_texture.h b/src/tint/type/sampled_texture.h index 2e82f28f21..d4f5fcce9a 100644 --- a/src/tint/type/sampled_texture.h +++ b/src/tint/type/sampled_texture.h @@ -35,9 +35,9 @@ class SampledTexture final : public Castable { /// @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_); } diff --git a/src/tint/type/sampler.cc b/src/tint/type/sampler.cc index c49a8efae8..5a3c94549c 100644 --- a/src/tint/type/sampler.cc +++ b/src/tint/type/sampler.cc @@ -31,7 +31,7 @@ size_t Sampler::Hash() const { return utils::Hash(TypeInfo::Of().full_hashcode, kind_); } -bool Sampler::Equals(const Type& other) const { +bool Sampler::Equals(const UniqueNode& other) const { if (auto* o = other.As()) { return o->kind_ == kind_; } diff --git a/src/tint/type/sampler.h b/src/tint/type/sampler.h index c8ff9d6b34..949d359702 100644 --- a/src/tint/type/sampler.h +++ b/src/tint/type/sampler.h @@ -35,9 +35,9 @@ class Sampler final : public Castable { /// @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_; } diff --git a/src/tint/type/storage_texture.cc b/src/tint/type/storage_texture.cc index 2bd2c28c90..b899deb3d2 100644 --- a/src/tint/type/storage_texture.cc +++ b/src/tint/type/storage_texture.cc @@ -35,7 +35,7 @@ size_t StorageTexture::Hash() const { return utils::Hash(TypeInfo::Of().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()) { return o->dim() == dim() && o->texel_format_ == texel_format_ && o->access_ == access_; } diff --git a/src/tint/type/storage_texture.h b/src/tint/type/storage_texture.h index 0e597754c5..2ff2d3b54c 100644 --- a/src/tint/type/storage_texture.h +++ b/src/tint/type/storage_texture.h @@ -48,9 +48,9 @@ class StorageTexture final : public Castable { /// @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_; } diff --git a/src/tint/type/struct.cc b/src/tint/type/struct.cc index 778a600c51..d179eb9efc 100644 --- a/src/tint/type/struct.cc +++ b/src/tint/type/struct.cc @@ -70,7 +70,7 @@ size_t Struct::Hash() const { return utils::Hash(TypeInfo::Of().full_hashcode, name_); } -bool Struct::Equals(const Type& other) const { +bool Struct::Equals(const UniqueNode& other) const { if (auto* o = other.As()) { return o->name_ == name_; } diff --git a/src/tint/type/struct.h b/src/tint/type/struct.h index 89467141d5..aff433efda 100644 --- a/src/tint/type/struct.h +++ b/src/tint/type/struct.h @@ -68,9 +68,9 @@ class Struct : public Castable { /// @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_; } diff --git a/src/tint/type/type.h b/src/tint/type/type.h index 00e1752c4a..74cd61fac5 100644 --- a/src/tint/type/type.h +++ b/src/tint/type/type.h @@ -18,7 +18,7 @@ #include #include -#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; /// Base class for a type in the system -class Type : public Castable { +class Type : public Castable { 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. diff --git a/src/tint/type/u32.cc b/src/tint/type/u32.cc index fd38cb900f..e9ae75de2d 100644 --- a/src/tint/type/u32.cc +++ b/src/tint/type/u32.cc @@ -35,7 +35,7 @@ size_t U32::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool U32::Equals(const Type& other) const { +bool U32::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/u32.h b/src/tint/type/u32.h index 6e2c4cc65e..59b288b355 100644 --- a/src/tint/type/u32.h +++ b/src/tint/type/u32.h @@ -33,9 +33,9 @@ class U32 final : public Castable { /// @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 diff --git a/src/tint/type/unique_node.cc b/src/tint/type/unique_node.cc new file mode 100644 index 0000000000..d52a6afe6a --- /dev/null +++ b/src/tint/type/unique_node.cc @@ -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 diff --git a/src/tint/type/unique_node.h b/src/tint/type/unique_node.h new file mode 100644 index 0000000000..84b22ce4b1 --- /dev/null +++ b/src/tint/type/unique_node.h @@ -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 + +#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 { + 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 { + /// @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 { + /// @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_ diff --git a/src/tint/type/vector.cc b/src/tint/type/vector.cc index 70b33bc428..5e7a5c0fdc 100644 --- a/src/tint/type/vector.cc +++ b/src/tint/type/vector.cc @@ -41,7 +41,7 @@ size_t Vector::Hash() const { return utils::Hash(TypeInfo::Of().full_hashcode, width_, subtype_); } -bool Vector::Equals(const Type& other) const { +bool Vector::Equals(const UniqueNode& other) const { if (auto* v = other.As()) { return v->width_ == width_ && v->subtype_ == subtype_; } diff --git a/src/tint/type/vector.h b/src/tint/type/vector.h index fb5834dcdb..6d171d7634 100644 --- a/src/tint/type/vector.h +++ b/src/tint/type/vector.h @@ -35,9 +35,9 @@ class Vector final : public Castable { /// @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_; } diff --git a/src/tint/type/void.cc b/src/tint/type/void.cc index b993dfe40e..4f21f5cac5 100644 --- a/src/tint/type/void.cc +++ b/src/tint/type/void.cc @@ -30,7 +30,7 @@ size_t Void::Hash() const { return static_cast(TypeInfo::Of().full_hashcode); } -bool Void::Equals(const Type& other) const { +bool Void::Equals(const UniqueNode& other) const { return other.Is(); } diff --git a/src/tint/type/void.h b/src/tint/type/void.h index 2106aea12e..4fc0b98c3c 100644 --- a/src/tint/type/void.h +++ b/src/tint/type/void.h @@ -33,9 +33,9 @@ class Void final : public Castable { /// @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