Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

ixlib_garbage.hh

Go to the documentation of this file.
00001 // ----------------------------------------------------------------------------
00002 //  Description      : Garbage collection
00003 // ----------------------------------------------------------------------------
00004 //  (c) Copyright 2000 by iXiONmedia, all rights reserved.
00005 // ----------------------------------------------------------------------------
00006 
00007 
00008 
00009 
00010 #ifndef IXLIB_GARBAGE
00011 #define IXLIB_GARBAGE
00012 
00013 
00014 
00015 
00016 #include <memory>
00017 #include <ixlib_exgen.hh>
00018 #include <ixlib_base.hh>
00019 
00020 
00021 
00022 
00023 namespace ixion {
00024   template<class T>
00025   class delete_deallocator {
00026     public:
00027       void operator()(T const *instance) {
00028         delete instance;
00029         }
00030     };
00031   template<class T>
00032   class delete_array_deallocator {
00033     public:
00034       void operator()(T const *instance) {
00035         delete[] instance;
00036         }
00037     };
00038 
00039   template<class T,class Deallocator = delete_deallocator<T> >
00040   class reference_manager;
00041 
00042   template<class T>
00043   class ref_base {
00044     protected:
00045       T                                 *Instance;
00046     
00047     public:
00048       ref_base(T *instance = NULL)
00049         : Instance(instance) {
00050         }
00051       ref_base(ref_base const &src) 
00052         : Instance(src.Instance) {
00053         }
00054 
00055       // comparison
00056       bool operator==(ref_base const &op2) const {
00057         return Instance == op2.Instance;
00058         }
00059       
00060       // smart pointer nitty-gritty
00061       T &operator*() const {
00062         return *Instance;
00063         }
00064       T *operator->() const {
00065         return Instance;
00066         }
00067       T *operator+(TIndex index) const {
00068         return Instance + index;
00069         }
00070       T &operator[](TIndex index) const {
00071         return Instance[index];
00072         }
00073 
00074       // methods
00075       T *get() const {
00076         return Instance;
00077         }
00078     };
00079 
00080 
00081 
00082 
00083   template<class T,class T_Managed = T>
00084   class ref;
00085   template<class T,class T_Managed = T>
00086   class no_free_ref;
00087 
00088 
00089 
00090 
00091   template<class T_Managed>
00092   class reference_manager_keeper {
00093     public:
00094     // *** FIXME should be private, but cannot be
00095     // (partial specializations cannot be declared friends)
00096       static reference_manager<T_Managed>       Manager;
00097     };
00098 
00099 
00100 
00101 
00102 
00122   template<class T,class T_Managed>
00123   class ref : public ref_base<T> {
00124     public:
00125       // we have to have an explicit copy constructor, otherwise the
00126       // compiler generates one, which is *ahem* - fatal
00127       ref(ref const &src)
00128         : ref_base<T>(src) {
00129         reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
00130         }
00131       template<class T2>
00132       ref(ref<T2,T_Managed> const &src)
00133         : ref_base<T>(src.get()) {
00134         reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
00135         }
00136       template<class T2>
00137       ref(no_free_ref<T2,T_Managed> const &src)
00138         : ref_base<T>(src.get()) {
00139         reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
00140         }
00141       ref(T *instance = NULL)
00142         : ref_base<T>(instance) {
00143         reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
00144         }
00145       ~ref() {
00146         reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
00147         }
00148         
00149       ref &operator=(ref const &src) {
00150         set(src.get());
00151         return *this;
00152         }
00153       ref &operator=(T *ptr) {
00154         set(ptr);
00155         return *this;
00156         }
00157       
00158       // methods
00159       void release() {
00160         reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
00161         Instance = NULL;
00162         }
00163       void set(T *instance) {
00164         if (instance == Instance) return;
00165         
00166         reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
00167         Instance = instance;
00168         reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
00169         }
00170       T *releaseFromGCArena() {
00171         T *oldinst = Instance;
00172         reference_manager_keeper<T_Managed>::Manager.forgetReference(Instance);
00173         Instance = NULL;
00174         return oldinst;
00175         }
00176     };
00177 
00178 
00179 
00180 
00196   template<class T,class T_Managed>
00197   class no_free_ref : public ref_base<T>{
00198     public:
00199       // we have to have an explicit copy constructor, otherwise the
00200       // compiler generates one, which is *ahem* - fatal
00201       no_free_ref(no_free_ref const &src)
00202         : ref_base<T>(src) {
00203         reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
00204         }
00205       template<class T2>
00206       no_free_ref(ref<T2,T_Managed> const &src)
00207         : ref_base<T>(src.get()) {
00208         reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
00209         }
00210       template<class T2>
00211       no_free_ref(no_free_ref<T2,T_Managed> const &src)
00212         : ref_base<T>(src.get()) {
00213         reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
00214         }
00215       no_free_ref(T *instance = NULL)
00216         : ref_base<T>(instance) {
00217         reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
00218         }
00219       ~no_free_ref() {
00220         reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
00221         }
00222         
00223       // assignment
00224       no_free_ref &operator=(no_free_ref const &src) {
00225         set(src.get());
00226         return *this;
00227         }
00228       no_free_ref &operator=(T *ptr) {
00229         set(ptr);
00230         return *this;
00231         }
00232       
00233       // methods
00234       void release() {
00235         reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
00236         Instance = NULL;
00237         }
00238       void set(T *instance) {
00239         if (instance == Instance) return;
00240         
00241         reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
00242         Instance = instance;
00243         reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
00244         }
00245       T *releaseFromGCArena() {
00246         T *oldinst = Instance;
00247         reference_manager_keeper<T_Managed>::Manager.forgetReference(Instance);
00248         Instance = NULL;
00249         return oldinst;
00250         }
00251     };
00252 
00253 
00254 
00255 
00260   template<class T>
00261   class dynamic_ref : public ref_base<T> {
00262     protected:
00263       reference_manager<T>      &Manager;
00264       
00265     public:
00266       dynamic_ref(dynamic_ref const &src)
00267         : ref_base<T>(src),Manager(src.Manager) {
00268         Manager.addReference(Instance);
00269         }
00270       dynamic_ref(reference_manager<T> &mgr,T *instance = NULL)
00271         : ref_base<T>(instance),Manager(mgr) {
00272         Manager.addReference(Instance);
00273         }
00274       ~dynamic_ref() {
00275         Manager.freeReference(Instance);
00276         }
00277       
00278       // assignment
00279       dynamic_ref &operator=(dynamic_ref const &src) {
00280         set(src.get());
00281         return *this;
00282         }
00283       dynamic_ref &operator=(T *ptr) {
00284         set(ptr);
00285         return *this;
00286         }
00287 
00288       // methods
00289       void release() {
00290         Manager.freeReference(Instance);
00291         Instance = NULL;
00292         }
00293       void set(T *instance) {
00294         if (instance == Instance) return;
00295         
00296         Manager.freeReference(Instance);
00297         Instance = instance;
00298         Manager.addReference(Instance);
00299         }
00300       T *releaseFromGCArena() {
00301         T *oldinst = Instance;
00302         Manager.forgetReference(Instance);
00303         Instance = NULL;
00304         return oldinst;
00305         }
00306     };
00307   
00308   
00309   
00310   
00325   template<class T>
00326   class no_free_dynamic_ref : public ref_base<T> {
00327     protected:
00328       reference_manager<T>      &Manager;
00329       
00330     public:
00331       no_free_dynamic_ref(no_free_dynamic_ref const &src)
00332         : ref_base<T>(src),Manager(src.Manager) {
00333         Manager.addNoFreeReference(Instance);
00334         }
00335       no_free_dynamic_ref(reference_manager<T> &mgr,T *instance = NULL)
00336         : ref_base<T>(instance),Manager(mgr) {
00337         Manager.addNoFreeReference(Instance);
00338         }
00339       ~no_free_dynamic_ref() {
00340         Manager.removeNoFreeReference(Instance);
00341         }
00342       
00343       // assignment
00344       no_free_dynamic_ref &operator=(no_free_dynamic_ref const &src) {
00345         set(src.get());
00346         return *this;
00347         }
00348       no_free_dynamic_ref &operator=(T *ptr) {
00349         set(ptr);
00350         return *this;
00351         }
00352 
00353       // methods
00354       void release() {
00355         Manager.removeNoFreeReference(Instance);
00356         Instance = NULL;
00357         }
00358       void set(T *instance) {
00359         if (instance == Instance) return;
00360         
00361         Manager.removeNoFreeReference(Instance);
00362         Instance = instance;
00363         Manager.addNoFreeReference(Instance);
00364         }
00365       T *releaseFromGCArena() {
00366         T *oldinst = Instance;
00367         Manager.forgetReference(Instance);
00368         Instance = NULL;
00369         return oldinst;
00370         }
00371     };
00372   
00373   
00374   
00375   
00376   template<class T,class Deallocator>
00377   class reference_manager {
00378     protected:
00379     
00380       struct instance_data {
00381         T const         *Instance;
00382         TSize           ReferenceCount,NoFreeReferenceCount;
00383         instance_data   *Next,*Previous;
00384         };
00385       
00386       class pointer_hash {
00387         public:
00388         };
00389 
00390       typedef unsigned hash_value;
00391       static hash_value const HASH_MAX = 0x3ff;
00392       
00393       instance_data                                     *Instances[HASH_MAX+1];
00394       Deallocator                                       Dealloc;
00395       
00396     public:
00397       reference_manager(Deallocator const &dealloc = Deallocator())
00398         : Dealloc(dealloc) {
00399         for (hash_value hv = 0;hv <= HASH_MAX;hv++)
00400           Instances[hv] = NULL;
00401         }
00402     
00403     // *** FIXME should be
00404     // protected:
00405     // but cannot because partial specializations cannot be declared friends
00406       void addReference(T const *instance) {
00407         if (!instance) return;
00408         instance_data *data = getHashEntry(instance);
00409         data->ReferenceCount++;
00410         }
00411       void freeReference(T const *instance) {
00412         if (!instance) return;
00413         instance_data *data = getHashEntry(instance);
00414         if (--data->ReferenceCount == 0 && data->NoFreeReferenceCount == 0) {
00415           removeHashEntry(data);
00416           Dealloc(instance);
00417           }
00418         }
00419       void addNoFreeReference(T const *instance) {
00420         if (!instance) return;
00421         instance_data *data = getHashEntry(instance);
00422         data->NoFreeReferenceCount++;
00423         }
00424       void removeNoFreeReference(T const *instance) {
00425         if (!instance) return;
00426         instance_data *data = getHashEntry(instance);
00427         if (--data->NoFreeReferenceCount == 0) {
00428           if (data->ReferenceCount != 0)
00429             EXGEN_THROW(EC_REMAININGREF)
00430           removeHashEntry(data);
00431           }
00432         }
00433       void forgetReference(T const *instance) {
00434         if (!instance) return;
00435         instance_data *data = getHashEntry(instance);
00436         if (data->ReferenceCount != 1) 
00437           EXGEN_THROW(EC_CANNOTREMOVEFROMGC)
00438         removeHashEntry(data);
00439         }
00440         
00441     private:
00442       hash_value hash(T const *ptr) const {
00443         unsigned u = reinterpret_cast<unsigned>(ptr);
00444         return (u ^ (u >> 8) ^ (u >> 16) ^ (u >> 24)) & HASH_MAX;
00445         }
00446       instance_data *getHashEntry(T const *instance) {
00447         instance_data *data = Instances[hash(instance)];
00448         while (data) {
00449           if (data->Instance == instance) return data;
00450           data = data->Next;
00451           }
00452         
00453         // not found, add new at front
00454         instance_data *link = Instances[hash(instance)];
00455         data = new instance_data;
00456         
00457         data->Instance = instance;
00458         data->ReferenceCount = 0;
00459         data->NoFreeReferenceCount = 0;
00460         data->Previous = NULL;
00461         data->Next = link;
00462         if (link) link->Previous = data;
00463         Instances[hash(instance)] = data;
00464         return data;
00465         }
00466       void removeHashEntry(instance_data *data) {
00467         instance_data *prev = data->Previous;
00468         if (prev) {
00469           prev->Next = data->Next;
00470           if (data->Next) data->Next->Previous = prev;
00471           delete data;
00472           }
00473         else {
00474           Instances[hash(data->Instance)] = data->Next;
00475           if (data->Next) data->Next->Previous = NULL;
00476           delete data;
00477           }
00478         }
00479     };
00480 
00481 
00482 
00483 
00484   #define IXLIB_GARBAGE_DECLARE_MANAGER(TYPE) \
00485     ixion::reference_manager<TYPE> ixion::reference_manager_keeper<TYPE>::Manager;
00486   }
00487 
00488 
00489 
00490 
00491 #endif

Generated on Wed Oct 31 17:12:24 2001 for ixlib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001