diff options
author | 2013-05-23 12:32:03 +0100 | |
---|---|---|
committer | 2013-05-23 20:57:31 +0100 | |
commit | e66605f52a93b86a87bb122f9c5032def378ae05 (patch) | |
tree | 4c1d55a494d9f8bc7f0a95af8191ece6c8abdac6 | |
parent | 3479c45da84cc79f0a69463c0b0470dd76e41053 (diff) | |
download | paludis-e66605f52a93b86a87bb122f9c5032def378ae05.tar.gz paludis-e66605f52a93b86a87bb122f9c5032def378ae05.tar.xz |
Add make_visitor, make_accept_returning
-rw-r--r-- | paludis/util/visitor.hh | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/paludis/util/visitor.hh b/paludis/util/visitor.hh index 547e27231..8b2c0d96a 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_> |