sharedptr.h

Go to the documentation of this file.
00001 /*
00002 **  ClanLib SDK
00003 **  Copyright (c) 1997-2009 The ClanLib Team
00004 **
00005 **  This software is provided 'as-is', without any express or implied
00006 **  warranty.  In no event will the authors be held liable for any damages
00007 **  arising from the use of this software.
00008 **
00009 **  Permission is granted to anyone to use this software for any purpose,
00010 **  including commercial applications, and to alter it and redistribute it
00011 **  freely, subject to the following restrictions:
00012 **
00013 **  1. The origin of this software must not be misrepresented; you must not
00014 **     claim that you wrote the original software. If you use this software
00015 **     in a product, an acknowledgment in the product documentation would be
00016 **     appreciated but is not required.
00017 **  2. Altered source versions must be plainly marked as such, and must not be
00018 **     misrepresented as being the original software.
00019 **  3. This notice may not be removed or altered from any source distribution.
00020 **
00021 **  Note: Some of the libraries ClanLib may link to may have additional
00022 **  requirements or restrictions.
00023 **
00024 **  File Author(s):
00025 **
00026 **    Magnus Norddahl
00027 */
00028 
00031 
00032 
00033 #pragma once
00034 
00035 
00036 #include "../api_core.h"
00037 #include "system.h"
00038 #include "mutex.h"
00039 #include "exception.h"
00040 #include "memory_pool.h"
00041 
00042 #ifndef WIN32
00043 #include <cstring>
00044 #endif
00045 
00048 class CL_API_CORE CL_SharedPtr_Impl
00049 {
00050 public:
00051         virtual ~CL_SharedPtr_Impl() { return; }
00052 };
00053 
00056 template <typename Type>
00057 class CL_SharedPtr_Deleter
00058 {
00059 public:
00060         CL_SharedPtr_Deleter(Type *instance) : instance(instance) { return; }
00061 
00062         virtual ~CL_SharedPtr_Deleter() { delete instance; }
00063 
00064         Type *instance;
00065 };
00066 
00069 template <typename Type>
00070 class CL_SharedPtr_DeleterPool
00071 {
00072 public:
00073         CL_SharedPtr_DeleterPool(Type *instance, CL_MemoryPool *pool)
00074         : instance(instance), pool(pool) { return; }
00075 
00076         virtual ~CL_SharedPtr_DeleterPool() { instance->~Type(); operator delete(instance, pool); }
00077 
00078         Type *instance;
00079 
00080         CL_MemoryPool *pool;
00081 };
00082 
00085 template <typename Type>
00086 class CL_SharedPtr_DeleterCallback
00087 {
00088 public:
00089         CL_SharedPtr_DeleterCallback(Type *instance, void (*free_callback)(Type *))
00090         : instance(instance), free_callback(free_callback) { return; }
00091 
00092         virtual ~CL_SharedPtr_DeleterCallback() { free_callback(instance); }
00093 
00094         Type *instance;
00095 
00096         void (*free_callback)(Type *);
00097 };
00098 
00101 template <typename Type, typename FreeClass>
00102 class CL_SharedPtr_DeleterClassCallback
00103 {
00104 public:
00105         CL_SharedPtr_DeleterClassCallback(Type *instance, FreeClass *free_class, void (FreeClass::*free_callback)(Type *))
00106         : instance(instance), free_class(free_class), free_callback(free_callback) { return; }
00107 
00108         virtual ~CL_SharedPtr_DeleterClassCallback() { (free_class->*free_callback)(instance); }
00109 
00110         Type *instance;
00111 
00112         FreeClass *free_class;
00113 
00114         void (FreeClass::*free_callback)(Type *);
00115 };
00116 
00117 // This was set to 32. This should have been enough for 4 pointers (including VTBL) of 64 bit size
00118 // However, due to compiler issues, in the following example:
00119 //      class X { void (*funx)(void); };
00120 //      class Z { void (X::*funx)(void); };
00121 // Using gcc 4.1.2 on a 64 bit machine:
00122 // sizeof(class X) = 8
00123 // sizeof(class Z) = 16
00124 //
00125 // See: http://www.codeproject.com/cpp/FastDelegate.asp
00126 // "Implementations of Member Function Pointers"
00127 // This has a table showning the various sizeof() operators for various function pointers on various compilers
00128 //
00129 // So, a "safer" option was chosen .. use sizeof((CL_SharedPtr_DeleterClassCallback<int,CL_MemoryPool>)
00130 // Where CL_SharedPtr_DeleterClassCallback contains the greatest number of template pointers
00131 // and CL_MemoryPool is an example class to use for the template.
00132 // (Modified by rombust 21 May 2007)
00133 #define CL_DELETER_SIZE (sizeof(CL_SharedPtr_DeleterClassCallback<int,CL_MemoryPool>))
00134 
00137 class CL_API_CORE CL_SharedPtr_Link
00138 {
00139 public:
00140         CL_SharedPtr_Link()
00141         : mutex(0), prev(0), next(0), weak_link(0)
00142         {
00143         }
00144 
00145         CL_SharedPtr_Link(const CL_SharedPtr_Link &copy)
00146         : mutex(0), prev(0), next(0), weak_link(0)
00147         {
00148                 connect(copy);
00149         }
00150 
00151         ~CL_SharedPtr_Link()
00152         {
00153                 if (prev != 0 || next != 0)
00154                         disconnect();
00155                 /*
00156                 mutex = (CL_Mutex *) 0xfdfdfdfd;
00157                 prev = (CL_SharedPtr_Link *) 0xfdfdfdfd;
00158                 next = (CL_SharedPtr_Link *) 0xfdfdfdfd;
00159                 memset(deleter, 0xfd, CL_DELETER_SIZE);
00160                 weak_link = 0xfd;
00161                 */
00162         }
00163 
00164         CL_SharedPtr_Link &operator =(const CL_SharedPtr_Link &copy)
00165         {
00166                 if (this != &copy)
00167                 {
00168                         disconnect();
00169                         connect(copy);
00170                 }
00171                 return *this;
00172         }
00173 
00174         template <typename Type>
00175         void create_deleter(Type *instance)
00176         {
00177                 #ifdef DEBUG_SHAREDPTR
00178                         if (sizeof(CL_SharedPtr_Deleter<Type>) > CL_DELETER_SIZE)
00179                                 throw CL_Exception("CL_DELETER_SIZE buffer too small!");
00180                 #endif
00181                 CL_SharedPtr_Deleter<Type> *d = (CL_SharedPtr_Deleter<Type> *) deleter;
00182                 CL_System::call_constructor(d, instance);
00183         }
00184 
00185         template <typename Type>
00186         void create_deleter(Type *ptr, CL_MemoryPool *pool)
00187         {
00188                 #ifdef DEBUG_SHAREDPTR
00189                         if (sizeof(CL_SharedPtr_DeleterPool<Type>) > CL_DELETER_SIZE)
00190                                 throw CL_Exception("CL_DELETER_SIZE buffer too small!");
00191                 #endif
00192                 CL_SharedPtr_DeleterPool<Type> *d = (CL_SharedPtr_DeleterPool<Type> *) deleter;
00193                 CL_System::call_constructor(d, ptr, pool);
00194         }
00195 
00196         template <typename Type>
00197         void create_deleter(Type *ptr, void (*free_callback)(Type *ptr))
00198         {
00199                 #ifdef DEBUG_SHAREDPTR
00200                         if (sizeof(CL_SharedPtr_DeleterCallback<Type>) > CL_DELETER_SIZE)
00201                                 throw CL_Exception("CL_DELETER_SIZE buffer too small!");
00202                 #endif
00203                 CL_SharedPtr_DeleterCallback<Type> *d = (CL_SharedPtr_DeleterCallback<Type> *) deleter;
00204                 CL_System::call_constructor(d, ptr, free_callback);
00205         }
00206 
00207         template <typename Type, typename FreeClass>
00208         void create_deleter(Type *ptr, FreeClass *free_class, void (FreeClass::*free_callback)(Type *ptr))
00209         {
00210                 #ifdef DEBUG_SHAREDPTR
00211                         if (sizeof(CL_SharedPtr_DeleterClassCallback<Type, FreeClass>) > CL_DELETER_SIZE)
00212                                 throw CL_Exception("CL_DELETER_SIZE buffer too small!");
00213                 #endif
00214                 CL_SharedPtr_DeleterClassCallback<Type, FreeClass> *d = (CL_SharedPtr_DeleterClassCallback<Type, FreeClass> *) deleter;
00215                 CL_System::call_constructor(d, ptr, free_class, free_callback);
00216         }
00217 
00218         void call_deleter()
00219         {
00220                 CL_SharedPtr_Impl *d = (CL_SharedPtr_Impl *) deleter;
00221                 CL_System::call_destructor(d);
00222         }
00223 
00224         void connect(const CL_SharedPtr_Link &copy)
00225         {
00226                 CL_MutexSection mutex_lock(copy.mutex);
00227                 #ifdef DEBUG_SHAREDPTR
00228                         if (prev != 0 || next != 0)
00229                                 throw CL_Exception("Memory corruption error in CL_SharedPtr_Link");
00230                         assert_list(&copy);
00231                 #endif
00232                 mutex = copy.mutex;
00233                 next = copy.next;
00234                 prev = (CL_SharedPtr_Link *) &copy;
00235                 copy.next = this;
00236                 if (next)
00237                         next->prev = this;
00238                 memcpy(deleter, copy.deleter, CL_DELETER_SIZE);
00239                 #ifdef DEBUG_SHAREDPTR
00240                         assert_list(prev);
00241                 #endif
00242         }
00243 
00245 
00246         bool disconnect()
00247         {
00248                 CL_MutexSection mutex_lock(mutex);
00249                 #ifdef DEBUG_SHAREDPTR
00250                         assert_list(prev);
00251                 #endif
00252                 if (weak_link == 2)
00253                         weak_link = 1;
00254                 if (prev == 0 && next == 0)
00255                         return true;
00256 
00257                 if (prev)
00258                         prev->next = next;
00259                 if (next)
00260                         next->prev = prev;
00261                 #ifdef DEBUG_SHAREDPTR
00262                         assert_list(prev);
00263                 #endif
00264 
00265                 CL_SharedPtr_Link *cur = prev;
00266                 while (cur)
00267                 {
00268                         if (!cur->weak_link)
00269                         {
00270                                 prev = 0;
00271                                 next = 0;
00272                                 return false;
00273                         }
00274                         cur = cur->prev;
00275                 }
00276 
00277                 cur = next;
00278                 while (cur)
00279                 {
00280                         if (!cur->weak_link)
00281                         {
00282                                 prev = 0;
00283                                 next = 0;
00284                                 return false;
00285                         }
00286                         cur = cur->next;
00287                 }
00288 
00289                 // Ok, empty or only contains weak links.
00290                 // Invalidate all weak links:
00291 
00292                 cur = prev;
00293                 while (cur)
00294                 {
00295                         cur->weak_link = 2;
00296                         cur = cur->prev;
00297                 }
00298 
00299                 cur = next;
00300                 while (cur)
00301                 {
00302                         cur->weak_link = 2;
00303                         cur = cur->next;
00304                 }
00305 
00306                 prev = 0;
00307                 next = 0;
00308                 return true;
00309         }
00310 
00311         void set_weak_link() { weak_link = 1; }
00312 
00313         bool is_invalid_weak_link() const { return weak_link != 1; }
00314 
00315         #ifdef DEBUG_SHAREDPTR
00316                 void assert_list(const CL_SharedPtr_Link *ptr)
00317                 {
00318                         if (ptr == 0)
00319                                 return;
00320                         while (ptr->prev != 0)
00321                         {
00322                                 if (ptr->prev->next != ptr)
00323                                         throw CL_Exception("Memory corruption error in CL_SharedPtr_Link");
00324                                 ptr = ptr->prev;
00325                         }
00326                         while (ptr && ptr->next)
00327                         {
00328                                 if (ptr->next->prev != ptr)
00329                                         throw CL_Exception("Memory corruption error in CL_SharedPtr_Link");
00330                                 ptr = ptr->next;
00331                         }
00332                 }
00333         #endif
00334 
00335 public:
00336         mutable CL_Mutex *mutex;
00337 
00338 private:
00339         mutable CL_SharedPtr_Link *prev;
00340 
00341         mutable CL_SharedPtr_Link *next;
00342 
00343         char deleter[CL_DELETER_SIZE];
00344 
00345         unsigned char weak_link;
00346 };
00347 
00351 class CL_API_CORE CL_UnknownSharedPtr : public CL_SharedPtr_Link
00352 {
00353 public:
00354         CL_UnknownSharedPtr()
00355         : ptr(0)
00356         {
00357         }
00358 
00359         CL_UnknownSharedPtr(const CL_SharedPtr_Link &link, void *ptr)
00360         : ptr(ptr)
00361         {
00362                 connect(link);
00363         }
00364 
00365         CL_UnknownSharedPtr(const CL_UnknownSharedPtr &copy)
00366         : ptr(0)
00367         {
00368                 connect(copy);
00369                 ptr = copy.ptr;
00370         }
00371 
00372         ~CL_UnknownSharedPtr()
00373         {
00374                 disconnect();
00375         }
00376 
00377         CL_UnknownSharedPtr &operator =(const CL_UnknownSharedPtr &copy)
00378         {
00379                 if (this == &copy)
00380                         return *this;
00381                 disconnect();
00382                 connect(copy);
00383                 ptr = copy.ptr;
00384                 return *this;
00385         }
00386 
00388 
00390         bool disconnect()
00391         {
00392                 bool result = CL_SharedPtr_Link::disconnect();
00393                 if ( result && ptr )
00394                 {
00395                         call_deleter();
00396                 }
00397                 ptr = NULL;
00398                 return result;
00399         }
00400 
00402 
00403         bool is_null() const { return ptr == 0; }
00404 
00406 
00407         void *get() { return ptr; }
00408 
00410 
00411         const void *get() const { return ptr; }
00412 
00413         operator void *() { return ptr; }
00414 
00415         operator const void *() const { return ptr; }
00416 
00417         void *operator ->() { return ptr; }
00418 
00419         const void *operator ->() const { return ptr; }
00420 
00421         template <typename OtherType>
00422         bool operator ==(OtherType *other) const { return ptr == other; }
00423 
00424         template <typename OtherType>
00425         bool operator !=(OtherType *other) const { return ptr != other; }
00426 
00427         template <typename OtherType>
00428         bool operator <(OtherType *other) const { return ptr < other; }
00429 
00430         template <typename OtherType>
00431         bool operator <=(OtherType *other) const { return ptr <= other; }
00432 
00433         template <typename OtherType>
00434         bool operator >(OtherType *other) const { return ptr > other; }
00435 
00436         template <typename OtherType>
00437         bool operator >=(OtherType *other) const { return ptr >= other; }
00438 
00439 public:
00440         void *ptr;
00441 };
00442 
00446 template <typename Type>
00447 class CL_SharedPtr : public CL_SharedPtr_Link
00448 {
00449 public:
00450         CL_SharedPtr()
00451         : ptr(0)
00452         {
00453         }
00454 
00455         CL_SharedPtr(const CL_SharedPtr<Type> &copy)
00456         : ptr(0)
00457         {
00458                 connect(copy);
00459                 ptr = copy.ptr;
00460         }
00461 
00462         explicit CL_SharedPtr(const CL_UnknownSharedPtr &copy)
00463         : ptr(0)
00464         {
00465                 connect(copy);
00466                 ptr = (Type *) copy.ptr;
00467         }
00468 
00469         template <typename InitType>
00470         explicit CL_SharedPtr(InitType *ptr)
00471         : ptr(ptr)
00472         {
00473                 mutex = CL_System::get_sharedptr_mutex();
00474                 if (ptr)
00475                         create_deleter(ptr);
00476         }
00477 
00478         template <typename InitType>
00479         explicit CL_SharedPtr(InitType *ptr, CL_Mutex *ref_mutex)
00480         : ptr(ptr)
00481         {
00482                 mutex = ref_mutex;
00483                 if (ptr)
00484                         create_deleter(ptr);
00485         }
00486 
00487         template <typename InitType>
00488         explicit CL_SharedPtr(InitType *ptr, CL_MemoryPool *memory_pool)
00489         : ptr(ptr)
00490         {
00491                 mutex = CL_System::get_sharedptr_mutex();
00492                 if (ptr)
00493                         create_deleter(ptr, memory_pool);
00494         }
00495 
00496         template <typename InitType>
00497         explicit CL_SharedPtr(InitType *ptr, CL_MemoryPool *memory_pool, CL_Mutex *ref_mutex)
00498         : ptr(ptr)
00499         {
00500                 mutex = ref_mutex;
00501                 if (ptr)
00502                         create_deleter(ptr, memory_pool);
00503         }
00504 
00505         template <typename InitType>
00506         explicit CL_SharedPtr(InitType *ptr, void (*free_callback)(InitType *ptr))
00507         : ptr(ptr)
00508         {
00509                 mutex = CL_System::get_sharedptr_mutex();
00510                 if (ptr)
00511                         create_deleter(ptr, free_callback);
00512         }
00513 
00514         template <typename InitType>
00515         explicit CL_SharedPtr(InitType *ptr, void (*free_callback)(InitType *ptr), CL_Mutex *ref_mutex)
00516         : ptr(ptr)
00517         {
00518                 mutex = ref_mutex;
00519                 if (ptr)
00520                         create_deleter(ptr, free_callback);
00521         }
00522 
00523         template <typename InitType, typename FreeClass>
00524         explicit CL_SharedPtr(InitType *ptr, FreeClass *free_class, void (FreeClass::*free_callback)(InitType *ptr))
00525         : ptr(ptr)
00526         {
00527                 mutex = CL_System::get_sharedptr_mutex();
00528                 if (ptr)
00529                         create_deleter(ptr, free_class, free_callback);
00530         }
00531 
00532         template <typename InitType, typename FreeClass>
00533         explicit CL_SharedPtr(InitType *ptr, FreeClass *free_class, void (FreeClass::*free_callback)(InitType *ptr), CL_Mutex *ref_mutex)
00534         : ptr(ptr)
00535         {
00536                 mutex = ref_mutex;
00537                 if (ptr)
00538                         create_deleter(ptr, free_class, free_callback);
00539         }
00540 
00541         CL_SharedPtr(const CL_SharedPtr_Link &link, Type *ptr)
00542         : ptr(ptr)
00543         {
00544                 connect(link);
00545         }
00546 
00547         ~CL_SharedPtr()
00548         {
00549                 disconnect();
00550         }
00551 
00552         CL_SharedPtr &operator =(const CL_SharedPtr &copy)
00553         {
00554                 if (this == &copy)
00555                         return *this;
00556                 disconnect();
00557                 connect(copy);
00558                 ptr = copy.ptr;
00559                 return *this;
00560         }
00561 
00563 
00565         bool disconnect()
00566         {
00567                 bool result = CL_SharedPtr_Link::disconnect();
00568                 if ( result && ptr )
00569                 {
00570                         call_deleter();
00571                 }
00572                 ptr = NULL;
00573                 return result;
00574         }
00575 
00577 
00578         bool is_null() const { return ptr == 0; }
00579 
00581 
00582         Type *get() { return ptr; }
00583 
00585 
00586         const Type *get() const { return ptr; }
00587 
00588         operator Type *() { return ptr; }
00589 
00590         operator const Type *() const { return ptr; }
00591 
00592         operator CL_UnknownSharedPtr() { return CL_UnknownSharedPtr(*this, ptr); }
00593 
00594         operator CL_UnknownSharedPtr() const { return CL_UnknownSharedPtr(*this, (Type *) ptr); }
00595 
00596         Type *operator ->() { return ptr; }
00597 
00598         const Type *operator ->() const { return ptr; }
00599 
00600         template <typename OtherType>
00601         bool operator ==(OtherType *other) const { return ptr == other; }
00602 
00603         template <typename OtherType>
00604         bool operator !=(OtherType *other) const { return ptr != other; }
00605 
00606         template <typename OtherType>
00607         bool operator <(OtherType *other) const { return ptr < other; }
00608 
00609         template <typename OtherType>
00610         bool operator <=(OtherType *other) const { return ptr <= other; }
00611 
00612         template <typename OtherType>
00613         bool operator >(OtherType *other) const { return ptr > other; }
00614 
00615         template <typename OtherType>
00616         bool operator >=(OtherType *other) const { return ptr >= other; }
00617 
00618 public:
00619         Type *ptr;
00620 
00621 };
00622 
00623 
00624 

Generated on Thu Dec 3 02:39:31 2009 for ClanLib by  doxygen 1.4.6