#define SOPHIA_TEMPLATE_PARAMS SOPHIA_MAKE_PARAMS1(SOPHIA_PARAM_COUNT,typename A)
// typename A0, class A1, class A2, ...
#define SOPHIA_TEMPLATE_ARGS SOPHIA_MAKE_PARAMS1(SOPHIA_PARAM_COUNT,A)
// A0, A1, A2, ...
#define SOPHIA_PARAMS SOPHIA_MAKE_PARAMS2(SOPHIA_PARAM_COUNT,A,a)
// A0 a0, A1 a1, A2 a2, ...
#define SOPHIA_ARGS SOPHIA_MAKE_PARAMS1(SOPHIA_PARAM_COUNT,a)
// a0, a1, a2, ...
#if SOPHIA_PARAM_COUNT > 0
#define SOPHIA_COMMA ,
#else
#define SOPHIA_COMMA
#endif // SOPHIA_PARAM_COUNT
template<typename R SOPHIA_COMMA SOPHIA_TEMPLATE_PARAMS>
class SOPHIA_DELEGATE_CLASSNAME : public delegate_root
{
template<typename _T>
struct thiscall_convention
{
typedef _T object_type;
typedef R (_T::*method)(SOPHIA_TEMPLATE_ARGS);
typedef R (_T::*const_method)(SOPHIA_TEMPLATE_ARGS) const;
typedef thiscall_convention<_never_exist_class_> rebind;
};
template<typename _T>
struct cdecl_convention
{
typedef _T object_type;
typedef R (__cdecl _T::*method)(SOPHIA_TEMPLATE_ARGS);
typedef R (__cdecl _T::*const_method)(SOPHIA_TEMPLATE_ARGS) const;
typedef cdecl_convention<_never_exist_class_> rebind;
};
template<typename _T>
struct stdcall_convention
{
typedef _T object_type;
typedef R (__stdcall _T::*method)(SOPHIA_TEMPLATE_ARGS);
typedef R (__stdcall _T::*const_method)(SOPHIA_TEMPLATE_ARGS) const;
typedef stdcall_convention<_never_exist_class_> rebind;
};
template<typename _T>
struct fastcall_convention
{
typedef _T object_type;
typedef R (__fastcall _T::*method)(SOPHIA_TEMPLATE_ARGS);
typedef R (__fastcall _T::*const_method)(SOPHIA_TEMPLATE_ARGS) const;
typedef fastcall_convention<_never_exist_class_> rebind;
};
template<class strategy_type>
struct strategy_t : public strategy_type
{
virtual R operator() (SOPHIA_PARAMS) const = 0;
};
typedef strategy_t<clone_option_never_clone::strategy> invokable_strategy;
struct null_strategy : public invokable_strategy
{
null_strategy()
{
this->init_null();
}
virtual R operator() (SOPHIA_PARAMS) const
{
throw bad_function_call();
}
virtual bool is_empty() const throw()
{
return true;
}
};
template<typename TFunction>
struct function_strategy : public invokable_strategy
{
function_strategy(TFunction fn)
{
this->init_function(fn);
}
virtual R operator() (SOPHIA_PARAMS) const
{
return (*(*(TFunction*)(&this->m_fn)))(SOPHIA_ARGS);
}
};
template<class calling_convention, class strategy_type>
struct method_strategy : public strategy_t<strategy_type>
{
using strategy_type::m_fn;
using strategy_type::m_object_ptr;
method_strategy(typename calling_convention::object_type* p,
typename calling_convention::method fn,
bool init_clone_object)
{
this->init_method(p, fn, init_clone_object);
}
method_strategy(typename calling_convention::object_type const* p,
typename calling_convention::const_method fn,
bool init_clone_object)
{
this->init_method(const_cast<typename calling_convention::object_type*>(p), fn, init_clone_object);
}
virtual R operator() (SOPHIA_PARAMS) const
{
typedef typename calling_convention::rebind rebind;
COMPILE_TIME_ASSERT(sizeof(typename rebind::method)==sizeof(m_fn));
return (this->m_object_ptr->*(*(typename rebind::method*)(&this->m_fn)))(SOPHIA_ARGS);
}
};
// construct delegate from 'thiscall' method
template<typename _T, typename clone_info>
void construct_method(_T* p, typename thiscall_convention<_T>::method fn, clone_info info) throw()
{
new (&this->m_strategy) method_strategy<thiscall_convention<_T>, typename clone_info::strategy>(p, fn, info);
}
// construct delegate from 'thiscall' const method
template<typename _T, typename clone_info>
void construct_method(_T const* p, typename thiscall_convention<_T>::const_method fn, clone_info info) throw()
{
new (&this->m_strategy) method_strategy<thiscall_convention<_T>, typename clone_info::strategy>(p, fn, info);
}
#if defined(SOPHIA_SUPPORT_CALLING_CONVENTION_FOR_METHOD)
// construct delegate from 'cdecl' method
template<typename _T, typename clone_info>
void construct_method(_T* p, typename cdecl_convention<_T>::method fn, clone_info info) throw()
{
new (&this->m_strategy) method_strategy<cdecl_convention<_T>, typename clone_info::strategy>(p, fn, info);
}
// construct delegate from 'cdecl' const method
template<typename _T, typename clone_info>
void construct_method(_T const* p, typename cdecl_convention<_T>::const_method fn, clone_info info) throw()
{
new (&this->m_strategy) method_strategy<cdecl_convention<_T>, typename clone_info::strategy>(p, fn, info);
}
// construct delegate from 'stdcall' method
template<typename _T, typename clone_info>
void construct_method(_T* p, typename stdcall_convention<_T>::method fn, clone_info info) throw()
{
new (&this->m_strategy) method_strategy<stdcall_convention<_T>, typename clone_info::strategy>(p, fn, info);
}
// construct delegate from 'stdcall' const method
template<typename _T, typename clone_info>
void construct_method(_T const* p, typename stdcall_convention<_T>::const_method fn, clone_info info) throw()
{
new (&this->m_strategy) method_strategy<stdcall_convention<_T>, typename clone_info::strategy>(p, fn, info);
}
// construct delegate from 'fastcall' method
template<typename _T, typename clone_info>
void construct_method(_T* p, typename fastcall_convention<_T>::method fn, clone_info info) throw()
{
new (&this->m_strategy) method_strategy<fastcall_convention<_T>, typename clone_info::strategy>(p, fn, info);
}
// construct delegate from 'fastcall' const method
template<typename _T, typename clone_info>
void construct_method(_T const* p, typename fastcall_convention<_T>::const_method fn, clone_info info) throw()
{
new (&this->m_strategy) method_strategy<fastcall_convention<_T>, typename clone_info::strategy>(p, fn, info);
}
#endif //defined(SOPHIA_SUPPORT_CALLING_CONVENTION_FOR_METHOD)
public:
// default constructor
SOPHIA_DELEGATE_CLASSNAME() throw()
{
new (&this->m_strategy) null_strategy();
}
// copy constructor
SOPHIA_DELEGATE_CLASSNAME(SOPHIA_DELEGATE_CLASSNAME const & _other) throw()
{
this->m_strategy = _other.m_strategy; // do bit-wise copy
this->strategy().object_clone(); // then clone object
}
// operator =
SOPHIA_DELEGATE_CLASSNAME& operator=(SOPHIA_DELEGATE_CLASSNAME const & _other) throw()
{
delegate_root old(*this); // cleaning up automatically on return
new (this) SOPHIA_DELEGATE_CLASSNAME(_other);
return *this;
}
// swap between 2 delegates
void swap(SOPHIA_DELEGATE_CLASSNAME& _other) throw()
{
// all operations are just bit-wise copy
strategy_place_holder temp(this->m_strategy);
this->m_strategy = _other.m_strategy;
_other.m_strategy = temp;
}
// reset to null
void clear() throw()
{
this->strategy().object_free();
new (&this->m_strategy) null_strategy();
}
// operator = NULL
const SOPHIA_DELEGATE_CLASSNAME& operator=(clear_type*)
{
this->clear();
return *this;
}
// Syntax 01: (*delegate)(param...)
invokable_strategy const& operator*() const throw()
{
return static_cast<invokable_strategy const&>(this->strategy());
}
// Syntax 02: delegate(param...)
// Note: syntax 02 might be slower than syntax 01 in some cases
R operator()(SOPHIA_PARAMS) const
{
return static_cast<invokable_strategy const&>(this->strategy())(SOPHIA_ARGS);
}
// constructor for function
template<typename TFunction>
SOPHIA_DELEGATE_CLASSNAME(TFunction fn)
{
new (&this->m_strategy) function_strategy<TFunction>(fn);
}
// constructor for method
template<typename _T, typename TMethod>
SOPHIA_DELEGATE_CLASSNAME(_T* p, TMethod fn)
{
this->construct_method(p, fn, clone_option_never_clone());
}
// constructor for const method
template<typename _T, typename TMethod>
SOPHIA_DELEGATE_CLASSNAME(_T const* p, TMethod fn)
{
this->construct_method(p, fn, clone_option_never_clone());
}
// constructor for method using clone-allocator
template<typename _T, typename TMethod, typename clone_info>
SOPHIA_DELEGATE_CLASSNAME(_T* p, TMethod fn, clone_info info)
{
this->construct_method(p, fn, clone_option_rebind<_T, typename clone_info::clone_allocator>(info));
}
// constructor for const method using clone-allocator
template<typename _T, typename TMethod, typename clone_info>
SOPHIA_DELEGATE_CLASSNAME(_T const* p, TMethod fn, clone_info info)
{
this->construct_method(p, fn, clone_option_rebind<_T, typename clone_info::clone_allocator>(info));
}
// bind to function
template<typename TFunction>
void bind(TFunction fn)
{
this->strategy().object_free();
new (&this->m_strategy) function_strategy<TFunction>(fn);
}
// bind to method
template<typename _T, typename TMethod>
void bind(_T* p, TMethod fn)
{
this->strategy().object_free();
this->construct_method(p, fn, clone_option_never_clone());
}
// bind to const method
template<typename _T, typename TMethod>
void bind(_T const* p, TMethod fn)
{
this->strategy().object_free();
this->construct_method(p, fn, clone_option_never_clone());
}
// bind to method using clone-allocator
template<typename _T, typename TMethod, typename clone_info>
void bind(_T* p, TMethod fn, clone_info info)
{
this->strategy().object_free();
this->construct_method(p, fn, clone_option_rebind<_T, typename clone_info::clone_allocator>(info));
}
// constructor for const method using clone-allocator
template<typename _T, typename TMethod, typename clone_info>
void bind(_T const* p, TMethod fn, clone_info info)
{
this->strategy().object_free();
this->construct_method(p, fn, clone_option_rebind<_T, typename clone_info::clone_allocator>(info));
}
};
#undef SOPHIA_TEMPLATE_PARAMS
#undef SOPHIA_TEMPLATE_ARGS
#undef SOPHIA_PARAMS
#undef SOPHIA_ARGS
#undef SOPHIA_COMMA