/************************************************************************************ Filename : OVR_Delegates.h Content : C++ Delegates Created : June 15, 2014 Authors : Chris Taylor Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); you may not use the Oculus VR Rift SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at http://www.oculusvr.com/licenses/LICENSE-3.2 Unless required by applicable law or agreed to in writing, the Oculus VR SDK distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ************************************************************************************/ /* Based on The Impossibly Fast C++ Delegates by Sergey Ryazanov from http://www.codeproject.com/KB/cpp/ImpossiblyFastCppDelegate.aspx (2005) */ /* Usage: Declare a delegate with a void (int) signature, also known as a function that returns void and has one parameter that is an int: typedef Delegate1 MyDelegate; MyDelegate d; Point the delegate to a member function: d.SetMember(&a); d = MyDelegate::FromMember(&a); Point the delegate to a const member function: d.SetConstMember(&c); d = MyDelegate::FromConstMember(&c); Point the delegate to a free function: d.SetFree<&FreeFunctionX>(); d = MyDelegate::FromFree<&FreeFunctionX>(); Invoke the function via the delegate (works for all 3 cases): d(1000); By default the delegates are uninitialized. To clear an array of delegates quickly just zero the memory. This implementation is nicer than FastDelegates in my opinion because it is simple and easy to read. It is a little slower for virtual functions, but the size of the delegate is small, and it will only get better as compilers improve. */ #ifndef OVR_Delegates_h #define OVR_Delegates_h #include "OVR_Types.h" namespace OVR { template class Delegate0 { typedef ret_type (*StubPointer)(void *); typedef Delegate0 this_type; void *_object; StubPointer _stub; OVR_FORCE_INLINE Delegate0(void *object, StubPointer stub) { _object = object; _stub = stub; } // Stubs template static OVR_FORCE_INLINE ret_type FreeStub(void *object) { return (F)(); } template static OVR_FORCE_INLINE ret_type MemberStub(void *object) { T *p = static_cast(object); return (p->*F)(); } template static OVR_FORCE_INLINE ret_type ConstMemberStub(void *object) { T *p = static_cast(object); return (p->*F)(); } public: OVR_FORCE_INLINE Delegate0() : _object(0), _stub(0){} // Function invocation OVR_FORCE_INLINE ret_type operator()() const { return (*_stub)(_object); } // Use stub pointer as a validity flag and equality checker OVR_FORCE_INLINE bool operator==(const this_type &rhs) const { return _object == rhs._object && _stub == rhs._stub; } OVR_FORCE_INLINE bool operator!=(const this_type &rhs) const { return _object != rhs._object || _stub != rhs._stub; } OVR_FORCE_INLINE bool IsValid() const { return _stub != 0; } OVR_FORCE_INLINE bool operator!() const { return _stub == 0; } OVR_FORCE_INLINE void Invalidate() { _stub = 0; } // Delegate creation from a function template static OVR_FORCE_INLINE this_type FromFree() { return this_type(0, &FreeStub); } template static OVR_FORCE_INLINE this_type FromMember(T *object) { return this_type(object, &MemberStub); } template static OVR_FORCE_INLINE this_type FromConstMember(T const *object) { return this_type(const_cast( object ), &ConstMemberStub); } // In-place assignment to a different function template OVR_FORCE_INLINE void SetFree() { *this = FromFree(); } template OVR_FORCE_INLINE void SetMember(T *object) { *this = FromMember(object); } template OVR_FORCE_INLINE void SetConstMember(T const *object) { *this = FromConstMember(object); } }; template class Delegate1 { typedef ret_type (*StubPointer)(void *, arg1_type); typedef Delegate1 this_type; void *_object; StubPointer _stub; OVR_FORCE_INLINE Delegate1(void *object, StubPointer stub) { _object = object; _stub = stub; } // Stubs template static OVR_FORCE_INLINE ret_type FreeStub(void *object, arg1_type a1) { return (F)(a1); } template static OVR_FORCE_INLINE ret_type MemberStub(void *object, arg1_type a1) { T *p = static_cast(object); return (p->*F)(a1); } template static OVR_FORCE_INLINE ret_type ConstMemberStub(void *object, arg1_type a1) { T *p = static_cast(object); return (p->*F)(a1); } public: OVR_FORCE_INLINE Delegate1() : _object(0), _stub(0){} // Function invocation OVR_FORCE_INLINE ret_type operator()(arg1_type a1) const { return (*_stub)(_object, a1); } // Use stub pointer as a validity flag and equality checker OVR_FORCE_INLINE bool operator==(const this_type &rhs) const { return _object == rhs._object && _stub == rhs._stub; } OVR_FORCE_INLINE bool operator!=(const this_type &rhs) const { return _object != rhs._object || _stub != rhs._stub; } OVR_FORCE_INLINE bool IsValid() const { return _stub != 0; } OVR_FORCE_INLINE bool operator!() const { return _stub == 0; } OVR_FORCE_INLINE void Invalidate() { _stub = 0; } // Delegate creation from a function template static OVR_FORCE_INLINE this_type FromFree() { return this_type(0, &FreeStub); } template static OVR_FORCE_INLINE this_type FromMember(T *object) { return this_type(object, &MemberStub); } template static OVR_FORCE_INLINE this_type FromConstMember(T const *object) { return this_type(const_cast( object ), &ConstMemberStub); } // In-place assignment to a different function template OVR_FORCE_INLINE void SetFree() { *this = FromFree(); } template OVR_FORCE_INLINE void SetMember(T *object) { *this = FromMember(object); } template OVR_FORCE_INLINE void SetConstMember(T const *object) { *this = FromConstMember(object); } }; template class Delegate2 { typedef ret_type (*StubPointer)(void *, arg1_type, arg2_type); typedef Delegate2 this_type; void *_object; StubPointer _stub; OVR_FORCE_INLINE Delegate2(void *object, StubPointer stub) { _object = object; _stub = stub; } // Stubs template static OVR_FORCE_INLINE ret_type FreeStub(void *object, arg1_type a1, arg2_type a2) { return (F)(a1, a2); } template static OVR_FORCE_INLINE ret_type MemberStub(void *object, arg1_type a1, arg2_type a2) { T *p = static_cast(object); return (p->*F)(a1, a2); } template static OVR_FORCE_INLINE ret_type ConstMemberStub(void *object, arg1_type a1, arg2_type a2) { T *p = static_cast(object); return (p->*F)(a1, a2); } public: OVR_FORCE_INLINE Delegate2() : _object(0), _stub(0){} // Function invocation OVR_FORCE_INLINE ret_type operator()(arg1_type a1, arg2_type a2) const { return (*_stub)(_object, a1, a2); } // Use stub pointer as a validity flag and equality checker OVR_FORCE_INLINE bool operator==(const this_type &rhs) const { return _object == rhs._object && _stub == rhs._stub; } OVR_FORCE_INLINE bool operator!=(const this_type &rhs) const { return _object != rhs._object || _stub != rhs._stub; } OVR_FORCE_INLINE bool IsValid() const { return _stub != 0; } OVR_FORCE_INLINE bool operator!() const { return _stub == 0; } OVR_FORCE_INLINE void Invalidate() { _stub = 0; } // Delegate creation from a function template static OVR_FORCE_INLINE this_type FromFree() { return this_type(0, &FreeStub); } template static OVR_FORCE_INLINE this_type FromMember(T *object) { return this_type(object, &MemberStub); } template static OVR_FORCE_INLINE this_type FromConstMember(T const *object) { return this_type(const_cast( object ), &ConstMemberStub); } // In-place assignment to a different function template OVR_FORCE_INLINE void SetFree() { *this = FromFree(); } template OVR_FORCE_INLINE void SetMember(T *object) { *this = FromMember(object); } template OVR_FORCE_INLINE void SetConstMember(T const *object) { *this = FromConstMember(object); } }; template class Delegate3 { typedef ret_type (*StubPointer)(void *, arg1_type, arg2_type, arg3_type); typedef Delegate3 this_type; void *_object; StubPointer _stub; OVR_FORCE_INLINE Delegate3(void *object, StubPointer stub) { _object = object; _stub = stub; } // Stubs template static OVR_FORCE_INLINE ret_type FreeStub(void *object, arg1_type a1, arg2_type a2, arg3_type a3) { return (F)(a1, a2, a3); } template static OVR_FORCE_INLINE ret_type MemberStub(void *object, arg1_type a1, arg2_type a2, arg3_type a3) { T *p = static_cast(object); return (p->*F)(a1, a2, a3); } template static OVR_FORCE_INLINE ret_type ConstMemberStub(void *object, arg1_type a1, arg2_type a2, arg3_type a3) { T *p = static_cast(object); return (p->*F)(a1, a2, a3); } public: OVR_FORCE_INLINE Delegate3() : _object(0), _stub(0){} // Function invocation OVR_FORCE_INLINE ret_type operator()(arg1_type a1, arg2_type a2, arg3_type a3) const { return (*_stub)(_object, a1, a2, a3); } // Use stub pointer as a validity flag and equality checker OVR_FORCE_INLINE bool operator==(const this_type &rhs) const { return _object == rhs._object && _stub == rhs._stub; } OVR_FORCE_INLINE bool operator!=(const this_type &rhs) const { return _object != rhs._object || _stub != rhs._stub; } OVR_FORCE_INLINE bool IsValid() const { return _stub != 0; } OVR_FORCE_INLINE bool operator!() const { return _stub == 0; } OVR_FORCE_INLINE void Invalidate() { _stub = 0; } // Delegate creation from a function template static OVR_FORCE_INLINE this_type FromFree() { return this_type(0, &FreeStub); } template static OVR_FORCE_INLINE this_type FromMember(T *object) { return this_type(object, &MemberStub); } template static OVR_FORCE_INLINE this_type FromConstMember(T const *object) { return this_type(const_cast( object ), &ConstMemberStub); } // In-place assignment to a different function template OVR_FORCE_INLINE void SetFree() { *this = FromFree(); } template OVR_FORCE_INLINE void SetMember(T *object) { *this = FromMember(object); } template OVR_FORCE_INLINE void SetConstMember(T const *object) { *this = FromConstMember(object); } }; // Add more here if needed, but keep in mind that a short, simple interface // is rewarded by making the delegates faster... } // namespace OVR #endif // OVR_Delegates_h