xvisitor.hpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /***************************************************************************
  2. * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
  3. * Copyright (c) QuantStack *
  4. * *
  5. * Distributed under the terms of the BSD 3-Clause License. *
  6. * *
  7. * The full license is in the file LICENSE, distributed with this software. *
  8. ****************************************************************************/
  9. #ifndef XTL_VISITOR_HPP
  10. #define XTL_VISITOR_HPP
  11. #include <stdexcept>
  12. #include "xmeta_utils.hpp"
  13. namespace xtl
  14. {
  15. // Loki's visitor ported to C++14
  16. // Original implementation can be found at:
  17. // https://github.com/snaewe/loki-lib/blob/master/include/loki/Visitor.h
  18. /****************
  19. * base_visitor *
  20. ****************/
  21. class base_visitor
  22. {
  23. public:
  24. virtual ~base_visitor() = default;
  25. };
  26. /***********
  27. * visitor *
  28. ***********/
  29. template <class T, class R = void, bool is_const = true>
  30. class visitor
  31. {
  32. public:
  33. using return_type = R;
  34. using param_type = std::conditional_t<is_const, const T, T>;
  35. virtual ~visitor() = default;
  36. virtual return_type visit(param_type&) = 0;
  37. };
  38. template <class R, bool is_const>
  39. class visitor<mpl::vector<>, R, is_const>
  40. {
  41. };
  42. template <class R, bool is_const, class T, class... U>
  43. class visitor<mpl::vector<T, U...>, R, is_const>
  44. : public visitor<T, R, is_const>
  45. , public visitor<mpl::vector<U...>, R, is_const>
  46. {
  47. };
  48. /**********************
  49. * catch_all policies *
  50. **********************/
  51. template <class R, class T>
  52. struct default_catch_all
  53. {
  54. static R on_unknown_visitor(T&, base_visitor&)
  55. {
  56. return R();
  57. }
  58. };
  59. template <class R, class T>
  60. struct throwing_catch_all
  61. {
  62. static R on_unknown_visitor(T&, base_visitor&)
  63. {
  64. XTL_THROW(std::runtime_error, "Unknown visited type");
  65. }
  66. };
  67. /******************
  68. * base_visitable *
  69. ******************/
  70. template
  71. <
  72. class R = void,
  73. bool const_visitable = false,
  74. template <class, class> class catch_all = default_catch_all
  75. >
  76. class base_visitable;
  77. template <class R, template <class, class> class catch_all>
  78. class base_visitable<R, false, catch_all>
  79. {
  80. public:
  81. using return_type = R;
  82. virtual ~base_visitable() = default;
  83. virtual return_type accept(base_visitor&) = 0;
  84. protected:
  85. template <class T>
  86. static return_type accept_impl(T& visited, base_visitor& vis)
  87. {
  88. if (auto* p = dynamic_cast<visitor<T, R, false>*>(&vis))
  89. {
  90. return p->visit(visited);
  91. }
  92. return catch_all<R, T>::on_unknown_visitor(visited, vis);
  93. }
  94. };
  95. template <class R, template <class, class> class catch_all>
  96. class base_visitable<R, true, catch_all>
  97. {
  98. public:
  99. using return_type = R;
  100. virtual ~base_visitable() = default;
  101. virtual return_type accept(base_visitor&) const = 0;
  102. protected:
  103. template <class T>
  104. static return_type accept_impl(const T& visited, base_visitor& vis)
  105. {
  106. if (auto* p = dynamic_cast<visitor<T, R, true>*>(&vis))
  107. {
  108. return p->visit(visited);
  109. }
  110. return catch_all<R, const T>::on_unknown_visitor(visited, vis);
  111. }
  112. };
  113. /************************
  114. * XTL_DEFINE_VISITABLE *
  115. ************************/
  116. #define XTL_DEFINE_VISITABLE() \
  117. return_type accept(::xtl::base_visitor& vis) override \
  118. { return accept_impl(*this, vis); }
  119. #define XTL_DEFINE_CONST_VISITABLE() \
  120. return_type accept(::xtl::base_visitor& vis) const override \
  121. { return accept_impl(*this, vis); }
  122. /******************
  123. * cyclic_visitor *
  124. ******************/
  125. template <class T, class R, bool is_const = true>
  126. class cyclic_visitor;
  127. template <class R, bool is_const, class... T>
  128. class cyclic_visitor<mpl::vector<T...>, R, is_const>
  129. : public visitor<mpl::vector<T...>, R, is_const>
  130. {
  131. public:
  132. using return_type = R;
  133. template <class V>
  134. return_type generic_visit(V& visited)
  135. {
  136. visitor<std::remove_const_t<V>, return_type, is_const>& sub_obj = *this;
  137. return sub_obj.visit(visited);
  138. }
  139. };
  140. /*******************************
  141. * XTL_DEFINE_CYCLIC_VISITABLE *
  142. *******************************/
  143. #define XTL_DEFINE_CYCLIC_VISITABLE(some_visitor) \
  144. virtual some_visitor::return_type accept(some_visitor& vis) \
  145. { \
  146. return vis.generic_visit(*this); \
  147. }
  148. #define XTL_DEFINE_CONST_CYCLIC_VISITABLE(some_visitor) \
  149. virtual some_visitor::return_type accept(some_visitor& vis) const \
  150. { \
  151. return vis.generic_visit(*this); \
  152. }
  153. }
  154. #endif