paludis  Version 2.0.0
visitor.hh
1 /* vim: set sw=4 sts=4 et foldmethod=syntax : */
2 
3 /*
4  * Copyright (c) 2008, 2009, 2010, 2011, 2013 Ciaran McCreesh
5  *
6  * This file is part of the Paludis package manager. Paludis is free software;
7  * you can redistribute it and/or modify it under the terms of the GNU General
8  * Public License version 2, as published by the Free Software Foundation.
9  *
10  * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17  * Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19 
20 #ifndef PALUDIS_GUARD_PALUDIS_UTIL_VISITOR_HH
21 #define PALUDIS_GUARD_PALUDIS_UTIL_VISITOR_HH 1
22 
24 #include <paludis/util/visitor-fwd.hh>
25 #include <paludis/util/no_type.hh>
26 #include <functional>
27 
28 namespace paludis
29 {
30  /**
31  * Used by accept_visitor.
32  *
33  * \nosubgrouping
34  * \ingroup g_visitors
35  */
36  template <typename Visitor_>
38  {
39  private:
40  Visitor_ & _v;
41 
42  public:
43  typedef void result_type;
44 
45  ///\name Visitor operations
46  ///\{
47 
48  AcceptVisitor(Visitor_ & v) :
49  _v(v)
50  {
51  }
52 
53  template <typename T_>
54  void operator() (T_ & t) const
55  {
56  t.accept(_v);
57  }
58 
59  ///\}
60  };
61 
62  /**
63  * Used by accept_visitor.
64  *
65  * \nosubgrouping
66  * \ingroup g_visitors
67  */
68  template <typename Visitor_, typename Returning_>
70  {
71  private:
72  Visitor_ & _v;
73 
74  public:
75  typedef Returning_ result_type;
76 
77  ///\name Visitor operations
78  ///\{
79 
80  AcceptVisitorReturning(Visitor_ & v) :
81  _v(v)
82  {
83  }
84 
85  template <typename T_>
86  Returning_ operator() (T_ & t) const
87  {
88  return t.template accept_returning<Returning_>(_v);
89  }
90 
91  ///\}
92  };
93 
94  /**
95  * Convenience function for using a visitor with a standard algorithm.
96  *
97  * \ingroup g_visitors
98  */
99  template <typename Visitor_>
101  {
102  return AcceptVisitor<Visitor_>(v);
103  }
104 
105  /**
106  * Convenience function for using a visitor with a standard algorithm.
107  *
108  * \ingroup g_visitors
109  */
110  template <typename Returning_, typename Visitor_>
112  {
114  }
115 
116  template <typename>
118 
119  template <typename T_, typename R_, typename A1_, typename... As_>
120  struct ExtractFirstArgumentType<R_ (T_::*) (A1_, As_...) const>
121  {
122  typedef A1_ Type;
123  };
124 
125  template <typename T_>
126  using FirstCallArgumentType = typename ExtractFirstArgumentType<decltype(&T_::operator())>::Type;
127 
128  template <typename>
130 
131  template <typename T_, typename R_, typename... As_>
132  struct ExtractResultType<R_ (T_::*) (As_...) const>
133  {
134  typedef R_ Type;
135  };
136 
137  template <typename T_>
138  using CallResultType = typename ExtractResultType<decltype(&T_::operator())>::Type;
139 
140  template <typename Revisitor_, typename Result_, typename... Cases_>
141  struct MadeVisitor;
142 
143  template <typename Revisitor_, typename Result_>
144  struct MadeVisitor<Revisitor_, Result_>
145  {
146  Result_ visit(const NoType<0u> &) const;
147  };
148 
149  template <typename>
151 
152  template <typename T_, typename R_, typename A1_>
153  struct CallThisCaseNeedsTwoArgs<R_ (T_::*) (A1_) const>
154  {
155  enum { value = false };
156  };
157 
158  template <typename T_, typename R_, typename A1_, typename A2_>
159  struct CallThisCaseNeedsTwoArgs<R_ (T_::*) (A1_, A2_) const>
160  {
161  enum { value = true };
162  };
163 
164  template <typename Result_, typename Case_, typename V_, bool needs_two_args_>
165  struct CallThisCase;
166 
167  template <typename Result_, typename Case_, typename V_>
168  struct CallThisCase<Result_, Case_, V_, false>
169  {
170  static Result_ call(const Case_ & thiscase, const FirstCallArgumentType<Case_> & v, const V_ &)
171  {
172  return thiscase(v);
173  }
174  };
175 
176  template <typename Result_, typename Case_, typename V_>
177  struct CallThisCase<Result_, Case_, V_, true>
178  {
179  static Result_ call(const Case_ & thiscase, const FirstCallArgumentType<Case_> & v, const V_ & revisitor)
180  {
181  return thiscase(v, accept_visitor_returning<Result_>(revisitor));
182  }
183  };
184 
185  template <typename Case_, typename V_>
186  struct CallThisCase<void, Case_, V_, true>
187  {
188  static void call(const Case_ & thiscase, const FirstCallArgumentType<Case_> & v, const V_ & revisitor)
189  {
190  thiscase(v, accept_visitor(revisitor));
191  }
192  };
193 
194  template <typename Revisitor_, typename Result_, typename Case_, typename... Rest_>
195  struct MadeVisitor<Revisitor_, Result_, Case_, Rest_...> :
196  MadeVisitor<Revisitor_, Result_, Rest_...>
197  {
198  const Case_ & thiscase;
199 
200  MadeVisitor(const Case_ & c, const Rest_ & ... cases) :
201  MadeVisitor<Revisitor_, Result_, Rest_...>(cases...),
202  thiscase(c)
203  {
204  }
205 
206  using MadeVisitor<Revisitor_, Result_, Rest_...>::visit;
207 
208  Result_ visit(const FirstCallArgumentType<Case_> & v) const
209  {
211  thiscase, v, *static_cast<const Revisitor_ *>(this));
212  }
213  };
214 
215  template <typename Result_, typename... Cases_>
217  MadeVisitor<BaseMadeVisitor<Result_, Cases_...>, Result_, Cases_...>
218  {
219  BaseMadeVisitor(const Cases_ & ... cases) :
220  MadeVisitor<BaseMadeVisitor<Result_, Cases_...>, Result_, Cases_...>(cases...)
221  {
222  }
223  };
224 
225  template <typename Case_, typename... Cases_>
226  auto make_visitor(const Case_ & firstcase, const Cases_ & ... cases) -> BaseMadeVisitor<CallResultType<Case_>, Case_, Cases_...>
227  {
228  return BaseMadeVisitor<CallResultType<Case_>, Case_, Cases_...>{ firstcase, cases... };
229  }
230 
231  template <typename Result_, typename Base_>
232  using Revisit = std::function<Result_ (const Base_ &)>;
233 
234  template <>
236  {
237  public:
238  void forward_visit(const NoType<0u> &);
239  };
240 
241  template <typename TypeList_>
243  public virtual DeclareAbstractVisitMethods<typename TypeList_::Tail>
244  {
245  public:
247 
248  virtual void forward_visit(typename TypeList_::Item &) = 0;
249  };
250 
251  template <typename TypeList_>
252  class WrappedVisitorBase :
253  public virtual DeclareAbstractVisitMethods<TypeList_>
254  {
255  };
256 
257  template <typename RealClass_>
259  {
260  public:
261  void forward_visit(const NoType<1u> &);
262  };
263 
264  template <typename RealClass_, typename TypeList_>
265  class ImplementVisitMethods :
266  public virtual DeclareAbstractVisitMethods<TypeList_>,
267  public ImplementVisitMethods<RealClass_, typename TypeList_::Tail>
268  {
269  public:
271 
272  virtual void forward_visit(typename TypeList_::Item & n)
273  {
274  /* avoid gcc being too clever about noreturn */
275  if (this)
276  static_cast<RealClass_ *>(this)->perform_visit(n);
277  }
278  };
279 
280  template <typename TypeList_, typename UnwrappedVisitor_>
281  class WrappedVoidResultVisitor :
282  public WrappedVisitorBase<TypeList_>,
283  public ImplementVisitMethods<WrappedVoidResultVisitor<TypeList_, UnwrappedVisitor_>, TypeList_>
284  {
285  private:
286  UnwrappedVisitor_ & _unwrapped_visitor;
287 
288  public:
289  WrappedVoidResultVisitor(UnwrappedVisitor_ & v) :
290  _unwrapped_visitor(v)
291  {
292  }
293 
294  template <typename C_>
295  void perform_visit(C_ & t)
296  {
297  _unwrapped_visitor.visit(t);
298  }
299  };
300 
301  template <typename TypeList_, typename Result_, typename UnwrappedVisitor_>
302  class WrappedNonVoidResultVisitor :
303  public WrappedVisitorBase<TypeList_>,
304  public ImplementVisitMethods<WrappedNonVoidResultVisitor<TypeList_, Result_, UnwrappedVisitor_>,
305  TypeList_>
306  {
307  private:
308  UnwrappedVisitor_ & _unwrapped_visitor;
309 
310  public:
311  Result_ result;
312 
313  WrappedNonVoidResultVisitor(UnwrappedVisitor_ & v, const Result_ & r) :
314  _unwrapped_visitor(v),
315  result(r)
316  {
317  }
318 
319  template <typename C_>
320  void perform_visit(C_ & t)
321  {
322  result = _unwrapped_visitor.visit(t);
323  }
324  };
325 
326  template <typename BaseClass_, typename VisitableTypeList_>
327  class DeclareAbstractAcceptMethods
328  {
329  private:
330  virtual void _real_accept(WrappedVisitorBase<VisitableTypeList_> &) = 0;
331  virtual void _real_accept_const(WrappedVisitorBase<typename MakeTypeListConst<VisitableTypeList_>::Type> &) const = 0;
332 
333  public:
334  typedef VisitableTypeList_ VisitableTypeList;
335  typedef BaseClass_ VisitableBaseClass;
336 
337  template <typename UnwrappedVisitor_>
338  void accept(UnwrappedVisitor_ & v)
339  {
340  WrappedVoidResultVisitor<VisitableTypeList_, UnwrappedVisitor_> vv(v);
341  _real_accept(vv);
342  }
343 
344  template <typename UnwrappedVisitor_>
345  void accept(UnwrappedVisitor_ & v) const
346  {
347  WrappedVoidResultVisitor<typename MakeTypeListConst<VisitableTypeList_>::Type, UnwrappedVisitor_> vv(v);
348  _real_accept_const(vv);
349  }
350 
351  template <typename UnwrappedVisitor_>
352  void accept(const UnwrappedVisitor_ & v)
353  {
354  WrappedVoidResultVisitor<VisitableTypeList_, const UnwrappedVisitor_> vv(v);
355  _real_accept(vv);
356  }
357 
358  template <typename UnwrappedVisitor_>
359  void accept(const UnwrappedVisitor_ & v) const
360  {
361  WrappedVoidResultVisitor<typename MakeTypeListConst<VisitableTypeList_>::Type, const UnwrappedVisitor_> vv(v);
362  _real_accept_const(vv);
363  }
364 
365  template <typename Result_, typename UnwrappedVisitor_>
366  Result_ accept_returning(UnwrappedVisitor_ & v, const Result_ & r = Result_())
367  {
368  WrappedNonVoidResultVisitor<VisitableTypeList_, Result_, UnwrappedVisitor_> vv(v, r);
369  _real_accept(vv);
370  return vv.result;
371  }
372 
373  template <typename Result_, typename UnwrappedVisitor_>
374  Result_ accept_returning(const UnwrappedVisitor_ & v, const Result_ & r = Result_())
375  {
376  WrappedNonVoidResultVisitor<VisitableTypeList_, Result_, const UnwrappedVisitor_> vv(v, r);
377  _real_accept(vv);
378  return vv.result;
379  }
380 
381  template <typename Result_, typename UnwrappedVisitor_>
382  Result_ accept_returning(UnwrappedVisitor_ & v, const Result_ & r = Result_()) const
383  {
384  WrappedNonVoidResultVisitor<typename MakeTypeListConst<VisitableTypeList_>::Type, Result_, UnwrappedVisitor_> vv(v, r);
385  _real_accept_const(vv);
386  return vv.result;
387  }
388 
389  template <typename Result_, typename UnwrappedVisitor_>
390  Result_ accept_returning(const UnwrappedVisitor_ & v, const Result_ & r = Result_()) const
391  {
392  WrappedNonVoidResultVisitor<typename MakeTypeListConst<VisitableTypeList_>::Type, Result_, const UnwrappedVisitor_> vv(v, r);
393  _real_accept_const(vv);
394  return vv.result;
395  }
396 
397  template <typename Case_, typename... Cases_>
398  auto make_accept_returning(const Case_ & firstcase, const Cases_ & ... cases) const -> CallResultType<Case_>
399  {
400  return this->accept_returning<CallResultType<Case_> >(make_visitor(firstcase, cases...));
401  }
402 
403  template <typename... Cases_>
404  void make_accept(const Cases_ & ... cases) const
405  {
406  this->accept(make_visitor(cases...));
407  }
408  };
409 
410  template <typename BaseClass_, typename RealClass_>
411  class PALUDIS_VISIBLE ImplementAcceptMethods :
412  public virtual DeclareAbstractAcceptMethods<BaseClass_, typename BaseClass_::VisitableTypeList>
413  {
414  private:
415  void _real_accept(WrappedVisitorBase<typename BaseClass_::VisitableTypeList> & v)
416  {
417  v.forward_visit(*static_cast<RealClass_ *>(this));
418  };
419 
420  void _real_accept_const(WrappedVisitorBase<typename MakeTypeListConst<typename BaseClass_::VisitableTypeList>::Type> & v) const
421  {
422  v.forward_visit(*static_cast<const RealClass_ *>(this));
423  };
424  };
425 }
426 
427 #endif
Definition: visitor-fwd.hh:28
Definition: type_list.hh:27
Definition: visitor.hh:141
Definition: visitor.hh:129
Definition: visitor.hh:117
AcceptVisitorReturning< Visitor_, Returning_ > PALUDIS_VISIBLE accept_visitor_returning(Visitor_ &v)
Definition: visitor.hh:111
Definition: visitor.hh:216
Definition: visitor.hh:150
Definition: visitor.hh:37
Definition: no_type.hh:43
Definition: visitor.hh:69
AcceptVisitor< Visitor_ > PALUDIS_VISIBLE accept_visitor(Visitor_ &v)
Definition: visitor.hh:100
Definition: visitor-fwd.hh:37
#define PALUDIS_VISIBLE
Definition: attributes.hh:71
Definition: visitor.hh:165