include/Containers/template/ChainedList.hpp

Go to the documentation of this file.
00001 
00002 
00003 #ifndef NotCopyable
00004 
00005 // Copy constructor
00006 template <class U, unsigned int pow2, class SearchPolicy>
00007 ChainedList<U, pow2, SearchPolicy>::ChainedList(const ChainedList & copy) 
00008 {
00009     unsigned int i;
00010     mbUseBlocks = copy.mbUseBlocks;
00011     mbIntegrity = copy.mbIntegrity;
00012     mlNumberOfNodes = copy.mlNumberOfNodes;
00013     mlNumberOfBlocks = copy.mlNumberOfBlocks;
00014 
00015     if (mbUseBlocks)
00016     {
00017         // If copy is empty
00018         if (copy.mpxBlock == NULL)
00019         {
00020             mpxFirst = mpxLast = mpxCurrent = NULL;
00021             mpxBlock = mpxBLast = NULL;
00022             return;
00023         }
00024         
00025         // Must copy block contents
00026         LinearBlock<ChainedBS> * pBlock = new LinearBlock<ChainedBS>;
00027         LinearBlock<ChainedBS> * copyBlock = copy.mpxBlock;
00028 
00029         if (pBlock == NULL) return;
00030 
00031         // Set first block info
00032         mpxBlock = pBlock;
00033         mpxBlock->spxPrevious = NULL;
00034         mpxBlock->spxNext = NULL;
00035         mpxBLast = pBlock;
00036         mpxBlock->soUsed = copy.mpxBlock->soUsed;
00037 
00038         // Create blocks
00039         for (i=1; i < mlNumberOfBlocks; i++)
00040         {
00041             if (!pBlock->CreateNewBlock()) return;
00042             pBlock->soUsed = copyBlock->soUsed;
00043             pBlock = pBlock->spxNext;
00044             copyBlock = copyBlock->spxNext;
00045             mpxBLast = pBlock;
00046         }
00047 
00048         // Link nodes
00049         Node * pNode = mpxBlock->GetData();
00050 
00051         mpxFirst = pNode;
00052         mpxFirst->mpxPrevious = NULL;
00053         mpxCurrent = NULL;
00054         pBlock = mpxBlock;
00055 
00056         for (i=0; i < mlNumberOfBlocks; i++)
00057         {
00058             pNode = pBlock->GetData();
00059             for (unsigned int j=0; j < ChainedBS; j++)
00060             {
00061                 pNode->mpxPrevious = mpxCurrent;
00062                 if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
00063                 mpxCurrent = pNode;
00064                 pNode ++;
00065             }
00066             pBlock = pBlock->spxNext;
00067         }
00068 
00069         // Fill with data
00070         Node * copyNode = copy.mpxFirst;
00071         pNode = mpxFirst;
00072 
00073         for (i=0; i < mlNumberOfNodes; i++)
00074         {
00075             if (pNode == NULL || copyNode == NULL) return;
00076             pNode->Set(*copyNode->mpuElement);
00077             pNode = pNode->mpxNext;
00078             copyNode = copyNode->mpxNext;
00079         }
00080 
00081 
00082         if (pNode!=NULL) mpxLast = pNode->mpxPrevious; else mpxLast = mpxCurrent;
00083         mpxCurrent = pNode;
00084         mpxLast->mpxNext = NULL;
00085         mbIntegrity = true;
00086     }
00087     else
00088     {
00089         // Define temporary variables
00090         Node * pNode0 = NULL;
00091         Node * pNode;
00092         Node * pCopy =  copy.mpxFirst;
00093         for (unsigned int i = 0; i < mlNumberOfNodes; i++)
00094         {
00095             pNode = new Node;
00096             // Test creation
00097             if (pNode == NULL) return;
00098             if (i==0) mpxFirst = pNode;
00099             pNode->mpxPrevious = pNode0;
00100             if (pNode->mpxPrevious != NULL) pNode->mpxPrevious->mpxNext = pNode;
00101             
00102             // Test data validity
00103             if (pCopy == NULL) return;
00104             // And copy it
00105             pNode->Set(*pCopy->mpuElement);
00106             pCopy = pCopy->mpxNext;
00107             pNode0 = pNode;
00108         }
00109 
00110         // That's ok, copy pointers infos
00111         mpxLast = pNode;
00112         mpxCurrent = mpxLast;
00113         mpxBlock = mpxBLast = NULL;
00114 
00115     }
00116 }
00117 
00118 template <class U, unsigned int pow2, class SearchPolicy>
00119 ChainedList<U, pow2, SearchPolicy>& ChainedList<U, pow2, SearchPolicy>::operator =(const ChainedList & copy) 
00120 {
00121     if (&copy == this) return (*this);  // Test a=a
00122 
00123     if (mpxBlock != NULL) 
00124         if (!mpxBlock->DeleteAll()) return (*this);
00125     
00126     unsigned int i;
00127     if (!mbUseBlocks)
00128     {
00129         Node * pNode = mpxFirst;
00130 
00131         // Must we delete nodes ?;
00132         if (mpxFirst!=NULL)
00133         {
00134             // We must clean node before anything else;
00135             while (pNode!=NULL)
00136             {
00137                 mpxFirst = pNode->mpxNext;
00138                 delete pNode;
00139                 pNode = mpxFirst;
00140             }
00141         }
00142     
00143     }
00144 
00145     mbUseBlocks = copy.mbUseBlocks;
00146     mbIntegrity = copy.mbIntegrity;
00147     mlNumberOfNodes = copy.mlNumberOfNodes;
00148     mlNumberOfBlocks = copy.mlNumberOfBlocks;
00149 
00150     if (mbUseBlocks)
00151     {
00152         // If copy is empty
00153         if (copy.mpxBlock == NULL)
00154         {
00155             mpxFirst = mpxLast = mpxCurrent = NULL;
00156             mpxBlock = mpxBLast = NULL;
00157             return (*this);
00158         }
00159         
00160         // Must copy block contents
00161         LinearBlock<ChainedBS> * pBlock = new LinearBlock<ChainedBS>;
00162         LinearBlock<ChainedBS> * copyBlock = copy.mpxBlock;
00163 
00164         if (pBlock == NULL) return (*this);
00165 
00166         // Set first block info
00167         mpxBlock = pBlock;
00168         mpxBlock->spxPrevious = NULL;
00169         mpxBlock->spxNext = NULL;
00170         mpxBLast = pBlock;
00171         mpxBlock->soUsed = copy.mpxBlock->soUsed;
00172 
00173         // Create blocks
00174         for (i=1; i < mlNumberOfBlocks; i++)
00175         {
00176             if (!pBlock->CreateNewBlock()) return (*this);
00177             pBlock->soUsed = copyBlock->soUsed;
00178             pBlock = pBlock->spxNext;
00179             copyBlock = copyBlock->spxNext;
00180             mpxBLast = pBlock;
00181         }
00182 
00183         // Link nodes
00184         Node * pNode = mpxBlock->GetData();
00185 
00186         mpxFirst = pNode;
00187         mpxFirst->mpxPrevious = NULL;
00188         mpxCurrent = NULL;
00189         pBlock = mpxBlock;
00190 
00191         for (i=0; i < mlNumberOfBlocks; i++)
00192         {
00193             pNode = pBlock->GetData();
00194             for (unsigned int j=0; j < ChainedBS; j++)
00195             {
00196                 pNode->mpxPrevious = mpxCurrent;
00197                 if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
00198                 mpxCurrent = pNode;
00199                 pNode ++;
00200             }
00201             pBlock = pBlock->spxNext;
00202         }
00203 
00204         // Fill with datas
00205         Node * copyNode = copy.mpxFirst;
00206         pNode = mpxFirst;
00207 
00208         for (i=0; i < mlNumberOfNodes; i++)
00209         {
00210             if ( pNode == NULL || copyNode == NULL) return (*this);
00211             // Copy the Node element
00212             pNode->Set(copyNode->Get());
00213             pNode = pNode->mpxNext;
00214             copyNode = copyNode->mpxNext;
00215         }
00216 
00217 
00218         if (pNode!=NULL) mpxLast = pNode->mpxPrevious; else mpxLast = mpxCurrent;
00219         mpxCurrent = pNode;
00220         mpxLast->mpxNext = NULL;
00221         mbIntegrity = true;
00222     }
00223     else
00224     {
00225         Node * pNode = NULL;
00226         
00227         // Define temporary variables
00228         Node * pNode0 = NULL;
00229         Node * pCopy =  copy.mpxFirst;
00230         for (unsigned int i = 0; i < mlNumberOfNodes; i++)
00231         {
00232             pNode = new Node;
00233             // Test creation
00234             if (pNode == NULL) return (*this);
00235             if (i==0) mpxFirst = pNode;
00236             pNode->mpxPrevious = pNode0;
00237             if (pNode->mpxPrevious != NULL) pNode->mpxPrevious->mpxNext = pNode;
00238             
00239             // Test data validity
00240             if (pCopy == NULL) return (*this);
00241             // And copy it
00242             pNode->Set(pCopy->Get());
00243             pCopy = pCopy->mpxNext;
00244             pNode0 = pNode;
00245         }
00246 
00247         // That's okay, copy pointers infos
00248         mpxLast = pNode;
00249         mpxCurrent = mpxLast;
00250         mpxBlock = mpxBLast = NULL;
00251 
00252     }
00253    
00254     return (*this);
00255 }
00256 
00257 template <class U, unsigned int pow2, class SearchPolicy>
00258 bool ChainedList<U, pow2, SearchPolicy>::Add(DefaultConstParamType a, const unsigned int& pos) 
00259 {
00260     return Add(new U(a), pos);
00261 }
00262 
00263 #endif
00264 
00265 
00266 // Default constructor
00267 template <class U, unsigned int pow2, class SearchPolicy>
00268 ChainedList<U, pow2, SearchPolicy>::ChainedList() : mlNumberOfNodes(0), mlNumberOfBlocks(0), mpxBlock(NULL), mpxFirst(NULL), mpxLast(NULL), mpxCurrent(NULL), mbIntegrity(true), mpxBLast(NULL)
00269 {
00270     mbUseBlocks = (pow2==0) ? false: true;
00271 }
00272 
00273 // Destructor
00274 template <class U, unsigned int pow2, class SearchPolicy>
00275 ChainedList<U, pow2, SearchPolicy>::~ChainedList() 
00276 {
00277     Free();
00278 }
00279 
00280 
00281 
00282 
00283 
00284 //
00285 /* - · ·· Functions                                ·· · - */
00286 //----------------------------------------------------------
00287 template <class U, unsigned int pow2, class SearchPolicy>
00288 bool ChainedList<U, pow2, SearchPolicy>::Connect(Node *pNode, Node *pP, Node *pN)
00289 {
00290     if (pNode == NULL) return false;
00291 
00292     if ( pP==NULL && pN==NULL && pNode->mpuElement!=NULL && (pNode->mpxPrevious!=NULL || pNode->mpxNext!=NULL))
00293     {
00294         // Warning connection will be lost...
00295         pNode->mpxPrevious = pP;
00296         pNode->mpxNext = pN;
00297         return false;
00298     }
00299     
00300     pNode->mpxPrevious = pP;
00301     pNode->mpxNext = pN;
00302 
00303     return true;
00304 }
00305 
00306 template <class U, unsigned int pow2, class SearchPolicy>
00307 unsigned int ChainedList<U, pow2, SearchPolicy>::indexOf(DefaultConstParamType arg)
00308 {
00309     if (mpxFirst==NULL) return ChainedEnd;
00310 
00311     unsigned int i=0;
00312     Node * pNode = mpxFirst;
00313     while (i < mlNumberOfNodes && pNode!=NULL)
00314     {
00315         if (SearchPolicy::Compare(pNode->Get(), arg)) return i;
00316         i++;
00317         pNode = pNode->mpxNext;
00318     }
00319 
00320     return ChainedEnd;
00321 }
00322 
00323 template <class U, unsigned int pow2, class SearchPolicy>
00324 unsigned int ChainedList<U, pow2, SearchPolicy>::lastIndexOf(DefaultConstParamType arg)
00325 {
00326     if (mpxLast==NULL) return ChainedEnd;
00327 
00328     unsigned int i=mlNumberOfNodes;
00329     Node * pNode = mpxLast;
00330     while (i > 0 && pNode != NULL)
00331     {
00332         if (SearchPolicy::Compare(pNode->Get(), arg)) return i - 1;
00333         i--;
00334         pNode = pNode->mpxPrevious;
00335     }
00336 
00337     return ChainedEnd;
00338 }
00339 
00340 
00341 template <class U, unsigned int pow2, class SearchPolicy>
00342 bool ChainedList<U, pow2, SearchPolicy>::UseBlocks(const bool & arg)
00343 {
00344     if (mpxBlock != NULL) return false;
00345 
00346     mbUseBlocks = arg;
00347     return true;
00348 }
00349 
00350 template <class U, unsigned int pow2, class SearchPolicy>
00351 bool ChainedList<U, pow2, SearchPolicy>::Add(const ChainedList& copy, const unsigned int &pos) 
00352 {
00353     if ((copy.mpxFirst==NULL)||(copy.mpxLast==NULL)) return false;
00354     
00355     if (pos >= mlNumberOfNodes-1)
00356     {
00357         // Want to add in the end...
00358         if (mbUseBlocks)
00359         {
00360             // Define temporary variables
00361             Node * pNode = NULL;
00362             Node * pNode0 = mpxLast;
00363             Node * pCopy =  copy.mpxFirst;
00364 
00365             for (unsigned int i=0; i < copy.mlNumberOfNodes; i++)
00366             {
00367                 pNode = CreateNode();
00368                 if (pNode == NULL) return false;
00369                 
00370                 if (mpxFirst == NULL) mpxFirst = pNode;
00371                 pNode->mpxPrevious = pNode0;
00372                 if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
00373                 
00374                 if (pCopy == NULL) return false;
00375                 pNode->Set(pCopy->mpuElement);
00376                 pCopy = pCopy->mpxNext;
00377                 pNode0 = pNode;
00378             }
00379 
00380             mlNumberOfNodes += copy.mlNumberOfNodes;
00381             mpxLast = pNode;
00382             mpxLast->mpxNext = NULL;
00383 
00384             return true;
00385             
00386         }
00387         else
00388         {
00389         
00390             // Define temporary variables
00391             Node * pNode = NULL;
00392             Node * pNode0 = mpxLast;
00393             Node * pCopy =  copy.mpxFirst;
00394 
00395             for (unsigned int i=0; i < copy.mlNumberOfNodes; i++)
00396             {
00397                 pNode = new Node;
00398                 if (pNode == NULL) return false;
00399                 
00400                 pNode->mpxPrevious = pNode0;
00401                 if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
00402                 
00403                 if (pCopy == NULL) return false;
00404                 pNode->Set(pCopy->mpuElement);
00405                 pCopy = pCopy->mpxNext;
00406                 pNode0 = pNode;
00407             }
00408 
00409             mlNumberOfNodes += copy.mlNumberOfNodes;
00410             mpxLast = pNode;
00411             mpxCurrent = mpxLast;
00412             mpxLast->mpxNext = NULL;
00413 
00414             return true;
00415         }
00416     }
00417     else
00418     {
00419         if (mbUseBlocks)
00420         {
00421             unsigned int i;
00422             Node * pNode = NULL;
00423             Node * pLast = mpxLast;
00424             
00425             // We must probably create blocks, so let's do it...
00426             for (i=0; i < copy.mlNumberOfNodes; i++)
00427             {
00428                 pNode = CreateNode();
00429                 if (pNode == NULL) return false;
00430                 
00431                 pNode->mpxPrevious = pLast;
00432                 if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
00433                 
00434                 pLast = pNode;
00435             }
00436             
00437             mlNumberOfNodes += copy.mlNumberOfNodes;
00438 
00439             // Now fill new nodes with previous datas
00440             Node * pInsert = pNode; 
00441             if (pInsert == NULL) return false;
00442             Node * pFirst = Goto(pos);
00443             if (pFirst == NULL) return false;
00444 
00445             pNode = mpxLast;
00446             mpxLast = pInsert;
00447             mpxLast->mpxNext = NULL;
00448 
00449             for (i=pos + copy.mlNumberOfNodes; i < mlNumberOfNodes; i++)
00450             {
00451                 if ((pInsert==NULL)||(pNode ==  NULL)) return false;
00452                 pInsert->Set(pNode->mpuElement);
00453                 
00454                 pInsert = pInsert->mpxPrevious;
00455                 pNode = pNode->mpxPrevious;
00456             }
00457 
00458             // Let's then copy the insertion 
00459             pInsert = pFirst;
00460             pNode = copy.mpxFirst;
00461             for (i = 0; i < copy.mlNumberOfNodes; i++)
00462             {
00463                 if ((pInsert==NULL)||(pNode ==  NULL)) return false;
00464                 pInsert->Set(pNode->mpuElement);
00465                 
00466                 pInsert = pInsert->mpxNext;
00467                 pNode = pNode->mpxNext;
00468             }
00469 
00470             // Okay, finish..
00471             return true;
00472 
00473         }   
00474         else
00475         {
00476             // Define temporary variables
00477             Node * pNode = NULL;
00478             Node * pFirst = Goto(pos);
00479             if (pFirst == NULL) return false;
00480             Node * pNode0 = pFirst->mpxPrevious;
00481             Node * pCopy =  copy.mpxFirst;
00482 
00483             for (unsigned int i=0; i < copy.mlNumberOfNodes; i++)
00484             {
00485                 pNode = new Node;
00486                 if (pNode == NULL) return false;
00487                 
00488                 pNode->mpxPrevious = pNode0;
00489                 if ((i==0)&&(pos==0)) mpxFirst = pNode;
00490                 if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
00491                 
00492                 if (pCopy == NULL) return false;
00493                 pNode->Set(pCopy->mpuElement);
00494                 pCopy = pCopy->mpxNext;
00495                 pNode0 = pNode;
00496             }
00497     
00498             mlNumberOfNodes += copy.mlNumberOfNodes;
00499             pNode->mpxNext = pFirst;
00500             pFirst->mpxPrevious = pNode;
00501 
00502             return true;
00503         }
00504     }
00505 
00506 }
00507 
00508 
00509 template <class U, unsigned int pow2, class SearchPolicy>
00510 bool ChainedList<U, pow2, SearchPolicy>::Add(U* a, const unsigned int& pos) 
00511 {
00512     if (pos >= mlNumberOfNodes)
00513     {
00514         // Add to end of list
00515         if (mbUseBlocks)
00516         {
00517             
00518             Node * pNode = CreateNode();
00519             if (pNode == NULL) return false;
00520             
00521             pNode->Set(a);
00522             if (mpxBlock==NULL) return false;
00523             mpxBLast->soUsed ++;  
00524             
00525             // Then test if it is the first node
00526             if (mlNumberOfNodes==0)
00527                 mpxFirst = pNode;
00528             else
00529                 mpxLast->mpxNext = pNode;
00530 
00531             pNode->mpxPrevious = mpxLast;
00532             mpxLast = pNode;
00533             pNode->mpxNext = NULL;
00534             mlNumberOfNodes++;
00535             
00536             // Okay it's right so let's finish
00537             return true;
00538         }
00539         else
00540         {
00541             if (mpxFirst==NULL)
00542             {
00543                 // List not existing, creating it
00544                 mpxFirst = new Node(a);
00545                 
00546                 // Check creation
00547                 if (mpxFirst == NULL) return false;
00548 
00549                 // Connect pointers
00550                 if (!Connect(mpxFirst,NULL,NULL)) return false;
00551                 
00552                 // Set other pointers
00553                 mpxLast = mpxFirst;
00554                 mpxCurrent = mpxFirst;
00555                 
00556                 // Increase number of nodes
00557                 mlNumberOfNodes = 1;
00558                 
00559                 // Okay return 
00560                 return true;
00561             }
00562             else
00563             {
00564                 // List existing, adding node
00565                 mpxCurrent = new Node(a);
00566             
00567                 // Check creation
00568                 if (mpxCurrent == NULL) return false;
00569 
00570                 // Connect pointers
00571                 if (!Connect(mpxCurrent,mpxLast,NULL)) return false;
00572                 mpxLast->mpxNext = mpxCurrent;
00573                 mpxLast = mpxCurrent;
00574 
00575                 // Increase number of nodes
00576                 mlNumberOfNodes ++;
00577                 
00578                 // Okay return 
00579                 return true;
00580             
00581             }
00582         }
00583     }
00584     else
00585     {
00586         // Insertion mode 
00587 
00588         // Do we use blocks ?
00589         if (mbUseBlocks)
00590         {
00591             // Must find the position to insert link
00592             Node *  pNode;
00593             // Test if a block exist, else call the same function
00594             // with correct argument
00595             if (mpxBlock==NULL)
00596             {   if (pos == 0) return Add(a); else return false;     }
00597             
00598             LinearBlock<ChainedBS> * pBlock = mpxBLast;
00599             // Inserting at the beginning
00600             if (pBlock->soUsed < ChainedBS)
00601             {
00602                 // We have the place to store this pointer
00603                 // so, go to the last element (mpxCurrent)
00604                 // Check if someone parsed the list
00605                 if (mpxCurrent->mpxPrevious == NULL || mpxCurrent->mpxPrevious->mpxNext == mpxCurrent || mpxCurrent->mpxNext == NULL) 
00606                 {
00607                     // Find the last node 
00608                     if (mpxLast != NULL && mpxLast >= &pBlock->sapxBlock[0] && mpxLast < &pBlock->sapxBlock[ChainedBS - 1])
00609                         mpxCurrent = (mpxLast + 1);
00610                 }
00611                 if (mpxCurrent == NULL) return false;
00612                 
00613                 mpxLast->mpxNext = mpxCurrent;
00614                 mpxLast = mpxCurrent;
00615                 mpxCurrent = mpxCurrent->mpxNext;
00616                 mpxLast->mpxNext = NULL; 
00617                 pNode = mpxLast;
00618                 
00619 
00620                 for (unsigned int i=pos; i < mlNumberOfNodes; i++)
00621                 {
00622                     if (pNode->mpxPrevious !=NULL)
00623                     {
00624                         pNode->Set(pNode->mpxPrevious->mpuElement);
00625                         pNode = pNode->mpxPrevious;
00626                     }
00627                 }
00628 
00629                 // Okay, set first pointer data
00630                 pNode->Set(a);
00631                 
00632                 pBlock->soUsed++;
00633                 mlNumberOfNodes ++;
00634                 return true;
00635             }
00636             else
00637             {
00638                 unsigned int i;
00639                 // Must create a new block...
00640                 if (!pBlock->CreateNewBlock()) return false;
00641                 
00642                 pBlock = pBlock->spxNext;
00643                 mpxBLast = pBlock;
00644 
00645                 // Attach pNode with beginning of datas
00646                 pNode = pBlock->GetData();
00647                 // The powerful thing is here, go from pointer by adding
00648                 // Then link list, in reverse order
00649                 mpxCurrent = mpxLast;
00650                 for (i = 0; i < ChainedBS; i++, pNode++)
00651                 {
00652                     pNode->mpxPrevious = mpxCurrent;
00653                     // the following line is not really needed, because after we are only going from 
00654                     // left to right... But, in case of a block disallocating, might 
00655                     // create a error... So, let this line enabled
00656                     if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
00657                     mpxCurrent = pNode;
00658                 }
00659             
00660                 mlNumberOfBlocks ++;
00661                 mpxCurrent -= ChainedBS - 1;
00662 
00663                 // We have the place to store this pointer
00664                 // so, go to the last element (mpxCurrent)
00665                 if (mpxCurrent == NULL) return false;
00666                 
00667                 mpxLast->mpxNext = mpxCurrent;
00668                 mpxLast = mpxCurrent;
00669                 mpxCurrent = mpxCurrent->mpxNext;
00670                 mpxLast->mpxNext = NULL;
00671                 pNode = mpxLast;
00672                 
00673 
00674                 for (i=pos; i < mlNumberOfNodes; i++)
00675                 {
00676                     if (pNode->mpxPrevious !=NULL)
00677                     {
00678                         pNode->Set(pNode->mpxPrevious->mpuElement);
00679                         pNode = pNode->mpxPrevious;
00680                     }
00681                     
00682                 
00683                 }
00684 
00685                 // Okay, set first pointer data
00686                 pNode->Set(a);
00687                 
00688                 pBlock->soUsed++;
00689                 mlNumberOfNodes ++;
00690                 return true;
00691 
00692             }
00693                 
00694         }
00695         else
00696         {
00697             // List existing, adding node
00698             Node * pNode = new Node(a);
00699             
00700             // Seeking list
00701             if (pos!=0) 
00702             {
00703                 mpxCurrent = Goto(pos-1);
00704                 if (mpxCurrent == NULL) return false;
00705                 // Enable connections
00706                 Connect(pNode, mpxCurrent, mpxCurrent->mpxNext);
00707                 mpxCurrent->mpxNext = pNode;
00708                 if (pNode->mpxNext!=NULL) pNode->mpxNext->mpxPrevious = pNode;
00709             } else
00710             {
00711                 // Enable connections
00712                 Connect(pNode, NULL, mpxFirst);
00713                 mpxFirst->mpxPrevious = pNode;
00714                 mpxFirst = pNode;
00715                 
00716             }
00717             
00718             // Increase number of nodes
00719             mlNumberOfNodes ++;
00720         }
00721         return true;    
00722     }
00723 }
00724 
00725 template <class U, unsigned int pow2, class SearchPolicy>
00726 bool ChainedList<U, pow2, SearchPolicy>::Sub(const unsigned int& pos)
00727 {
00728     if (pos >= mlNumberOfNodes-1)
00729     {
00730         // Remove last node
00731         if (mbUseBlocks)
00732         {
00733             // Check if list exist
00734             if ((mpxLast == NULL)||(mpxBlock == NULL)) return false;
00735 
00736             LinearBlock<ChainedBS> *        pBlock = mpxBLast;
00737             Node * pNode = mpxLast->mpxPrevious;
00738 
00739             if (pNode==NULL) 
00740             {
00741                 // We have to clear the list...
00742                 if (!mpxBlock->DeleteAll()) return false;
00743                 mpxBlock = NULL;
00744                 mpxBLast = NULL;
00745                 mlNumberOfNodes = 0;
00746                 mlNumberOfBlocks = 0;
00747                 mbUseBlocks = true;
00748                 mbIntegrity = true;
00749                 mpxCurrent = mpxFirst = mpxLast = NULL;
00750                 return true;
00751             }
00752 
00753             if (pBlock->soUsed == 1)
00754             {
00755                 // This block will be empty after deletion, so delete it
00756                 pNode->mpxNext = NULL;
00757                 mpxLast = pNode;
00758                 mpxCurrent = NULL;
00759                 pBlock->soUsed = 0;
00760                 mlNumberOfNodes --;
00761                 mlNumberOfBlocks --;
00762                 mpxBLast = pBlock->spxPrevious;
00763                 pBlock->Delete();
00764                 
00765                 return true;
00766             } 
00767             
00768             // Okay block is at least filled with 2 pointers, can destroy the last one
00769             pNode->mpxNext = NULL;
00770             mpxLast->mpxNext = mpxCurrent;
00771             mpxCurrent = mpxLast;
00772             mpxLast = pNode;
00773 
00774             mlNumberOfNodes --;
00775             pBlock->soUsed --;
00776 
00777             return true;
00778 
00779 
00780         }
00781         else
00782         {
00783             if (mpxLast == NULL) return false;
00784             Node * pNode = mpxLast->mpxPrevious;
00785             
00786             if (pNode == NULL) 
00787             {
00788                 // Only one node in list, delete list
00789                 delete mpxLast;
00790                 mpxLast = mpxFirst = mpxCurrent = NULL;
00791                 mlNumberOfNodes = 0;
00792                 return true;
00793             }
00794             
00795             pNode->mpxNext = NULL;
00796             delete mpxLast;
00797             mpxLast = pNode;
00798             mpxCurrent = mpxLast;
00799             mlNumberOfNodes --;
00800 
00801             return true;
00802         }
00803     }
00804     else
00805     {
00806         // Remove a node
00807         if (mbUseBlocks)
00808         {
00809             // Check if list exist
00810             if ((mpxLast == NULL)||(mpxBlock == NULL)) return false;
00811 
00812             LinearBlock<ChainedBS> *        pBlock = mpxBLast;
00813             Node * pNode = Goto(pos);
00814             // Does this node exist ?
00815             if ((pNode == NULL)||(pBlock==NULL)) return false;
00816 
00817             // Delete the node content
00818             delete pNode->mpuElement;
00819             pNode->mpuElement = NULL;
00820 
00821             if (pBlock->soUsed == 1) 
00822             {
00823                 // We have to clear a block
00824                 for (unsigned int i = pos+1; i < mlNumberOfNodes; i++)
00825                 {
00826                     if (pNode->mpxNext == NULL) return false;
00827                     pNode->Set(pNode->mpxNext->mpuElement);
00828                     pNode = pNode->mpxNext;
00829                 }
00830                 
00831                 // Set beginning of free tab
00832                 mpxCurrent = NULL;
00833                 // And decrease list size
00834                 mpxLast = mpxLast->mpxPrevious;
00835                 mpxLast->mpxNext = NULL;
00836                 // Delete last block
00837                 pBlock->soUsed = 0;
00838                 mpxBLast = pBlock->spxPrevious;
00839                 pBlock->Delete();
00840 
00841                 mlNumberOfNodes --;
00842                 mlNumberOfBlocks --;
00843                 
00844                 return true;
00845             }
00846             
00847             // We have to traverse list
00848             for (unsigned int i = pos+1; i < mlNumberOfNodes; i++)
00849             {
00850                 if (pNode->mpxNext == NULL) return false;
00851                 pNode->Set(pNode->mpxNext->mpuElement);
00852                 pNode = pNode->mpxNext;
00853             }
00854             
00855             // Restore free tab consistency
00856             mpxLast->mpxNext = mpxCurrent;
00857             // Set beginning of free tab
00858             mpxCurrent = mpxLast;           
00859             // And decrease list size
00860             mpxLast = mpxLast->mpxPrevious;
00861             mpxLast->mpxNext = NULL;
00862             // Set the current pointer data to NULL too 
00863             mpxCurrent->Set((U*)NULL);
00864             // Delete last block
00865             pBlock->soUsed --;
00866 
00867             mlNumberOfNodes --;
00868                 
00869             return true;
00870             
00871 
00872         }
00873         else
00874         {
00875             // Get the node pointer we want to detroy, and test it
00876             Node * pNode = Goto(pos);
00877             if (pNode == NULL) return false;
00878             
00879             // Make connections
00880             if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode->mpxNext;
00881             if (pNode->mpxNext!=NULL) pNode->mpxNext->mpxPrevious = pNode->mpxPrevious;
00882             
00883             
00884             if (pNode == mpxFirst) mpxFirst = pNode->mpxNext;
00885             // this case shouldn't occur, but...
00886             if (pNode == mpxLast) mpxLast = pNode->mpxPrevious;
00887             
00888             // Delete node
00889             delete pNode;
00890             mlNumberOfNodes --;
00891 
00892             return true;
00893         }
00894     
00895     }
00896 }
00897 
00898 template <class U, unsigned int pow2, class SearchPolicy>
00899 bool ChainedList<U, pow2, SearchPolicy>::Insert(DefaultConstParamType a, const unsigned int& pos) 
00900 {
00901     if (pos>= mlNumberOfNodes) return Add(a); // Add the node to last position
00902     
00903     Node * pNode;
00904     if (mbUseBlocks)
00905     {
00906         // Create a node in the block
00907         pNode = CreateNode();
00908 
00909         // Set integrity to false (pNode->mpxNext != pNode++)
00910         mbIntegrity = false;
00911     }
00912     else
00913     {
00914         pNode = new Node(a);
00915     }
00916 
00917     if (pNode == NULL) return false;
00918     // Set element
00919     pNode->Set(a);
00920     
00921     // Make connections
00922     pNode->mpxNext = Goto(pos); 
00923     if (pNode->mpxNext==NULL) return false;
00924 
00925     pNode->mpxPrevious = pNode->mpxNext->mpxPrevious;
00926     if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
00927     pNode->mpxNext->mpxPrevious = pNode;
00928 
00929     return true;
00930 }
00931 
00932 template <class U, unsigned int pow2, class SearchPolicy>
00933 bool ChainedList<U, pow2, SearchPolicy>::Swap(const unsigned int& pos0, const unsigned int& pos1) 
00934 {
00935     if ( pos0>= mlNumberOfNodes || pos1>= mlNumberOfNodes) return false; 
00936     
00937     // Get node pointers
00938     Node * pNode0 = Goto(pos0);
00939     Node * pNode1 = Goto(pos1);
00940     // And test them
00941     if ((pNode0==NULL)||(pNode1==NULL)) return false;
00942 
00943     if (mbUseBlocks)
00944     {
00945         // Here we must change contents
00946         // (in real linked list, it's only pointers that are 
00947         // exchanged, but this system preserve integrity
00948         U * a = pNode1->mpuElement;
00949         pNode1->Set(pNode0->mpuElement);
00950         pNode0->Set(a);
00951 
00952         return true;
00953     }
00954     else
00955     {
00956         if ((pNode0->mpxNext == pNode1)||(pNode0->mpxPrevious == pNode1))
00957         {
00958             // this nodes are linked...
00959             if (pNode0->mpxNext == pNode1)
00960             {
00961                 // Is 1 after 0 ?
00962                 if (pNode0->mpxPrevious!=NULL) pNode0->mpxPrevious->mpxNext = pNode1;               
00963                 if (pNode1->mpxNext!=NULL) pNode1->mpxNext->mpxPrevious = pNode0;               
00964                 
00965                 pNode0->mpxNext = pNode1->mpxNext;
00966                 pNode1->mpxPrevious = pNode0->mpxPrevious;
00967                 pNode0->mpxPrevious = pNode1;
00968                 pNode1->mpxNext = pNode0;
00969             } else
00970             {
00971                 // Is 0 after 1 ?
00972                 if (pNode1->mpxPrevious!=NULL) pNode1->mpxPrevious->mpxNext = pNode0;               
00973                 if (pNode0->mpxNext!=NULL) pNode0->mpxNext->mpxPrevious = pNode1;               
00974                 
00975                 pNode1->mpxNext = pNode0->mpxNext;
00976                 pNode0->mpxPrevious = pNode1->mpxPrevious;
00977                 pNode1->mpxPrevious = pNode0;
00978                 pNode0->mpxNext = pNode1;
00979             }
00980         
00981             return true;
00982         }
00983         
00984         
00985         Node * pNodeTemp0 = pNode0->mpxPrevious;
00986         Node * pNodeTemp1 = pNode0->mpxNext;
00987 
00988         if (pNode0->mpxPrevious!=NULL)  pNode0->mpxPrevious->mpxNext = pNode1;
00989         if (pNode0->mpxNext!=NULL)      pNode0->mpxNext->mpxPrevious = pNode1;
00990         if (pNode1->mpxPrevious!=NULL)  pNode1->mpxPrevious->mpxNext = pNode0;
00991         if (pNode1->mpxNext!=NULL)      pNode1->mpxNext->mpxPrevious = pNode0;
00992 
00993         pNode0->mpxPrevious = pNode1->mpxPrevious;
00994         pNode0->mpxNext = pNode1->mpxNext;
00995 
00996         pNode1->mpxPrevious = pNodeTemp0;
00997         pNode1->mpxNext = pNodeTemp1;
00998 
00999         if (pNode0 == mpxLast) mpxLast = pNode1;
01000         if (pNode1 == mpxLast) mpxLast = pNode0;
01001         if (pNode0 == mpxFirst) mpxFirst = pNode1;
01002         if (pNode1 == mpxFirst) mpxFirst = pNode0;
01003 
01004         return true;
01005     }
01006 }
01007 
01008 template <class U, unsigned int pow2, class SearchPolicy>
01009 bool ChainedList<U, pow2, SearchPolicy>::Remove(const unsigned int& pos) 
01010 {
01011     if (pos>= mlNumberOfNodes) return false; 
01012     
01013     // Get node pointer
01014     Node * pNode = Goto(pos);
01015     if (pNode == NULL) return false;
01016 
01017     if (mbUseBlocks)
01018     {
01019 
01020         if (pNode==mpxLast) 
01021         {
01022             LinearBlock<ChainedBS> * pBlock = mpxBLast;
01023             if (pBlock == NULL) return false;
01024             if (pBlock->soUsed == 1)
01025             {
01026                 // must destroy a block
01027                 pNode = mpxLast->mpxPrevious;
01028                 if (pNode != NULL) pNode->mpxNext = NULL;
01029                 mpxLast = pNode;
01030                 mpxCurrent = NULL;
01031 
01032 
01033                 pBlock->soUsed = 0;
01034                 mlNumberOfNodes --;
01035                 mlNumberOfBlocks --;
01036                 mpxBLast = pBlock->spxPrevious;
01037                 pBlock->Delete();
01038 
01039                 if (!mlNumberOfBlocks) mpxBlock = NULL;
01040                 if (!mlNumberOfNodes)  mpxFirst = NULL;
01041             }
01042             else
01043             {
01044                 mpxLast->mpxNext = mpxCurrent;
01045                 mpxCurrent = mpxLast;
01046                 mpxLast = mpxLast->mpxPrevious;
01047                 mpxLast->mpxNext= NULL;
01048 
01049                 mlNumberOfNodes --;
01050                 pBlock->soUsed --;
01051 
01052             }
01053             delete pNode->mpuElement;
01054             pNode->Set((U*)NULL);
01055             return true;        
01056         }
01057         
01058         // Find block that contains that node
01059         LinearBlock<ChainedBS> * pBlock = mpxBlock->Find(pNode);
01060         if (pBlock == NULL) return false;
01061         pBlock->soUsed --;
01062         // Set integrity to false (pNode->mpxNext != pNode++)
01063         mbIntegrity = false;
01064         
01065     }
01066 
01067     // Make connections
01068     if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode->mpxNext;
01069     if (pNode->mpxNext!=NULL) pNode->mpxNext->mpxPrevious = pNode->mpxPrevious;
01070     
01071     
01072     if (pNode == mpxFirst) mpxFirst = pNode->mpxNext;
01073     // this case shouldn't occur, but...
01074     if (pNode == mpxLast) mpxLast = pNode->mpxPrevious;
01075     
01076     // Delete node
01077     if (!mbUseBlocks) delete pNode; else { delete pNode->mpuElement; pNode->Set((U*)NULL); }
01078     mlNumberOfNodes --;
01079 
01080     return true;
01081 }
01082 
01083 template <class U, unsigned int pow2, class SearchPolicy>
01084 typename ChainedList<U, pow2, SearchPolicy>::Node* ChainedList<U, pow2, SearchPolicy>::CreateNode() 
01085 {
01086     if (mpxCurrent == NULL)
01087     {
01088         
01089         // Here no block is available, so create a new block
01090         LinearBlock<ChainedBS> * pBlock;
01091         if (mpxBlock == NULL) 
01092         {
01093             mpxBlock = new LinearBlock<ChainedBS>;
01094             if (mpxBlock==NULL) return NULL;
01095             mpxBLast = mpxBlock;
01096             pBlock = mpxBlock;
01097         }
01098         else 
01099         {
01100             // Check if used reach the needed point...
01101             if (mpxBlock->soUsed < ChainedBS) 
01102             {
01103                 // If a node (not the last one) has been deleted within this block 
01104                 // Can find it, and return it, instead...
01105                 
01106                 Node * pNode = mpxBlock->GetData();
01107                 for (unsigned int i = 0; i < ChainedBS; i++)
01108                 {
01109                     if (pNode == NULL) return NULL;
01110                     if (pNode->mpxNext !=  (pNode+1))
01111                     {
01112                         // pNode+1 is the free node
01113                         return (pNode+1);
01114                     }
01115 
01116                     pNode ++;
01117                 }
01118                 return NULL;
01119             }
01120             
01121             pBlock = mpxBLast;
01122             if (pBlock->CreateNewBlock()!=true) return NULL;
01123             pBlock = pBlock->spxNext;
01124             mpxBLast = pBlock;
01125         }
01126         
01127         // Now, pBlock contains a new free block
01128         // Fill it with free pointers
01129         Node * pNode = (Node*) pBlock->GetData();
01130         
01131         // The powerful thing is here, go from pointer by adding
01132         // Then link list, in reverse order
01133         for (unsigned int i = 0; i < ChainedBS; i++, pNode++)
01134         {
01135             pNode->mpxPrevious = mpxCurrent;
01136             // the following line is not really needed, because after we are only going from 
01137             // left to right... But, in case of a block disallocating, might 
01138             // create a error... So, let this line enabled
01139             if (pNode->mpxPrevious!=NULL) pNode->mpxPrevious->mpxNext = pNode;
01140             mpxCurrent = pNode;
01141         }
01142     
01143         mpxCurrent -= ChainedBS - 1; 
01144         //if (mpxCurrent->mpxNext!=NULL)    mpxCurrent->mpxNext->mpxPrevious = mpxCurrent;
01145 
01146         mlNumberOfBlocks ++;
01147 
01148         mpxCurrent = mpxCurrent->mpxNext;
01149         return mpxCurrent->mpxPrevious;
01150 
01151     }
01152     
01153     if (mpxCurrent==NULL) return NULL;
01154     
01155     // Check if someone parsed the list
01156     if (mpxCurrent->mpxPrevious == NULL || mpxCurrent->mpxPrevious->mpxNext == mpxCurrent || mpxCurrent->mpxNext == NULL) 
01157     {
01158         // Not the last one
01159         if (mpxBLast != NULL && mpxBLast->soUsed < ChainedBS)
01160         {
01161             // Need to find the first free node
01162             Node * pNode = mpxBLast->GetData();
01163             for (unsigned int i = 0; i < ChainedBS; i++)
01164             {
01165                 if (pNode == NULL) return NULL;
01166                 if (pNode->mpxNext !=  (pNode+1))
01167                 {
01168                     // pNode+1 is the free node
01169 
01170                     // Need to check if pNode+1 is outside the block
01171                     if ((pNode+1) > (mpxBLast->GetData() + ChainedBS))
01172                     {
01173                         // pNode + 1 is outside this block, need to create a new block
01174                         mpxCurrent = NULL;
01175                         return CreateNode();
01176                     }
01177                     else
01178                     // Now need to set back mpxCurrent correctly
01179                     {
01180                         mpxCurrent = (pNode + 1)->mpxNext;
01181                     }
01182 
01183                     return (pNode+1);
01184                 }
01185                 pNode ++;
01186             }
01187         } 
01188         // Get the next available pointer, in the next block that need to be created
01189         else
01190         {
01191             mpxCurrent = NULL;
01192             return CreateNode();
01193         }
01194     }
01195     
01196     mpxCurrent = mpxCurrent->mpxNext;
01197     
01198     return mpxCurrent->mpxPrevious;
01199 }
01200 
01201 
01202 
01203 template <class U, unsigned int pow2, class SearchPolicy>
01204 typename ChainedList<U, pow2, SearchPolicy>::Node* ChainedList<U, pow2, SearchPolicy>::Goto(const unsigned int& pos) 
01205 {
01206     if (mpxFirst == NULL) return NULL;
01207 
01208     Node* pT;
01209     if ( mbUseBlocks && mbIntegrity )
01210     {
01211         if (mpxBlock==NULL) return NULL;
01212     
01213         unsigned int distinblock = (pos>>pow2);
01214         LinearBlock<ChainedBS> *pBlock = mpxBlock;
01215 
01216 
01217         for (unsigned int i = 0; i < distinblock; i++)
01218         {
01219             if (pBlock==NULL) return NULL;
01220             pBlock = pBlock->spxNext;
01221         }
01222 
01223         pT = pBlock->GetData();
01224         pT += pos - (distinblock<<pow2);
01225 
01226     }
01227     else
01228     {
01229         if (pos <= (mlNumberOfNodes>>1))
01230         {
01231             // It's quicklier to reach pos starting by the beginning
01232             pT = mpxFirst;
01233             
01234             for (unsigned int i=0; i<pos; i++)
01235             {
01236                 if (pT==NULL) return NULL;
01237                 pT = pT->mpxNext;
01238             }
01239         } else
01240         {
01241             // It's quicklier to reach pos starting by the end
01242             pT = mpxLast;
01243             
01244             for (unsigned int i=pos+1; i < mlNumberOfNodes; i++)
01245             {
01246                 if (pT==NULL) return NULL;
01247                 pT = pT->mpxPrevious;
01248             }
01249         
01250         }
01251     }
01252     return pT;
01253 }
01254 
01255 template <class U, unsigned int pow2, class SearchPolicy>
01256 bool ChainedList<U, pow2, SearchPolicy>::Change(DefaultConstParamType  a, const unsigned int & pos) 
01257 {
01258     if (mpxFirst == NULL) return false;
01259 
01260     if (pos > mlNumberOfNodes) return false;
01261     // Can add if last pos is selected...
01262     if (pos == mlNumberOfNodes) Add(a);
01263 
01264     Node* pT = Goto(pos);
01265     if (pT == NULL) return false;
01266 
01267     if (pT->mpuElement != NULL)
01268         delete pT->mpuElement;
01269 
01270     pT->Set(a);
01271      
01272     return true;
01273     
01274 }
01275 
01276 
01277 template <class U, unsigned int pow2, class SearchPolicy>
01278 bool ChainedList<U, pow2, SearchPolicy>::Free() 
01279 {
01280     if (mpxFirst == NULL) return false;
01281 
01282     if (mbUseBlocks)
01283     {
01284         if (mpxBlock == NULL) return false;
01285         
01286         mpxBlock->DeleteAll();
01287         mpxBlock = NULL;
01288         mpxFirst = mpxLast = mpxCurrent = NULL;
01289         mlNumberOfNodes = 0;
01290         mlNumberOfBlocks = 0;
01291         mbIntegrity = true;
01292         mbUseBlocks = true;
01293     
01294     }
01295     else
01296     {
01297         mpxCurrent = mpxFirst;
01298         for (unsigned int i=0; i < mlNumberOfNodes; i++)
01299         {
01300             if (mpxCurrent == NULL) return false;
01301             mpxLast = mpxCurrent->mpxNext;
01302             delete mpxCurrent;
01303 
01304             mpxCurrent = mpxLast;
01305         }
01306 
01307         mpxFirst = mpxLast = mpxCurrent = NULL;
01308         mlNumberOfNodes = 0;
01309         mbIntegrity = true;
01310     }
01311 
01312     return true;
01313 }
01314 
01315 template <class U, unsigned int pow2, class SearchPolicy>
01316 U* ChainedList<U, pow2, SearchPolicy>::parseList(const bool & bInit) const 
01317 {
01318     if (mpxFirst == NULL) return NULL;
01319 
01320     if (bInit) { mpxCurrent = mpxFirst; return mpxCurrent->mpuElement; }
01321     else if (mpxCurrent!=mpxLast)      { mpxCurrent = mpxCurrent->mpxNext; return mpxCurrent->mpuElement; }
01322     else return NULL;
01323 }
01324 
01325 template <class U, unsigned int pow2, class SearchPolicy>
01326 U* ChainedList<U, pow2, SearchPolicy>::parseListStart(const unsigned int & uiPos) const
01327 {
01328     if (uiPos != ChainedEnd)  { mpxCurrent = Goto(uiPos); if (mpxCurrent!=NULL) return mpxCurrent->mpuElement; else return NULL; }
01329     else if (mpxCurrent!=NULL)     { mpxCurrent = mpxCurrent->mpxNext; return mpxCurrent->mpuElement; }
01330     else return NULL;
01331 }
01332 
01333 template <class U, unsigned int pow2, class SearchPolicy>
01334 U* ChainedList<U, pow2, SearchPolicy>::reverseParseList(const bool & bInit) const
01335 {
01336     if (mpxLast == NULL) return NULL;
01337 
01338     if (bInit) { mpxCurrent = mpxLast; return mpxCurrent->mpuElement; }
01339     else if (mpxCurrent!=mpxFirst)     { mpxCurrent = mpxCurrent->mpxPrevious; return mpxCurrent->mpuElement; }
01340     else return NULL;
01341 }
01342 
01343 template <class U, unsigned int pow2, class SearchPolicy>
01344 U* ChainedList<U, pow2, SearchPolicy>::reverseParseListStart(const unsigned int & uiPos) const
01345 {
01346     if (uiPos != ChainedEnd)  { mpxCurrent = Goto(uiPos); if (mpxCurrent!=NULL) return mpxCurrent->mpuElement; else return NULL; }
01347     else if (mpxCurrent!=NULL)     { mpxCurrent = mpxCurrent->mpxPrevious; return mpxCurrent->mpuElement; }
01348     else return NULL;
01349 }
01350 
01351 
01352 
01353 
01354 

(C) An X-Ryl669 project 2007

This document describes Unlimited Zooming Interface source code. UZI stands for Unlimited Zooming Interface, and source code license is