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

ChainNode.hh

Go to the documentation of this file.
00001 #ifndef NO_PTR_CHAIN_NODE_2_H
00002 #define NO_PTR_CHAIN_NODE_2_H
00003 
00023 #include <assert.h>
00024 #include "NoPtrFwd.hh"
00025 #include "nullness.hh"
00026 
00027 namespace NoPtr
00028 {
00029     namespace NoPtrImpl
00030     {
00031 
00032     /* A node of a double-linked chain of segments. Only slightly 
00033        more complex conceptually than SegmentNode, yet double memory
00034        needed, and operations in general more expensive. 
00035        
00036        ChainNode arranges so that the first item is never null if 
00037        the list of two neighbor nodes is not empty. I.e., it first
00038        sets others[0] before others[1], and moves others[1] to 
00039        others[0] if others[0] gets removed. This simplifies certain
00040        algorithms. 
00041        
00042        Note that, as with SegmentNode, copy implies connection to the 
00043        \a rhs node. Unlike SegmentNode, each chain node can have two 
00044        neighbors. This means that the two examples of failures shown
00045        for SegmentNode succeed for ChainNode. Actually, ChainNode 
00046        can handle any depth of function call with pass-by-value. An
00047        example of where ChainNode would fail is:
00048        \code
00049         void func1(ChainNode cn) {
00050             ChainNode cn2(cn); 
00051             func2(cn);
00052         }
00053         void func2(ChainNode) {} // assertion fails here
00054         func1( ChainNode() );
00055         \endcode
00056        
00057        */
00058     class ChainNode
00059     {
00060         public:
00061             // default is unlinked
00062             ChainNode() {others[0] = others[1] = NullPtr;}
00063             // just connect us to \a rhs, if rhs still has free slot
00064             ChainNode(ChainNode& rhs) 
00065             {
00066                 assert(rhs.others[1] == NullPtr); 
00067                 connectBare(rhs);
00068             }
00069             // unlink self from chain
00070            ~ChainNode() {removeSelf();}
00071 
00072             // connect us to \a rhs; disconnects us first, if necessary
00073             void connect(ChainNode& rhs) 
00074             {
00075                 if (this != &rhs)
00076                 {
00077                     removeSelf();
00078                     connectBare(rhs);
00079                 }
00080             }
00081             // disconnect us from neighbor nodes
00082             void disconnect()
00083             {
00084                 removeSelf();
00085                 others[0] = others[1] = NullPtr;
00086             }
00087             // swap with another node; rather expensive op, avoid using. 
00088             void swap(ChainNode& rhs)
00089             { 
00090                 // First, swap others[0] and rhs.others[0]
00091                 ChainNode* tmp = others[0];
00092                 others[0]     = rhs.others[0];
00093                 rhs.others[0] = tmp;
00094 
00095                 // then swap others[1] and rhs.others[1]
00096                 tmp           = others[1];
00097                 others[1]     = rhs.others[1];
00098                 rhs.others[1] = tmp;
00099 
00100                 // Next, reconnect those that point to rhs to point to us
00101                 reconnect(others[0], &rhs, this);
00102                 reconnect(others[1], &rhs, this);
00103 
00104                 // Finally, reconnect those in rhs that point to us to point to rhs
00105                 reconnect(rhs.others[0], this, &rhs);
00106                 reconnect(rhs.others[1], this, &rhs);
00107             }
00108             // true if at least one neighbor node
00109             bool isConnected() const {return others[0] != NullPtr;}
00110             // Only for debugging: get neighbors
00111             const ChainNode* const * neighbors() const {return others;}
00112 
00113         private:
00114             // just connect us to \a rhs straight
00115             void connectBare(ChainNode& rhs)
00116             {
00117                 rhs.add(this);
00118                 others[0] = &rhs;
00119                 others[1] = NullPtr;
00120             }
00121             // needed by swap: connect \a other to \a nnew
00122             // instead of \a old
00123             void reconnect(ChainNode* other, 
00124                            ChainNode* old, ChainNode* nnew)
00125             {
00126                 // only if new is not the other itself!
00127                 if (other && other != nnew) other->replace(old, nnew);
00128             }
00129             // remove from neighbors list; if this requires 
00130             // reconnecting one of the two neighbors to the other
00131             // so the chain is not broken
00132             void removeSelf()
00133             {
00134                 if (others[1] != NullPtr) // replace self to not break chain
00135                 {
00136                     others[0]->replace(this, others[1]);
00137                     others[1]->replace(this, others[0]);
00138                 }
00139                 else if (others[0] != NullPtr) 
00140                     // end of chain, just remove us:
00141                     others[0]->remove(this);
00142             }
00143             // directly add \a newNode to our list of neighbors; 
00144             // asserts that slot available
00145             void add(ChainNode* newNode)
00146             {
00147                 if (others[0] == NullPtr) 
00148                 {
00149                     others[0] = newNode;
00150                     assert(others[1] == NullPtr);
00151                 }
00152                 else 
00153                 {
00154                     assert(others[1] != newNode);
00155                     others[1] = newNode;
00156                 }
00157             }
00158             // directly remove \a obsNode from our list
00159             void remove(ChainNode* obsNode)
00160             {
00161                 if (others[0] == obsNode) 
00162                 {
00163                     others[0] = others[1];
00164                     others[1] = NullPtr;
00165                 }
00166                 else
00167                 {
00168                     assert(others[1] == obsNode);
00169                     others[1] = NullPtr;
00170                 }
00171             }
00172             // replace \a obsNode with \a newNode in *this
00173             void replace(ChainNode* obsNode, ChainNode* newNode)
00174             {
00175                 if (others[0] == obsNode) 
00176                 {
00177                     others[0] = newNode;
00178                     assert(others[1] != newNode);
00179                 }
00180                 else
00181                 {
00182                     assert(others[1] == obsNode);
00183                     others[1] = newNode;
00184                 }
00185             }
00186 
00187         private:
00188             ChainNode(const ChainNode&); // forbidden
00189             ChainNode& operator=(const ChainNode&); // forbidden
00190                 
00191         private:
00192             ChainNode* others[2]; // two pointers
00193     };
00194     
00195     } // implementation namespace
00196     
00197 } // namespace
00198 
00199 #endif // NO_PTR_CHAIN_NODE_2_H    

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