#!/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__