Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members

children_holder.h

00001 // Author: stephan beal <stephan@s11n.net>
00002 // License: Public Domain
00003 #ifndef s11n_CHILDRENHOLDER_H_INCLUDED
00004 #define s11n_CHILDRENHOLDER_H_INCLUDED 1
00005 
00006 #include <string>
00007 #include <list>
00008 #include <map>
00009 #include <vector>
00010 //#include <deque> // causes crashes in some cases where vector does not :/
00011 
00012 namespace s11n
00013 {
00014     /**
00015            EXPERIMENTAL!
00016 
00017            children_holder is an experimental object for creating pointer
00018            containers for arbitrary child types. The idea is that many objects
00019            i create have a heirarchical structure, and i'm looking for a
00020            generic way to code this pattern.
00021 
00022            The interface should allow any given class, including
00023            non-modifiable 3rd-party classes, to have any number of
00024            child types.
00025 
00026            This code does no automatic clean-up of children. Client
00027            code may free all child pointers by calling
00028            cleanup_parent(), and subclasses or proxies of this object
00029            should call that in their dtor.
00030         */
00031     template < class PType, class CType > class children_holder
00032     {
00033           public:
00034                 /**
00035                    The type of this object's parents in
00036                    parent-child relationships.
00037                  */
00038         typedef PType parent_type;
00039 
00040                 /**
00041                    The type of this object's children in
00042                    parent-child relationships.
00043                  */
00044         typedef CType child_type;
00045 
00046                 /**
00047                    The container type used to store the lists of children.
00048                  */
00049         typedef std::list < child_type * >list_type;
00050 
00051                 /**
00052                    A shortcut typedef to help ease the implementation code for this class.
00053                  */
00054         typedef children_holder < parent_type, child_type > ThisType;
00055 
00056                 /**
00057                    iterator which can be dereferenced to a (child_type *).
00058                  */
00059         typedef typename list_type::iterator iterator;
00060                 /**
00061                    iterator which can be dereferenced to a (const child_type *).
00062                  */
00063         typedef typename list_type::const_iterator const_iterator;
00064 
00065         /**
00066                    Returns the child list for the given parent
00067                    object. If creationPolicy is non-zero then this
00068                    function will create the child list if it does not
00069                    yet exist (in that case, this function will never
00070                    return NULL except on an out-of-memory error).
00071 
00072                    The caller takes ownership of the returned
00073                    pointer. All children in the list can be deleted at
00074                    once by calling cleanup_parent( parent ).
00075 
00076                    Different calls to this function will always return
00077                    the same list (or the same NULL, depending on
00078                    creationPolicy ;) until either unmap_parent() or
00079                    cleanup_parent() are called, in which case further
00080                    calls to this function may return a different
00081                    pointer the next time it is called.
00082                 */
00083         static ThisType::list_type * child_list( const ThisType::parent_type * parent, int creationPolicy = 0 )
00084         {
00085             if ( !parent ) return NULL;
00086             static ThisType::map_type & cmap = parentChildMap();
00087             typename map_type::const_iterator it = cmap.find( parent );
00088             if ( cmap.end() != it ) return ( *it ).second;
00089             if ( 0 == creationPolicy ) return NULL;
00090             list_type *cl = new list_type();
00091                         cmap[parent] = cl;
00092                         return cl;
00093         }
00094 
00095 
00096         /**
00097                    Removes parent from this object's internal
00098                    map. This only removes the pointer to the parent's
00099                    child list and the mapping which binds the parent
00100                    to the children, but does not delete() anything.
00101 
00102                    Returns true if it unmaps the parent, else
00103                    false. It will only fail if it doesn't have an
00104                    entry for parent.
00105 
00106 
00107                    This is more of a maintenance detail than anything
00108                    else.
00109 
00110                 */
00111         static bool unmap_parent( const ThisType::parent_type * parent )
00112         {
00113             if ( !parent ) return false;
00114             static ThisType::map_type & cmap = parentChildMap();
00115             typename ThisType::map_type::iterator it = cmap.find( parent );
00116             if ( it == cmap.end() ) return false;
00117             cmap.erase( parent );
00118             return true;
00119         }
00120 
00121         /**
00122                    Simlar as unmap_parent(), but also deletes the
00123                    children in the list and then deletes the list.
00124 
00125                    Subclasses or proxies of this class should call
00126                    this function from their dtor, in order to avoid
00127                    leaving any dangling pointers in this class'
00128                    internal data.
00129                 */
00130         static bool cleanup_parent( const ThisType::parent_type * parent )
00131         {
00132             if ( !parent )
00133                 return false;
00134             static ThisType::map_type & cmap = parentChildMap();
00135             typename ThisType::map_type::iterator it = cmap.find( parent );
00136             if ( it == cmap.end() )
00137             {
00138                 // we were probably just never registed because children() was never called.
00139                 return false;
00140             }
00141             typename ThisType::list_type * li = ( *it ).second;
00142             if ( !unmap_parent( parent ) )
00143             {
00144                 return false;
00145             }
00146             typename ThisType::list_type::iterator vit;
00147             typename ThisType::child_type * child = 0;
00148             for ( vit = li->begin(); li->begin() != li->end(); )
00149             {
00150                                 // note: i explicitely call begin()/end() on each iteration
00151                                 // because i'm not certain of iterator invalidation here :/
00152                 child = ( *vit );
00153                 li->erase( vit );
00154                 delete( child );
00155                 child = 0;
00156             }
00157             delete( li );
00158             return true;
00159         }
00160 
00161 
00162           private:
00163         typedef std::map < const ThisType::parent_type *, ThisType::list_type * > map_type;
00164                 /**
00165                    i hate working with static objects in template
00166                    classes (for syntax reasons), and parentChildMap()
00167                    is a helper to avoid that.
00168                  */
00169         static map_type & parentChildMap()
00170         {
00171             static map_type meyers;
00172             return meyers;
00173         }
00174 
00175 
00176     };
00177 
00178 
00179 };              //  namespace s11n
00180 #endif // s11n_CHILDRENHOLDER_H_INCLUDED

Generated on Tue Oct 26 18:25:59 2004 for s11n by  doxygen 1.3.9.1