#ifndef BB_FUNCTION_H #define BB_FUNCTION_H #include "bbtypes.h" #include "bbdebug.h" namespace bbGC{ void *malloc( size_t size ); void free( void *p ); } template class bbFunction; template struct bbFunction{ typedef R(*F)(A...); struct FunctionRep; struct SequenceRep; template struct MethodRep; static R castErr( A... ){ puts( "Null Function Error" ); exit( -1 ); return R(); } struct Rep{ int refs=0; virtual ~Rep(){ } virtual R invoke( A... ){ return R(); } virtual bool equals( Rep *rep ){ return rep==this; } virtual int compare( Rep *rhs ){ if( thisrhs ) return 1; return 0; } virtual Rep *remove( Rep *rep ){ if( equals( rep ) ) return &_nullRep; return this; } virtual void gcMark(){ } void *operator new( size_t size ){ return bbGC::malloc( size ); } void operator delete( void *p ){ bbGC::free( p ); } }; struct FunctionRep : public Rep{ F p; FunctionRep( F p ):p( p ){ } virtual R invoke( A...a ){ return p( a... ); } virtual bool equals( Rep *rhs ){ FunctionRep *t=dynamic_cast( rhs ); return t && p==t->p; } virtual int compare( Rep *rhs ){ FunctionRep *t=dynamic_cast( rhs ); if( t && p==t->p ) return 0; return Rep::compare( rhs ); } virtual F Cast(){ return p; } }; template struct MethodRep : public Rep{ typedef R(C::*T)(A...); C *c; T p; MethodRep( C *c,T p ):c(c),p(p){ } virtual R invoke( A...a ){ return (c->*p)( a... ); } virtual bool equals( Rep *rhs ){ MethodRep *t=dynamic_cast( rhs ); return t && c==t->c && p==t->p; } virtual int compare( Rep *rhs ){ MethodRep *t=dynamic_cast( rhs ); if( t && c==t->c && p==t->p ) return 0; return Rep::compare( rhs ); } virtual void gcMark(){ bbGCMark( c ); } }; struct SequenceRep : public Rep{ bbFunction lhs,rhs; SequenceRep( const bbFunction &lhs,const bbFunction &rhs ):lhs( lhs ),rhs( rhs ){ } virtual R invoke( A...a ){ lhs( a... ); return rhs( a... ); } virtual Rep *remove( Rep *rep ){ if( rep==this ) return &_nullRep; Rep *lhs2=lhs._rep->remove( rep ); Rep *rhs2=rhs._rep->remove( rep ); if( lhs2==lhs._rep && rhs2==rhs._rep ) return this; if( lhs2!=&_nullRep && rhs2 !=&_nullRep ) return new SequenceRep( lhs2,rhs2 ); if( lhs2!=&_nullRep ) return lhs2; if( rhs2!=&_nullRep ) return rhs2; return &_nullRep; } virtual void gcMark(){ lhs._rep->gcMark(); rhs._rep->gcMark(); } }; Rep *_rep; static Rep _nullRep; void retain()const{ ++_rep->refs; } void release(){ if( !--_rep->refs && _rep!=&_nullRep ) delete _rep; } bbFunction( Rep *rep ):_rep( rep ){ retain(); } public: bbFunction():_rep( &_nullRep ){ } bbFunction( const bbFunction &p ):_rep( p._rep ){ retain(); } template bbFunction( C *c,typename MethodRep::T p ):_rep( new MethodRep(c,p) ){ retain(); } bbFunction( F p ):_rep( new FunctionRep( p ) ){ retain(); } ~bbFunction(){ release(); } void discard(){ if( _rep==&_nullRep ) return; delete _rep; _rep=&_nullRep; } bbFunction &operator=( const bbFunction &p ){ p.retain(); release(); _rep=p._rep; return *this; } bbFunction operator+( const bbFunction &rhs )const{ if( _rep==&_nullRep ) return rhs; if( rhs._rep==&_nullRep ) return *this; return new SequenceRep( *this,rhs ); } bbFunction operator-( const bbFunction &rhs )const{ return _rep->remove( rhs._rep ); } bbFunction &operator+=( const bbFunction &rhs ){ *this=*this+rhs; return *this; } bbFunction &operator-=( const bbFunction &rhs ){ *this=*this-rhs; return *this; } bbBool operator==( const bbFunction &rhs )const{ return _rep->equals( rhs._rep ); } bbBool operator!=( const bbFunction &rhs )const{ return !_rep->equals( rhs._rep ); } operator bbBool()const{ return _rep==&_nullRep; } R operator()( A...a )const{ return _rep->invoke( a... ); } //cast to simple static function ptr // operator F()const{ FunctionRep *t=dynamic_cast( _rep ); if( t ) return t->p; return castErr; } }; template typename bbFunction::Rep bbFunction::_nullRep; template bbFunction bbMethod( C *c,R(C::*p)(A...) ){ return bbFunction( c,p ); } template bbFunction bbMethod( const bbGCVar &c,R(C::*p)(A...) ){ return bbFunction( c.get(),p ); } template bbFunction bbMakefunc( R(*p)(A...) ){ return bbFunction( p ); } template void bbGCMark( const bbFunction &t ){ t._rep->gcMark(); } template int bbCompare( const bbFunction &x,const bbFunction &y ){ return x._rep->compare( y._rep ); } template bbString bbDBType( bbFunction *p ){ return bbDBType()+"()"; } template bbString bbDBValue( bbFunction *p ){ return "function?????"; } #endif