LibreCAD
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
visitor.h
Go to the documentation of this file.
1 //
2 // Created by R. van Twisk on 3/28/15.
3 //
4 
5 #pragma once
6 
7 #include <cad/const.h>
8 #include <memory>
9 #include <array>
10 
11 namespace lc {
12  namespace geo {
13  class Base;
14  class Vector;
15  class Coordinate;
16  class Area;
17  class Circle;
18  class Vector;
19  class Ellipse;
20  class Spline;
21  class Arc;
22  class BezierBase;
23  }
24 
25  class EntityDispatch;
26  class Visitable;
27 
28  namespace entity {
29  class Arc;
31 
32  class Point;
34 
35  class Line;
37 
38  class Text;
40 
41  class Spline;
43 
44  class Ellipse;
46 
47  class Circle;
49 
50  class CADEntity;
51  DECLARE_SHORT_SHARED_PTR(CADEntity)
52 
53  class DimAligned;
54  DECLARE_SHORT_SHARED_PTR(DimAligned)
55 
56  class DimAngular;
57  DECLARE_SHORT_SHARED_PTR(DimAngular)
58 
59  class DimDiametric;
60  DECLARE_SHORT_SHARED_PTR(DimDiametric)
61 
62  class DimLinear;
63  DECLARE_SHORT_SHARED_PTR(DimLinear)
64 
65  class DimRadial;
66  DECLARE_SHORT_SHARED_PTR(DimRadial)
67 
68  class LWPolyline;
69  DECLARE_SHORT_SHARED_PTR(LWPolyline)
70 
71  class Image;
73 
74  class Insert;
76  }
77 }
78 
79 
80 
81 
82 // sequence of size_t // not in C++11
83 template <std::size_t ...> struct index_sequence {};
84 
85 // Create index_sequence<0, >
86 template <std::size_t N, std::size_t ...Is>
87 struct make_index_sequence : make_index_sequence <N - 1, N - 1, Is... > {};
88 
89 template <std::size_t ... Is>
90 struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
91 
92 // Generic IVisitor
93 // Do: using MyIVisitor = IVisitorTs<Child1, Child2, ...>
94 template <typename ... Ts> class IVisitorTs;
95 
96 template <typename T, typename ... Ts>
97 class IVisitorTs<T, Ts...> : public IVisitorTs<Ts...>
98 {
99 public:
100  using tuple_type = std::tuple<T, Ts...>;
101  using IVisitorTs<Ts...>::visit;
102 
103  virtual void visit(const T& t) = 0;
104 };
105 
106 template <typename T> class IVisitorTs<T>
107 {
108 public:
109  using tuple_type = std::tuple<T>;
110 
111  virtual void visit(const T& t) = 0;
112 };
113 
114 namespace detail {
115 
116 // retrieve the index of T in Ts...
117  template <typename T, typename ... Ts> struct get_index;
118 
119  template <typename T, typename ... Ts>
120  struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
121 
122  template <typename T, typename Tail, typename ... Ts>
123  struct get_index<T, Tail, Ts...> :
124  std::integral_constant < std::size_t, 1 + get_index<T, Ts...>::value > {};
125 
126 // retrieve the index of T in Tuple<Ts...>
127  template <typename T, typename Tuple> struct get_index_in_tuple;
128 
129  template <typename T, template <typename...> class C, typename ... Ts>
130  struct get_index_in_tuple<T, C<Ts...>> : get_index<T, Ts...> {};
131 
132 // get element of a multiarray
133  template <std::size_t I>
135  {
136  template <typename T, std::size_t N>
137  static constexpr auto get(const T& a, const std::array<std::size_t, N>& index)
138  -> decltype(multi_array_getter<I - 1>::get(a[index[N - I]], index))
139  {
140  return multi_array_getter<I - 1>::get(a[index[N - I]], index);
141  }
142  };
143 
144  template <>
146  {
147  template <typename T, std::size_t N>
148  static constexpr auto get(const T& a, const std::array<std::size_t, N>& index)
149  -> decltype(a)
150  {
151  return a;
152  }
153  };
154 
155 // Provide an implementation of visitor
156 // by forwarding to C implementation (which may be non virtual)
157  template <typename IVisitor, typename C, typename...Ts> struct IVisitorImpl;
158 
159  template <typename IVisitor, typename C, typename T, typename...Ts>
160  struct IVisitorImpl<IVisitor, C, T, Ts...> : IVisitorImpl<IVisitor, C, Ts...>
161  {
162  virtual void visit(const T& t) override { C::visit(t); } // NOLINT
163  };
164 
165  template <typename IVisitor, typename C, typename T>
166  struct IVisitorImpl<IVisitor, C, T> : IVisitor, C
167  {
168  virtual void visit(const T& t) override { C::visit(t); }
169  };
170 
171 // helper to expand child type to IVisitorImpl
172  template <typename IVisitor, typename C>
174 
175  template <typename ... Ts, typename C>
176  struct IVisitorImplType<IVisitorTs<Ts...>, C>
177  {
178  using type = IVisitorImpl<IVisitorTs<Ts...>, C, Ts...>;
179  };
180 
181 // Create an multi array of pointer of function
182 // (with all combinaisons of overload).
183  template <typename Ret, typename F, typename Arg>
185  {
186  private:
187  template <typename...Ts>
188  struct Functor
189  {
190  // function which will be in array.
191  static Ret call(F&f, const Arg& arg)
192  {
193  return call_helper(f, arg, make_index_sequence<sizeof...(Ts)>());
194  }
195  private:
196  // The final dispatched function
197  template <std::size_t ... Is>
198  static Ret call_helper(F&f, const Arg& arg, index_sequence<Is...>)
199  {
200  using RetTuple = std::tuple<const Ts&...>;
201  // static cast is suffisant if arg is the abstract type
202  // when given arg is concrete type, reinterpret_cast is required.
203  // TODO: build a smaller table with only possible value to avoid that
204 // return f(static_cast<typename std::tuple_element<Is, RetTuple>::type>(std::get<Is>(arg))...);
205  return f(reinterpret_cast<typename std::tuple_element<Is, RetTuple>::type>(std::get<Is>(arg))...);
206  }
207  };
208 
209  // helper class to create the multi array of function pointer
210  template <std::size_t N, typename Tuple, typename...Ts>
211  struct Builder;
212 
213  template <typename...Ts, typename...Ts2>
214  struct Builder<1, std::tuple<Ts...>, Ts2...>
215  {
216  using RetType = std::array<Ret (*)(F&, const Arg&), sizeof...(Ts)>;
217 
218  static constexpr RetType build()
219  {
220  return RetType{ &Functor<Ts2..., Ts>::call... };
221  }
222  };
223 
224  template <std::size_t N, typename ...Ts, typename...Ts2>
225  struct Builder<N, std::tuple<Ts...>, Ts2...>
226  {
227  template <typename T>
228  using RecType = Builder<N - 1, std::tuple<Ts...>, Ts2..., T>;
229  using T0 = typename std::tuple_element<0, std::tuple<Ts...>>::type;
230  using RetType = std::array<decltype(RecType<T0>::build()), sizeof...(Ts)>;
231 
232  static constexpr RetType build() {
233  return RetType{ RecType<Ts>::build()... };
234  }
235  };
236 
237  public:
238  template <std::size_t N, typename VisitorTuple>
239  static constexpr auto get()
240  -> decltype(Builder<N, VisitorTuple>::build())
241  {
243  }
244  };
245 
246  template <typename Ret, typename IVisitor, typename F, std::size_t N>
248  {
249  private:
250  std::array<std::size_t, N> index;
251 
253  {
254  template <typename T>
255  void visit(const T&) const
256  {
258  }
259 
260  void setIndexPtr(std::size_t& index) { this->index = &index; }
261  private:
262  std::size_t* index = nullptr;
263  };
264 
265  template <std::size_t I, typename Tuple>
266  void set_index(const Tuple&t)
267  {
268  using VisitorType = typename IVisitorImplType<IVisitor, visitorCallImpl>::type;
269  VisitorType visitor;
270  visitor.setIndexPtr(index[I]);
271 
272  std::get<I>(t).accept(visitor);
273  }
274  public:
275  template <typename Tuple, std::size_t ... Is>
276  Ret operator () (F&& f, const Tuple&t, index_sequence<Is...>)
277  {
278  const int dummy[] = {(set_index<Is>(t), 0)...};
279  static_cast<void>(dummy); // silent the warning unused variable
280  constexpr auto a = GetAllOverload<Ret, F&&, Tuple>::
281  template get<sizeof...(Is), typename IVisitor::tuple_type>();
282  auto func = multi_array_getter<N>::get(a, index);
283  return (*func)(f, t);
284  }
285  };
286 
287 } // namespace detail
288 
289 template <typename Ret, typename Visitor, typename F, typename ... Ts>
290 Ret visitorDispatcher(F&& f, Ts&...args)
291 {
292  constexpr std::size_t size = sizeof...(Ts);
294  return d(std::forward<F>(f), std::tie(args...), make_index_sequence<size>());
295 }
296 
297 namespace lc {
298 
299 
300 
303  geo::Vector, geo::Circle, geo::Arc, geo::Area, geo::Ellipse,
304  entity::CADEntity, entity::Point, entity::Line, entity::Arc, entity::Circle, entity::Ellipse,
305  entity::LWPolyline, entity::Image
306  >;
307 
308  class Visitable {
309  public:
310  virtual ~Visitable() = default;
311  virtual void accept(GeoEntityVisitor &) const = 0;
312  };
313 }
typename std::tuple_element< 0, std::tuple< Ts...>>::type T0
Definition: visitor.h:229
virtual void visit(const T &t) override
Definition: visitor.h:162
void set_index(const Tuple &t)
Definition: visitor.h:266
Ret visitorDispatcher(F &&f, Ts &...args)
Definition: visitor.h:290
static Ret call(F &f, const Arg &arg)
Definition: visitor.h:191
void setIndexPtr(std::size_t &index)
Definition: visitor.h:260
virtual void visit(const T &t) override
Definition: visitor.h:168
DECLARE_SHORT_SHARED_PTR(Document)
Definition: cadentity.h:12
static Ret call_helper(F &f, const Arg &arg, index_sequence< Is...>)
Definition: visitor.h:198
void visit(const T &) const
Definition: visitor.h:255
std::array< Ret(*)(F &, const Arg &), sizeof...(Ts)> RetType
Definition: visitor.h:216
std::tuple< T > tuple_type
Definition: visitor.h:109
std::tuple< T, Ts...> tuple_type
Definition: visitor.h:100
IVisitorTs< lc::Visitable, geo::Vector, geo::Circle, geo::Arc, geo::Area, geo::Ellipse, entity::CADEntity, entity::Point, entity::Line, entity::Arc, entity::Circle, entity::Ellipse, entity::LWPolyline, entity::Image > GeoEntityVisitor
Definition: visitor.h:306
std::array< decltype(RecType< T0 >::build()), sizeof...(Ts)> RetType
Definition: visitor.h:230
std::array< std::size_t, N > index
Definition: visitor.h:250