X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=libs%2Fgeneric%2Fcallback.h;h=36653a73d4297b85122525d4c762a217e755bfd1;hp=e5a8c8b4ad04403ea3d2e76c9d6eddd377eed91d;hb=620247ad5c80068970db40fa5aa87d9fdb24bcfc;hpb=12b372f89ce109a4db9d510884fbe7d05af79870 diff --git a/libs/generic/callback.h b/libs/generic/callback.h index e5a8c8b4..36653a73 100644 --- a/libs/generic/callback.h +++ b/libs/generic/callback.h @@ -23,28 +23,206 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define INCLUDED_GENERIC_CLOSURE_H /// \file -/// \brief Type-safe techniques for binding the first argument of an anonymous callback. +/// \brief Type-safe techniques for binding the first argument of an opaque callback. #include +#include "functional.h" +#include "callbackfwd.h" -/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer. -/// -/// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller. -class Callback +template +inline void* convertToOpaque(Type* t) { - typedef void (*Thunk)(void*); - void* m_environment; - Thunk m_thunk; + return t; +} +template +inline void* convertToOpaque(const Type* t) +{ + return const_cast(t); +} +template +inline void* convertToOpaque(Type& t) +{ + return &t; +} +template +inline void* convertToOpaque(const Type& t) +{ + return const_cast(&t); +} + + +template +class ConvertFromOpaque +{ +}; + +template +class ConvertFromOpaque +{ +public: + static Type& apply(void* p) + { + return *static_cast(p); + } +}; - static void nullThunk(void*) +template +class ConvertFromOpaque +{ +public: + static const Type& apply(void* p) { + return *static_cast(p); } +}; + +template +class ConvertFromOpaque +{ +public: + static Type* apply(void* p) + { + return static_cast(p); + } +}; + +template +class ConvertFromOpaque +{ +public: + static const Type* apply(void* p) + { + return static_cast(p); + } +}; + +template +class BindFirstOpaque +{ + typedef typename Caller::first_argument_type FirstBound; + FirstBound firstBound; public: - Callback() : m_environment(0), m_thunk(nullThunk) + typedef typename Caller::result_type result_type; + explicit BindFirstOpaque(FirstBound firstBound) : firstBound(firstBound) { } - Callback(void* environment, Thunk function) : m_environment(environment), m_thunk(function) + result_type operator()() const + { + return Caller::call(firstBound); + } + FirstBound getBound() const + { + return firstBound; + } + static result_type thunk(void* environment) + { + return Caller::call(ConvertFromOpaque::apply(environment)); + } + void* getEnvironment() const + { + return convertToOpaque(firstBound); + } +}; + +template +class BindFirstOpaque1 +{ + typedef typename Caller::first_argument_type FirstBound; + FirstBound firstBound; +public: + typedef typename Caller::second_argument_type first_argument_type; + typedef typename Caller::result_type result_type; + explicit BindFirstOpaque1(FirstBound firstBound) : firstBound(firstBound) + { + } + result_type operator()(first_argument_type a1) const + { + return Caller::call(firstBound, a1); + } + FirstBound getBound() const + { + return firstBound; + } + static result_type thunk(void* environment, first_argument_type a1) + { + return Caller::call(ConvertFromOpaque::apply(environment), a1); + } + void* getEnvironment() const + { + return convertToOpaque(firstBound); + } +}; + +template +class BindFirstOpaque2 +{ + typedef typename Caller::first_argument_type FirstBound; + FirstBound firstBound; +public: + typedef typename Caller::second_argument_type first_argument_type; + typedef typename Caller::third_argument_type second_argument_type; + typedef typename Caller::result_type result_type; + explicit BindFirstOpaque2(FirstBound firstBound) : firstBound(firstBound) + { + } + result_type operator()(first_argument_type a1, second_argument_type a2) const + { + return Caller::call(firstBound, a1, a2); + } + FirstBound getBound() const + { + return firstBound; + } + static result_type thunk(void* environment, first_argument_type a1, second_argument_type a2) + { + return Caller::call(ConvertFromOpaque::apply(environment), a1, a2); + } + void* getEnvironment() const + { + return convertToOpaque(firstBound); + } +}; + +template +class BindFirstOpaque3 +{ + typedef typename Caller::first_argument_type FirstBound; + FirstBound firstBound; +public: + typedef typename Caller::second_argument_type first_argument_type; + typedef typename Caller::third_argument_type second_argument_type; + typedef typename Caller::fourth_argument_type third_argument_type; + typedef typename Caller::result_type result_type; + explicit BindFirstOpaque3(FirstBound firstBound) : firstBound(firstBound) + { + } + result_type operator()(first_argument_type a1, second_argument_type a2, third_argument_type a3) const + { + return Caller::call(firstBound, a1, a2, a3); + } + FirstBound getBound() const + { + return firstBound; + } + static result_type thunk(void* environment, first_argument_type a1, second_argument_type a2, third_argument_type a3) + { + return Caller::call(ConvertFromOpaque::apply(environment), a1, a2, a3); + } + void* getEnvironment() const + { + return convertToOpaque(firstBound); + } +}; + +template +class CallbackBase +{ + void* m_environment; + Thunk_ m_thunk; +public: + typedef Thunk_ Thunk; + CallbackBase(void* environment, Thunk function) : m_environment(environment), m_thunk(function) { } void* getEnvironment() const @@ -55,113 +233,226 @@ public: { return m_thunk; } - void operator()() const - { - m_thunk(m_environment); - } }; -inline bool operator==(const Callback& self, const Callback& other) +template +inline bool operator==(const CallbackBase& self, const CallbackBase& other) { return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk(); } -inline bool operator<(const Callback& self, const Callback& other) +template +inline bool operator!=(const CallbackBase& self, const CallbackBase& other) +{ + return !(self == other); +} +template +inline bool operator<(const CallbackBase& self, const CallbackBase& other) { return self.getEnvironment() < other.getEnvironment() || (!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk()); } -/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and one other argument. + +/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer. /// -/// Use with the callback constructors MemberCaller1, ConstMemberCaller1, ReferenceCaller1, ConstReferenceCaller1, PointerCaller1, ConstPointerCaller1 and FreeCaller1. -template -class Callback1 +/// Use with the callback constructors MemberCaller, ConstMemberCaller, ReferenceCaller, ConstReferenceCaller, PointerCaller, ConstPointerCaller and FreeCaller. +template +class Callback0 : public CallbackBase { - typedef void (*Thunk)(void*, FirstArgument); - void* m_environment; - Thunk m_thunk; - - static void nullThunk(void*, FirstArgument) + typedef CallbackBase Base; + static Result nullThunk(void*) { } public: - typedef FirstArgument first_argument_type; + typedef Result result_type; - Callback1() : m_environment(0), m_thunk(nullThunk) - { - } - Callback1(void* environment, Thunk function) : m_environment(environment), m_thunk(function) + Callback0() : Base(0, nullThunk) { } - void* getEnvironment() const + template + Callback0(const BindFirstOpaque& caller) : Base(caller.getEnvironment(), BindFirstOpaque::thunk) { - return m_environment; } - Thunk getThunk() const + Callback0(void* environment, Thunk function) : Base(environment, function) { - return m_thunk; } - void operator()(FirstArgument firstArgument) const + result_type operator()() const { - m_thunk(m_environment, firstArgument); + return getThunk()(getEnvironment()); } }; -template -inline bool operator==(const Callback1& self, const Callback1& other) +template +inline Callback0 makeCallback0(const Caller& caller, typename Caller::first_argument_type callee) { - return self.getEnvironment() == other.getEnvironment() && self.getThunk() == other.getThunk(); + return Callback0(BindFirstOpaque(callee)); } -template -inline bool operator<(const Callback1& self, const Callback1& other) +template +inline Callback0 makeStatelessCallback0(const Caller& caller) { - return self.getEnvironment() < other.getEnvironment() || - (!(other.getEnvironment() < self.getEnvironment()) && self.getThunk() < other.getThunk()); + return makeCallback0(Caller0To1(), 0); } -template -class FunctorInvoke +typedef Callback0 Callback; + + + +/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and one other argument. +/// +/// Use with the callback constructors MemberCaller1, ConstMemberCaller1, ReferenceCaller1, ConstReferenceCaller1, PointerCaller1, ConstPointerCaller1 and FreeCaller1. +template +class Callback1 : public CallbackBase { + typedef CallbackBase Base; + static Result nullThunk(void*, FirstArgument) + { + } + public: - inline void operator()(Functor functor) + typedef FirstArgument first_argument_type; + typedef Result result_type; + + Callback1() : Base(0, nullThunk) { - functor(); + } + template + Callback1(const BindFirstOpaque1& caller) : Base(caller.getEnvironment(), BindFirstOpaque1::thunk) + { + } + Callback1(void* environment, Thunk function) : Base(environment, function) + { + } + result_type operator()(FirstArgument firstArgument) const + { + return getThunk()(getEnvironment(), firstArgument); } }; -typedef FunctorInvoke CallbackInvoke; +template +inline Callback1 makeCallback1(const Caller& caller, typename Caller::first_argument_type callee) +{ + return Callback1(BindFirstOpaque1(callee)); +} +template +inline Callback1 makeStatelessCallback1(const Caller& caller) +{ + return makeCallback1(Caller1To2(), 0); +} -template -class Functor1Invoke +/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and two other arguments. +/// +template +class Callback2 : public CallbackBase { - FirstArgument m_firstArgument; + typedef CallbackBase Base; + static Result nullThunk(void*, FirstArgument, SecondArgument) + { + } + public: - Functor1Invoke(FirstArgument firstArgument) : m_firstArgument(firstArgument) + typedef FirstArgument first_argument_type; + typedef SecondArgument second_argument_type; + typedef Result result_type; + + Callback2() : Base(0, nullThunk) + { + } + template + Callback2(const BindFirstOpaque2& caller) : Base(caller.getEnvironment(), BindFirstOpaque2::thunk) { } - inline void operator()(Functor functor) + Callback2(void* environment, Thunk function) : Base(environment, function) { - functor(m_firstArgument); + } + result_type operator()(FirstArgument firstArgument, SecondArgument secondArgument) const + { + return getThunk()(getEnvironment(), firstArgument, secondArgument); } }; +template +inline Callback2< + typename Caller::second_argument_type, + typename Caller::third_argument_type, + typename Caller::result_type +> makeCallback2(const Caller& caller, typename Caller::first_argument_type callee) +{ + return Callback2< + typename Caller::second_argument_type, + typename Caller::third_argument_type, + typename Caller::result_type + >(BindFirstOpaque2(callee)); +} +template +inline Callback2< + typename Caller::first_argument_type, + typename Caller::second_argument_type, + typename Caller::result_type +> makeStatelessCallback2(const Caller& caller) +{ + return makeCallback2(Caller2To3(), 0); +} -typedef Callback1 BoolImportCallback; -typedef Callback1 BoolExportCallback; -typedef Callback1 IntImportCallback; -typedef Callback1 IntExportCallback; +/// \brief Combines a void pointer with a pointer to a function which operates on a void pointer and three other arguments. +/// +template +class Callback3 : public CallbackBase +{ + typedef CallbackBase Base; + static Result nullThunk(void*, FirstArgument, SecondArgument, ThirdArgument) + { + } -typedef Callback1 FloatImportCallback; -typedef Callback1 FloatExportCallback; +public: + typedef FirstArgument first_argument_type; + typedef SecondArgument second_argument_type; + typedef ThirdArgument third_argument_type; + typedef Result result_type; -typedef Callback1 StringImportCallback; -typedef Callback1 StringExportCallback; + Callback3() : Base(0, nullThunk) + { + } + template + Callback3(const BindFirstOpaque3& caller) : Base(caller.getEnvironment(), BindFirstOpaque3::thunk) + { + } + Callback3(void* environment, Thunk function) : Base(environment, function) + { + } + result_type operator()(FirstArgument firstArgument, SecondArgument secondArgument, ThirdArgument thirdArgument) const + { + return getThunk()(getEnvironment(), firstArgument, secondArgument, thirdArgument); + } +}; -typedef Callback1 SizeImportCallback; -typedef Callback1 SizeExportCallback; +template +inline Callback3< + typename Caller::second_argument_type, + typename Caller::third_argument_type, + typename Caller::fourth_argument_type, + typename Caller::result_type +> makeCallback3(const Caller& caller, typename Caller::first_argument_type callee) +{ + return Callback3< + typename Caller::second_argument_type, + typename Caller::third_argument_type, + typename Caller::fourth_argument_type, + typename Caller::result_type + >(BindFirstOpaque3(callee)); +} +template +inline Callback3< + typename Caller::first_argument_type, + typename Caller::second_argument_type, + typename Caller::third_argument_type, + typename Caller::result_type +> makeStatelessCallback3(const Caller& caller) +{ + return makeCallback3(Caller3To4(), 0); +} /// \brief Forms a Callback from a non-const Environment reference and a non-const Environment member-function. @@ -170,24 +461,11 @@ typedef Callback1 SizeExportCallback; /// \skipline MemberCaller example /// \until end example template -class MemberCaller +class MemberCaller : public BindFirstOpaque< Member > { - Environment& m_environment; public: - MemberCaller(Environment& environment) : m_environment(environment) - { - } - void* getEnvironment() const + MemberCaller(Environment& environment) : BindFirstOpaque< Member >(environment) { - return &m_environment; - } - static void thunk(void* environment) - { - ((*reinterpret_cast(environment)).*member)(); - } - operator Callback() const - { - return Callback(getEnvironment(), thunk); } }; @@ -197,71 +475,32 @@ public: /// \skipline MemberCaller example /// \until end example template -class ConstMemberCaller +class ConstMemberCaller : public BindFirstOpaque< ConstMember > { - const Environment& m_environment; public: - ConstMemberCaller(const Environment& environment) : m_environment(environment) - { - } - void* getEnvironment() const + ConstMemberCaller(const Environment& environment) : BindFirstOpaque< ConstMember >(environment) { - return const_cast(&m_environment); - } - static void thunk(void* environment) - { - ((*reinterpret_cast(environment)).*member)(); - } - operator Callback() const - { - return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a non-const Environment reference and a const Environment member-function which takes one argument. template -class MemberCaller1 +class MemberCaller1 : public BindFirstOpaque1< Member1 > { - Environment& m_environment; public: - MemberCaller1(Environment& environment) : m_environment(environment) + MemberCaller1(Environment& environment) : BindFirstOpaque1< Member1 >(environment) { } - void* getEnvironment() const - { - return &m_environment; - } - static void thunk(void* environment, FirstArgument firstArgument) - { - ((*reinterpret_cast(environment)).*member)(firstArgument); - } - operator Callback1() const - { - return Callback1(getEnvironment(), thunk); - } }; /// \brief Forms a Callback from a const Environment reference and a const Environment member-function which takes one argument. template -class ConstMemberCaller1 +class ConstMemberCaller1 : public BindFirstOpaque1< ConstMember1 > { - const Environment& m_environment; public: - ConstMemberCaller1(const Environment& environment) : m_environment(environment) + ConstMemberCaller1(const Environment& environment) : BindFirstOpaque1< ConstMember1 >(environment) { } - void* getEnvironment() const - { - return const_cast(&m_environment); - } - static void thunk(void* environment, FirstArgument firstArgument) - { - ((*reinterpret_cast(environment)).*member)(firstArgument); - } - operator Callback1() const - { - return Callback1(getEnvironment(), thunk); - } }; /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference. @@ -270,24 +509,11 @@ public: /// \skipline ReferenceCaller example /// \until end example template -class ReferenceCaller +class ReferenceCaller : public BindFirstOpaque< Function1 > { - Environment& m_environment; public: - ReferenceCaller(Environment& environment) : m_environment(environment) - { - } - void* getEnvironment() const + ReferenceCaller(Environment& environment) : BindFirstOpaque< Function1 >(environment) { - return &m_environment; - } - static void thunk(void* environment) - { - (func)(*reinterpret_cast(environment)); - } - operator Callback() const - { - return Callback(getEnvironment(), thunk); } }; @@ -297,201 +523,91 @@ public: /// \skipline ReferenceCaller example /// \until end example template -class ConstReferenceCaller +class ConstReferenceCaller : public BindFirstOpaque< Function1 > { - const Environment& m_environment; public: - ConstReferenceCaller(const Environment& environment) : m_environment(environment) - { - } - void* getEnvironment() const - { - return const_cast(&m_environment); - } - static void thunk(void* environment) + ConstReferenceCaller(const Environment& environment) : BindFirstOpaque< Function1 >(environment) { - (func)(*reinterpret_cast(environment)); - } - operator Callback() const - { - return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a non-const Environment reference and a free function which operates on a non-const Environment reference and one other argument. template -class ReferenceCaller1 +class ReferenceCaller1 : public BindFirstOpaque1< Function2 > { - Environment& m_environment; public: - ReferenceCaller1(Environment& environment) : m_environment(environment) - { - } - void* getEnvironment() const + ReferenceCaller1(Environment& environment) : BindFirstOpaque1< Function2 >(environment) { - return &m_environment; - } - static void thunk(void* environment, FirstArgument firstArgument) - { - (func)(*reinterpret_cast(environment), firstArgument); - } - operator Callback1() const - { - return Callback1(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a const Environment reference and a free function which operates on a const Environment reference and one other argument. template -class ConstReferenceCaller1 +class ConstReferenceCaller1 : public BindFirstOpaque1< Function2 > { - const Environment& m_environment; public: - ConstReferenceCaller1(const Environment& environment) : m_environment(environment) + ConstReferenceCaller1(const Environment& environment) : BindFirstOpaque1< Function2 >(environment) { } - void* getEnvironment() const - { - return const_cast(&m_environment); - } - static void thunk(void* environment, FirstArgument firstArgument) - { - (func)(*reinterpret_cast(environment), firstArgument); - } - operator Callback1() const - { - return Callback1(getEnvironment(), thunk); - } }; /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer. template -class PointerCaller +class PointerCaller : public BindFirstOpaque< Function1 > { - Environment* m_environment; public: - PointerCaller(Environment* environment) : m_environment(environment) + PointerCaller(Environment* environment) : BindFirstOpaque< Function1 >(environment) { } - void* getEnvironment() const - { - return m_environment; - } - static void thunk(void* environment) - { - (func)(reinterpret_cast(environment)); - } - operator Callback() const - { - return Callback(getEnvironment(), thunk); - } }; /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer. template -class ConstPointerCaller +class ConstPointerCaller : public BindFirstOpaque< Function1 > { - const Environment* m_environment; public: - ConstPointerCaller(const Environment* environment) : m_environment(environment) - { - } - void* getEnvironment() const - { - return const_cast(m_environment); - } - static void thunk(void* environment) - { - (func)(reinterpret_cast(environment)); - } - operator Callback() const + ConstPointerCaller(const Environment* environment) : BindFirstOpaque< Function1 >(environment) { - return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a non-const Environment pointer and a free function which operates on a non-const Environment pointer and one other argument. template -class PointerCaller1 +class PointerCaller1 : public BindFirstOpaque1< Function2 > { - Environment* m_environment; public: - PointerCaller1(Environment* environment) : m_environment(environment) - { - } - void* getEnvironment() const - { - return m_environment; - } - static void thunk(void* environment, FirstArgument firstArgument) + PointerCaller1(Environment* environment) : BindFirstOpaque1< Function2 >(environment) { - (func)(reinterpret_cast(environment), firstArgument); - } - operator Callback1() const - { - return Callback1(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a const Environment pointer and a free function which operates on a const Environment pointer and one other argument. template -class ConstPointerCaller1 +class ConstPointerCaller1 : public BindFirstOpaque1< Function2 > { - const Environment* m_environment; public: - ConstPointerCaller1(const Environment* environment) : m_environment(environment) - { - } - void* getEnvironment() const + ConstPointerCaller1(const Environment* environment) : BindFirstOpaque1< Function2 >(environment) { - return const_cast(m_environment); - } - static void thunk(void* environment, FirstArgument firstArgument) - { - (func)(reinterpret_cast(environment), firstArgument); - } - operator Callback1() const - { - return Callback1(getEnvironment(), thunk); } }; - /// \brief Forms a Callback from a free function which takes no arguments. template -class FreeCaller +class FreeCaller : public BindFirstOpaque< Caller0To1< Function0 > > { public: - void* getEnvironment() const - { - return 0; - } - static void thunk(void*) - { - (func)(); - } - operator Callback() const + FreeCaller() : BindFirstOpaque< Caller0To1< Function0 > >(0) { - return Callback(getEnvironment(), thunk); } }; /// \brief Forms a Callback from a free function which takes a single argument. template -class FreeCaller1 +class FreeCaller1 : public BindFirstOpaque1< Caller1To2< Function1 > > { public: - void* getEnvironment() const - { - return 0; - } - static void thunk(void*, FirstArgument firstArgument) + FreeCaller1() : BindFirstOpaque1< Caller1To2< Function1 > >(0) { - (func)(firstArgument); - } - operator Callback1() const - { - return Callback1(getEnvironment(), thunk); } }; @@ -534,4 +650,21 @@ inline Callback1 makeCallback1(const Func return Callback1(ConstMemberCaller1(functor)); } + +typedef Callback1 BoolImportCallback; +typedef Callback1 BoolExportCallback; + +typedef Callback1 IntImportCallback; +typedef Callback1 IntExportCallback; + +typedef Callback1 FloatImportCallback; +typedef Callback1 FloatExportCallback; + +typedef Callback1 StringImportCallback; +typedef Callback1 StringExportCallback; + +typedef Callback1 SizeImportCallback; +typedef Callback1 SizeExportCallback; + + #endif