/* * Copyright (c) 2014, Siemens AG. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef EMBB_BASE_INTERNAL_FUNCTION2_H_ #define EMBB_BASE_INTERNAL_FUNCTION2_H_ #include #include #include #include #include #include #include #include namespace embb { namespace base { namespace internal { template class Function2 { public: virtual ~Function2() {} virtual R operator () (T1, T2) = 0; virtual void CopyTo(void* dst) = 0; }; template class FunctionPointer2 : public Function2 { public: typedef R(*FuncPtrType)(T1, T2); explicit FunctionPointer2(FuncPtrType func) : function_(func) {} virtual R operator () (T1 p1, T2 p2) { return function_(p1, p2); } virtual void CopyTo(void* dst) { new(dst)FunctionPointer2(function_); } private: FuncPtrType function_; }; template class FunctionPointer2 : public Function2 { public: typedef void(*FuncPtrType)(T1, T2); explicit FunctionPointer2(FuncPtrType func) : function_(func) {} virtual void operator () (T1 p1, T2 p2) { function_(p1, p2); } virtual void CopyTo(void* dst) { new(dst)FunctionPointer2(function_); } private: FuncPtrType function_; }; template class MemberFunctionPointer2 : public Function2 { public: typedef R(C::*MemFuncPtrType)(T1, T2); typedef C & ClassRefType; MemberFunctionPointer2(ClassRefType obj, MemFuncPtrType func) : object_(obj), function_(func) {} explicit MemberFunctionPointer2(ClassRefType obj) : object_(obj), function_(&C::operator()) {} void operator = (MemberFunctionPointer2 const & memfunc) { object_ = memfunc.object_; function_ = memfunc.function_; } virtual R operator () (T1 p1, T2 p2) { return (object_.*function_)(p1, p2); } virtual void CopyTo(void* dst) { new(dst)MemberFunctionPointer2(object_, function_); } private: ClassRefType object_; MemFuncPtrType function_; }; template class MemberFunctionPointer2 : public Function2 { public: typedef void(C::*MemFuncPtrType)(T1, T2); typedef C & ClassRefType; MemberFunctionPointer2(ClassRefType obj, MemFuncPtrType func) : object_(obj), function_(func) {} explicit MemberFunctionPointer2(ClassRefType obj) : object_(obj), function_(&C::operator()) {} void operator = (MemberFunctionPointer2 const & memfunc) { object_ = memfunc.object_; function_ = memfunc.function_; } virtual void operator () (T1 p1, T2 p2) { (object_.*function_)(p1, p2); } virtual void CopyTo(void* dst) { new(dst)MemberFunctionPointer2(object_, function_); } private: ClassRefType object_; MemFuncPtrType function_; }; template class FunctorWrapper2 : public Function2 { public: FunctorWrapper2() : object_(NULL), ref_count_(NULL) {} explicit FunctorWrapper2(C const & obj) { object_ = Allocation::New(obj); ref_count_ = Allocation::New >(1); } explicit FunctorWrapper2(FunctorWrapper2 const & other) { object_ = other.object_; ref_count_ = other.ref_count_; ++*ref_count_; } virtual ~FunctorWrapper2() { if (0 == --*ref_count_) { Allocation::Delete(ref_count_); Allocation::Delete(object_); } } virtual R operator () (T1 p1, T2 p2) { return (*object_)(p1, p2); } virtual void CopyTo(void* dst) { new(dst)FunctorWrapper2(*this); } private: C * object_; Atomic * ref_count_; }; template class FunctorWrapper2 : public Function2 { public: FunctorWrapper2() : object_(NULL), ref_count_(NULL) {} explicit FunctorWrapper2(C const & obj) { object_ = Allocation::New(obj); ref_count_ = Allocation::New >(1); } explicit FunctorWrapper2(FunctorWrapper2 const & other) { object_ = other.object_; ref_count_ = other.ref_count_; ++*ref_count_; } virtual ~FunctorWrapper2() { if (0 == --*ref_count_) { Allocation::Delete(ref_count_); Allocation::Delete(object_); } } virtual void operator () (T1 p1, T2 p2) { (*object_)(p1, p2); } virtual void CopyTo(void* dst) { new(dst)FunctorWrapper2(*this); } private: C * object_; Atomic * ref_count_; }; // bind to function0 template class Bound2Functor0 { public: Bound2Functor0(Function func, T1 p1, T2 p2) : function_(func) , p1_(p1), p2_(p2) {} Bound2Functor0(Bound2Functor0 const & func) : function_(func.function_) , p1_(func.p1_), p2_(func.p2_) {} R operator() () { return function_(p1_, p2_); } private: Function function_; T1 p1_; T2 p2_; }; // bind to function1 template class Bound2Functor1_Arg1 { public: Bound2Functor1_Arg1(Function func , T2 p2) : function_(func) , p2_(p2) {} Bound2Functor1_Arg1(Bound2Functor1_Arg1 const & func) : function_(func.function_) , p2_(func.p2_) {} R operator() (T1 p1) { return function_(p1, p2_); } private: Function function_; T2 p2_; }; template class Bound2Functor1_Arg2 { public: Bound2Functor1_Arg2(Function func , T1 p1) : function_(func) , p1_(p1) {} Bound2Functor1_Arg2(Bound2Functor1_Arg2 const & func) : function_(func.function_) , p1_(func.p1_) {} R operator() (T2 p2) { return function_(p1_, p2); } private: Function function_; T1 p1_; }; } // namespace internal using embb::base::internal::Nil; template class Function { public: typedef internal::Function2 * FuncPtrType; Function() : function_(NULL) {} template explicit Function(C const & obj) { function_ = new(storage_) internal::FunctorWrapper2(obj); } Function(Function const & func) { func.function_->CopyTo(&storage_[0]); function_ = reinterpret_cast(&storage_[0]); } ~Function() { Free(); } void operator = (R(*func)(T1, T2)) { Free(); function_ = new(storage_) internal::FunctionPointer2(func); } void operator = (Function & func) { Free(); func.function_->CopyTo(&storage_[0]); function_ = reinterpret_cast(&storage_[0]); } template void operator = (C const & obj) { Free(); function_ = new(storage_) internal::FunctorWrapper2(obj); } explicit Function(R(*func)(T1, T2)) { function_ = new(storage_) internal::FunctionPointer2(func); } template Function(C & obj, R(C::*func)(T1, T2)) { function_ = new(storage_) internal::MemberFunctionPointer2(obj, func); } R operator () (T1 p1, T2 p2) { return (*function_)(p1, p2); } private: char storage_[sizeof( internal::MemberFunctionPointer2)]; FuncPtrType function_; void Free() { if (NULL != function_) { function_->~Function2(); function_ = NULL; } } }; // wrap member function template Function MakeFunction(C & obj, R(C::*func)(T1, T2)) { return Function(obj, func); } // wrap function pointer template Function MakeFunction( R(*func)(T1, T2)) { return Function(func); } // bind to function0 template Function Bind(Function func, T1 p1, T2 p2) { return Function( internal::Bound2Functor0( func, p1, p2)); } template Function Bind(R(*func)(T1, T2), T1 p1, T2 p2) { return Bind(Function(func), p1, p2); } template Function Bind(C & obj, R(C::*func)(T1, T2), T1 p1, T2 p2) { return Bind(Function(obj, func), p1, p2); } // bind to function1 template Function Bind(Function func , Placeholder::Arg_1, T2 p2) { return Function( internal::Bound2Functor1_Arg1(func , p2)); } template Function Bind(R(*func)(T1, T2) , Placeholder::Arg_1 p1, T2 p2) { return Bind(Function(func), p1, p2); } template Function Bind(C & obj, R(C::*func)(T1, T2) , Placeholder::Arg_1 p1, T2 p2) { return Bind(Function(obj, func), p1, p2); } template Function Bind(Function func , T1 p1, Placeholder::Arg_1) { return Function( internal::Bound2Functor1_Arg2(func , p1)); } template Function Bind(R(*func)(T1, T2) , T1 p1, Placeholder::Arg_1 p2) { return Bind(Function(func), p1, p2); } template Function Bind(C & obj, R(C::*func)(T1, T2) , T1 p1, Placeholder::Arg_1 p2) { return Bind(Function(obj, func), p1, p2); } // bind to Function2 template Function Bind( C & obj, R(C::*func)(T1, T2), Placeholder::Arg_1 p1, Placeholder::Arg_2 p2) { return Function(obj, func); } template Function Bind( R(*func)(T1, T2), Placeholder::Arg_1 p1, Placeholder::Arg_2 p2) { return Function(func); } } // namespace base } // namespace embb #endif // EMBB_BASE_INTERNAL_FUNCTION2_H_