GEL
2
GEL is a library for Geometry and Linear Algebra
|
00001 #ifndef __UTIL_RESOURCE_MANAGER_H 00002 #define __UTIL_RESOURCE_MANAGER_H 00003 00004 #include <cassert> 00005 #include <string> 00006 #include <list> 00007 #include <typeinfo> 00008 00009 #define CLEAN_SHUTDOWN 1 00010 00011 namespace Util 00012 { 00013 00014 typedef unsigned char FlagByte; 00015 const FlagByte REMOVE_WHEN_UNUSED = 0x01; 00016 const FlagByte STATIC_RESOURCE = 0x02; 00017 00023 template<class RES> 00024 class ResourceRecord 00025 { 00027 const std::string name; 00028 00030 RES * const res; 00031 00033 int usage; 00034 00036 FlagByte flags; 00037 00038 public: 00039 00041 ResourceRecord(): res(0), usage(0), flags(0) {} 00042 00044 ResourceRecord(const std::string& _name, RES* _res, bool static_res=false): 00045 name(_name), 00046 res(_res), 00047 usage(0), 00048 flags(static_res ? STATIC_RESOURCE : 0) 00049 { 00050 assert(res != 0); 00051 } 00052 00053 ~ResourceRecord() 00054 { 00055 #if CLEAN_SHUTDOWN 00056 assert(usage==0); 00057 #endif 00058 } 00059 00060 void erase_resource() 00061 { 00062 assert(usage==0); 00063 if(!(flags&STATIC_RESOURCE)) 00064 { 00065 delete res; 00066 } 00067 } 00068 00070 void increment_usage() 00071 { 00072 assert(usage>=0); 00073 ++usage; 00074 } 00075 00077 void decrement_usage() 00078 { 00079 assert(usage>0); 00080 --usage; 00081 } 00082 00084 int get_usage() const { return usage; } 00085 00087 const std::string& get_name() const {return name;} 00088 00090 RES * const get_ptr() 00091 { 00092 return res; 00093 } 00094 00096 const RES * const get_ptr() const 00097 { 00098 return res; 00099 } 00100 00101 void remove_when_unused() 00102 { 00103 /* assert(!(flags&STATIC_RESOURCE)); */ 00104 /* if(!(flags&STATIC_RESOURCE)) */ 00105 flags = flags|REMOVE_WHEN_UNUSED; 00106 } 00107 00108 FlagByte get_flags() const { return flags;} 00109 00110 }; 00111 00112 00113 template<class RES> class ResourceManager; 00114 00115 00125 template<class RES> 00126 class ResourcePtr 00127 { 00128 typedef ResourceRecord<RES> RR; 00129 typedef std::list<RR> RRList; 00130 typedef typename RRList::iterator RRListIter; 00131 00132 static RRListIter get_null_rrlist_iter() 00133 { 00134 static RRList l; 00135 return l.end(); 00136 } 00137 00138 #define NULL_RRLIST_ITER ResourcePtr<RES>::get_null_rrlist_iter() 00139 00140 friend class ResourceManager<RES>; 00141 00142 private: 00143 RRListIter rr; 00144 RES* res; 00145 00148 explicit ResourcePtr(const RRListIter& _rr): rr(_rr), res(0) 00149 { 00150 if(rr != NULL_RRLIST_ITER) 00151 { 00152 rr->increment_usage(); 00153 res = rr->get_ptr(); 00154 } 00155 } 00156 00157 void decrement_usage(); 00158 00159 public: 00160 00161 ResourcePtr(): rr(NULL_RRLIST_ITER), res(0) {} 00162 00163 ResourcePtr(const ResourcePtr& r2): rr(r2.rr), res(0) 00164 { 00165 if(rr != NULL_RRLIST_ITER) 00166 { 00167 rr->increment_usage(); 00168 res = rr->get_ptr(); 00169 } 00170 } 00171 00172 const ResourcePtr& operator=(const ResourcePtr& r2) 00173 { 00174 // Guard against self-assignment 00175 if (r2.rr != this->rr) 00176 { 00177 if(rr != NULL_RRLIST_ITER) decrement_usage(); 00178 00179 rr = r2.rr; 00180 res = 0; 00181 00182 if(rr != NULL_RRLIST_ITER) 00183 { 00184 res = rr->get_ptr(); 00185 rr->increment_usage(); 00186 } 00187 } 00188 return *this; 00189 } 00190 00191 ~ResourcePtr() {decrement_usage();} 00192 00193 RES& operator*() const 00194 { 00195 assert(rr != NULL_RRLIST_ITER); 00196 assert(res != 0); 00197 return *res; 00198 } 00199 00200 RES* const operator->() const 00201 { 00202 assert(rr != NULL_RRLIST_ITER); 00203 assert(res !=0); 00204 return res; 00205 } 00206 00207 RES* const get_raw_ptr() const 00208 { 00209 assert(rr != NULL_RRLIST_ITER); 00210 assert(res != 0); 00211 return res; 00212 } 00213 00214 int usage() const 00215 { 00216 if(rr != NULL_RRLIST_ITER) 00217 return rr->get_usage(); 00218 return -1; 00219 } 00220 00221 bool is_valid() const {return rr != NULL_RRLIST_ITER;} 00222 00223 void relinquish_resource() 00224 { 00225 ResourcePtr p; 00226 *this = p; 00227 } 00228 00231 void remove_when_unused() { rr->remove_when_unused(); } 00232 }; 00233 00234 00249 template<class RES> 00250 class ResourceManager 00251 { 00252 typedef ResourceRecord<RES> RR; 00253 typedef std::list<RR> RRList; 00254 typedef typename RRList::iterator RRListIter; 00255 RRList resources; 00256 00257 ResourceManager(): resources(0) {} 00258 ResourceManager(const ResourceManager&); 00259 ResourceManager& operator=(const ResourceManager&); 00260 00261 public: 00262 00263 00264 ~ResourceManager() 00265 { 00266 #if CLEAN_SHUTDOWN 00267 RRListIter i = resources.begin(); 00268 while(i != resources.end()) 00269 { 00270 if(i->get_usage()==0) 00271 { 00272 RRListIter tmp = i; 00273 ++i; 00274 erase_resource(tmp); 00275 } 00276 else 00277 { 00278 std::cout << "Warning, ResourceManager:\n\n" 00279 << (typeid(this).name()) 00280 << "\n\nis shutting down, and resource \n\n" 00281 << i->get_name() << "\n\nhas usage: " << i->get_usage() 00282 << std::endl; 00283 std::cout << 00284 "In other words, this resource is not unused at this\n" 00285 "point. That is unfortunate because then it cannot\n" 00286 "be deleted (since it might be used by some other\n" 00287 "part of the program during shutdown). Please ensure\n" 00288 "that all resources are unused at program\n" 00289 "termination. If you use a global ResourcePtr, this is\n" 00290 "done by calling relinquish_resource just before\n" 00291 "exiting.\n" 00292 << std::endl; 00293 ++i; 00294 } 00295 } 00296 #endif 00297 } 00298 00299 int get_no_resources() const 00300 { 00301 return resources.size(); 00302 } 00303 00304 static ResourceManager& get_instance() 00305 { 00306 static ResourceManager instance; 00307 return instance; 00308 } 00309 00310 void erase_resource(RRListIter iter) 00311 { 00312 iter->erase_resource(); 00313 resources.erase(iter); 00314 } 00315 00318 ResourcePtr<RES> get_resource_ptr(const std::string& str) 00319 { 00320 for(RRListIter i = resources.begin(); i != resources.end(); ++i) 00321 if((*i).get_name() == str) 00322 return ResourcePtr<RES>(i); 00323 return ResourcePtr<RES>(NULL_RRLIST_ITER); 00324 } 00325 00329 ResourcePtr<RES> register_resource(const std::string& str, 00330 RES* res, bool static_resource) 00331 { 00332 for(RRListIter i = resources.begin(); i != resources.end(); ++i) 00333 if(i->get_name() == str) 00334 return (ResourcePtr<RES>(NULL_RRLIST_ITER)); 00335 00336 resources.push_front(RR(str, res, static_resource)); 00337 ResourcePtr<RES> ptr = ResourcePtr<RES>(resources.begin()); 00338 return ptr; 00339 } 00340 00341 /* friend class ResourcePtr<RES>; 00342 friend int get_no_resources<RES>(); 00343 friend ResourcePtr<RES> get_resource_ptr<RES>(const std::string& str); 00344 friend ResourcePtr<RES> register_static_resource<RES>(const std::string&, 00345 RES*); 00346 friend ResourcePtr<RES> register_dynamic_resource<RES>(const std::string&, 00347 RES*);*/ 00348 }; 00349 00350 template<class RES> 00351 inline void ResourcePtr<RES>::decrement_usage() 00352 { 00353 assert( (rr == NULL_RRLIST_ITER) || (res != 0)); 00354 if(rr != NULL_RRLIST_ITER) 00355 { 00356 rr->decrement_usage(); 00357 if(rr->get_usage() == 0 && (rr->get_flags()&REMOVE_WHEN_UNUSED)) 00358 { 00359 ResourceManager<RES>& man = ResourceManager<RES>::get_instance(); 00360 man.erase_resource(rr); 00361 } 00362 } 00363 } 00364 00365 template<class RES> 00366 inline int get_no_resources() 00367 { 00368 ResourceManager<RES>& man = ResourceManager<RES>::get_instance(); 00369 return man.get_no_resources(); 00370 } 00371 00372 template<class RES> 00373 inline ResourcePtr<RES> get_resource_ptr(const std::string& str) 00374 { 00375 ResourceManager<RES>& man = ResourceManager<RES>::get_instance(); 00376 return man.get_resource_ptr(str); 00377 } 00378 00379 template<class RES> 00380 inline ResourcePtr<RES> register_dynamic_resource(const std::string& str,RES* res) 00381 { 00382 ResourceManager<RES>& man = ResourceManager<RES>::get_instance(); 00383 ResourcePtr<RES> ptr = man.register_resource(str, res, false); 00384 return ptr; 00385 } 00386 00387 template<class RES> 00388 inline ResourcePtr<RES> register_static_resource(const std::string& str,RES* res) 00389 { 00390 ResourceManager<RES>& man = ResourceManager<RES>::get_instance(); 00391 ResourcePtr<RES> ptr = man.register_resource(str, res, true); 00392 return ptr; 00393 } 00394 00395 } 00396 00397 00398 #endif