| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- /// @file
- /// The file contains visitor concepts
- ///
- /// @par The main classes are:
- /// @li Visitable: For non related types
- /// @li VisitableCommonBase: For types with common base
- #ifndef ANKI_UTIL_VISITOR_H
- #define ANKI_UTIL_VISITOR_H
- #include "anki/util/Assert.h"
- #include "anki/util/Array.h"
- #include "anki/util/StdTypes.h"
- namespace anki {
- /// @addtogroup util
- /// @{
- /// @addtogroup patterns
- /// @{
- /// Namespace for visitor internal classes
- namespace visitor_detail {
- /// A smart struct that given a type and a list of types finds a const integer
- /// indicating the type's position from the back of the list.
- ///
- /// Example of usage:
- /// @code
- /// GetVariadicTypeId<int, float, std::string>::get<float> == 1
- /// GetVariadicTypeId<int, float, std::string>::get<int> == 0
- /// GetVariadicTypeId<int, float, std::string>::get<char> // Compiler error
- /// @endcode
- template<typename... Types>
- struct GetVariadicTypeId
- {
- // Forward
- template<typename Type, typename... Types_>
- struct Helper;
- // Declaration
- template<typename Type, typename TFirst, typename... Types_>
- struct Helper<Type, TFirst, Types_...>: Helper<Type, Types_...>
- {};
- // Specialized
- template<typename Type, typename... Types_>
- struct Helper<Type, Type, Types_...>
- {
- static const I ID = sizeof...(Types_);
- };
- /// Get the id
- template<typename Type>
- static constexpr I get()
- {
- return sizeof...(Types) - Helper<Type, Types...>::ID - 1;
- }
- };
- /// A struct that from a variadic arguments list it returnes the type using an
- /// ID.
- /// Example of usage:
- /// @code
- /// GetTypeUsingId<std::string, int, float>::DataType<0> x = "a string";
- /// GetTypeUsingId<std::string, int, float>::DataType<1> y = 123;
- /// GetTypeUsingId<std::string, int, float>::DataType<2> y = 123.456f;
- /// @endcode
- template<typename... Types>
- struct GetTypeUsingId
- {
- // Forward declaration
- template<I id, typename... Types_>
- struct Helper;
- // Declaration
- template<I id, typename TFirst, typename... Types_>
- struct Helper<id, TFirst, Types_...>: Helper<id - 1, Types_...>
- {};
- // Specialized
- template<typename TFirst, typename... Types_>
- struct Helper<0, TFirst, Types_...>
- {
- typedef TFirst DataType;
- };
- template<I id>
- using DataType = typename Helper<id, Types...>::DataType;
- };
- } // end namespace visitor_detail
- /// Visitable class
- template<typename... Types>
- class Visitable
- {
- public:
- Visitable()
- {}
- template<typename T>
- Visitable(T* t)
- {
- setupVisitable(t);
- }
- I getVisitableTypeId() const
- {
- return what;
- }
- template<typename T>
- static constexpr I getVariadicTypeId()
- {
- return visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
- }
- /// Apply visitor
- template<typename TVisitor>
- void acceptVisitor(TVisitor& v)
- {
- ANKI_ASSERT(what != -1 && address != nullptr);
- acceptVisitorInternal<TVisitor, Types...>(v);
- }
- /// Apply visitor (const version)
- template<typename TVisitor>
- void acceptVisitor(TVisitor& v) const
- {
- ANKI_ASSERT(what != -1 && address != nullptr);
- acceptVisitorInternalConst<TVisitor, Types...>(v);
- }
- /// Setup the data
- template<typename T>
- void setupVisitable(T* t)
- {
- ANKI_ASSERT(t != nullptr); // Null arg
- // Setting for second time? Now allowed
- ANKI_ASSERT(address == nullptr && what == -1);
- address = t;
- what = visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
- }
- private:
- I what = -1; ///< The type ID
- void* address = nullptr; ///< The address to the data
- /// @name Accept visitor template methods
- /// @{
- template<typename TVisitor, typename TFirst>
- void acceptVisitorInternal(TVisitor& v)
- {
- switch(what)
- {
- case 0:
- v.template visit(*reinterpret_cast<TFirst*>(address));
- break;
- default:
- ANKI_ASSERT(0 && "Wrong type ID");
- break;
- }
- }
- template<typename TVisitor, typename TFirst, typename TSecond,
- typename... Types_>
- void acceptVisitorInternal(TVisitor& v)
- {
- constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
- switch(what)
- {
- case i:
- v.template visit(*reinterpret_cast<TSecond*>(address));
- break;
- default:
- acceptVisitorInternal<TVisitor, TFirst, Types_...>(v);
- break;
- }
- }
- template<typename TVisitor, typename TFirst>
- void acceptVisitorInternalConst(TVisitor& v) const
- {
- switch(what)
- {
- case 0:
- v.template visit(*reinterpret_cast<const TFirst*>(address));
- break;
- default:
- ANKI_ASSERT(0 && "Wrong type ID");
- break;
- }
- }
- template<typename TVisitor, typename TFirst, typename TSecond,
- typename... Types_>
- void acceptVisitorInternalConst(TVisitor& v) const
- {
- constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
- switch(what)
- {
- case i:
- v.template visit(*reinterpret_cast<const TSecond*>(address));
- break;
- default:
- acceptVisitorInternalConst<TVisitor, TFirst, Types_...>(v);
- break;
- }
- }
- /// @}
- };
- /// Visitable for types with common base
- /// @tparam TBase The base class
- /// @tparam Types The types that compose the visitable. They are derived from
- /// TBase
- ///
- /// @note In debug mode it uses dynamic cast as an extra protection reason
- template<typename TBase, typename... Types>
- class VisitableCommonBase
- {
- public:
- #if ANKI_DEBUG
- // Allow dynamic cast in acceptVisitor
- virtual ~VisitableCommonBase()
- {}
- #endif
- I getVisitableTypeId() const
- {
- return what;
- }
- template<typename T>
- static constexpr I getVariadicTypeId()
- {
- return visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
- }
- /// Apply mutable visitor
- template<typename TVisitor>
- void acceptVisitor(TVisitor& v)
- {
- ANKI_ASSERT(what != -1);
- acceptVisitorInternal<TVisitor, Types...>(v);
- }
- /// Apply const visitor
- template<typename TVisitor>
- void acceptVisitor(TVisitor& v) const
- {
- ANKI_ASSERT(what != -1);
- acceptVisitorInternalConst<TVisitor, Types...>(v);
- }
- /// Setup the type ID
- template<typename T>
- void setupVisitable(const T*)
- {
- ANKI_ASSERT(what == -1); // Setting for second time not allowed
- what = visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
- }
- private:
- I what = -1; ///< The type ID
- /// @name Accept visitor template methods
- /// @{
- template<typename TVisitor, typename TFirst>
- void acceptVisitorInternal(TVisitor& v)
- {
- switch(what)
- {
- case 0:
- {
- #if ANKI_DEBUG
- TFirst* base = dynamic_cast<TFirst*>(this);
- ANKI_ASSERT(base != nullptr);
- #else
- TFirst* base = static_cast<TFirst*>(this);
- #endif
- v.template visit(*base);
- }
- break;
- default:
- ANKI_ASSERT(0 && "Wrong type ID");
- break;
- }
- }
- template<typename TVisitor, typename TFirst, typename TSecond,
- typename... Types_>
- void acceptVisitorInternal(TVisitor& v)
- {
- constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
- switch(what)
- {
- case i:
- {
- #if ANKI_DEBUG
- TSecond* base = dynamic_cast<TSecond*>(this);
- ANKI_ASSERT(base != nullptr);
- #else
- TSecond* base = static_cast<TSecond*>(this);
- #endif
- v.template visit(*base);
- }
- break;
- default:
- acceptVisitorInternal<TVisitor, TFirst, Types_...>(v);
- break;
- }
- }
- template<typename TVisitor, typename TFirst>
- void acceptVisitorInternalConst(TVisitor& v) const
- {
- switch(what)
- {
- case 0:
- {
- #if ANKI_DEBUG
- const TFirst* base = dynamic_cast<const TFirst*>(this);
- ANKI_ASSERT(base != nullptr);
- #else
- const TFirst* base = static_cast<const TFirst*>(this);
- #endif
- v.template visit(*base);
- }
- break;
- default:
- ANKI_ASSERT(0 && "Wrong type ID");
- break;
- }
- }
- template<typename TVisitor, typename TFirst, typename TSecond,
- typename... Types_>
- void acceptVisitorInternalConst(TVisitor& v) const
- {
- constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
- switch(what)
- {
- case i:
- {
- #if ANKI_DEBUG
- const TSecond* base = dynamic_cast<const TSecond*>(this);
- ANKI_ASSERT(base != nullptr);
- #else
- const TSecond* base = static_cast<const TSecond*>(this);
- #endif
- v.template visit(*base);
- }
- break;
- default:
- acceptVisitorInternalConst<TVisitor, TFirst, Types_...>(v);
- break;
- }
- }
- /// @}
- };
- /// @}
- /// @}
- } // end namespace anki
- #endif
|