aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2013-05-23 12:32:03 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2013-05-23 20:57:31 +0100
commite66605f52a93b86a87bb122f9c5032def378ae05 (patch)
tree4c1d55a494d9f8bc7f0a95af8191ece6c8abdac6
parent3479c45da84cc79f0a69463c0b0470dd76e41053 (diff)
downloadpaludis-e66605f52a93b86a87bb122f9c5032def378ae05.tar.gz
paludis-e66605f52a93b86a87bb122f9c5032def378ae05.tar.xz
Add make_visitor, make_accept_returning
-rw-r--r--paludis/util/visitor.hh112
1 files changed, 112 insertions, 0 deletions
diff --git a/paludis/util/visitor.hh b/paludis/util/visitor.hh
index 547e272..8b2c0d9 100644
--- a/paludis/util/visitor.hh
+++ b/paludis/util/visitor.hh
@@ -112,6 +112,112 @@ namespace paludis
return AcceptVisitorReturning<Visitor_, Returning_>(v);
}
+ template <typename>
+ struct ExtractFirstArgumentType;
+
+ template <typename T_, typename R_, typename A1_, typename... As_>
+ struct ExtractFirstArgumentType<R_ (T_::*) (A1_, As_...) const>
+ {
+ typedef A1_ Type;
+ };
+
+ template <typename T_>
+ using FirstCallArgumentType = typename ExtractFirstArgumentType<decltype(&T_::operator())>::Type;
+
+ template <typename>
+ struct ExtractResultType;
+
+ template <typename T_, typename R_, typename... As_>
+ struct ExtractResultType<R_ (T_::*) (As_...) const>
+ {
+ typedef R_ Type;
+ };
+
+ template <typename T_>
+ using CallResultType = typename ExtractResultType<decltype(&T_::operator())>::Type;
+
+ template <typename Revisitor_, typename Result_, typename... Cases_>
+ struct MadeVisitor;
+
+ template <typename Revisitor_, typename Result_>
+ struct MadeVisitor<Revisitor_, Result_>
+ {
+ Result_ visit(const NoType<0u> &) const;
+ };
+
+ template <typename>
+ struct CallThisCaseNeedsTwoArgs;
+
+ template <typename T_, typename R_, typename A1_>
+ struct CallThisCaseNeedsTwoArgs<R_ (T_::*) (A1_) const>
+ {
+ enum { value = false };
+ };
+
+ template <typename T_, typename R_, typename A1_, typename A2_>
+ struct CallThisCaseNeedsTwoArgs<R_ (T_::*) (A1_, A2_) const>
+ {
+ enum { value = true };
+ };
+
+ template <typename Result_, typename Case_, typename V_, bool needs_two_args_>
+ struct CallThisCase;
+
+ template <typename Result_, typename Case_, typename V_>
+ struct CallThisCase<Result_, Case_, V_, false>
+ {
+ static Result_ call(const Case_ & thiscase, const FirstCallArgumentType<Case_> & v, const V_ &)
+ {
+ return thiscase(v);
+ }
+ };
+
+ template <typename Result_, typename Case_, typename V_>
+ struct CallThisCase<Result_, Case_, V_, true>
+ {
+ static Result_ call(const Case_ & thiscase, const FirstCallArgumentType<Case_> & v, const V_ & revisitor)
+ {
+ return thiscase(v, accept_visitor_returning<Result_>(revisitor));
+ }
+ };
+
+ template <typename Revisitor_, typename Result_, typename Case_, typename... Rest_>
+ struct MadeVisitor<Revisitor_, Result_, Case_, Rest_...> :
+ MadeVisitor<Revisitor_, Result_, Rest_...>
+ {
+ const Case_ & thiscase;
+
+ MadeVisitor(const Case_ & c, const Rest_ & ... cases) :
+ MadeVisitor<Revisitor_, Result_, Rest_...>(cases...),
+ thiscase(c)
+ {
+ }
+
+ using MadeVisitor<Revisitor_, Result_, Rest_...>::visit;
+
+ Result_ visit(const FirstCallArgumentType<Case_> & v) const
+ {
+ return CallThisCase<Result_, Case_, Revisitor_, CallThisCaseNeedsTwoArgs<decltype(&Case_::operator())>::value>::call(
+ thiscase, v, *static_cast<const Revisitor_ *>(this));
+ }
+ };
+
+ template <typename Result_, typename... Cases_>
+ struct BaseMadeVisitor :
+ MadeVisitor<BaseMadeVisitor<Result_, Cases_...>, Result_, Cases_...>
+ {
+ BaseMadeVisitor(const Cases_ & ... cases) :
+ MadeVisitor<BaseMadeVisitor<Result_, Cases_...>, Result_, Cases_...>(cases...)
+ {
+ }
+ };
+
+ template <typename Case_, typename... Cases_>
+ auto make_visitor(const Case_ & firstcase, const Cases_ & ... cases) -> BaseMadeVisitor<CallResultType<Case_>, Case_, Cases_...>
+ {
+ return BaseMadeVisitor<CallResultType<Case_>, Case_, Cases_...>{ firstcase, cases... };
+ }
+
template <>
class DeclareAbstractVisitMethods<TypeListTail>
{
@@ -274,6 +380,12 @@ namespace paludis
_real_accept_const(vv);
return vv.result;
}
+
+ template <typename Case_, typename... Cases_>
+ auto make_accept_returning(const Case_ & firstcase, const Cases_ & ... cases) const -> CallResultType<Case_>
+ {
+ return this->accept_returning<CallResultType<Case_> >(make_visitor(firstcase, cases...));
+ }
};
template <typename BaseClass_, typename RealClass_>