Pull Is() out of castable and into a new TypeInfo
Allows you to query type inheritance without having an instance of the type.
Also add TypeInfo::name. Helpful for decent error messages. Strings can be removed from NDEBUG builds if we consider them too large.
Change-Id: Ie501b37f46e63d956cc020f8c9b68e91737472f0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/42920
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3c211b6..376193d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -161,6 +161,7 @@
-Wno-format-pedantic
-Wno-return-std-move-in-c++11
-Wno-unknown-warning-option
+ -Wno-undefined-var-template
-Weverything
)
endif()
diff --git a/src/castable.cc b/src/castable.cc
index 9b50383..7cab369 100644
--- a/src/castable.cc
+++ b/src/castable.cc
@@ -14,12 +14,23 @@
#include "src/castable.h"
-TINT_INSTANTIATE_CLASS_ID(tint::CastableBase);
-
namespace tint {
-bool CastableBase::Is(ClassID id) const {
- return ClassID::Of<CastableBase>() == id;
+/// The unique TypeInfo for the CastableBase type
+/// @return doxygen-thinks-this-static-field-is-a-function :(
+template <>
+const TypeInfo detail::TypeInfoOf<CastableBase>::info{
+ nullptr,
+ "CastableBase",
+};
+
+bool TypeInfo::Is(const TypeInfo& typeinfo) const {
+ for (auto* ti = this; ti != nullptr; ti = ti->base) {
+ if (ti == &typeinfo) {
+ return true;
+ }
+ }
+ return false;
}
} // namespace tint
diff --git a/src/castable.h b/src/castable.h
index 1fe4464..f619467 100644
--- a/src/castable.h
+++ b/src/castable.h
@@ -22,57 +22,49 @@
namespace tint {
-class ClassID;
+namespace detail {
+template <typename T>
+struct TypeInfoOf;
+} // namespace detail
/// Helper macro to instantiate the TypeInfo<T> template for `CLASS`.
-#define TINT_INSTANTIATE_CLASS_ID(CLASS) \
- template <> \
- const char tint::UniqueToken<CLASS>::token = 0; \
- template <> \
- const uintptr_t tint::TypeInfo<CLASS>::unique_id = \
- reinterpret_cast<uintptr_t>(&tint::UniqueToken<CLASS>::token)
+#define TINT_INSTANTIATE_CLASS_ID(CLASS) \
+ template <> \
+ const tint::TypeInfo tint::detail::TypeInfoOf<CLASS>::info { \
+ &tint::detail::TypeInfoOf<CLASS::TrueBase>::info, #CLASS, \
+ }
-/// TypeInfo holds type information for the type T.
+/// TypeInfo holds type information for a Castable type.
+struct TypeInfo {
+ /// The base class of this type.
+ const TypeInfo* base;
+ /// The type name
+ const char* name;
+
+ /// @param type the test type info
+ /// @returns true if the class with this TypeInfo is of, or derives from the
+ /// class with the given TypeInfo.
+ bool Is(const tint::TypeInfo& type) const;
+
+ /// @returns the static TypeInfo for the type T
+ template <typename T>
+ static const TypeInfo& Of() {
+ return detail::TypeInfoOf<T>::info;
+ }
+};
+
+namespace detail {
+
+/// TypeInfoOf contains a single TypeInfo field for the type T.
/// TINT_INSTANTIATE_CLASS_ID() must be defined in a .cpp file for each type
/// `T`.
template <typename T>
-struct TypeInfo {
- /// The unique identifier for the type T.
- static const uintptr_t unique_id;
+struct TypeInfoOf {
+ /// The unique TypeInfo for the type T.
+ static const TypeInfo info;
};
-/// UniqueToken holds a single static const char, which is uniquely declared for
-/// each specialization of the template class.
-/// Use by TINT_INSTANTIATE_CLASS_ID() to generate a unique pointer, which is in
-/// turn used to generate TypeInfo<T>::unique_id.
-template <typename T>
-struct UniqueToken {
- /// A dummy static variable that is unique for the type T.
- static const char token;
-};
-
-/// ClassID represents a unique, comparable identifier for a C++ type.
-class ClassID {
- public:
- /// @returns the unique ClassID for the type T.
- template <typename T>
- static inline ClassID Of() {
- return ClassID(TypeInfo<T>::unique_id);
- }
-
- /// Equality operator
- /// @param rhs the ClassID to compare against
- /// @returns true if this ClassID is equal to `rhs`
- inline bool operator==(const ClassID& rhs) const { return id == rhs.id; }
-
- /// @return the unique numerical identifier of this ClassID
- inline uintptr_t ID() const { return id; }
-
- private:
- inline explicit ClassID(uintptr_t v) : id(v) {}
-
- const uintptr_t id;
-};
+} // namespace detail
/// CastableBase is the base class for all Castable objects.
/// It is not encouraged to directly derive from CastableBase without using the
@@ -88,10 +80,8 @@
virtual ~CastableBase() = default;
- /// @returns true if this object is of, or derives from a class with the
- /// ClassID `id`.
- /// @param id the ClassID to test for
- virtual bool Is(ClassID id) const;
+ /// @returns the TypeInfo of the object
+ virtual const tint::TypeInfo& TypeInfo() const = 0;
/// @returns true if this object is of, or derives from the class `TO`
template <typename TO>
@@ -106,7 +96,7 @@
return true;
}
- return Is(ClassID::Of<TO>());
+ return TypeInfo().Is(TypeInfo::Of<TO>());
}
/// @returns this object dynamically cast to the type `TO` or `nullptr` if
@@ -157,11 +147,12 @@
/// use Base in the `CLASS` constructor.
using Base = Castable;
- /// @returns true if this object is of, or derives from a class with the
- /// ClassID `id`.
- /// @param id the ClassID to test for
- inline bool Is(ClassID id) const override {
- return ClassID::Of<CLASS>() == id || BASE::Is(id);
+ /// A type alias for `BASE`.
+ using TrueBase = BASE;
+
+ /// @returns the TypeInfo of the object
+ const tint::TypeInfo& TypeInfo() const override {
+ return TypeInfo::Of<CLASS>();
}
/// @returns true if this object is of, or derives from the class `TO`
@@ -177,7 +168,7 @@
return true;
}
- return Is(ClassID::Of<TO>());
+ return TypeInfo().Is(TypeInfo::Of<TO>());
}
/// @returns this object dynamically cast to the type `TO` or `nullptr` if
@@ -209,20 +200,4 @@
} // namespace tint
-namespace std {
-
-/// Custom std::hash specialization for tint::ClassID so ClassID can be used as
-/// keys for std::unordered_map and std::unordered_set.
-template <>
-class hash<tint::ClassID> {
- public:
- /// @param id the ClassID to hash
- /// @return the ClassID's internal numerical identifier
- inline std::size_t operator()(const tint::ClassID& id) const {
- return static_cast<std::size_t>(id.ID());
- }
-};
-
-} // namespace std
-
#endif // SRC_CASTABLE_H_
diff --git a/src/transform/transform.h b/src/transform/transform.h
index bf996e6..47a950a 100644
--- a/src/transform/transform.h
+++ b/src/transform/transform.h
@@ -67,14 +67,14 @@
void Put(std::unique_ptr<T>&& data) {
static_assert(std::is_base_of<Data, T>::value,
"T does not derive from Data");
- map_[ClassID::Of<T>()] = std::move(data);
+ map_[&TypeInfo::Of<T>()] = std::move(data);
}
/// @returns a pointer to the Data placed into the DataMap with a call to
/// Put()
template <typename T>
T const* Get() const {
- auto it = map_.find(ClassID::Of<T>());
+ auto it = map_.find(&TypeInfo::Of<T>());
if (it == map_.end()) {
return nullptr;
}
@@ -102,7 +102,7 @@
PutAll(std::forward<Tn>(remainder)...);
}
- std::unordered_map<ClassID, std::unique_ptr<Data>> map_;
+ std::unordered_map<const TypeInfo*, std::unique_ptr<Data>> map_;
};
/// Interface for Program transforms