// Copyright 2020 The Dawn & Tint Authors // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef SRC_TINT_UTILS_RTTI_CASTABLE_H_ #define SRC_TINT_UTILS_RTTI_CASTABLE_H_ #include <stdint.h> #include <functional> #include <tuple> #include <type_traits> #include <utility> #include "src/tint/utils/macros/compiler.h" #include "src/tint/utils/math/crc32.h" #include "src/tint/utils/math/hash.h" #include "src/tint/utils/rtti/ignore.h" #include "src/tint/utils/traits/traits.h" #if defined(__clang__) /// Temporarily disable certain warnings when using Castable API #define TINT_CASTABLE_PUSH_DISABLE_WARNINGS() … /// Restore disabled warnings #define TINT_CASTABLE_POP_DISABLE_WARNINGS() … #else #define TINT_CASTABLE_PUSH_DISABLE_WARNINGS … #define TINT_CASTABLE_POP_DISABLE_WARNINGS … #endif TINT_CASTABLE_PUSH_DISABLE_WARNINGS(…); // Forward declarations namespace tint { class CastableBase; } // namespace tint namespace tint::detail { template <typename T> struct TypeInfoOf; } // namespace tint::detail namespace tint { /// True if all template types that are not Ignore derive from CastableBase IsCastable; /// Helper macro to instantiate the TypeInfo<T> template for `CLASS`. #define TINT_INSTANTIATE_TYPEINFO(CLASS) … /// Bit flags that can be passed to the template parameter `FLAGS` of Is() and As(). enum CastFlags { … }; /// TypeCode is a bit pattern used by Tint's RTTI system to determine whether two types are related /// by inheritance. /// Each TypeCode has exactly two bits set. struct TypeCode { … }; /// TypeCodeSet is a set of TypeCodes, and internally uses a single integer to represent its /// contents. TypeCodeSet acts as a bloom-filter, exposing methods to query whether the set _may_ /// contain one or more TypeCodes. If these methods return `false` then the set definitely does /// contain the TypeCode(s), however returning `true` means the *set has a possibility* of /// containing the TypeCodes(s). /// @see https://en.wikipedia.org/wiki/Bloom_filter struct TypeCodeSet { … }; /// TypeInfo holds type information for a Castable type. struct TypeInfo { … }; namespace detail { /// TypeInfoOf contains a single TypeInfo field for the type T. /// TINT_INSTANTIATE_TYPEINFO() must be defined in a .cpp file for each type `T`. template <typename T> struct TypeInfoOf { … }; /// A placeholder structure used for template parameters that need a default type, but can always be /// automatically inferred. struct Infer; } // namespace detail /// @returns true if `obj` is a valid pointer, and is of, or derives from the class `TO` /// @param obj the object to test from /// @see CastFlags template <typename TO, int FLAGS = 0, typename FROM = tint::detail::Infer> inline bool Is(FROM* obj) { … } /// @returns true if `obj` is a valid pointer, and is of, or derives from the type `TYPE`, and /// pred(const TYPE*) returns true /// @param obj the object to test from /// @param pred predicate function with signature `bool(const TYPE*)` called iff object is of, or /// derives from the class `TYPE`. /// @see CastFlags template <typename TYPE, int FLAGS = 0, typename OBJ = tint::detail::Infer, typename Pred = tint::detail::Infer> inline bool Is(OBJ* obj, Pred&& pred) { … } /// @returns true if `obj` is a valid pointer, and is of, or derives from any of the types in /// `TYPES`. /// @param obj the object to query. template <typename... TYPES, typename OBJ> inline bool IsAnyOf(OBJ* obj) { … } /// @returns obj dynamically cast to the type `TO` or `nullptr` if this object does not derive from /// `TO`. /// @param obj the object to cast from /// @see CastFlags template <typename TO, int FLAGS = 0, typename FROM = tint::detail::Infer> inline TO* As(FROM* obj) { … } /// @returns obj dynamically cast to the type `TO` or `nullptr` if this object does not derive from /// `TO`. /// @param obj the object to cast from /// @see CastFlags template <typename TO, int FLAGS = 0, typename FROM = tint::detail::Infer> inline const TO* As(const FROM* obj) { … } /// CastableBase is the base class for all Castable objects. /// It is not encouraged to directly derive from CastableBase without using the Castable helper /// template. /// @see Castable class CastableBase { … }; /// Castable is a helper to derive `CLASS` from `BASE`, automatically implementing the Is() and As() /// methods, along with a #Base type alias. /// /// Example usage: /// /// ``` /// class Animal : public Castable<Animal> {}; /// /// class Sheep : public Castable<Sheep, Animal> {}; /// /// Sheep* cast_to_sheep(Animal* animal) { /// // You can query whether a Castable is of the given type with Is<T>(): /// printf("animal is a sheep? %s", animal->Is<Sheep>() ? "yes" : "no"); /// /// // You can always just try the cast with As<T>(). /// // If the object is not of the correct type, As<T>() will return nullptr: /// return animal->As<Sheep>(); /// } /// ``` template <typename CLASS, typename BASE = CastableBase> class Castable : public BASE { … }; namespace detail { /// <code>typename CastableCommonBaseImpl<TYPES>::type</code> resolves to the common base class for /// all of TYPES. template <typename... TYPES> struct CastableCommonBaseImpl { … }; /// Alias to typename CastableCommonBaseImpl<TYPES>::type CastableCommonBase; /// CastableCommonBaseImpl template specialization for a single type CastableCommonBaseImpl<T>; /// CastableCommonBaseImpl A <-> CastableBase specialization CastableCommonBaseImpl<A, CastableBase>; /// CastableCommonBaseImpl T <-> Ignore specialization CastableCommonBaseImpl<T, Ignore>; /// CastableCommonBaseImpl Ignore <-> T specialization CastableCommonBaseImpl<Ignore, T>; /// CastableCommonBaseImpl A <-> B specialization CastableCommonBaseImpl<A, B>; /// CastableCommonBaseImpl 3+ types specialization CastableCommonBaseImpl<A, B, OTHERS...>; } // namespace detail /// Resolves to the common most derived type that each of the types in `TYPES` derives from. CastableCommonBase; } // namespace tint namespace tint { As; Is; } // namespace tint TINT_CASTABLE_POP_DISABLE_WARNINGS(…); #endif // SRC_TINT_UTILS_RTTI_CASTABLE_H_