commit b849d8c7ce2ef213259d41ed814a99bc0e6fb9c2 Author: Stephen Waits Date: Thu Sep 30 15:28:07 2010 -0700 create signal repo diff --git a/callbacktest.sln b/callbacktest.sln new file mode 100644 index 0000000..5575fff --- /dev/null +++ b/callbacktest.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "callbacktest", "callbacktest.vcproj", "{43D38036-45DA-4DD1-950C-AE8AE57F819D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {43D38036-45DA-4DD1-950C-AE8AE57F819D}.Debug.ActiveCfg = Debug|Win32 + {43D38036-45DA-4DD1-950C-AE8AE57F819D}.Debug.Build.0 = Debug|Win32 + {43D38036-45DA-4DD1-950C-AE8AE57F819D}.Release.ActiveCfg = Release|Win32 + {43D38036-45DA-4DD1-950C-AE8AE57F819D}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/callbacktest.vcproj b/callbacktest.vcproj new file mode 100644 index 0000000..9c34297 --- /dev/null +++ b/callbacktest.vcproj @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/Signal.h b/source/Signal.h new file mode 100644 index 0000000..6c15061 --- /dev/null +++ b/source/Signal.h @@ -0,0 +1,131 @@ +#ifndef __Signal_h__ +#define __Signal_h__ + + + +#include "signal/signal0.h" +#include "signal/signal1.h" +#include "signal/signal2.h" +#include "signal/signal3.h" +#include "signal/signal4.h" +#include "signal/signal5.h" +#include "signal/signal6.h" +#include "signal/signal7.h" +#include "signal/signal8.h" +#include "signal/signal9.h" +#include "signal/signal10.h" +#include "signal/signal11.h" +#include "signal/signal12.h" +#include "signal/signal13.h" +#include "signal/signal14.h" +#include "signal/signal15.h" +#include "signal/signal16.h" + + + +struct nilarg; + +template +class Signal : + public Signal16 +{ +}; + +template +class Signal : + public Signal15 +{ +}; + +template +class Signal : + public Signal14 +{ +}; + +template +class Signal : + public Signal13 +{ +}; + +template +class Signal : + public Signal12 +{ +}; + +template +class Signal : + public Signal11 +{ +}; + +template +class Signal : + public Signal10 +{ +}; + +template +class Signal : + public Signal9 +{ +}; + +template +class Signal : + public Signal8 +{ +}; + +template +class Signal : + public Signal7 +{ +}; + +template +class Signal : + public Signal6 +{ +}; + +template +class Signal : + public Signal5 +{ +}; + +template +class Signal : + public Signal4 +{ +}; + +template +class Signal : + public Signal3 +{ +}; + +template +class Signal : + public Signal2 +{ +}; + +template +class Signal : + public Signal1 +{ +}; + +template +class Signal : + public Signal0 +{ +}; + + +#endif // __Signal_h__ diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..4cd0e7a --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,199 @@ +#include +#include +#include +#include + + + +#include "Signal.h" + + + +void Function() +{ + printf("Function()\n"); +} + +void Function1(int x) +{ + printf("Function1(%d)\n",x); +} + +void Function5(int a,int b, int c, int d, int e) +{ + printf("Function5(%d,%d,%d,%d,%d)\n",a,b,c,d,e); +} + + + +class Dummy +{ +public: + + virtual void member() + { + printf("Dummy::member()\n"); + } + + void operator() () + { + printf("Dummy::operator()()\n"); + } + + void member5(int a,int b, int c, int d, int e) const + { + printf("Dummy::member5(%d,%d,%d,%d,%d)\n",a,b,c,d,e); + } + +}; + + + +class DummyChild: public Dummy +{ +public: + + virtual void member() + { + printf("DummyChild::member()\n"); + } +}; + + + +class OverloadedMembers +{ +public: + + void member(int x) + { + printf("OverloadedMembers::member(%d)\n",x); + } + + void member(int x, int y) + { + printf("OverloadedMembers::member(%d,%d)\n",x,y); + } +}; + + + +class MySlot: public Signal::SlotBase +{ +public: + + MySlot(int id) + { + this->some_id = id; + } + + virtual void operator() () const + { + printf("MySlot::operator() [some_id = %d]\n",some_id); + } + + virtual bool operator== (const Slot0* other) const + { + const MySlot* pother = dynamic_cast(other); + if ( pother ) + { + return this->some_id == pother->some_id; + } + else + { + return false; + } + } + + virtual Slot0* clone() const + { + return new MySlot(some_id); + } + +private: + + int some_id; +}; + + + +MySlot Create_MySlot(int x) +{ + return MySlot(x); +} + + + +int main() +{ + Signal sig; + Signal sig_copy; + Signal sig1; + Signal sig2; + Signal sig5; + Signal count_test; + + assert( !count_test.IsConnected(Function) ); + count_test.Connect(Function,2); + assert( count_test.IsConnected(Function) ); + count_test(); + count_test(); + count_test(); + + OverloadedMembers bf; + + assert( !sig1.IsConnected(&bf,&OverloadedMembers::member) ); + assert( !sig2.IsConnected(&bf,&OverloadedMembers::member) ); + sig1.Connect(&bf,&OverloadedMembers::member); + sig2.Connect(&bf,&OverloadedMembers::member); + assert( sig1.IsConnected(&bf,&OverloadedMembers::member) ); + assert( sig2.IsConnected(&bf,&OverloadedMembers::member) ); + sig1(10); + sig2(1,2); + + assert( !sig.IsConnected(Create_MySlot(1)) ); + sig.Connect(Create_MySlot(1)); + assert( sig.IsConnected(Create_MySlot(1)) ); + sig.Disconnect(Create_MySlot(1)); + assert( !sig.IsConnected(Create_MySlot(1)) ); + + sig1.Connect(Function1); + sig1(0); + sig1(1); + sig1(2); + sig1(3); + + Dummy d; + Dummy d2; + DummyChild dc; + + sig5.Connect(Function5); + sig5.Connect(&d,&Dummy::member5); + sig5.Connect(&dc,&Dummy::member5); + sig5(0,1,2,3,4); + + printf("\n---\n\n"); + sig.Connect(Function); + + sig.Connect(&d); + sig.Connect(&d2); + sig.Connect(&d,&Dummy::member); + sig.Connect(&dc,&DummyChild::member); + sig.Connect(&dc,&Dummy::member); + sig.Connect(&dc); + + sig.Emit(); + + printf("\n---\n\n"); + sig.Disconnect(Function); + sig.Emit(); + + printf("\n---\n\n"); + + sig_copy = sig; + sig_copy.Emit(); + + return 0; +} + + diff --git a/source/signal/signal.pl b/source/signal/signal.pl new file mode 100644 index 0000000..237bcb3 --- /dev/null +++ b/source/signal/signal.pl @@ -0,0 +1,1178 @@ +#!/usr/bin/perl + + +############################################## +# +# globals +# +############################################## + +# a variable to store our template text in +my $template = ""; + + +############################################## +# +# main() +# +############################################## + +# load template text (see bottom of script) +while() +{ + $template .= $_; +} + +# generate [signal0.h,signal16.h] +for (my $i=0;$i<=16;$i++) +{ + GenerateSignalXHeader($i); +} + + +############################################## +# +# Subroutines +# +############################################## + +# subroutine to generate one signal header file +sub GenerateSignalXHeader +{ + # only argument is number of template arguments to allow for this signal + my($nargs) = @_; + + # create a local copy of template text + my $file = $template; + + # create other substitution strings + my $narg_str = ""; + my $template_arg_decl_str = ""; + my $template_arg_str = ""; + my $formal_arg_decl_str = ""; + my $formal_arg_str = ""; + + # create subst string for # of args + $narg_str = sprintf("%d",$nargs); + + # create subst strings for template and function arguments + if ( $nargs > 0 ) + { + # template args follow T_return, so start with a comma + $template_arg_decl_str = ", "; + $template_arg_str = ", "; + + for (my $i=0;$i<($nargs-1);$i++) + { + # args with trailing comma + $template_arg_decl_str .= sprintf("typename T_arg%d, ",$i); + $template_arg_str .= sprintf("T_arg%d, ",$i); + $formal_arg_decl_str .= sprintf("T_arg%d a%d, ",$i,$i); + $formal_arg_str .= sprintf("a%d, ",$i); + } + + # args without trailing comma + $template_arg_decl_str .= sprintf("typename T_arg%d",$nargs-1); + $template_arg_str .= sprintf("T_arg%d",$nargs-1); + $formal_arg_decl_str .= sprintf("T_arg%d a%d",$nargs-1,$nargs-1); + $formal_arg_str .= sprintf("a%d",$nargs-1); + } + + # do substitution + $file =~ s/=NARG=/$narg_str/g; + $file =~ s/=TEMPLATE_ARG_DECL=/$template_arg_decl_str/g; + $file =~ s/=TEMPLATE_ARG=/$template_arg_str/g; + $file =~ s/=FORMAL_ARG_DECL=/$formal_arg_decl_str/g; + $file =~ s/=FORMAL_ARG=/$formal_arg_str/g; + + # create filename + my $filename = sprintf("signal%d.h",$nargs); + + # write file + open(OUTFILE,">$filename") || die; + print OUTFILE $file; + close(OUTFILE); +} + + +############################################## +# +# Data +# +############################################## + +__DATA__ +#ifndef __signal=NARG=_h__ +#define __signal=NARG=_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with =NARG= parameter(s). + */ +template +class Slot=NARG= +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (=FORMAL_ARG_DECL=) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot=NARG=* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot=NARG=* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with =NARG= parameter(s). + */ +template +class SlotFunction=NARG= : public Slot=NARG= +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(=FORMAL_ARG_DECL=); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot=NARG= SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction=NARG= (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (=FORMAL_ARG_DECL=) const + { + return pFunction(=FORMAL_ARG=); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction=NARG=* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction=NARG=* copy = new SlotFunction=NARG=(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with =NARG= parameter(s). + */ +template +class SlotMember=NARG= : public Slot=NARG= +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot=NARG= SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember=NARG= (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (=FORMAL_ARG_DECL=) const + { + return (pObject->*pMember)(=FORMAL_ARG=); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember=NARG=* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember=NARG=* copy = new SlotMember=NARG=(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with =NARG= parameter(s). + */ +template +class Signal=NARG= +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(=FORMAL_ARG_DECL=); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot=NARG= SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal=NARG=(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal=NARG=(const Signal=NARG=& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal=NARG=<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal=NARG=& operator= (const Signal=NARG=& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal=NARG=<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal=NARG=() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal=NARG=<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(=FORMAL_ARG_DECL=), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(=FORMAL_ARG_DECL=) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(=FORMAL_ARG_DECL=), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(=FORMAL_ARG_DECL=) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(=FORMAL_ARG_DECL=)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(=FORMAL_ARG_DECL=) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(=FORMAL_ARG_DECL=)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(=FORMAL_ARG_DECL=) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(=FORMAL_ARG_DECL=)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(=FORMAL_ARG_DECL=) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(=FORMAL_ARG_DECL=)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(=FORMAL_ARG_DECL=) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (=FORMAL_ARG_DECL=) + { + Emit(=FORMAL_ARG=); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(=FORMAL_ARG_DECL=) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal=NARG=<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(=FORMAL_ARG=); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction=NARG=(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction=NARG=(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction=NARG=(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember=NARG=(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember=NARG=(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember=NARG=(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal=NARG=_h__ + diff --git a/source/signal/signal0.h b/source/signal/signal0.h new file mode 100644 index 0000000..3229913 --- /dev/null +++ b/source/signal/signal0.h @@ -0,0 +1,1074 @@ +#ifndef __signal0_h__ +#define __signal0_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 0 parameter(s). + */ +template +class Slot0 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() () const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot0* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot0* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 0 parameter(s). + */ +template +class SlotFunction0 : public Slot0 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot0 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction0 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() () const + { + return pFunction(); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction0* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction0* copy = new SlotFunction0(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 0 parameter(s). + */ +template +class SlotMember0 : public Slot0 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot0 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember0 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() () const + { + return (pObject->*pMember)(); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember0* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember0* copy = new SlotMember0(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 0 parameter(s). + */ +template +class Signal0 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot0 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal0(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal0(const Signal0& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal0<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal0& operator= (const Signal0& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal0<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal0() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal0<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)() const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)() const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)()) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)() const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)()) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)() const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)()) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)() const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)()) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)() const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() () + { + Emit(); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit() + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal0<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction0(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction0(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction0(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember0(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember0(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember0(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal0_h__ + diff --git a/source/signal/signal1.h b/source/signal/signal1.h new file mode 100644 index 0000000..ad6aaef --- /dev/null +++ b/source/signal/signal1.h @@ -0,0 +1,1074 @@ +#ifndef __signal1_h__ +#define __signal1_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 1 parameter(s). + */ +template +class Slot1 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot1* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot1* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 1 parameter(s). + */ +template +class SlotFunction1 : public Slot1 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot1 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction1 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0) const + { + return pFunction(a0); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction1* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction1* copy = new SlotFunction1(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 1 parameter(s). + */ +template +class SlotMember1 : public Slot1 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot1 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember1 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0) const + { + return (pObject->*pMember)(a0); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember1* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember1* copy = new SlotMember1(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 1 parameter(s). + */ +template +class Signal1 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot1 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal1(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal1(const Signal1& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal1<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal1& operator= (const Signal1& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal1<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal1() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal1<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0) + { + Emit(a0); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal1<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction1(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction1(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction1(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember1(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember1(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember1(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal1_h__ + diff --git a/source/signal/signal10.h b/source/signal/signal10.h new file mode 100644 index 0000000..2e63bba --- /dev/null +++ b/source/signal/signal10.h @@ -0,0 +1,1074 @@ +#ifndef __signal10_h__ +#define __signal10_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 10 parameter(s). + */ +template +class Slot10 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot10* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot10* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 10 parameter(s). + */ +template +class SlotFunction10 : public Slot10 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot10 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction10 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction10* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction10* copy = new SlotFunction10(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 10 parameter(s). + */ +template +class SlotMember10 : public Slot10 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot10 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember10 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember10* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember10* copy = new SlotMember10(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 10 parameter(s). + */ +template +class Signal10 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot10 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal10(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal10(const Signal10& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal10<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal10& operator= (const Signal10& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal10<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal10() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal10<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal10<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction10(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction10(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction10(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember10(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember10(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember10(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal10_h__ + diff --git a/source/signal/signal11.h b/source/signal/signal11.h new file mode 100644 index 0000000..c2e1a56 --- /dev/null +++ b/source/signal/signal11.h @@ -0,0 +1,1074 @@ +#ifndef __signal11_h__ +#define __signal11_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 11 parameter(s). + */ +template +class Slot11 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot11* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot11* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 11 parameter(s). + */ +template +class SlotFunction11 : public Slot11 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot11 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction11 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction11* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction11* copy = new SlotFunction11(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 11 parameter(s). + */ +template +class SlotMember11 : public Slot11 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot11 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember11 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember11* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember11* copy = new SlotMember11(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 11 parameter(s). + */ +template +class Signal11 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot11 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal11(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal11(const Signal11& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal11<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal11& operator= (const Signal11& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal11<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal11() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal11<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal11<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction11(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction11(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction11(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember11(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember11(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember11(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal11_h__ + diff --git a/source/signal/signal12.h b/source/signal/signal12.h new file mode 100644 index 0000000..37fd810 --- /dev/null +++ b/source/signal/signal12.h @@ -0,0 +1,1074 @@ +#ifndef __signal12_h__ +#define __signal12_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 12 parameter(s). + */ +template +class Slot12 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot12* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot12* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 12 parameter(s). + */ +template +class SlotFunction12 : public Slot12 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot12 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction12 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction12* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction12* copy = new SlotFunction12(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 12 parameter(s). + */ +template +class SlotMember12 : public Slot12 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot12 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember12 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember12* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember12* copy = new SlotMember12(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 12 parameter(s). + */ +template +class Signal12 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot12 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal12(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal12(const Signal12& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal12<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal12& operator= (const Signal12& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal12<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal12() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal12<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal12<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction12(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction12(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction12(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember12(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember12(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember12(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal12_h__ + diff --git a/source/signal/signal13.h b/source/signal/signal13.h new file mode 100644 index 0000000..bbaea16 --- /dev/null +++ b/source/signal/signal13.h @@ -0,0 +1,1074 @@ +#ifndef __signal13_h__ +#define __signal13_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 13 parameter(s). + */ +template +class Slot13 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot13* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot13* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 13 parameter(s). + */ +template +class SlotFunction13 : public Slot13 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot13 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction13 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction13* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction13* copy = new SlotFunction13(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 13 parameter(s). + */ +template +class SlotMember13 : public Slot13 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot13 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember13 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember13* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember13* copy = new SlotMember13(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 13 parameter(s). + */ +template +class Signal13 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot13 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal13(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal13(const Signal13& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal13<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal13& operator= (const Signal13& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal13<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal13() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal13<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal13<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction13(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction13(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction13(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember13(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember13(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember13(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal13_h__ + diff --git a/source/signal/signal14.h b/source/signal/signal14.h new file mode 100644 index 0000000..f25cc34 --- /dev/null +++ b/source/signal/signal14.h @@ -0,0 +1,1074 @@ +#ifndef __signal14_h__ +#define __signal14_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 14 parameter(s). + */ +template +class Slot14 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot14* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot14* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 14 parameter(s). + */ +template +class SlotFunction14 : public Slot14 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot14 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction14 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction14* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction14* copy = new SlotFunction14(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 14 parameter(s). + */ +template +class SlotMember14 : public Slot14 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot14 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember14 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember14* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember14* copy = new SlotMember14(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 14 parameter(s). + */ +template +class Signal14 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot14 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal14(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal14(const Signal14& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal14<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal14& operator= (const Signal14& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal14<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal14() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal14<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal14<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction14(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction14(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction14(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember14(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember14(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember14(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal14_h__ + diff --git a/source/signal/signal15.h b/source/signal/signal15.h new file mode 100644 index 0000000..0c3bfc3 --- /dev/null +++ b/source/signal/signal15.h @@ -0,0 +1,1074 @@ +#ifndef __signal15_h__ +#define __signal15_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 15 parameter(s). + */ +template +class Slot15 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot15* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot15* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 15 parameter(s). + */ +template +class SlotFunction15 : public Slot15 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot15 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction15 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction15* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction15* copy = new SlotFunction15(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 15 parameter(s). + */ +template +class SlotMember15 : public Slot15 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot15 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember15 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember15* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember15* copy = new SlotMember15(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 15 parameter(s). + */ +template +class Signal15 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot15 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal15(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal15(const Signal15& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal15<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal15& operator= (const Signal15& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal15<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal15() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal15<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal15<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction15(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction15(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction15(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember15(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember15(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember15(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal15_h__ + diff --git a/source/signal/signal16.h b/source/signal/signal16.h new file mode 100644 index 0000000..5ffec13 --- /dev/null +++ b/source/signal/signal16.h @@ -0,0 +1,1074 @@ +#ifndef __signal16_h__ +#define __signal16_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 16 parameter(s). + */ +template +class Slot16 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot16* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot16* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 16 parameter(s). + */ +template +class SlotFunction16 : public Slot16 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot16 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction16 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction16* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction16* copy = new SlotFunction16(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 16 parameter(s). + */ +template +class SlotMember16 : public Slot16 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot16 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember16 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember16* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember16* copy = new SlotMember16(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 16 parameter(s). + */ +template +class Signal16 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot16 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal16(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal16(const Signal16& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal16<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal16& operator= (const Signal16& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal16<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal16() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal16<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8, T_arg9 a9, T_arg10 a10, T_arg11 a11, T_arg12 a12, T_arg13 a13, T_arg14 a14, T_arg15 a15) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal16<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction16(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction16(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction16(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember16(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember16(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember16(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal16_h__ + diff --git a/source/signal/signal2.h b/source/signal/signal2.h new file mode 100644 index 0000000..80595e5 --- /dev/null +++ b/source/signal/signal2.h @@ -0,0 +1,1074 @@ +#ifndef __signal2_h__ +#define __signal2_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 2 parameter(s). + */ +template +class Slot2 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot2* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot2* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 2 parameter(s). + */ +template +class SlotFunction2 : public Slot2 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot2 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction2 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1) const + { + return pFunction(a0, a1); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction2* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction2* copy = new SlotFunction2(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 2 parameter(s). + */ +template +class SlotMember2 : public Slot2 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot2 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember2 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1) const + { + return (pObject->*pMember)(a0, a1); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember2* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember2* copy = new SlotMember2(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 2 parameter(s). + */ +template +class Signal2 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot2 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal2(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal2(const Signal2& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal2<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal2& operator= (const Signal2& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal2<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal2() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal2<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1) + { + Emit(a0, a1); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal2<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction2(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction2(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction2(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember2(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember2(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember2(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal2_h__ + diff --git a/source/signal/signal3.h b/source/signal/signal3.h new file mode 100644 index 0000000..04bd0fd --- /dev/null +++ b/source/signal/signal3.h @@ -0,0 +1,1074 @@ +#ifndef __signal3_h__ +#define __signal3_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 3 parameter(s). + */ +template +class Slot3 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot3* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot3* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 3 parameter(s). + */ +template +class SlotFunction3 : public Slot3 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot3 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction3 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2) const + { + return pFunction(a0, a1, a2); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction3* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction3* copy = new SlotFunction3(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 3 parameter(s). + */ +template +class SlotMember3 : public Slot3 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot3 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember3 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2) const + { + return (pObject->*pMember)(a0, a1, a2); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember3* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember3* copy = new SlotMember3(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 3 parameter(s). + */ +template +class Signal3 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot3 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal3(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal3(const Signal3& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal3<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal3& operator= (const Signal3& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal3<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal3() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal3<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2) + { + Emit(a0, a1, a2); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal3<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction3(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction3(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction3(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember3(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember3(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember3(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal3_h__ + diff --git a/source/signal/signal4.h b/source/signal/signal4.h new file mode 100644 index 0000000..dc65ea8 --- /dev/null +++ b/source/signal/signal4.h @@ -0,0 +1,1074 @@ +#ifndef __signal4_h__ +#define __signal4_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 4 parameter(s). + */ +template +class Slot4 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot4* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot4* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 4 parameter(s). + */ +template +class SlotFunction4 : public Slot4 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot4 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction4 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const + { + return pFunction(a0, a1, a2, a3); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction4* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction4* copy = new SlotFunction4(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 4 parameter(s). + */ +template +class SlotMember4 : public Slot4 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot4 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember4 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const + { + return (pObject->*pMember)(a0, a1, a2, a3); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember4* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember4* copy = new SlotMember4(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 4 parameter(s). + */ +template +class Signal4 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot4 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal4(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal4(const Signal4& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal4<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal4& operator= (const Signal4& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal4<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal4() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal4<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) + { + Emit(a0, a1, a2, a3); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal4<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction4(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction4(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction4(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember4(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember4(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember4(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal4_h__ + diff --git a/source/signal/signal5.h b/source/signal/signal5.h new file mode 100644 index 0000000..507dd0a --- /dev/null +++ b/source/signal/signal5.h @@ -0,0 +1,1074 @@ +#ifndef __signal5_h__ +#define __signal5_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 5 parameter(s). + */ +template +class Slot5 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot5* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot5* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 5 parameter(s). + */ +template +class SlotFunction5 : public Slot5 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot5 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction5 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const + { + return pFunction(a0, a1, a2, a3, a4); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction5* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction5* copy = new SlotFunction5(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 5 parameter(s). + */ +template +class SlotMember5 : public Slot5 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot5 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember5 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember5* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember5* copy = new SlotMember5(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 5 parameter(s). + */ +template +class Signal5 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot5 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal5(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal5(const Signal5& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal5<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal5& operator= (const Signal5& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal5<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal5() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal5<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) + { + Emit(a0, a1, a2, a3, a4); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal5<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction5(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction5(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction5(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember5(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember5(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember5(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal5_h__ + diff --git a/source/signal/signal6.h b/source/signal/signal6.h new file mode 100644 index 0000000..cbbc3dc --- /dev/null +++ b/source/signal/signal6.h @@ -0,0 +1,1074 @@ +#ifndef __signal6_h__ +#define __signal6_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 6 parameter(s). + */ +template +class Slot6 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot6* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot6* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 6 parameter(s). + */ +template +class SlotFunction6 : public Slot6 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot6 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction6 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const + { + return pFunction(a0, a1, a2, a3, a4, a5); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction6* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction6* copy = new SlotFunction6(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 6 parameter(s). + */ +template +class SlotMember6 : public Slot6 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot6 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember6 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember6* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember6* copy = new SlotMember6(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 6 parameter(s). + */ +template +class Signal6 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot6 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal6(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal6(const Signal6& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal6<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal6& operator= (const Signal6& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal6<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal6() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal6<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) + { + Emit(a0, a1, a2, a3, a4, a5); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal6<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction6(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction6(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction6(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember6(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember6(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember6(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal6_h__ + diff --git a/source/signal/signal7.h b/source/signal/signal7.h new file mode 100644 index 0000000..e5f8342 --- /dev/null +++ b/source/signal/signal7.h @@ -0,0 +1,1074 @@ +#ifndef __signal7_h__ +#define __signal7_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 7 parameter(s). + */ +template +class Slot7 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot7* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot7* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 7 parameter(s). + */ +template +class SlotFunction7 : public Slot7 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot7 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction7 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction7* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction7* copy = new SlotFunction7(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 7 parameter(s). + */ +template +class SlotMember7 : public Slot7 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot7 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember7 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember7* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember7* copy = new SlotMember7(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 7 parameter(s). + */ +template +class Signal7 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot7 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal7(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal7(const Signal7& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal7<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal7& operator= (const Signal7& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal7<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal7() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal7<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) + { + Emit(a0, a1, a2, a3, a4, a5, a6); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal7<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction7(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction7(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction7(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember7(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember7(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember7(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal7_h__ + diff --git a/source/signal/signal8.h b/source/signal/signal8.h new file mode 100644 index 0000000..9f39dae --- /dev/null +++ b/source/signal/signal8.h @@ -0,0 +1,1074 @@ +#ifndef __signal8_h__ +#define __signal8_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 8 parameter(s). + */ +template +class Slot8 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot8* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot8* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 8 parameter(s). + */ +template +class SlotFunction8 : public Slot8 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot8 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction8 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction8* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction8* copy = new SlotFunction8(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 8 parameter(s). + */ +template +class SlotMember8 : public Slot8 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot8 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember8 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember8* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember8* copy = new SlotMember8(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 8 parameter(s). + */ +template +class Signal8 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot8 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal8(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal8(const Signal8& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal8<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal8& operator= (const Signal8& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal8<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal8() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal8<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal8<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction8(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction8(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction8(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember8(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember8(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember8(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal8_h__ + diff --git a/source/signal/signal9.h b/source/signal/signal9.h new file mode 100644 index 0000000..d2a2737 --- /dev/null +++ b/source/signal/signal9.h @@ -0,0 +1,1074 @@ +#ifndef __signal9_h__ +#define __signal9_h__ + + + +#if defined(_DEBUG) +# include +#endif + + + +/** + * Abstract base class for Slots with 9 parameter(s). + */ +template +class Slot9 +{ +public: + + /** + * Method which performs the actual callback. Must be overridden. + * + * @return Returns an object of type T_return; the result of the user callback. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const = 0; + + /** + * Equality operator. + * + * @param other Pointer to another Slot. + * + * @return true if this slot is equivalent to other; false otherwise + */ + virtual bool operator== (const Slot9* other) const = 0; + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual Slot9* clone() const = 0; + +}; + + + +/** + * Concrete slot class for calling a global function with 9 parameter(s). + */ +template +class SlotFunction9 : public Slot9 +{ +public: + + /** + * Convenience typedef of a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot9 SlotBase; + + /** + * Constructor with function pointer initializer. + * + * @param func function pointer to be called by this slot. + */ + SlotFunction9 (FUNCTION_POINTER func): + pFunction(func) + { + } + + /** + * Method which performs the callback of the global function. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const + { + return pFunction(a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotFunction9* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pFunction == pother->pFunction ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotFunction9* copy = new SlotFunction9(pFunction); + return copy; + } + +private: + + /** + * Actual function pointer. + */ + FUNCTION_POINTER pFunction; + +}; + + + +/** + * Concrete slot class for calling a member function with 9 parameter(s). + */ +template +class SlotMember9 : public Slot9 +{ +public: + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot9 SlotBase; + + /** + * Constructor with object pointer and class member (pointer) initializers. + * + * @param func function pointer to be called by this slot. + */ + SlotMember9 (T_object* c, T_member m): + pObject(c), + pMember(m) + { + } + + /** + * Method which performs the callback of the object member. + * + * @return The result of the user global function; type T_return. + */ + virtual T_return operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const + { + return (pObject->*pMember)(a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + /** + * Equality operator. + * + * @param other slot object to compare against + * + * @return true if this slot object is equivalent to other; false otherwise. + */ + virtual bool operator== (const SlotBase* other) const + { + const SlotMember9* pother = dynamic_cast*>(other); + if ( pother ) + { + return ( this->pObject == pother->pObject && this->pMember == pother->pMember ); + } + else + { + return false; + } + } + + /** + * Create a copy of this slot. + * + * @return a new copy constructed instance of this slot object. + */ + virtual SlotBase* clone() const + { + SlotMember9* copy = new SlotMember9(pObject,pMember); + return copy; + } + +private: + + /** + * Pointer to object of callback. + */ + T_object* pObject; + + /** + * Class member function pointer. + */ + T_member pMember; + +}; + + + +/** + * Signal with 9 parameter(s). + */ +template +class Signal9 +{ +public: + + /** + * Convenience typedef to a regular function pointer. + */ + typedef T_return (*FUNCTION_POINTER)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8); + + /** + * Convenience typedef to our base slot type. + */ + typedef Slot9 SlotBase; + + /** + * Default constructor. + * + * Initializes Slot list to empty. + */ + Signal9(): + head(0), + emitting(false) + { + } + + /** + * Copy constructor. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + */ + Signal9(const Signal9& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal9<...> @ 0x%p is being copy constructed during Emit!\n",this); + } +#endif + + // defer to assignment operator + *this = other; + } + + /** + * Assignment operator. + * + * Create a copy of other signal object's Slot list. + * + * @param other signal object to copy. + * + * @return reference to '*this' after copy. + */ + Signal9& operator= (const Signal9& other) + { +#if defined(_DEBUG) + if ( emitting ) + { + printf("ERROR!: Signal9<...> @ 0x%p is being assigned during Emit!\n",this); + } +#endif + + // destroy current slot list + clear(); + + // walk other slot list, copying as we go + slotitem* current = other.head; + while ( current ) + { + // make a local copy of slot + SlotBase* slotcopy = current->slot->clone(); + + // add to our list + insertslot(slotcopy,current->lifetime); + + // move to next item + current = current->next; + } + + return *this; + } + + /** + * Destructor. + * + * Release all heap and empty Slot list. + */ + ~Signal9() + { + // warn if slots still attached +#if defined(_DEBUG) + if ( !Empty() ) + { + printf("WARNING: Signal9<...> @ 0x%p destroyed with %d slots still connected!\n",this,Count()); + } +#endif + + // delete slots on list + clear(); + } + + /** + * Determine if a signal is empty (no slots attached). + */ + bool Empty() + { + return ( head == 0 ); + } + + /** + * Count number of slots attached. + * + * @return count of slots attached to this signal + */ + unsigned int Count() + { + unsigned int count = 0; + slotitem* current = head; + while ( current ) + { + ++count; + current = current->next; + } + return count; + } + + /** + * Connect to a slot. + * + * @param slot slot to connect to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(const SlotBase& slot, int lifetime = -1) + { + return connect_slot(slot,lifetime); + } + + /** + * Connect to a regular function pointer. + * + * @param func function pointer to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + bool Connect(FUNCTION_POINTER func, int lifetime = -1) + { + return connect_function(func,lifetime); + } + + /** + * Connect to a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, int lifetime = -1) + { + return connect_member(object, &T_object::operator(),lifetime); + } + + /** + * Connect to a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8), int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const, int lifetime = -1) + { + return connect_member(object, method,lifetime); + } + + /** + * Connect to a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8), int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Connect to a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * @param lifetime number of times to signal slot before automatic removal. + * + * @return true on success; false otherwise. + */ + template + bool Connect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const, int lifetime = -1) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return connect_member(ancestor, method,lifetime); + } + else + { + return false; + } + } + + /** + * Disconnect from a slot. + * + * @param slot slot to disconnect from. + * + * @return true on success; false otherwise. + */ + bool Disconnect(const SlotBase& slot) + { + return disconnect_slot(slot); + } + + /** + * Disconnect from a regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool Disconnect(FUNCTION_POINTER func) + { + return disconnect_function(func); + } + + /** + * Disconnect from a functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object) + { + return disconnect_member(object, &T_object::operator()); + } + + /** + * Disconnect from a member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8)) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const) + { + return disconnect_member(object, method); + } + + /** + * Disconnect from a parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect from a const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool Disconnect(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return disconnect_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Disconnect all slots. + */ + void DisconnectAll() + { + clear(); + } + + /** + * Search for a connected slot. + * + * @param slot slot to connect to. + * + * @return true on success; false otherwise. + */ + bool IsConnected(const SlotBase& slot) + { + return search_slot(slot); + } + + /** + * Search for a connected regular function pointer. + * + * @param func function pointer to callback. + * + * @return true on success; false otherwise. + */ + bool IsConnected(FUNCTION_POINTER func) + { + return search_function(func); + } + + /** + * Search for a connected functor. + * + * @param T_object type of object + * @param object pointer to functor object to callback. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object) + { + return search_member(object, &T_object::operator()); + } + + /** + * Search for a connected member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8)) + { + return search_member(object, method); + } + + /** + * Search for a connected const member function. + * + * @param T_object type of object + * @param object pointer to object to callback to. + * @param method pointer to class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_object::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const) + { + return search_member(object, method); + } + + /** + * Search for a connected parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8)) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Search for a connected const parent member function. + * + * @param T_object type of object + * @param T_parent type of parent class + * @param object pointer to object to callback to. + * @param method pointer to parent class method to callback to. + * + * @return true on success; false otherwise. + */ + template + bool IsConnected(T_object* object, T_return (T_parent::*method)(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) const) + { + T_parent* ancestor = dynamic_cast(object); + if ( ancestor ) + { + return search_member(ancestor, method); + } + else + { + return false; + } + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void operator() (T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) + { + Emit(a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + /** + * Emit signal. + * + * Calls all slots connected to this signal. + */ + void Emit(T_arg0 a0, T_arg1 a1, T_arg2 a2, T_arg3 a3, T_arg4 a4, T_arg5 a5, T_arg6 a6, T_arg7 a7, T_arg8 a8) + { + // if already emitting bail, disallow recursive emission + if ( emitting ) + { +#if defined(_DEBUG) + printf("WARNING: Signal9<...> @ 0x%p recursive Emit attempt\n",this); +#endif + + return; + } + + // set emission flag + emitting = true; + + // get pointer to first slot + slotitem* current = head; + slotitem* prev = 0; + + // walk slot list, call all slots + while ( current ) + { + // call slot + (*(current->slot))(a0, a1, a2, a3, a4, a5, a6, a7, a8); + + // is this current's last call? + if ( current->lifetime != 1 ) + { + // not current's last call, count and move forward normally + + // current has a valid lifetime? + if ( current->lifetime > 0 ) + { + // decrement call count + --current->lifetime; + } + + // move to next item + prev = current; + current = current->next; + } + else + { + // this was current's last call, delete it from our slot list + + // save next item + slotitem* next = current->next; + + // set list to skip over current element + if ( prev ) + { + // set prev's next to current's next + prev->next = next; + } + else + { + // nothing previous, set head to next + head = next; + } + + // delete current element + delete current->slot; + delete current; + + // move to next item + current = next; + } + } // while( current ) + + // done emitting + emitting = false; + + // now delete any slots we may have added during emission + erasepending(); + } + +private: + + /** + * Structure to hold a slot element (for linked list). + */ + typedef struct slotitem + { + SlotBase* slot; + int lifetime; + slotitem* next; + bool erase; + } slotitem; + + /** + * Head of our slot linked list. + */ + slotitem* head; + + /** + * true if we're emitting + */ + bool emitting; + + /** + * Insert a new slot at head of linked list. + */ + bool insertslot(const SlotBase* slot, int lifetime) + { + // check slot + if ( !slot || lifetime == 0 ) + { + return false; + } + + // create a slot item + slotitem* item = new slotitem; + if ( !item ) + { + return false; + } + + // put slot in new item + item->slot = const_cast( slot ); + item->lifetime = lifetime; + item->erase = false; + + // add item to list + item->next = head; + head = item; + + // success + return true; + } + + /** + * Mark a slot for erase (search using equality operator) from linked list. + */ + bool queueeraseslot(const SlotBase* slot) + { + slotitem* current = head; + + while ( current ) + { + if ( *current->slot == slot ) + { + // found a match. set list to skip over it + current->erase = true; + + // done + return true; + } + else + { + // no match, move to next item normally + current = current->next; + } + } + + // not found + return false; + } + + /** + * Remove any marked-for-erase slots. + */ + bool erasepending() + { + if ( !emitting ) + { + slotitem* previous = 0; + slotitem* current = head; + + while ( current ) + { + if ( current->erase ) + { + // found something to delete. set list to skip over it + if ( previous ) + { + previous->next = current->next; + } + else + { + head = current->next; + } + + // now mark item for erasue + delete current->slot; + delete current; + + // done + return true; + } + else + { + // no match, move to next item normally + previous = current; + current = current->next; + } + } + } + + // now delete item + return false; + } + + /** + * Remove a slot (using equality operator) from linked list. + */ + bool eraseslot(const SlotBase* slot) + { + // done + if ( queueeraseslot(slot) ) + { + // no match, move to next item normally + return erasepending(); + } + + // not found + return false; + } + + /** + * Empty slot list. + */ + void clear() + { + slotitem* current = head; + while ( current ) + { + // remember next item + slotitem* next = current->next; + + // delete current + delete current->slot; + delete current; + + // set to next + current = next; + } + + // set our list to empty + head = 0; + } + + /** + * Add a function slot. + */ + bool connect_function(FUNCTION_POINTER func, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotFunction9(func), lifetime ); + } + + /** + * Remove a function slot. + */ + bool disconnect_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotFunction9(func) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + bool search_function(FUNCTION_POINTER func) + { + // create temp slot and attempt disconnect + return search_slot( SlotFunction9(func) ); + } + + /** + * Add a member function slot. + */ + template + bool connect_member(T_object* object, T_member method, int lifetime) + { + // create temp slot and attempt connect + return connect_slot( SlotMember9(object, method), lifetime ); + } + + /** + * Remove a member function slot. + */ + template + bool disconnect_member(T_object* object, T_member method) + { + // create temp slot and attempt disconnect + return disconnect_slot( SlotMember9(object, method) ); + } + + /** + * Test to search for an equivalent slot already connected. + * + * @return true if this slot is already connected + */ + template + bool search_member(T_object* object, T_member method) + { + // create temp slot and search + return search_slot( SlotMember9(object, method) ); + } + + /** + * Add a generic slot. + */ + bool connect_slot(const SlotBase& slot, int lifetime) + { + // create a new slot + SlotBase* newslot = slot.clone(); + if ( !newslot ) + { + return false; + } + + // insert slot into list + if ( !insertslot(newslot,lifetime) ) + { + delete newslot; + return false; + } + + // success + return true; + } + + /** + * Remove a generic slot. + */ + bool disconnect_slot(const SlotBase& slot) + { + return eraseslot(&slot); + } + + /** + * Tests to see if an equivalent slot is already connected. + * + * @return true if slot is already connected + */ + bool search_slot(const SlotBase& slot) + { + slotitem* current = head; + while ( current ) + { + if ( *current->slot == &slot ) + { + return true; + } + current = current->next; + } + return false; + } + +}; + + + +#endif // __signal9_h__ +