111 lines
3.1 KiB
C++
111 lines
3.1 KiB
C++
#pragma once
|
|
#include <fc/utility.hpp>
|
|
#include <fc/shared_ptr.hpp>
|
|
|
|
namespace fc {
|
|
template<typename R,typename ... Args>
|
|
class function {
|
|
public:
|
|
function(){}
|
|
|
|
template<typename Functor>
|
|
function( Functor&& f )
|
|
:func( new impl<Functor>( fc::forward<Functor>(f) ) ){};
|
|
|
|
function( const function& c ):func(c.func){}
|
|
function( function&& c ) { fc::swap( func, c.func); }
|
|
~function(){}
|
|
|
|
template<typename Functor>
|
|
function& operator=( Functor&& f ) {
|
|
func.reset( new impl<Functor>( fc::forward<Functor>(f) ) );
|
|
return *this;
|
|
}
|
|
|
|
function& operator=( const function& c ) { func = c.func; return *this; }
|
|
function& operator=( function&& c ) { fc::swap(func,c.func); return *this; }
|
|
|
|
R operator()( Args... args)const { return func->call(args...); }
|
|
|
|
bool operator!()const { return !func; }
|
|
|
|
protected:
|
|
|
|
struct impl_base : public fc::retainable {
|
|
virtual ~impl_base(){}
|
|
virtual R call(Args...)const = 0;
|
|
};
|
|
|
|
template<typename Functor>
|
|
struct impl : impl_base {
|
|
template<typename U>
|
|
impl( U&& u ):func( fc::forward<U>(u) ){}
|
|
|
|
virtual R call(Args... args)const { return func(args...); }
|
|
|
|
Functor func;
|
|
};
|
|
function( const fc::shared_ptr<impl_base>& f ):func(f){}
|
|
function( fc::shared_ptr<impl_base>&& f ):func(fc::move(f)){}
|
|
|
|
fc::shared_ptr<impl_base> func;
|
|
};
|
|
|
|
/**
|
|
* Provides functionality similar to boost::function.
|
|
*
|
|
* Functions have 'reference semantics', meaning that copies will all
|
|
* refer to the same underlying function.
|
|
*
|
|
* TODO: Small functions are allocated on the stack, large functors are
|
|
* allocated on the heap.
|
|
*
|
|
* Simply including boost/function adds an additional 0.6 seconds to every
|
|
* object file compared to using fc/function.
|
|
*
|
|
* Including <functional> on the other hand adds a mere 0.05
|
|
* seconds to every object file compared to fc/function.
|
|
*/
|
|
template<typename R>
|
|
class function<R()> : public function<R> {
|
|
public:
|
|
function(){}
|
|
template<typename U>
|
|
function( U&& u ) { *this = fc::forward<U>(u); }
|
|
using function<R>::operator=;
|
|
};
|
|
|
|
template<typename R,typename A1>
|
|
class function<R(A1)> : public function<R,A1> {
|
|
public:
|
|
function(){}
|
|
function( const function<R,A1>& u ):function<R,A1>(u){}
|
|
function( function<R,A1>&& u ):function<R,A1>(u){}
|
|
function( const function& u ):function<R,A1>(u.func){}
|
|
function( function&& u ):function<R,A1>(fc::move(u.func)){}
|
|
|
|
using function<R,A1>::operator=;
|
|
};
|
|
|
|
template<typename R,typename A1,typename A2>
|
|
class function<R(A1,A2)> : public function<R,A1,A2> {
|
|
public:
|
|
function(){}
|
|
template<typename U>
|
|
function( U&& u ):function<R,A1,A2>( fc::forward<U>(u) ){}
|
|
function( const function& c ):function<R,A1,A2>(c.func){}
|
|
using function<R,A1,A2>::operator=;
|
|
};
|
|
|
|
template<typename R,typename A1,typename A2, typename A3>
|
|
class function<R(A1,A2,A3)> : public function<R,A1,A2,A3> {
|
|
public:
|
|
function(){}
|
|
template<typename U>
|
|
function( U&& u ):function<R,A1,A2,A3>( fc::forward<U>(u) ){}
|
|
function( const function& c ):function<R,A1,A2,A3>(c.func){}
|
|
using function<R,A1,A2,A3>::operator=;
|
|
};
|
|
|
|
}
|
|
|