Visitor.h 8.5 KB

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