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 Wed Jul 28 16:04:14 2004 for s11n by doxygen 1.3.7