Main Page | Namespace List | Class Hierarchy | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages

Contexts.hh

Go to the documentation of this file.
00001 #ifndef NO_PTR_CONTEXTS_H
00002 #define NO_PTR_CONTEXTS_H
00003 
00023 #include "SegmentNode.hh" // typedef template param
00024 #include "ChainNode.hh" // typedef template param
00025 
00026 namespace NoPtr
00027 {
00028     namespace NoPtrImpl
00029     {
00030 
00031     /*  The default context for DynObj is the "no context", i.e. 
00032         a DynObj in a class or function, but not in a container.
00033         It basically does nothing, has no data, etc and should 
00034         be completely optimized away by compiler.
00035         */
00036     class DefaultDynObjContext
00037     {
00038         protected:
00039             DefaultDynObjContext() {}
00040            ~DefaultDynObjContext() {}
00041             // When free, we are always the sole owner
00042             bool soleOwner() const {return true;}
00043             void swap(DefaultDynObjContext&) {}
00044             // don't define checkCopyable();
00045             // so that a compile error is generated instead of assert
00046             
00047         private:
00048             void operator=(const DefaultDynObjContext&); // not allowed
00049             DefaultDynObjContext(const DefaultDynObjContext&); // not allowed
00050     };
00051          
00052     /*  This context represents the "inside a value container" context. 
00053         It allows shallow copy of DynObj by keeping track, via the 
00054         use of a chain node (template parameter ChainType) that 
00055         gets linked when the context is copied. This way, the DynObj
00056         knows if it should delete its pointer when destroyed by 
00057         calling soleOwner(), which will return true only if the 
00058         DynObj isn't currently sharing the DAO with any other DynObj.
00059         Note that it is up to DynObj to enforce that its methods 
00060         are called only when soleOwner() is true. 
00061         */
00062     template <class ChainType>   
00063     class InValueContainer
00064     {
00065         protected:
00066             InValueContainer() {}
00067            ~InValueContainer() {}
00068             InValueContainer(const InValueContainer& rhs)
00069                 : _chainNode(rhs._chainNode) {}
00070             InValueContainer& operator=(const InValueContainer& rhs)
00071             {
00072                 _chainNode.connect(rhs._chainNode);
00073                 return *this;
00074             }
00075             void swap(InValueContainer& rhs) 
00076             {
00077                 _chainNode.swap(rhs._chainNode);
00078             }
00079             
00080             // we're the sole owner only if chain not connected to anything else
00081             bool soleOwner() const {return ! _chainNode.isConnected();}
00082             // this is a way of getting compilation to fail if context 
00083             // does not allow shallow copying
00084             static void checkCopyable() {}
00085             
00086         private:
00087             // This is not state, just technique
00088             mutable ChainType _chainNode;
00089     };
00090     
00091     typedef size_t RefCount;
00092     
00093     /*  Most generic implementation of "inside a value-based
00094         container"  context, i.e. using reference count. This will be
00095         the default  non-free context implementation, but if you know
00096         that  one of the other ones will work you can get speed gains 
00097         by using InValueContainer<Segment> or
00098         InValueContainer<ChainNode>.
00099 
00100         Implementation note: the ref count is allocated at construction
00101         of the context object. This saves on several checks for
00102         nullness that would have to be done if it were created only
00103         when used the  first time. Moreover, this context implies that
00104         an object created  will require copy almost immediately e.g.
00105         during insertion so  in practice the case of allocating the
00106         count and not making use  of it is much more seldom than the
00107         reverse situation. */
00108     template <>   
00109     class InValueContainer<RefCount>
00110     {
00111         protected:
00112             InValueContainer(): _sharedOwnerCount(new RefCount(1)) {}
00113             InValueContainer(const InValueContainer& rhs)
00114                 : _sharedOwnerCount(rhs._sharedOwnerCount) 
00115             {
00116                 (*_sharedOwnerCount) ++;
00117             }
00118             void operator=(const InValueContainer& rhs) 
00119             {
00120                 clearCount();
00121                 _sharedOwnerCount = rhs._sharedOwnerCount;
00122                 (*_sharedOwnerCount) ++;
00123             }
00124             
00125            ~InValueContainer() 
00126             {
00127                 clearCount();
00128             }
00129             
00130             void swap(InValueContainer& rhs) 
00131             {
00132                 std::swap(_sharedOwnerCount, rhs._sharedOwnerCount);
00133             }
00134            
00135             bool soleOwner() const 
00136             {
00137                 return ((*_sharedOwnerCount) == 1);
00138             }
00139             // this is a way of getting compilation to fail if context 
00140             // does not allow shallow copying
00141             static void checkCopyable() {}
00142             
00143         private:
00144             void clearCount() 
00145             {
00146                 if ((--(*_sharedOwnerCount)) <= 0) 
00147                     delete _sharedOwnerCount;
00148             }
00149             
00150         private:
00151             RefCount* _sharedOwnerCount;
00152     };
00153     
00154     /* This used to be InValueContainer<RefCount> but was found to 
00155        have 10% less performance than current implementation. 
00156        This is because when the _sharedOwnerCount is initialized 
00157        only when used, there are several checks for nullness that 
00158        must be included. Creating the count upon construction 
00159        has the potential overhead that the count is not used, but
00160        in practice it is still better the old implementation.
00161         */
00162     template <>   
00163     class InValueContainer<void>
00164     {
00165         protected:
00166             InValueContainer(): _sharedOwnerCount(NullPtr) {}
00167             InValueContainer(const InValueContainer& rhs)
00168                 : _sharedOwnerCount(rhs.getCount()) 
00169             {
00170                 (*_sharedOwnerCount) ++;
00171             }
00172             void operator=(const InValueContainer& rhs) 
00173             {
00174                 clearCount();
00175                 _sharedOwnerCount = rhs.getCount();
00176                 (*_sharedOwnerCount) ++;
00177             }
00178             
00179            ~InValueContainer() 
00180             {
00181                 clearCount();
00182             }
00183             
00184             void swap(InValueContainer& rhs) 
00185             {
00186                 std::swap(_sharedOwnerCount, rhs._sharedOwnerCount);
00187             }
00188            
00189             bool soleOwner() const 
00190             {
00191                 return ((_sharedOwnerCount == NullPtr) 
00192                         || (*_sharedOwnerCount) == 1);
00193             }
00194             // this is a way of getting compilation to fail if context 
00195             // does not allow shallow copying
00196             static void checkCopyable() {}
00197             
00198         private:
00199             RefCount* getCount() const 
00200             {
00201                 if (!_sharedOwnerCount) 
00202                     const_cast<RefCount*&>(_sharedOwnerCount) = new RefCount(1);
00203                     //_sharedOwnerCount = new RefCount(1);
00204                 return _sharedOwnerCount;
00205             }
00206             void clearCount() 
00207             {
00208                 if (_sharedOwnerCount && (--(*_sharedOwnerCount)) <= 0) 
00209                     delete _sharedOwnerCount;
00210             }
00211             
00212         private:
00213             RefCount* _sharedOwnerCount;
00214     };
00215     
00216     } // implementation namespace
00217     
00218 } // namespace
00219 
00220 #endif // NO_PTR_CONTEXTS_H    

Generated on Mon Aug 4 18:51:23 2003 for NoPtr C++ Library by doxygen 1.3.2