]> 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 bd253486bb0d0a654ed1651b445ff5e7bf23a44c..2b4fe1b2e61ce2cd2ff64116b93b144951e56799 100644 (file)
-
-#if !defined(INCLUDED_FUNCTIONAL_H)
+#if !defined( INCLUDED_FUNCTIONAL_H )
 #define INCLUDED_FUNCTIONAL_H
 
-template<typename Object, typename R, R (Object::*member)()>
-class Member
-{
-public:
-  typedef Object& first_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type object)
-  {
-    return (object.*member)();
-  }
-};
-
-template<typename Object, typename R, R (Object::*member)() const>
-class ConstMember
-{
-public:
-  typedef const Object& first_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type object)
-  {
-    return (object.*member)();
-  }
-};
-
-template<typename Object, typename A1, typename R, R (Object::*member)(A1)>
-class Member1
-{
-public:
-  typedef Object& first_argument_type;
-  typedef A1 second_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type object, second_argument_type a1)
-  {
-    return (object.*member)(a1);
-  }
-};
-
-template<typename Object, typename A1, typename R, R (Object::*member)(A1) const>
-class ConstMember1
-{
-public:
-  typedef const Object& first_argument_type;
-  typedef A1 second_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type object, second_argument_type a1)
-  {
-    return (object.*member)(a1);
-  }
-};
-
-template<typename Object, typename A2, typename A3, typename R, R (Object::*member)(A2, A3)>
-class Member2
-{
-public:
-  typedef Object& first_argument_type;
-  typedef A2 second_argument_type;
-  typedef A3 third_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type object, second_argument_type a2, third_argument_type a3)
-  {
-    return (object.*member)(a2, a3);
-  }
-};
-
-template<typename Object, typename A2, typename A3, typename R, R (Object::*member)(A2, A3) const>
-class ConstMember2
-{
-public:
-  typedef const Object& first_argument_type;
-  typedef A2 second_argument_type;
-  typedef A3 third_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type object, second_argument_type a2, third_argument_type a3)
-  {
-    return (object.*member)(a2, a3);
-  }
-};
-
-template<typename Object, typename A2, typename A3, typename A4, typename R, R (Object::*member)(A2, A3, A4)>
-class Member3
-{
-public:
-  typedef Object& first_argument_type;
-  typedef A2 second_argument_type;
-  typedef A3 third_argument_type;
-  typedef A4 fourth_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type object, second_argument_type a2, third_argument_type a3, fourth_argument_type a4)
-  {
-    return (object.*member)(a2, a3, a4);
-  }
-};
-
-template<typename Object, typename A2, typename A3, typename A4, typename R, R (Object::*member)(A2, A3, A4) const>
-class ConstMember3
-{
-public:
-  typedef const Object& first_argument_type;
-  typedef A2 second_argument_type;
-  typedef A3 third_argument_type;
-  typedef A4 fourth_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type object, second_argument_type a2, third_argument_type a3, fourth_argument_type a4)
-  {
-    return (object.*member)(a2, a3, a4);
-  }
-};
-
-template<typename R, R (*func)()> 
-class Function0
-{
-public:
-  typedef R result_type;
-  static result_type call()
-  {
-    return (func)();
-  }
-};
-
-template<typename A1, typename R, R (*func)(A1)> 
-class Function1
-{
-public:
-  typedef A1 first_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type a1)
-  {
-    return (func)(a1);
-  }
-};
-
-template<typename A1, typename A2, typename R, R (*func)(A1, A2)> 
-class Function2
-{
-public:
-  typedef A1 first_argument_type;
-  typedef A2 second_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type a1, second_argument_type a2)
-  {
-    return (func)(a1, a2);
-  }
-};
-
-template<typename A1, typename A2, typename A3, typename R, R (*func)(A1, A2, A3)> 
-class Function3
-{
-public:
-  typedef A1 first_argument_type;
-  typedef A2 second_argument_type;
-  typedef A3 third_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type a1, second_argument_type a2, third_argument_type a3)
-  {
-    return (func)(a1, a2, a3);
-  }
-};
-
-template<typename A1, typename A2, typename A3, typename A4, typename R, R (*func)(A1, A2, A3, A4)> 
-class Function4
-{
-public:
-  typedef A1 first_argument_type;
-  typedef A2 second_argument_type;
-  typedef A3 third_argument_type;
-  typedef A4 fourth_argument_type;
-  typedef R result_type;
-  static result_type call(first_argument_type a1, second_argument_type a2, third_argument_type a3, fourth_argument_type a4)
-  {
-    return (func)(a1, a2, a3, a4);
-  }
-};
-
-template<typename Caller, typename FirstArgument = void*> 
-class Caller0To1
-{
-public:
-  typedef FirstArgument first_argument_type;
-  typedef typename Caller::result_type result_type;
-  static result_type call(first_argument_type)
-  {
-    return Caller::call();
-  }
-};
-
-template<typename Caller, typename FirstArgument = void*> 
-class Caller1To2
-{
-public:
-  typedef FirstArgument first_argument_type;
-  typedef typename Caller::first_argument_type second_argument_type;
-  typedef typename Caller::result_type result_type;
-  static result_type call(first_argument_type, second_argument_type a2)
-  {
-    return Caller::call(a2);
-  }
-};
-
-template<typename Caller, typename FirstArgument = void*> 
-class Caller2To3
-{
-public:
-  typedef FirstArgument first_argument_type;
-  typedef typename Caller::first_argument_type second_argument_type;
-  typedef typename Caller::second_argument_type third_argument_type;
-  typedef typename Caller::result_type result_type;
-  static result_type call(first_argument_type, second_argument_type a2, third_argument_type a3)
-  {
-    return Caller::call(a2, a3);
-  }
-};
-
-template<typename Caller, typename FirstArgument = void*> 
-class Caller3To4
-{
-public:
-  typedef FirstArgument first_argument_type;
-  typedef typename Caller::first_argument_type second_argument_type;
-  typedef typename Caller::second_argument_type third_argument_type;
-  typedef typename Caller::third_argument_type fourth_argument_type;
-  typedef typename Caller::result_type result_type;
-  static result_type call(first_argument_type, second_argument_type a2, third_argument_type a3, fourth_argument_type a4)
-  {
-    return Caller::call(a2, a3, a4);
-  }
-};
-
-template<typename Functor>
-class FunctorInvoke
-{
-public:
-  typedef typename Functor::result_type result_type;
-  inline result_type operator()(Functor functor)
-  {
-    return functor();
-  }
-};
-
-template<typename Functor>
-class Functor1Invoke
-{
-  typename Functor::first_argument_type a1;
-public:
-  typedef typename Functor::first_argument_type first_argument_type;
-  typedef typename Functor::result_type result_type;
-  Functor1Invoke(first_argument_type a1) : a1(a1)
-  {
-  }
-  inline result_type operator()(Functor functor)
-  {
-    return functor(a1);
-  }
-};
-
-template<typename Functor>
-class Functor2Invoke
-{
-  typename Functor::first_argument_type a1;
-  typename Functor::second_argument_type a2;
-public:
-  typedef typename Functor::first_argument_type first_argument_type;
-  typedef typename Functor::second_argument_type second_argument_type;
-  typedef typename Functor::result_type result_type;
-  Functor2Invoke(first_argument_type a1, second_argument_type a2)
-    : a1(a1), a2(a2)
-  {
-  }
-  inline result_type operator()(Functor functor)
-  {
-    return functor(a1, a2);
-  }
-};
-
-template<typename Functor>
-class Functor3Invoke
-{
-  typename Functor::first_argument_type a1;
-  typename Functor::second_argument_type a2;
-  typename Functor::third_argument_type a3;
-public:
-  typedef typename Functor::first_argument_type first_argument_type;
-  typedef typename Functor::second_argument_type second_argument_type;
-  typedef typename Functor::third_argument_type third_argument_type;
-  typedef typename Functor::result_type result_type;
-  Functor3Invoke(first_argument_type a1, second_argument_type a2, third_argument_type a3)
-    : a1(a1), a2(a2), a3(a3)
-  {
-  }
-  inline result_type operator()(Functor functor)
-  {
-    return functor(a1, a2, a3);
-  }
-};
-
-template<typename Other, typename True, typename False, typename Type>
-class TypeEqual
-{
-public:
-  typedef False type;
-};
-template<typename Other, typename True, typename False>
-class TypeEqual<Other, True, False, Other>
-{
-public:
-  typedef True type;
-};
+#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;
+
+    template<class R, class... Ts>
+    struct Fn<R(Ts...)> {
+        using result_type = R;
+
+        template<int N>
+        using get = typename std::tuple_element<N, std::tuple<Ts...>>::type;
+    };
+}
+
+template<class Caller>
+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<get_func<Caller>>::template get<N>;
+
+namespace detail {
+
+    template<class F>
+    class FunctionN;
+
+    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 F, F *func>
+using Function = typename detail::FunctionN<F>::template instance<func>;
+
+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;
+    };
+}
+
+namespace detail {
+    template<class Object, class F>
+    class MemberN;
+
+    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...);
+
+            static R call(Object &object, Ts... args) {
+                return (object.*f)(args...);
+            }
+        };
+    };
+}
+
+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>;
+
+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;
+
+template<class Object, class F, ConstMemberFunction<Object, F> func>
+using ConstMember = typename detail::ConstMemberN<Object, F>::template instance<func>;
+
+// misc
+
+namespace detail {
+    template<int ...>
+    struct seq {
+    };
+
+    template<int N, int... S>
+    struct gens : gens<N - 1, N - 1, S...> {
+    };
+
+    template<int... S>
+    struct gens<0, S...> {
+        using type = seq<S...>;
+    };
+
+    template<int N>
+    using seq_new = typename gens<N>::type;
+
+    template<class Functor, class F>
+    class FunctorNInvoke;
+
+    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<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<seq_new<sizeof...(Ts)>>::call(this, functor);
+        }
+    };
+}
+
+template<class Functor>
+using FunctorInvoke = detail::FunctorNInvoke<Functor, get_func<Functor>>;
 
 #endif