00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifndef CEYLAN_COUNTED_POINTER_H_
00028 #define CEYLAN_COUNTED_POINTER_H_
00029
00030
00031 #include "CeylanTypes.h"
00032 #include "CeylanTextDisplayable.h"
00033
00034
00035
00036 #include <string>
00037
00038
00039
00060
00061
00062
00063
00064
00065
00066
00067
00068 #define CEYLAN_COUNTED_POINTER_USE_COPY_ON_WRITE 0
00069
00070
00071
00072
00073 #define CEYLAN_COUNTED_POINTER_DEBUG 0
00074
00075
00076 #ifdef CEYLAN_COUNTED_POINTER_DEBUG
00077
00078 #include <iostream>
00079
00080 #define CEYLAN_DISPLAY_REFCOUNT(message) std::cout << "[CountedPointer] " << message << std::endl ;
00081
00082 #else // CEYLAN_COUNTED_POINTER_DEBUG
00083
00084 #define CEYLAN_DISPLAY_REFCOUNT(message)
00085
00086 #endif // CEYLAN_COUNTED_POINTER_DEBUG
00087
00088
00089
00090
00091 namespace Ceylan
00092 {
00093
00094
00095
00097 typedef Ceylan::Uint32 ReferenceCount ;
00098
00099
00100
00153 template< typename T >
00154 class CountedPointer : public Ceylan::TextDisplayable
00155 {
00156
00157
00158
00159
00160
00161 public:
00162
00163
00165 typedef T ElementType ;
00166
00167
00168
00185 CountedPointer( ElementType * resourcePointer = 0 )
00186 {
00187
00188
00189 static Referent staticRef( 0,
00190 1 ) ;
00191
00192 setReferent( ( resourcePointer == 0 ) ?
00193 &staticRef : new Referent( resourcePointer ) ) ;
00194
00195 }
00196
00197
00198
00206 CountedPointer( const CountedPointer<T> & source ) :
00207 Ceylan::TextDisplayable()
00208 {
00209
00210 setReferent( source._referent ) ;
00211
00212 }
00213
00214
00215
00226 CountedPointer<T> & operator=( const CountedPointer<T> & source )
00227 {
00228
00229 if ( _referent != source._referent )
00230 {
00231
00232 reset( source._referent ) ;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 return * this ;
00242
00243 }
00244
00245
00246
00255 ~CountedPointer() throw()
00256 {
00257
00258 release() ;
00259
00260 }
00261
00262
00263
00269 ElementType & operator*() const
00270 {
00271
00272 return * get() ;
00273
00274 }
00275
00276
00277
00282 ElementType * operator->() const
00283 {
00284
00285 return get() ;
00286
00287 }
00288
00289
00290
00295 ElementType * get() const
00296 {
00297
00298 return _referent->_resourcePointer ;
00299
00300 }
00301
00302
00303
00309 bool isUnique() const
00310 {
00311
00312 return ( _referent->_refCount == 1 ) ;
00313
00314 }
00315
00316
00317
00322 ReferenceCount getReferenceCount() const
00323 {
00324
00325 return _referent->_refCount ;
00326
00327 }
00328
00329
00330
00337 virtual const std::string toString( VerbosityLevels level = high )
00338 const
00339 {
00340
00341 if ( _referent != 0 )
00342 {
00343
00344 std::string res = "Counted pointer keeping track of "
00345 + Ceylan::toString( _referent->_refCount )
00346 + " reference(s) to its wrapped resource" ;
00347
00348 if ( level == Ceylan::low )
00349 return res ;
00350
00351 if ( _referent->_resourcePointer == 0 )
00352 return res + ", which is a null pointer (abnormal)" ;
00353 else
00354 return res + ", which is: " +
00355 _referent->_resourcePointer->toString( level ) ;
00356
00357 }
00358 else
00359 {
00360 return "Counted pointer with no resource referenced" ;
00361 }
00362
00363 }
00364
00365
00366 #if CEYLAN_COUNTED_POINTER_USE_COPY_ON_WRITE
00367
00368
00381 void isolate()
00382 {
00383
00384 if ( isUnique() )
00385 {
00386
00387
00388 return ;
00389
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 ElementType * newElement = new ElementType( * get() ) ;
00410
00411
00412 try
00413 {
00414
00415
00416
00417
00418
00419
00420 reset( new Referent( newElement ) ) ;
00421
00422 }
00423 catch( ... )
00424 {
00425
00426 delete newElement ;
00427
00428
00429 throw ;
00430
00431 }
00432
00433 }
00434
00435
00436 #endif // CEYLAN_COUNTED_POINTER_USE_COPY_ON_WRITE
00437
00438
00439
00441
00442
00443 private:
00444
00445
00447 struct Referent
00448 {
00449
00450
00451
00452
00453
00462 Referent( ElementType * resourcePointer = 0,
00463 ReferenceCount initialCount = 0 ):
00464 _resourcePointer( resourcePointer ),
00465 _refCount( initialCount )
00466 {
00467
00468 CEYLAN_DISPLAY_REFCOUNT(
00469 "after referent construction, refcount = " << _refCount ) ;
00470
00471 }
00472
00473
00474 ~Referent() throw()
00475 {
00476
00477
00478 delete _resourcePointer ;
00479
00480 }
00481
00482
00483
00484
00485
00486
00488 ElementType * _resourcePointer ;
00489
00490
00492 ReferenceCount _refCount ;
00493
00494
00495 } * _referent ;
00496
00497
00498
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00518 void reset( Referent * refPointer )
00519 {
00520
00521
00522
00523 release() ;
00524 setReferent( refPointer ) ;
00525
00526 }
00527
00528
00529
00535 void setReferent( Referent * refPointer )
00536 {
00537
00538
00539
00540 ( _referent = refPointer )->_refCount++ ;
00541
00542 CEYLAN_DISPLAY_REFCOUNT( "after setReferent, refcount = "
00543 << _referent->_refCount ) ;
00544
00545 }
00546
00547
00548
00554 void release()
00555 {
00556
00557
00558
00559 if ( --_referent->_refCount == 0 )
00560 {
00561
00562 CEYLAN_DISPLAY_REFCOUNT( "after release, refcount is null, "
00563 "deallocating resource" ) ;
00564
00565
00566 delete _referent ;
00567 _referent = 0 ;
00568
00569 }
00570 else
00571 {
00572
00573 CEYLAN_DISPLAY_REFCOUNT( "after release, refcount = "
00574 << _referent->_refCount ) ;
00575 }
00576
00577 }
00578
00579
00580
00581 } ;
00582
00583
00584
00585 }
00586
00587
00588
00589 #endif // CEYLAN_COUNTED_POINTER_H_
00590