]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/generic/functional.h
last minute fix to save legacy Makefile life one more time
[xonotic/netradiant.git] / libs / generic / functional.h
index 7d76a8b0e5bf17060c38b8aa95564fa03e6593ed..2b4fe1b2e61ce2cd2ff64116b93b144951e56799 100644 (file)
@@ -1,9 +1,56 @@
 #if !defined( INCLUDED_FUNCTIONAL_H )
 #define INCLUDED_FUNCTIONAL_H
 
+#include <functional>
 #include <tuple>
 
 namespace detail {
+
+    template<int N>
+    struct rank : rank<N - 1> {
+    };
+
+    template<>
+    struct rank<0> {
+    };
+
+    struct get_func {
+
+        template<class T>
+        struct wrapper {
+            using type = T;
+        };
+
+        template<class F>
+        using func_member = wrapper<typename F::func>;
+
+        template<class F>
+        static wrapper<func_member<F>> test(rank<2>) { return {}; }
+
+        template<class F>
+        struct func_lambda {
+            using type = typename func_lambda<decltype(&F::operator())>::type;
+        };
+
+        template<class R, class... Ts>
+        struct func_lambda<R(*)(Ts...)> {
+            using type = R(Ts...);
+        };
+
+        template<class Object, class R, class... Ts>
+        struct func_lambda<R(Object::*)(Ts...) const> {
+            using type = R(Ts...);
+        };
+
+        template<class Object, class R, class... Ts>
+        struct func_lambda<R(Object::*)(Ts...)> {
+            using type = R(Ts...);
+        };
+
+        template<class F, class = func_lambda<F>>
+        static wrapper<func_lambda<F>> test(rank<1>) { return {}; }
+    };
+
     template<class F>
     struct Fn;
 
@@ -17,77 +64,100 @@ namespace detail {
 }
 
 template<class Caller>
-using get_result_type = typename detail::Fn<typename Caller::func>::result_type;
+using get_func = typename decltype(detail::get_func::test<Caller>(detail::rank<2>{}))::type::type;
+
+template<class Caller>
+using get_result_type = typename detail::Fn<get_func<Caller>>::result_type;
 
 template<class Caller, int N>
-using get_argument = typename detail::Fn<typename Caller::func>::template get<N>;
+using get_argument = typename detail::Fn<get_func<Caller>>::template get<N>;
 
-template<class Object, class F>
-class MemberN;
+namespace detail {
 
-template<class Object, class R, class... Ts>
-class MemberN<Object, R(Ts...)> {
-public:
-    template<R(Object::*f)(Ts...)>
-    class instance {
-    public:
-        using func = R(Object &, Ts...);
+    template<class F>
+    class FunctionN;
 
-        static R call(Object &object, Ts... args) {
-            return (object.*f)(args...);
-        }
+    template<class R, class... Ts>
+    class FunctionN<R(Ts...)> {
+    public:
+        template<R(*f)(Ts...)>
+        class instance {
+        public:
+            using func = R(Ts...);
+
+            static R call(Ts... args) {
+                return (f)(args...);
+            }
+        };
     };
-};
 
-template<class Object, class F>
-class ConstMemberN;
+}
 
-template<class Object, class R, class... Ts>
-class ConstMemberN<Object, R(Ts...)> {
-public:
-    template<R(Object::*f)(Ts...) const>
-    class instance {
-    public:
-        using func = R(const Object &, Ts...);
+template<class F, F *func>
+using Function = typename detail::FunctionN<F>::template instance<func>;
 
-        static R call(const Object &object, Ts... args) {
-            return (object.*f)(args...);
-        }
+namespace detail {
+    template<class Object, class F>
+    struct MemberFunction;
+
+    template<class Object, class R, class... Ts>
+    struct MemberFunction<Object, R(Ts...)> {
+        using type = R(Object::*)(Ts...);
+        using type_const = R(Object::*)(Ts...) const;
     };
-};
+}
 
-template<class F>
-class FunctionN;
+namespace detail {
+    template<class Object, class F>
+    class MemberN;
 
-template<class R, class... Ts>
-class FunctionN<R(Ts...)> {
-public:
-    template<R(*f)(Ts...)>
-    class instance {
+    template<class Object, class R, class... Ts>
+    class MemberN<Object, R(Ts...)> {
     public:
-        using func = R(Ts...);
-
-        static R call(Ts... args) {
-            return (f)(args...);
-        }
+        template<R(Object::*f)(Ts...)>
+        class instance {
+        public:
+            using func = R(Object &, Ts...);
+
+            static R call(Object &object, Ts... args) {
+                return (object.*f)(args...);
+            }
+        };
     };
-};
+}
 
-template<class Caller, class F>
-class CallerShiftFirst;
+template<class Object, class F>
+using MemberFunction = typename detail::MemberFunction<Object, F>::type;
+
+template<class Object, class F, MemberFunction<Object, F> func>
+using Member = typename detail::MemberN<Object, F>::template instance<func>;
 
-template<class Caller, class R, class FirstArgument, class... Ts>
-class CallerShiftFirst<Caller, R(FirstArgument, Ts...)> {
-public:
-    using func = R(FirstArgument, Ts...);
+namespace detail {
+    template<class Object, class F>
+    class ConstMemberN;
+
+    template<class Object, class R, class... Ts>
+    class ConstMemberN<Object, R(Ts...)> {
+    public:
+        template<R(Object::*f)(Ts...) const>
+        class instance {
+        public:
+            using func = R(const Object &, Ts...);
+
+            static R call(const Object &object, Ts... args) {
+                return (object.*f)(args...);
+            }
+        };
+    };
+}
+
+template<class Object, class F>
+using ConstMemberFunction = typename detail::MemberFunction<Object, F>::type_const;
 
-    static R call(FirstArgument, Ts... args) {
-        return Caller::call(args...);
-    }
-};
+template<class Object, class F, ConstMemberFunction<Object, F> func>
+using ConstMember = typename detail::ConstMemberN<Object, F>::template instance<func>;
 
-template<class Functor, class F>
-class FunctorNInvoke;
+// misc
 
 namespace detail {
     template<int ...>
@@ -105,98 +175,36 @@ namespace detail {
 
     template<int N>
     using seq_new = typename gens<N>::type;
-}
-
-template<class Functor, class R, class... Ts>
-class FunctorNInvoke<Functor, R(Ts...)> {
-    std::tuple<Ts...> args;
-
-    template<class T>
-    struct caller;
 
-    template<int ...I>
-    struct caller<detail::seq<I...>> {
-        static inline R call(FunctorNInvoke<Functor, R(Ts...)> *self, Functor functor) {
-            (void) self;
-            return functor(std::get<I>(self->args)...);
-        }
-    };
-
-public:
-    FunctorNInvoke(Ts... args) : args(args...) {
-    }
-
-    inline R operator()(Functor functor) {
-        return caller<detail::seq_new<sizeof...(Ts)>>::call(this, functor);
-    }
-};
-
-template<class Functor>
-using FunctorInvoke = FunctorNInvoke<Functor, typename Functor::func>;
+    template<class Functor, class F>
+    class FunctorNInvoke;
 
-template<class Object, class R, R(Object::*member)()>
-using Member = typename MemberN<Object, R()>::template instance<member>;
+    template<class Functor, class R, class... Ts>
+    class FunctorNInvoke<Functor, R(Ts...)> {
+        std::tuple<Ts...> args;
 
-template<class Object, class R, R(Object::*member)() const>
-using ConstMember = typename ConstMemberN<Object, R()>::template instance<member>;
+        template<class T>
+        struct caller;
 
-template<class Object, class A1, class R, R(Object::*member)(A1)>
-using Member1 = typename MemberN<Object, R(A1)>::template instance<member>;
+        template<int ...I>
+        struct caller<seq<I...>> {
+            static inline R call(FunctorNInvoke<Functor, R(Ts...)> *self, Functor functor) {
+                (void) self;
+                return functor(std::get<I>(self->args)...);
+            }
+        };
 
-template<class Object, class A1, class R, R(Object::*member)(A1) const>
-using ConstMember1 = typename ConstMemberN<Object, R(A1)>::template instance<member>;
-
-template<class Object, class A1, class A2, class R, R(Object::*member)(A1, A2)>
-using Member2 = typename MemberN<Object, R(A1, A2)>::template instance<member>;
-
-template<class Object, class A1, class A2, class R, R(Object::*member)(A1, A2) const>
-using ConstMember2 = typename ConstMemberN<Object, R(A1, A2)>::template instance<member>;
-
-template<class Object, class A1, class A2, class A3, class R, R(Object::*member)(A1, A2, A3)>
-using Member3 = typename MemberN<Object, R(A1, A2, A3)>::template instance<member>;
-
-template<class Object, class A1, class A2, class A3, class R, R(Object::*member)(A1, A2, A3) const>
-using ConstMember3 = typename ConstMemberN<Object, R(A1, A2, A3)>::template instance<member>;
-
-template<class R, R(*func)()>
-using Function0 = typename FunctionN<R()>::template instance<func>;
-
-template<class A1, class R, R(*func)(A1)>
-using Function1 = typename FunctionN<R(A1)>::template instance<func>;
-
-template<class A1, class A2, class R, R(*func)(A1, A2)>
-using Function2 = typename FunctionN<R(A1, A2)>::template instance<func>;
-
-template<class A1, class A2, class A3, class R, R(*func)(A1, A2, A3)>
-using Function3 = typename FunctionN<R(A1, A2, A3)>::template instance<func>;
-
-template<class A1, class A2, class A3, class A4, class R, R(*func)(A1, A2, A3, A4)>
-using Function4 = typename FunctionN<R(A1, A2, A3, A4)>::template instance<func>;
-
-template<class Caller, class FirstArgument = void *>
-using Caller0To1 = CallerShiftFirst<Caller, get_result_type<Caller>(
-        FirstArgument
-)>;
-
-template<class Caller, class FirstArgument = void *>
-using Caller1To2 = CallerShiftFirst<Caller, get_result_type<Caller>(
-        FirstArgument,
-        get_argument<Caller, 0>
-)>;
+    public:
+        FunctorNInvoke(Ts... args) : args(args...) {
+        }
 
-template<class Caller, class FirstArgument = void *>
-using Caller2To3 = CallerShiftFirst<Caller, get_result_type<Caller>(
-        FirstArgument,
-        get_argument<Caller, 0>,
-        get_argument<Caller, 1>
-)>;
+        inline R operator()(Functor functor) {
+            return caller<seq_new<sizeof...(Ts)>>::call(this, functor);
+        }
+    };
+}
 
-template<class Caller, class FirstArgument = void *>
-using Caller3To4 = CallerShiftFirst<Caller, get_result_type<Caller>(
-        FirstArgument,
-        get_argument<Caller, 0>,
-        get_argument<Caller, 1>,
-        get_argument<Caller, 2>
-)>;
+template<class Functor>
+using FunctorInvoke = detail::FunctorNInvoke<Functor, get_func<Functor>>;
 
 #endif