Visitor.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /// @file
  2. /// The file contains visitor concepts
  3. ///
  4. /// @par The main classes are:
  5. /// @li Visitable: For non related types
  6. /// @li VisitableCommonBase: For types with common base
  7. #ifndef ANKI_UTIL_VISITOR_H
  8. #define ANKI_UTIL_VISITOR_H
  9. #include "anki/util/Assert.h"
  10. #include "anki/util/Array.h"
  11. #include "anki/util/StdTypes.h"
  12. namespace anki {
  13. /// @addtogroup util
  14. /// @{
  15. /// @addtogroup patterns
  16. /// @{
  17. /// Namespace for visitor internal classes
  18. namespace visitor_detail {
  19. /// A smart struct that given a type and a list of types finds a const integer
  20. /// indicating the type's position from the back of the list.
  21. ///
  22. /// Example of usage:
  23. /// @code
  24. /// GetVariadicTypeId<int, float, std::string>::get<float> == 1
  25. /// GetVariadicTypeId<int, float, std::string>::get<int> == 0
  26. /// GetVariadicTypeId<int, float, std::string>::get<char> // Compiler error
  27. /// @endcode
  28. template<typename... Types>
  29. struct GetVariadicTypeId
  30. {
  31. // Forward
  32. template<typename Type, typename... Types_>
  33. struct Helper;
  34. // Declaration
  35. template<typename Type, typename TFirst, typename... Types_>
  36. struct Helper<Type, TFirst, Types_...>: Helper<Type, Types_...>
  37. {};
  38. // Specialized
  39. template<typename Type, typename... Types_>
  40. struct Helper<Type, Type, Types_...>
  41. {
  42. static const I ID = sizeof...(Types_);
  43. };
  44. /// Get the id
  45. template<typename Type>
  46. static constexpr I get()
  47. {
  48. return sizeof...(Types) - Helper<Type, Types...>::ID - 1;
  49. }
  50. };
  51. /// A struct that from a variadic arguments list it returnes the type using an
  52. /// ID.
  53. /// Example of usage:
  54. /// @code
  55. /// GetTypeUsingId<std::string, int, float>::DataType<0> x = "a string";
  56. /// GetTypeUsingId<std::string, int, float>::DataType<1> y = 123;
  57. /// GetTypeUsingId<std::string, int, float>::DataType<2> y = 123.456f;
  58. /// @endcode
  59. template<typename... Types>
  60. struct GetTypeUsingId
  61. {
  62. // Forward declaration
  63. template<I id, typename... Types_>
  64. struct Helper;
  65. // Declaration
  66. template<I id, typename TFirst, typename... Types_>
  67. struct Helper<id, TFirst, Types_...>: Helper<id - 1, Types_...>
  68. {};
  69. // Specialized
  70. template<typename TFirst, typename... Types_>
  71. struct Helper<0, TFirst, Types_...>
  72. {
  73. typedef TFirst DataType;
  74. };
  75. template<I id>
  76. using DataType = typename Helper<id, Types...>::DataType;
  77. };
  78. } // end namespace visitor_detail
  79. /// Visitable class
  80. template<typename... Types>
  81. class Visitable
  82. {
  83. public:
  84. Visitable()
  85. {}
  86. template<typename T>
  87. Visitable(T* t)
  88. {
  89. setupVisitable(t);
  90. }
  91. I getVisitableTypeId() const
  92. {
  93. return what;
  94. }
  95. template<typename T>
  96. static constexpr I getVariadicTypeId()
  97. {
  98. return visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
  99. }
  100. /// Apply visitor
  101. template<typename TVisitor>
  102. void acceptVisitor(TVisitor& v)
  103. {
  104. ANKI_ASSERT(what != -1 && address != nullptr);
  105. acceptVisitorInternal<TVisitor, Types...>(v);
  106. }
  107. /// Apply visitor (const version)
  108. template<typename TVisitor>
  109. void acceptVisitor(TVisitor& v) const
  110. {
  111. ANKI_ASSERT(what != -1 && address != nullptr);
  112. acceptVisitorInternalConst<TVisitor, Types...>(v);
  113. }
  114. /// Setup the data
  115. template<typename T>
  116. void setupVisitable(T* t)
  117. {
  118. ANKI_ASSERT(t != nullptr); // Null arg
  119. // Setting for second time? Now allowed
  120. ANKI_ASSERT(address == nullptr && what == -1);
  121. address = t;
  122. what = visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
  123. }
  124. private:
  125. I what = -1; ///< The type ID
  126. void* address = nullptr; ///< The address to the data
  127. /// @name Accept visitor template methods
  128. /// @{
  129. template<typename TVisitor, typename TFirst>
  130. void acceptVisitorInternal(TVisitor& v)
  131. {
  132. switch(what)
  133. {
  134. case 0:
  135. v.template visit(*reinterpret_cast<TFirst*>(address));
  136. break;
  137. default:
  138. ANKI_ASSERT(0 && "Wrong type ID");
  139. break;
  140. }
  141. }
  142. template<typename TVisitor, typename TFirst, typename TSecond,
  143. typename... Types_>
  144. void acceptVisitorInternal(TVisitor& v)
  145. {
  146. constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
  147. switch(what)
  148. {
  149. case i:
  150. v.template visit(*reinterpret_cast<TSecond*>(address));
  151. break;
  152. default:
  153. acceptVisitorInternal<TVisitor, TFirst, Types_...>(v);
  154. break;
  155. }
  156. }
  157. template<typename TVisitor, typename TFirst>
  158. void acceptVisitorInternalConst(TVisitor& v) const
  159. {
  160. switch(what)
  161. {
  162. case 0:
  163. v.template visit(*reinterpret_cast<const TFirst*>(address));
  164. break;
  165. default:
  166. ANKI_ASSERT(0 && "Wrong type ID");
  167. break;
  168. }
  169. }
  170. template<typename TVisitor, typename TFirst, typename TSecond,
  171. typename... Types_>
  172. void acceptVisitorInternalConst(TVisitor& v) const
  173. {
  174. constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
  175. switch(what)
  176. {
  177. case i:
  178. v.template visit(*reinterpret_cast<const TSecond*>(address));
  179. break;
  180. default:
  181. acceptVisitorInternalConst<TVisitor, TFirst, Types_...>(v);
  182. break;
  183. }
  184. }
  185. /// @}
  186. };
  187. /// Visitable for types with common base
  188. /// @tparam TBase The base class
  189. /// @tparam Types The types that compose the visitable. They are derived from
  190. /// TBase
  191. ///
  192. /// @note In debug mode it uses dynamic cast as an extra protection reason
  193. template<typename TBase, typename... Types>
  194. class VisitableCommonBase
  195. {
  196. public:
  197. #if ANKI_DEBUG
  198. // Allow dynamic cast in acceptVisitor
  199. virtual ~VisitableCommonBase()
  200. {}
  201. #endif
  202. I getVisitableTypeId() const
  203. {
  204. return what;
  205. }
  206. template<typename T>
  207. static constexpr I getVariadicTypeId()
  208. {
  209. return visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
  210. }
  211. /// Apply mutable visitor
  212. template<typename TVisitor>
  213. void acceptVisitor(TVisitor& v)
  214. {
  215. ANKI_ASSERT(what != -1);
  216. acceptVisitorInternal<TVisitor, Types...>(v);
  217. }
  218. /// Apply const visitor
  219. template<typename TVisitor>
  220. void acceptVisitor(TVisitor& v) const
  221. {
  222. ANKI_ASSERT(what != -1);
  223. acceptVisitorInternalConst<TVisitor, Types...>(v);
  224. }
  225. /// Setup the type ID
  226. template<typename T>
  227. void setupVisitable(const T*)
  228. {
  229. ANKI_ASSERT(what == -1); // Setting for second time not allowed
  230. what = visitor_detail::GetVariadicTypeId<Types...>::template get<T>();
  231. }
  232. private:
  233. I what = -1; ///< The type ID
  234. /// @name Accept visitor template methods
  235. /// @{
  236. template<typename TVisitor, typename TFirst>
  237. void acceptVisitorInternal(TVisitor& v)
  238. {
  239. switch(what)
  240. {
  241. case 0:
  242. {
  243. #if ANKI_DEBUG
  244. TFirst* base = dynamic_cast<TFirst*>(this);
  245. ANKI_ASSERT(base != nullptr);
  246. #else
  247. TFirst* base = static_cast<TFirst*>(this);
  248. #endif
  249. v.template visit(*base);
  250. }
  251. break;
  252. default:
  253. ANKI_ASSERT(0 && "Wrong type ID");
  254. break;
  255. }
  256. }
  257. template<typename TVisitor, typename TFirst, typename TSecond,
  258. typename... Types_>
  259. void acceptVisitorInternal(TVisitor& v)
  260. {
  261. constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
  262. switch(what)
  263. {
  264. case i:
  265. {
  266. #if ANKI_DEBUG
  267. TSecond* base = dynamic_cast<TSecond*>(this);
  268. ANKI_ASSERT(base != nullptr);
  269. #else
  270. TSecond* base = static_cast<TSecond*>(this);
  271. #endif
  272. v.template visit(*base);
  273. }
  274. break;
  275. default:
  276. acceptVisitorInternal<TVisitor, TFirst, Types_...>(v);
  277. break;
  278. }
  279. }
  280. template<typename TVisitor, typename TFirst>
  281. void acceptVisitorInternalConst(TVisitor& v) const
  282. {
  283. switch(what)
  284. {
  285. case 0:
  286. {
  287. #if ANKI_DEBUG
  288. const TFirst* base = dynamic_cast<const TFirst*>(this);
  289. ANKI_ASSERT(base != nullptr);
  290. #else
  291. const TFirst* base = static_cast<const TFirst*>(this);
  292. #endif
  293. v.template visit(*base);
  294. }
  295. break;
  296. default:
  297. ANKI_ASSERT(0 && "Wrong type ID");
  298. break;
  299. }
  300. }
  301. template<typename TVisitor, typename TFirst, typename TSecond,
  302. typename... Types_>
  303. void acceptVisitorInternalConst(TVisitor& v) const
  304. {
  305. constexpr I i = sizeof...(Types) - sizeof...(Types_) - 1;
  306. switch(what)
  307. {
  308. case i:
  309. {
  310. #if ANKI_DEBUG
  311. const TSecond* base = dynamic_cast<const TSecond*>(this);
  312. ANKI_ASSERT(base != nullptr);
  313. #else
  314. const TSecond* base = static_cast<const TSecond*>(this);
  315. #endif
  316. v.template visit(*base);
  317. }
  318. break;
  319. default:
  320. acceptVisitorInternalConst<TVisitor, TFirst, Types_...>(v);
  321. break;
  322. }
  323. }
  324. /// @}
  325. };
  326. /// @}
  327. /// @}
  328. } // end namespace anki
  329. #endif