list.cpp

Go to the documentation of this file.
00001 // $Id: list.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098                                          
00099 /**********************************************************************************************
00100  LIST.CPP - List class definition file.
00101 
00102     This is the Camelot list class. It is an implementation of a doubly linked-list and will be
00103     used rampantly throughout Camelot.
00104 
00105 **********************************************************************************************/
00106 
00107 
00108 #include "camtypes.h"
00109                                                     
00110 //#include "list.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 
00113 CC_IMPLEMENT_DYNAMIC( List, CCObject )
00114 
00115 
00116 #ifdef _DEBUG
00117 
00118 /********************************************************************************************
00119 
00120     Preference:     DebugLevel
00121     Section:        Debug
00122     Range:          0 to 2
00123     Purpose:        Controls how much checking is done in the List class.
00124                     0 - No checking
00125                     1 - Normal debug checking
00126                     2 - Extra debug checking
00127     SeeAlso:        -
00128 
00129 ********************************************************************************************/
00130 
00131 INT32 List::ListDebugLevel = 0;
00132 #endif
00133 
00134 /**********************************************************************************************
00135 
00136 >   List::List() 
00137 
00138     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00139     Created:    13/4/93
00140     Inputs:     None
00141     Outputs:    None
00142     Returns:    None
00143     Purpose:    List class constructor
00144     Errors:     None
00145 
00146 **********************************************************************************************/
00147 
00148 List::List() 
00149 {
00150     HeadItem = NULL;
00151     TailItem = NULL;
00152     ItemCount = 0;
00153 
00154 #ifdef _DEBUG
00155     LastItemRemoved = NULL;
00156 #endif
00157 }
00158 
00159 /**********************************************************************************************
00160 
00161 >   virtual List::~List() 
00162 
00163     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00164     Created:    13/4/93
00165     Inputs:     None
00166     Outputs:    None
00167     Returns:    None
00168     Purpose:    List class destructor. NOTE that this does NOT destroy the list items -
00169                 it simply delinks all items in the list and deletes the list header.
00170 
00171                 When destructing a list, you should really delete all objects from within
00172                 it (by deriving a class from List with a special destructor, or calling
00173                 List::DeleteAll() on it first, or some other appropriate action) before
00174                 calling delete on the List header.
00175 
00176     Notes:      In DEBUG builds, any non-empty lists are reported to the TRACE output,
00177                 in order to encourage people to discard their used lists thoughtfully.
00178                 To remove this TRACE, you must either delete (DeleteAll()) or delink
00179                 (RemoveItem()) the items from the list before calling the destructor.
00180 
00181                 In ALL builds, any items still in the list when it is destructed are delinked
00182                 (RemoveItem()) from the list, in order to ensure their next/previous
00183                 pointers remain valid.
00184 
00185 **********************************************************************************************/
00186 
00187 List::~List()
00188 {
00189 #ifdef _DEBUG
00190     if (!IsEmpty())
00191     {
00192         TRACE( _T("NON EMPTY LIST DELETED! Its items may appear as memory leaks on exit\n")
00193               _T("The %ld items are listed below. I have delinked them from the list\n"),
00194               (INT32) GetCount());
00195     
00196         // Dump the contents of the list
00197         ListItem *Ptr = GetHead();
00198         while (Ptr != NULL)
00199         {
00200             TRACE( _T("  '%s' at 0x%x\n"), Ptr->GetRuntimeClass()->GetClassName(), Ptr );
00201             Ptr = GetNext(Ptr);
00202         }
00203         TRACE( _T("\n") );
00204     }
00205 #endif
00206 
00207     // In all builds, if the list was deleted while non-empty, we delink all items from it
00208     // to ensure that their next/previous pointers are all NULL, rather than pointing at
00209     // possibly invalid areas of memory. This will at least mean that the items can be
00210     // safely added to other lists, without causing complete screwups.
00211     // These items will show up as memory leaks if they are not properly deleted by anyone
00212     // so we don't really need to concern ourselves with alerting the programmer too much
00213     // at this point
00214     while (!IsEmpty())
00215         RemoveHead();
00216 }
00217 
00218 
00219 
00220 /**********************************************************************************************
00221 
00222 >   virtual ListItem *List::RemoveHead() 
00223 
00224     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00225     Created:    13/4/93
00226     Inputs:     None
00227     Outputs:    None
00228     Returns:    ListItem that was head of list
00229                 NULL if list is empty
00230     Purpose:
00231         
00232         RemoveHead does not as its name may suggest delete the ListItem at the head
00233         of the list. It instead removes pointers to and from the ListItem at the head
00234         of the list, in effect removing it from the list. RemoveHead returns a pointer 
00235         to the  ListItem 'removed'. It is the responsibility of the caller to delete
00236         the ListItem from memory. 
00237  
00238     Errors:     None.
00239 
00240 **********************************************************************************************/
00241 
00242 ListItem *List::RemoveHead() 
00243 {
00244 //  CC_ASSERT_VALID(this);
00245 
00246     if (this->IsEmpty())              // if list is empty return a null pointer
00247         return NULL;
00248                                 
00249     ListItem *oldHead;
00250 
00251     oldHead = HeadItem;
00252     HeadItem = HeadItem->Next;      // list head pointed to next item in list
00253 
00254     if (HeadItem != NULL)           // if list is not empty
00255         HeadItem->Previous = NULL;  //     pointer to old list head must be nullified       
00256     else
00257         TailItem = NULL;            //     tail item must be nullified
00258         
00259     ItemCount -= 1;                 // decrement item counter
00260 
00261 #ifdef _DEBUG
00262     LastItemRemoved = oldHead;
00263 #endif
00264 
00265     return oldHead;
00266 }
00267 
00268 
00269 
00270 /**********************************************************************************************
00271 
00272 >   virtual ListItem *List::RemoveTail() 
00273 
00274     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00275     Created:    13/4/93
00276     Inputs:     None
00277     Outputs:    None
00278     Returns:    ListItem that was tail of list
00279                 NULL if it is an empty list
00280     Purpose:     
00281         
00282         RemoveTail does not as its name may suggest delete the ListItem at the tail
00283         of the list. It instead removes pointers to and from the ListItem at the tail
00284         of the list, in effect removing it from the list. RemoveTail returns a pointer 
00285         to the  ListItem 'removed'. It is the responsibility of the caller to delete
00286         the ListItem from memory.
00287  
00288     Errors:     None.
00289 
00290 **********************************************************************************************/
00291     
00292 ListItem *List::RemoveTail() 
00293 {
00294 //  CC_ASSERT_VALID(this);
00295 
00296     if (this->IsEmpty())              // if list is empty return a null pointer
00297         return NULL;
00298                 
00299     ListItem *oldTail;
00300 
00301     oldTail = TailItem;
00302     TailItem = TailItem->Previous;  // list tail pointed to previous item in list
00303 
00304     if (TailItem != NULL)           // if list is not empty
00305         TailItem->Next = NULL;      //     pointer to old list tail must be nullified
00306     else
00307         HeadItem = NULL;            //     head item must be nullified
00308     
00309     ItemCount -= 1;                 // decrement item counter
00310 
00311 #ifdef _DEBUG
00312     LastItemRemoved = oldTail;
00313 #endif
00314     
00315     return oldTail;
00316 }
00317 
00318 
00319 
00320 /********************************************************************************************
00321 
00322 >   virtual void List::DeleteAll()
00323 
00324     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00325     Created:    11/2/94
00326     Inputs:     -
00327     Outputs:    -
00328     Returns:    -
00329     Purpose:    Deletes the list, calling the destructors of all ListItems
00330     Errors:     -
00331     SeeAlso:    -
00332 
00333 ********************************************************************************************/
00334 
00335 void List::DeleteAll()
00336 {
00337     while (!IsEmpty())
00338     {
00339         delete (RemoveTail()); 
00340     }
00341 }
00342 
00343 
00344 
00345 /**********************************************************************************************
00346 
00347 >   virtual void List::AddHead( ListItem* )
00348 
00349     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00350     Created:    14/4/93
00351     Inputs:     ListItem to be inserted
00352     Outputs:    None
00353     Returns:    void
00354     Purpose:    To insert a ListItem at the head of the list.
00355     Errors:     None.
00356 
00357 **********************************************************************************************/
00358 /*
00359 Technical notes:
00360 
00361     If a new item is added to the list that already exists the list will become corrupted.
00362     In order to trap this error the FindPosition() function can be used to scan the list, 
00363     but this will cause a performance overhead. The solution is to perform the scan only in  
00364     debug mode so that users of the list are warned during development while release versions 
00365     of the software do not suffer from inadequate performance.
00366 
00367 **********************************************************************************************/
00368 
00369 void List::AddHead( ListItem* newHead )
00370 {
00371 //  CC_ASSERT_VALID(this);
00372     
00373     if (this->IsEmpty())                // if list is empty
00374     {                       
00375         newHead->Next = NULL;           // init next prev pointers
00376         newHead->Previous = NULL;
00377         HeadItem = newHead;             // head & tail point to first item
00378         TailItem = newHead;
00379     }
00380     else
00381     {
00382 #ifdef _DEBUG
00383         if (ListDebugLevel > 0)
00384         {
00385             ENSURE( this->FindPosition(newHead) == NOT_IN_LIST, 
00386                     "AddHead: New head item is already in the list");
00387         }
00388 #endif      
00389         newHead->Next = HeadItem;       // new head pointed to old head
00390         newHead->Previous = NULL;       // new head previous pointer nullified
00391         HeadItem->Previous = newHead;   // old head pointed back to new head
00392         HeadItem = newHead;             // head pointer pointed to new head
00393     }
00394         
00395     ItemCount += 1;                     // increment item counter 
00396 
00397 #ifdef _DEBUG
00398     if (newHead == LastItemRemoved)
00399         LastItemRemoved = NULL;
00400 #endif
00401 }
00402 
00403 
00404 
00405 /**********************************************************************************************
00406 
00407 >   virtual void List::AddTail( ListItem* )
00408 
00409     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00410     Created:    14/4/93
00411     Inputs:     ListItem to be inserted
00412     Outputs:    None
00413     Returns:    void
00414     Purpose:    To insert a ListItem at the tail of the list.
00415     Errors:     None.
00416 
00417 **********************************************************************************************/
00418 /*
00419 Technical notes:
00420 
00421     If a new item is added to the list that already exists the list will become corrupted.
00422     In order to trap this error the FindPosition() function can be used to scan the list, 
00423     but this will cause a performance overhead. The solution is to perform the scan only in  
00424     debug mode so that users of the list are warned during development while release versions 
00425     of the software do not suffer from inadequate performance.
00426 
00427 **********************************************************************************************/
00428     
00429 void List::AddTail( ListItem* newTail ) 
00430 {                                     
00431 //  CC_ASSERT_VALID(this);
00432 
00433     if (this->IsEmpty())                // if list is empty
00434     {                       
00435         newTail->Next = NULL;           // init next prev pointers
00436         newTail->Previous = NULL;
00437         HeadItem = newTail;             // head & tail point to first item
00438         TailItem = newTail;
00439     }
00440     else
00441     {
00442 #ifdef _DEBUG
00443         if (ListDebugLevel > 0)
00444         {
00445             ENSURE(this->FindPosition(newTail) == NOT_IN_LIST, 
00446                     "AddTail: New tail item is already in the list");
00447         }
00448 #endif
00449 
00450         newTail->Previous = TailItem;   // previous points old tail
00451         newTail->Next = NULL;           // next is nullified  
00452         TailItem->Next = newTail;       // old tail next points to new tail
00453         TailItem = newTail;             // update tail pointer
00454     }
00455     
00456     ItemCount += 1;                     // increment item counter
00457 
00458 #ifdef _DEBUG
00459     if (newTail == LastItemRemoved)
00460         LastItemRemoved = NULL;
00461 #endif
00462 }
00463 
00464 
00465 
00466 /**********************************************************************************************
00467 
00468 >   ListItem *List::GetHead() const
00469 
00470     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00471     Created:    14/4/93
00472     Inputs:     None
00473     Outputs:    None
00474     Returns:    ListItem if not empty
00475                 NULL if empty list
00476     Purpose:    To allow access to the ListItem at the head of the list.
00477     Errors:     None.
00478 
00479 **********************************************************************************************/
00480     
00481 ListItem *List::GetHead() const
00482 {
00483 //  CC_ASSERT_VALID(this);
00484     
00485     if (this->IsEmpty())
00486         return NULL;
00487     else
00488         return HeadItem;    
00489 }
00490 
00491 
00492 
00493 /**********************************************************************************************
00494 
00495 >   ListItem *List::GetTail() const
00496 
00497     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00498     Created:    14/4/93
00499     Inputs:     None
00500     Outputs:    None
00501     Returns:    ListItem if not empty
00502                 NULL if list empty
00503     Purpose:    To allow access to the ListItem at the tail of the list.
00504     Errors:     None.
00505 
00506 **********************************************************************************************/
00507     
00508 ListItem *List::GetTail( ) const
00509 {
00510 //  CC_ASSERT_VALID(this);
00511     
00512     if (this->IsEmpty())
00513         return NULL;
00514     else
00515         return TailItem;
00516 }
00517 
00518 
00519 
00520 /**********************************************************************************************
00521 
00522 >   LISTPOS List::GetHeadPosition() const
00523 
00524     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00525     Created:    14/4/93
00526     Inputs:     None
00527     Outputs:    None
00528     Returns:    ListPosition of head
00529                 EMPTY_LIST error flag 
00530     Purpose:    Gives the user the relative position of the head of the list
00531     Errors:     None.
00532 
00533 **********************************************************************************************/
00534 /*
00535 Technical notes: 
00536 
00537     The first position in the list is always zero.
00538 
00539 **********************************************************************************************/
00540 
00541 LISTPOS List::GetHeadPosition() const
00542 {
00543 //  CC_ASSERT_VALID(this);
00544     
00545     if (this->IsEmpty())
00546         return EMPTY_LIST;
00547     else
00548         return 0;
00549 }
00550 
00551 
00552 
00553 /**********************************************************************************************
00554 
00555 >   LISTPOS List::GetTailPosition() const
00556 
00557     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00558     Created:    14/4/93
00559     Inputs:     None
00560     Outputs:    None
00561     Returns:    ListPosition of tail item
00562                 EMPTY_LIST error flag 
00563     Purpose:    Gives the user the relative position of the tail of the list
00564     Errors:     None.
00565 
00566 
00567 **********************************************************************************************/
00568 /*
00569 Technical notes: 
00570 
00571     The first position in the list is zero therefore the last is:  
00572             
00573             ( Number of Items - 1 )
00574 
00575 **********************************************************************************************/
00576 
00577 LISTPOS List::GetTailPosition() const
00578 {
00579 //  CC_ASSERT_VALID(this);
00580                           
00581     if (this->IsEmpty())
00582         return EMPTY_LIST;
00583     else                      
00584         return (ItemCount - 1);
00585 }
00586 
00587 
00588 
00589 /**********************************************************************************************
00590 
00591 >   LISTPOS List::FindPosition(ListItem * here) const
00592 
00593     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00594     Created:    14/4/93
00595     Inputs:     ListItem
00596     Outputs:    None
00597     Returns:    ListPosition if found
00598                 NOT_IN_LIST if not found or input is NULL
00599                 EMPTY_LIST if list is empty
00600     Purpose:    Gives the user the relative position of the ListItem passed in.
00601     Errors:     None.
00602 
00603 
00604 **********************************************************************************************/
00605 
00606 LISTPOS List::FindPosition(ListItem * here) const
00607 {
00608 //  CC_ASSERT_VALID(this);
00609 
00610 
00611     if (this->IsEmpty())                            // if list is empty return a null pointer
00612         return EMPTY_LIST;                                
00613    
00614     if (here == NULL)                               // if input list item is NULL
00615         return NOT_IN_LIST;
00616 
00617     ListItem *listIter;                             // list iterator 
00618     LISTPOS listCount = 0;                          // list iterator count
00619                  
00620     listIter = HeadItem;
00621     
00622     while (listIter != here && listIter != NULL)    // iterate until input ListItem found
00623     {
00624         listIter = listIter->Next;
00625         listCount += 1;
00626     }
00627         
00628     if (listIter == NULL)
00629         return NOT_IN_LIST;
00630     else
00631         return listCount;
00632 }
00633 
00634 
00635 
00636 /**********************************************************************************************
00637 
00638 >   ListItem *List::FindItem(LISTPOS here) const
00639 
00640     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00641     Created:    21/4/93
00642     Inputs:     ListItem
00643     Outputs:    None
00644     Returns:    ListItem if found
00645                 NULL if not found or input is less than zero or list is empty
00646     Purpose:    Gives the user the ListItem at list position passed in.
00647     Errors:     None.
00648 
00649 
00650 **********************************************************************************************/
00651 
00652 ListItem *List::FindItem(LISTPOS  here) const
00653 {
00654 //  CC_ASSERT_VALID(this);
00655 
00656 
00657     if ((this->IsEmpty()) || (here < 0))            // if list is empty return a null pointer
00658         return NULL;
00659 
00660     ListItem *listIter;                             // list iterator 
00661     LISTPOS listCount = 0;                          // list iterator count
00662                  
00663     listIter = HeadItem;
00664     
00665     while (listCount != here && listIter != NULL)   // iterate until input List position found
00666     {
00667         listIter = listIter->Next;
00668         listCount += 1;
00669     }
00670         
00671     return listIter;
00672 }
00673 
00674 
00675 
00676 /**********************************************************************************************
00677 
00678 >   virtual ListItem *List::RemoveItem( ListItem* )
00679 
00680     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00681     Created:    15/4/93
00682     Inputs:     ListItem
00683     Outputs:    None
00684     Returns:    ListItem removed
00685                 NULL if not found or if list empty or input is NULL
00686     Purpose:                
00687     
00688         Removes the ListItem passed in as a parameter. It is the responsibility of the
00689         caller to delete the removed ListItem from memory.  
00690         
00691     Errors:     In debug builds, an ENSURE is triggered if the item to be removed is not
00692                 actually in the list.
00693 
00694 
00695 **********************************************************************************************/
00696 /*
00697 Technical notes: 
00698 
00699     Assert is used to trap the error caused by trying to remove an item not in the list. It
00700     does this by scanning the entire list with the function FindPosition() and if item is not 
00701     found assert will stop the program. This will only occur in the debug version of the list
00702     class, the release copy will not include this overhead. 
00703 
00704 **********************************************************************************************/
00705 
00706 ListItem *List::RemoveItem( ListItem* oldItem )
00707 {
00708 //  CC_ASSERT_VALID(this);
00709 
00710 #ifdef _DEBUG
00711     if (ListDebugLevel > 0)
00712     {
00713         ENSURE( this->FindPosition(oldItem) != NOT_IN_LIST,
00714                 "RemoveItem: List item to be removed is not in the list");
00715     }
00716 #endif
00717 
00718     if ((this->IsEmpty()) ||                            // if list is empty or
00719         (oldItem == NULL))                              //    NULL input or
00720         return NULL;
00721 
00722     ListItem *adjacentItem;
00723                                                    
00724     if ((oldItem->Previous) != NULL) 
00725     {
00726         adjacentItem = oldItem->Previous;               //  point to previous item in list
00727         adjacentItem->Next = oldItem->Next;             //  by pass old item forwards
00728         if ((oldItem->Next) != NULL)                    // Remove from middle of ist
00729         {                                               //  there are items both sides
00730             adjacentItem = oldItem->Next;               //  point to next item in list
00731             adjacentItem->Previous = oldItem->Previous; //  by pass old item backwards
00732         }
00733         else
00734         {                                               // Removal of tail of list 
00735             TailItem = adjacentItem;                    //  new tail item
00736         } 
00737     }   
00738     else
00739     {                                                   // Removal of head of list
00740         if ((oldItem->Next) != NULL)
00741         {
00742             adjacentItem = oldItem->Next;               //  next item in list
00743             adjacentItem->Previous = NULL;              //  nullify prev pointer to old item
00744             HeadItem = adjacentItem;                    //  new head item       
00745         }
00746         else
00747         {   
00748             HeadItem = NULL;                            // nullify head and tail pointers
00749             TailItem = NULL;                        
00750         }
00751     }
00752     
00753     ItemCount -= 1;                                     // decrement item counter
00754 
00755 #ifdef _DEBUG
00756     LastItemRemoved = oldItem;                          // Check for stupidity - see GetNext/Prev
00757 #endif
00758 
00759     oldItem->Previous = NULL;                           // Er, we should vape the disused links
00760     oldItem->Next = NULL;                               // shouldn't we?
00761 
00762     return oldItem;
00763 }                   
00764 
00765 
00766 
00767 /**********************************************************************************************
00768 
00769 >   virtual LISTPOS List::InsertBefore(LISTPOS here, ListItem* newItem)
00770 
00771     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00772     Created:    15/4/93
00773     Inputs:     ListItem to be inserted
00774                 List position 
00775     Outputs:    None
00776     Returns:    List position new item is inserted at.
00777                 INVALID_LISTPOS when the list position goes beyond the list size 
00778                 INVALID_NEWITEM when the new item is NULL
00779     Purpose:    Inserts a ListItem in the list position before the one that is passed in.
00780     Notes:      This function involves scanning the entire list until 'here' is found,
00781                 so is much slower on average than the other flavour of InsertBefore
00782     Errors:     This ALWAYS checks that the item you wish to insert
00783                 before is actually in the list, and that the item you are inserting
00784                 is not already in the list - an ENSURE failure results if not.
00785     
00786 **********************************************************************************************/
00787 /*
00788 Technical notes:   
00789 
00790     If a new item is added to the list that already exists the list will become corrupted.
00791     In order to trap this error the FindPosition() function can be used to scan the list, 
00792     but this will cause a performance overhead. The solution is to perform the scan only in  
00793     debug mode so that users of the list are warned during development while release versions 
00794     of the software do not suffer from inadequate performance.
00795    
00796 **********************************************************************************************/
00797 
00798 LISTPOS List::InsertBefore(LISTPOS here, ListItem* newItem)
00799 {           
00800 //  CC_ASSERT_VALID(this);
00801 
00802 #ifdef _DEBUG
00803     if (ListDebugLevel > 0)
00804     {
00805         if (!this->IsEmpty())
00806             ENSURE( this->FindPosition(newItem) == NOT_IN_LIST, 
00807                     "InsertBefore: Item to be inserted is already in the list");
00808     }
00809 #endif
00810 
00811     if ((this->IsEmpty()) && (here > 0))
00812         return INVALID_LISTPOS;
00813     
00814     if (newItem == NULL)                            // if input parameter is NULL
00815         return INVALID_NEWITEM; 
00816     
00817     if (here == this->GetHeadPosition())            // if head of list 
00818     {
00819         this->AddHead(newItem);                     // insert before head
00820         return this->GetHeadPosition();
00821     }
00822 
00823     ListItem *listIter;                             // list iterator 
00824     LISTPOS listCount = this->GetHeadPosition();    // list iterator count
00825                  
00826     listIter = HeadItem;
00827     
00828     while (listCount != here && listIter != NULL)   // iterate until list position found
00829     {
00830         listIter = listIter->Next;
00831         listCount += 1;
00832     }
00833 
00834     if (listIter == NULL)                           // list position does not exist in list
00835         return INVALID_LISTPOS;
00836 
00837     newItem->Next = listIter;                       // point new item to before one
00838     newItem->Previous = listIter->Previous;         // point new item to previous one 
00839     listIter->Previous = newItem;                   // point before item to new one
00840     newItem->Previous->Next = newItem;              // point previous item back new one
00841     ItemCount += 1;                                 // increment item counter
00842 
00843 #ifdef _DEBUG
00844     if (newItem == LastItemRemoved)
00845         LastItemRemoved = NULL;
00846 #endif
00847 
00848     return listCount;
00849 }
00850 
00851 
00852 
00853 /**********************************************************************************************
00854 
00855 >   virtual ListItem *List::InsertBefore(ListItem* here, ListItem* newItem)
00856 
00857     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00858     Created:    15/4/93
00859     Inputs:     ListItem to be inserted
00860                 ListItem before insertion 
00861     Outputs:    None
00862     Returns:    ListItem inserted
00863                 INVALID_NEWITEM when the new item is NULL
00864                 NULL if list empty or ListItem not found or parameters are NULL
00865     Purpose:    Inserts the 'newItem' ListItem before 'here' ListItem in the list.
00866     Errors:     In the debug build, this checks that the item you wish to insert
00867                 before is actually in the list, and that the item you are inserting
00868                 is not already in the list - an ENSURE failure results if not.
00869     
00870 **********************************************************************************************/
00871 /*
00872 Technical notes:   
00873 
00874     If a new item is added to the list that already exists the list will become corrupted.
00875     In order to trap this error the FindPosition() function can be used to scan the list, 
00876     but this will cause a performance overhead. The solution is to perform the scan only in  
00877     debug mode so that users of the list are warned during development while release versions 
00878     of the software do not suffer from inadequate performance.
00879    
00880 **********************************************************************************************/
00881 
00882 ListItem *List::InsertBefore(ListItem* here, ListItem* newItem)
00883 {
00884 //  CC_ASSERT_VALID(this);
00885 
00886 #ifdef _DEBUG
00887     if (ListDebugLevel > 0)
00888     {
00889         if (!this->IsEmpty())
00890             ENSURE( this->FindPosition(newItem) == NOT_IN_LIST, 
00891                     "InsertBefore: Item to be inserted is already in the list");
00892     }
00893 #endif
00894 
00895     if (this->IsEmpty() || (here == NULL) || (newItem == NULL))
00896         return NULL;
00897     
00898     if (here == HeadItem)                           // if head of list 
00899     {
00900         this->AddHead(newItem);                     // insert before head
00901         return newItem;
00902     }
00903 
00904 #ifdef _DEBUG
00905     if (ListDebugLevel > 0)
00906     {
00907         ListItem *listIter;                             // list iterator
00908                  
00909         listIter = HeadItem;
00910     
00911         while (listIter != here && listIter != NULL)    // iterate until list position found
00912             listIter = listIter->Next;
00913 
00914         ENSURE (listIter != NULL, "List::InsertBefore(Here) - 'Here' does not exist!");
00915     }
00916 #endif
00917 
00918     newItem->Next = here;                           // point new item to before one
00919     newItem->Previous = here->Previous;             // point new item to previous one 
00920     here->Previous = newItem;                       // point before item to new one
00921     newItem->Previous->Next = newItem;              // point previous item back new one
00922 
00923 #ifdef _DEBUG
00924     if (newItem == LastItemRemoved)
00925         LastItemRemoved = NULL;
00926 #endif
00927 
00928     ItemCount += 1;                                 // increment item counter
00929     return newItem;
00930 }
00931 
00932 
00933 
00934 /**********************************************************************************************
00935 
00936 >   virtual LISTPOS List::InsertAfter(LISTPOS here, ListItem* newItem)
00937 
00938     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00939     Created:    14/4/93
00940     Inputs:     ListItem to be inserted
00941                 List position 
00942     Outputs:    None
00943     Returns:    List position new item is inserted at.
00944                 INVALID_LISTPOS when the list position goes beyond the list size
00945                 INVALID_NEWITEM when new list item is NULL
00946     Purpose:    Inserts a ListItem in the list position after the one that is passed in.
00947     Notes:      To find 'here', the list must be scanned, so this is much slower on
00948                 average than the other flavour of InsertAfter
00949     Errors:     This ALWAYS checks that the item you wish to insert
00950                 after is actually in the list, and that the item you are inserting
00951                 is not already in the list - an ENSURE failure results if not.
00952 
00953 **********************************************************************************************/
00954 /*
00955 Technical notes:   
00956 
00957     If a new item is added to the list that already exists the list will become corrupted.
00958     In order to trap this error the FindPosition() function can be used to scan the list, 
00959     but this will cause a performance overhead. The solution is to perform the scan only in  
00960     debug mode so that users of the list are warned during development while release versions 
00961     of the software do not suffer from inadequate performance.
00962    
00963 **********************************************************************************************/
00964 
00965 LISTPOS List::InsertAfter(LISTPOS here, ListItem* newItem)
00966 {
00967 //  CC_ASSERT_VALID(this);
00968 
00969 #ifdef _DEBUG
00970     if (ListDebugLevel > 0)
00971     {
00972         if (!this->IsEmpty())
00973             ENSURE( this->FindPosition(newItem) == NOT_IN_LIST, 
00974                     "InsertAfter: Item to be inserted is already in the list");
00975     }
00976 #endif
00977 
00978     if ((this->IsEmpty()) && (here > 0))
00979         return INVALID_LISTPOS;
00980         
00981     if (newItem == NULL)                            
00982         return INVALID_NEWITEM;
00983     
00984     if (here == this->GetTailPosition())            // if tail of list 
00985     {
00986         this->AddTail(newItem);                     // insert after tail
00987         return this->GetTailPosition();
00988     }
00989 
00990     ListItem *listIter;                             // list iterator 
00991     LISTPOS listCount = GetHeadPosition();          // list iterator count
00992                  
00993     listIter = HeadItem;
00994     
00995     while (listCount != here && listIter != NULL)   // iterate until list position found
00996     {
00997         listIter = listIter->Next;
00998         listCount += 1;
00999     }
01000 
01001     if (listIter == NULL)                           // list position does not exist in list
01002         return INVALID_LISTPOS;
01003 
01004 
01005     newItem->Previous = listIter;                   // point new item to previous one in list
01006     newItem->Next = listIter->Next;                 // point new item to next one
01007     listIter->Next = newItem;                       // point after item to new one
01008     newItem->Next->Previous = newItem;              // point next item back to new one
01009     ItemCount += 1;                                 // increment item counter
01010 
01011 #ifdef _DEBUG
01012     if (newItem == LastItemRemoved)
01013         LastItemRemoved = NULL;
01014 #endif
01015 
01016     return (listCount + 1);
01017 }
01018 
01019 
01020 
01021 /**********************************************************************************************
01022 
01023 >   virtual ListItem *List::InsertAfter(ListItem* here, ListItem* newItem)
01024 
01025     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
01026     Created:    15/4/93
01027     Inputs:     ListItem to be inserted
01028                 ListItem after insertion 
01029     Outputs:    None
01030     Returns:    ListItem inserted
01031                 NULL if list empty or ListItem not found or parameters are NULL
01032     Purpose:    Inserts the 'newItem' ListItem after 'here' ListItem in the list.
01033     Errors:     In the debug build, this checks that the item you wish to insert
01034                 after is actually in the list, and that the item you are inserting
01035                 is not already in the list - an ENSURE failure results if not.
01036 
01037 **********************************************************************************************/
01038 /*
01039 Technical notes:   
01040 
01041     If a new item is added to the list that already exists the list will become corrupted.
01042     In order to trap this error the FindPosition() function can be used to scan the list, 
01043     but this will cause a performance overhead. The solution is to perform the scan only in  
01044     debug mode so that users of the list are warned during development while release versions 
01045     of the software do not suffer from inadequate performance.
01046    
01047 **********************************************************************************************/
01048 
01049 ListItem *List::InsertAfter(ListItem* here, ListItem* newItem)
01050 {
01051 //  CC_ASSERT_VALID(this);
01052 
01053 #ifdef _DEBUG
01054     if (ListDebugLevel > 0)
01055     {
01056         if (!this->IsEmpty())
01057             ENSURE( this->FindPosition(newItem) == NOT_IN_LIST, 
01058                     "InsertAfter: Item to be inserted is already in the list");
01059     }
01060 #endif
01061 
01062     if ((this->IsEmpty()) || (here == NULL) || (newItem == NULL))
01063         return NULL;
01064         
01065     
01066     if (here == TailItem)                           // if tail of list 
01067     {
01068         this->AddTail(newItem);                     // insert after tail
01069         return newItem;
01070     }
01071 
01072 #ifdef _DEBUG
01073     if (ListDebugLevel > 0)
01074     {
01075         ListItem *listIter = HeadItem;
01076 
01077         while (listIter != here && listIter != NULL)    // iterate until list position found
01078             listIter = listIter->Next;
01079 
01080         if (listIter == NULL)                           // list position does not exist in list
01081         {
01082             return NULL;
01083         }
01084     }
01085 #endif
01086 
01087     newItem->Previous = here;                       // point new item to previous one in list
01088     newItem->Next = here->Next;                     // point new item to next one
01089     here->Next = newItem;                           // point after item to new one
01090     newItem->Next->Previous = newItem;              // point next item back to new one
01091 
01092 #ifdef _DEBUG
01093     if (newItem == LastItemRemoved)
01094         LastItemRemoved = NULL;
01095 #endif
01096 
01097     ItemCount += 1;                                 // increment item counter
01098     return newItem;
01099 }   
01100 
01101 
01102 
01103 /**********************************************************************************************
01104 
01105 >   UINT32 List::GetCount() const
01106 
01107     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
01108     Created:    14/4/93
01109     Inputs:     None
01110     Outputs:    None
01111     Returns:    Number of items in the list
01112     Purpose:    To give user of list an indication of its size in terms of number of items. 
01113     Errors:     None
01114 
01115 **********************************************************************************************/
01116 
01117 UINT32 List::GetCount() const
01118 {
01119 //  CC_ASSERT_VALID(this);
01120 
01121     return ItemCount;
01122 }
01123 
01124 
01125 
01126 /**********************************************************************************************
01127 
01128 >   BOOL List::IsEmpty() const
01129 
01130     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
01131     Created:    14/4/93
01132     Inputs:     None
01133     Outputs:    None
01134     Returns:    TRUE if list is empty
01135                 FALSE if list is not empty
01136     Purpose:    Allows user to see if list is empty or not
01137     Errors:     None
01138 
01139 **********************************************************************************************/
01140 
01141 BOOL List::IsEmpty() const
01142 {
01143 //  CC_ASSERT_VALID(this);
01144 
01145     if (ItemCount == 0)
01146         return TRUE;
01147     else
01148         return FALSE;
01149 }
01150 
01151 /********************************************************************************************
01152 
01153 >   BOOL List::CreateIndex(List* ListIndex)
01154 
01155     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01156     Created:    28/9/95
01157     Outputs:    A List of in-order pointers into 'this' list. Each item on the list is a
01158                 ListItemIdx.
01159     Returns:    FALSE if we run out of memory. All items on the output list are deleted
01160                 if this occurs.
01161     Purpose:    Creates a list of in-order pointers into this list. 
01162     
01163                 This has many uses eg.
01164 
01165                 You wish to scan a list repeatedly, not wasting time considering items
01166                 you are not interested in. This method avoids changing the order of the
01167                 items within the list.
01168 
01169                 Could be used for list sorting etc.
01170                  
01171     SeeAlso:    ListItemIdx
01172 
01173 ********************************************************************************************/
01174 
01175 BOOL List::CreateIndex(List* ListIndex)
01176 {
01177     
01178     ListItem* pi = GetHead();     // pointer to this lists item
01179     ListItemIdx* ppi;             // pointer to pi
01180     while (pi)
01181     {
01182         ppi = new ListItemIdx();
01183         if (!ppi)
01184         {
01185             ListIndex->DeleteAll(); // Tidyup
01186             return FALSE;   
01187         }
01188         ppi->pItem = pi;
01189         ListIndex->AddTail(ppi);
01190         pi = GetNext(pi);  
01191     }
01192     return TRUE;
01193 } 
01194 
01195 
01196 
01197 /**********************************************************************************************
01198 
01199 >   void List::AssertValid() const
01200 
01201     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
01202     Created:    14/4/93
01203     Inputs:     None
01204     Outputs:    None
01205     Returns:    void
01206     Purpose:                  
01207     
01208         Validates the internal state of the object. If an inconsistency is detected
01209         an error message is indicated. This function will not be included in the release 
01210         version.
01211     
01212     Errors:     ENSURE failures will occur if the list is found to be inconsistent
01213 
01214 **********************************************************************************************/
01215 /*
01216 Technical notes: 
01217 
01218         Use of AfxIsValidAddress will cause portability problems if it is not implemented as 
01219         part of the memory management functions of the OIL. It is currently being used on a
01220         temporary basis.
01221 
01222 **********************************************************************************************/
01223 
01224 #ifdef _DEBUG
01225 void List::AssertValid() const
01226 {
01227     CCObject::AssertValid();
01228 
01229     if (ItemCount == 0)
01230     {
01231         // empty list
01232         ENSURE(HeadItem == NULL, "Head item of a non-empty list should never be null");
01233         ENSURE(TailItem == NULL, "Tail item of a non-empty list should never be null");
01234     }
01235 }
01236 #endif   
01237 
01238 // End of List class

Generated on Sat Nov 10 03:45:38 2007 for Camelot by  doxygen 1.4.4