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 #include "CeylanOperators.h"
00034
00035
00036
00037 #include <string>
00038
00039
00040
00061
00062
00063
00064
00065
00066
00067
00068
00069 #define CEYLAN_COUNTED_POINTER_USE_COPY_ON_WRITE 0
00070
00071
00072
00073
00074 #define CEYLAN_COUNTED_POINTER_DEBUG 0
00075
00076
00077
00078 #if CEYLAN_COUNTED_POINTER_DEBUG
00079
00080 #include <iostream>
00081
00082 #define CEYLAN_DISPLAY_REFCOUNT(message) std::cout << "[CountedPointer] " << message << std::endl ;
00083
00084 #else // CEYLAN_COUNTED_POINTER_DEBUG
00085
00086 #define CEYLAN_DISPLAY_REFCOUNT(message)
00087
00088 #endif // CEYLAN_COUNTED_POINTER_DEBUG
00089
00090
00091
00092
00093 namespace Ceylan
00094 {
00095
00096
00097
00099 typedef Ceylan::Uint32 ReferenceCount ;
00100
00101
00102
00160 template< typename T >
00161 class CountedPointer : public Ceylan::TextDisplayable
00162 {
00163
00164
00165
00166
00167
00168 public:
00169
00170
00172 typedef T ElementType ;
00173
00174
00175
00192 CountedPointer( ElementType * resourcePointer = 0 )
00193 {
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 static Referent staticRef( 0,
00205 1 ) ;
00206
00207 setReferent( ( resourcePointer == 0 ) ?
00208 &staticRef : new Referent( resourcePointer ) ) ;
00209
00210 }
00211
00212
00213
00221 CountedPointer( const CountedPointer<T> & source ) :
00222 Ceylan::TextDisplayable()
00223 {
00224
00225 setReferent( source._referent ) ;
00226
00227 }
00228
00229
00230
00241 CountedPointer<T> & operator=( const CountedPointer<T> & source )
00242 {
00243
00244 if ( _referent != source._referent )
00245 {
00246
00247 reset( source._referent ) ;
00248 }
00249
00250
00251
00252
00253
00254
00255
00256 return * this ;
00257
00258 }
00259
00260
00261
00270 ~CountedPointer() throw()
00271 {
00272
00273 release() ;
00274
00275 }
00276
00277
00278
00284 ElementType & operator*() const
00285 {
00286
00287 return * get() ;
00288
00289 }
00290
00291
00292
00297 ElementType * operator->() const
00298 {
00299
00300 return get() ;
00301
00302 }
00303
00304
00305
00310 ElementType * get() const
00311 {
00312
00313 return _referent->_resourcePointer ;
00314
00315 }
00316
00317
00318
00324 bool isUnique() const
00325 {
00326
00327 return ( _referent->_refCount == 1 ) ;
00328
00329 }
00330
00331
00332
00337 ReferenceCount getReferenceCount() const
00338 {
00339
00340 return _referent->_refCount ;
00341
00342 }
00343
00344
00345
00352 virtual const std::string toString( VerbosityLevels level = high )
00353 const
00354 {
00355
00356 if ( _referent != 0 )
00357 {
00358
00359 std::string res = "Counted pointer keeping track of "
00360 + Ceylan::toString( _referent->_refCount )
00361 + " reference(s) to its wrapped resource ("
00362 + Ceylan::toString( _referent->_resourcePointer )
00363 + ")" ;
00364
00365 if ( level == Ceylan::low )
00366 return res ;
00367
00368 if ( _referent->_resourcePointer == 0 )
00369 return res + ", which is a null pointer (abnormal)" ;
00370 else
00371 return res + ", which is: " +
00372 _referent->_resourcePointer->toString( level ) ;
00373
00374 }
00375 else
00376 {
00377 return "Counted pointer with no resource referenced" ;
00378 }
00379
00380 }
00381
00382
00383 #if CEYLAN_COUNTED_POINTER_USE_COPY_ON_WRITE
00384
00385
00398 void isolate()
00399 {
00400
00401 if ( isUnique() )
00402 {
00403
00404
00405 return ;
00406
00407 }
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 ElementType * newElement = new ElementType( * get() ) ;
00427
00428
00429 try
00430 {
00431
00432
00433
00434
00435
00436
00437 reset( new Referent( newElement ) ) ;
00438
00439 }
00440 catch( ... )
00441 {
00442
00443 delete newElement ;
00444
00445
00446 throw ;
00447
00448 }
00449
00450 }
00451
00452
00453 #endif // CEYLAN_COUNTED_POINTER_USE_COPY_ON_WRITE
00454
00455
00456
00457
00458
00460
00461
00462 private:
00463
00464
00466 struct Referent
00467 {
00468
00469
00470
00471
00472
00481 Referent( ElementType * resourcePointer = 0,
00482 ReferenceCount initialCount = 0 ):
00483 _resourcePointer( resourcePointer ),
00484 _refCount( initialCount )
00485 {
00486
00487 CEYLAN_DISPLAY_REFCOUNT(
00488 "after referent construction for resource pointer "
00489 << Ceylan::toString( _resourcePointer )
00490 << ", refcount = " << _refCount ) ;
00491
00492 }
00493
00494
00495 ~Referent() throw()
00496 {
00497
00498 CEYLAN_DISPLAY_REFCOUNT(
00499 "referent destructor deallocating its resource "
00500 << Ceylan::toString( _resourcePointer ) ) ;
00501
00502
00503 delete _resourcePointer ;
00504
00505 }
00506
00507
00508
00509
00510
00511
00513 ElementType * _resourcePointer ;
00514
00515
00517 ReferenceCount _refCount ;
00518
00519
00520 } * _referent ;
00521
00522
00523
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00543 void reset( Referent * refPointer )
00544 {
00545
00546
00547
00548 release() ;
00549 setReferent( refPointer ) ;
00550
00551 }
00552
00553
00554
00560 void setReferent( Referent * refPointer )
00561 {
00562
00563
00564
00565 ( _referent = refPointer )->_refCount++ ;
00566
00567 CEYLAN_DISPLAY_REFCOUNT( "after setReferent, refcount = "
00568 << _referent->_refCount << " for "
00569 << Ceylan::toString( _referent->_resourcePointer ) ) ;
00570
00571 }
00572
00573
00574
00580 void release()
00581 {
00582
00583
00584
00585 if ( --_referent->_refCount == 0 )
00586 {
00587
00588 CEYLAN_DISPLAY_REFCOUNT( "after release, refcount is null, "
00589 "deallocating resource "
00590 << Ceylan::toString( _referent->_resourcePointer ) ) ;
00591
00592
00593 delete _referent ;
00594 _referent = 0 ;
00595
00596 }
00597 else
00598 {
00599
00600 CEYLAN_DISPLAY_REFCOUNT( "after release, refcount = "
00601 << _referent->_refCount << " for "
00602 << Ceylan::toString( _referent->_resourcePointer ) ) ;
00603 }
00604
00605 }
00606
00607
00608
00609 } ;
00610
00611
00612
00613 }
00614
00615
00616
00617 #endif // CEYLAN_COUNTED_POINTER_H_
00618