00001
00002
00003
00004
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
00056 bool operator==(ref_base const &op2) const {
00057 return Instance == op2.Instance;
00058 }
00059
00060
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
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
00095
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
00126
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
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
00200
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
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
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
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
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
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
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
00404
00405
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
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