1 //////////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxList implementation 
   4 // Author:      Julian Smart 
   5 // Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows license 
  10 //////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================= 
  14 // ============================================================================= 
  16 // ----------------------------------------------------------------------------- 
  18 // ----------------------------------------------------------------------------- 
  20 #pragma implementation "list.h" 
  23 // For compilers that support precompilation, includes "wx.h". 
  24 #include "wx/wxprec.h" 
  37     #include "wx/utils.h"   // for copystring() (beurk...) 
  40 // ============================================================================= 
  42 // ============================================================================= 
  44 // ----------------------------------------------------------------------------- 
  46 // ----------------------------------------------------------------------------- 
  48 wxListKey wxDefaultListKey
; 
  50 bool wxListKey::operator==(wxListKeyValue value
) const 
  55             wxFAIL_MSG(wxT("bad key type.")); 
  56             // let compiler optimize the line above away in release build 
  57             // by not putting return here... 
  60             return wxStrcmp(m_key
.string
, value
.string
) == 0; 
  63             return m_key
.integer 
== value
.integer
; 
  67 // ----------------------------------------------------------------------------- 
  69 // ----------------------------------------------------------------------------- 
  71 wxNodeBase::wxNodeBase(wxListBase 
*list
, 
  72                        wxNodeBase 
*previous
, wxNodeBase 
*next
, 
  73                        void *data
, const wxListKey
& key
) 
  77     m_previous 
= previous
; 
  80     switch ( key
.GetKeyType() ) 
  86             m_key
.integer 
= key
.GetNumber(); 
  90             // to be free()d later 
  91             m_key
.string 
= wxStrdup(key
.GetString()); 
  95             wxFAIL_MSG(wxT("invalid key type")); 
  99         previous
->m_next 
= this; 
 102         next
->m_previous 
= this; 
 105 wxNodeBase::~wxNodeBase() 
 107     // handle the case when we're being deleted from the list by the user (i.e. 
 108     // not by the list itself from DeleteNode) - we must do it for 
 109     // compatibility with old code 
 110     if ( m_list 
!= NULL 
) 
 112         if ( m_list
->m_keyType 
== wxKEY_STRING 
) 
 117         m_list
->DetachNode(this); 
 121 int wxNodeBase::IndexOf() const 
 123     wxCHECK_MSG( m_list
, wxNOT_FOUND
, wxT("node doesn't belong to a list in IndexOf")); 
 125     // It would be more efficient to implement IndexOf() completely inside 
 126     // wxListBase (only traverse the list once), but this is probably a more 
 127     // reusable way of doing it. Can always be optimized at a later date (since 
 128     // IndexOf() resides in wxListBase as well) if efficiency is a problem. 
 130     wxNodeBase 
*prev 
= m_previous
; 
 132     for( i 
= 0; prev
; i
++ ) 
 134         prev 
= prev
->m_previous
; 
 140 // ----------------------------------------------------------------------------- 
 142 // ----------------------------------------------------------------------------- 
 144 void wxListBase::Init(wxKeyType keyType
) 
 147   m_nodeLast 
= (wxNodeBase 
*) NULL
; 
 153 wxListBase::wxListBase(size_t count
, void *elements
[]) 
 157   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 163 void wxListBase::DoCopy(const wxListBase
& list
) 
 165     wxASSERT_MSG( !list
.m_destroy
, 
 166                   wxT("copying list which owns it's elements is a bad idea") ); 
 168     m_destroy 
= list
.m_destroy
; 
 169     m_keyType 
= list
.m_keyType
; 
 171     m_nodeLast 
= (wxNodeBase 
*) NULL
; 
 178                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 180                     key 
= node
->GetKeyInteger(); 
 181                     Append(key
, node
->GetData()); 
 189                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 191                     key 
= node
->GetKeyString(); 
 192                     Append(key
, node
->GetData()); 
 199                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 201                     Append(node
->GetData()); 
 207     wxASSERT_MSG( m_count 
== list
.m_count
, _T("logic error in wxList::DoCopy") ); 
 210 wxListBase::~wxListBase() 
 212   wxNodeBase 
*each 
= m_nodeFirst
; 
 213   while ( each 
!= NULL 
) 
 215       wxNodeBase 
*next 
= each
->GetNext(); 
 221 wxNodeBase 
*wxListBase::AppendCommon(wxNodeBase 
*node
) 
 226         m_nodeLast 
= m_nodeFirst
; 
 230         m_nodeLast
->m_next 
= node
; 
 239 wxNodeBase 
*wxListBase::Append(void *object
) 
 241     // all objects in a keyed list should have a key 
 242     wxCHECK_MSG( m_keyType 
== wxKEY_NONE
, (wxNodeBase 
*)NULL
, 
 243                  wxT("need a key for the object to append") ); 
 245     wxNodeBase 
*node 
= CreateNode(m_nodeLast
, (wxNodeBase 
*)NULL
, object
); 
 247     return AppendCommon(node
); 
 250 wxNodeBase 
*wxListBase::Append(long key
, void *object
) 
 252     wxCHECK_MSG( (m_keyType 
== wxKEY_INTEGER
) || 
 253                  (m_keyType 
== wxKEY_NONE 
&& m_count 
== 0), 
 255                  wxT("can't append object with numeric key to this list") ); 
 257     wxNodeBase 
*node 
= CreateNode(m_nodeLast
, (wxNodeBase 
*)NULL
, object
, key
); 
 258     return AppendCommon(node
); 
 261 wxNodeBase 
*wxListBase::Append (const wxChar 
*key
, void *object
) 
 263     wxCHECK_MSG( (m_keyType 
== wxKEY_STRING
) || 
 264                  (m_keyType 
== wxKEY_NONE 
&& m_count 
== 0), 
 266                  wxT("can't append object with string key to this list") ); 
 268     wxNodeBase 
*node 
= CreateNode(m_nodeLast
, (wxNodeBase 
*)NULL
, object
, key
); 
 269     return AppendCommon(node
); 
 272 wxNodeBase 
*wxListBase::Insert(wxNodeBase 
*position
, void *object
) 
 274     // all objects in a keyed list should have a key 
 275     wxCHECK_MSG( m_keyType 
== wxKEY_NONE
, (wxNodeBase 
*)NULL
, 
 276                  wxT("need a key for the object to insert") ); 
 278     wxCHECK_MSG( !position 
|| position
->m_list 
== this, (wxNodeBase 
*)NULL
, 
 279                  wxT("can't insert before a node from another list") ); 
 281     // previous and next node for the node being inserted 
 282     wxNodeBase 
*prev
, *next
; 
 285         prev 
= position
->GetPrevious(); 
 290         // inserting in the beginning of the list 
 291         prev 
= (wxNodeBase 
*)NULL
; 
 295     wxNodeBase 
*node 
= CreateNode(prev
, next
, object
); 
 311 wxNodeBase 
*wxListBase::Item(size_t n
) const 
 313     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 321     wxFAIL_MSG( wxT("invalid index in wxListBase::Item") ); 
 323     return (wxNodeBase 
*)NULL
; 
 326 wxNodeBase 
*wxListBase::Find(const wxListKey
& key
) const 
 328     wxASSERT_MSG( m_keyType 
== key
.GetKeyType(), 
 329                   wxT("this list is not keyed on the type of this key") ); 
 331     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 333         if ( key 
== current
->m_key 
) 
 340     return (wxNodeBase 
*)NULL
; 
 343 wxNodeBase 
*wxListBase::Find(void *object
) const 
 345     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 347         if ( current
->GetData() == object 
) 
 352     return (wxNodeBase 
*)NULL
; 
 355 int wxListBase::IndexOf(void *object
) const 
 357     wxNodeBase 
*node 
= Find( object 
); 
 359     return node 
? node
->IndexOf() : wxNOT_FOUND
; 
 362 void wxListBase::DoDeleteNode(wxNodeBase 
*node
) 
 365     if ( m_keyType 
== wxKEY_STRING 
) 
 367         free(node
->m_key
.string
); 
 375     // so that the node knows that it's being deleted by the list 
 380 wxNodeBase 
*wxListBase::DetachNode(wxNodeBase 
*node
) 
 382     wxCHECK_MSG( node
, NULL
, wxT("detaching NULL wxNodeBase") ); 
 383     wxCHECK_MSG( node
->m_list 
== this, NULL
, 
 384                  wxT("detaching node which is not from this list") ); 
 387     wxNodeBase 
**prevNext 
= node
->GetPrevious() ? &node
->GetPrevious()->m_next
 
 389     wxNodeBase 
**nextPrev 
= node
->GetNext() ? &node
->GetNext()->m_previous
 
 392     *prevNext 
= node
->GetNext(); 
 393     *nextPrev 
= node
->GetPrevious(); 
 397     // mark the node as not belonging to this list any more 
 403 bool wxListBase::DeleteNode(wxNodeBase 
*node
) 
 405     if ( !DetachNode(node
) ) 
 413 bool wxListBase::DeleteObject(void *object
) 
 415     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 417         if ( current
->GetData() == object 
) 
 428 void wxListBase::Clear() 
 430     wxNodeBase 
*current 
= m_nodeFirst
; 
 433         wxNodeBase 
*next 
= current
->GetNext(); 
 434         DoDeleteNode(current
); 
 439     m_nodeLast 
= (wxNodeBase 
*)NULL
; 
 444 void wxListBase::ForEach(wxListIterateFunction F
) 
 446     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 448         (*F
)(current
->GetData()); 
 452 void *wxListBase::FirstThat(wxListIterateFunction F
) 
 454     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 456         if ( (*F
)(current
->GetData()) ) 
 457             return current
->GetData(); 
 460     return (wxNodeBase 
*)NULL
; 
 463 void *wxListBase::LastThat(wxListIterateFunction F
) 
 465     for ( wxNodeBase 
*current 
= GetLast(); current
; current 
= current
->GetPrevious() ) 
 467         if ( (*F
)(current
->GetData()) ) 
 468             return current
->GetData(); 
 471     return (wxNodeBase 
*)NULL
; 
 474 // (stefan.hammes@urz.uni-heidelberg.de) 
 476 // function for sorting lists. the concept is borrowed from 'qsort'. 
 477 // by giving a sort function, arbitrary lists can be sorted. 
 479 // - put wxObject pointers into an array 
 480 // - sort the array with qsort 
 481 // - put back the sorted wxObject pointers into the list 
 483 // CAVE: the sort function receives pointers to wxObject pointers (wxObject **), 
 484 //       so dereference right! 
 486 //   int listcompare(const void *arg1, const void *arg2) 
 488 //      return(compare(**(wxString **)arg1, 
 489 //                     **(wxString **)arg2)); 
 496 //     list.Append(new wxString("DEF")); 
 497 //     list.Append(new wxString("GHI")); 
 498 //     list.Append(new wxString("ABC")); 
 499 //     list.Sort(listcompare); 
 502 void wxListBase::Sort(const wxSortCompareFunction compfunc
) 
 504     // allocate an array for the wxObject pointers of the list 
 505     const size_t num 
= GetCount(); 
 506     void **objArray 
= new void *[num
]; 
 507     void **objPtr 
= objArray
; 
 509     // go through the list and put the pointers into the array 
 511     for ( node 
= GetFirst(); node
; node 
= node
->Next() ) 
 513         *objPtr
++ = node
->Data(); 
 517     qsort((void *)objArray
,num
,sizeof(wxObject 
*),compfunc
); 
 519     // put the sorted pointers back into the list 
 521     for ( node 
= GetFirst(); node
; node 
= node
->Next() ) 
 523         node
->SetData(*objPtr
++); 
 530 // ----------------------------------------------------------------------------- 
 531 // wxList (a.k.a. wxObjectList) 
 532 // ----------------------------------------------------------------------------- 
 534 void wxObjectListNode::DeleteData() 
 536     delete (wxObject 
*)GetData(); 
 539 // ----------------------------------------------------------------------------- 
 541 // ----------------------------------------------------------------------------- 
 543 // instead of WX_DEFINE_LIST(wxStringListBase) we define this function 
 545 void wxStringListNode::DeleteData() 
 547     delete [] (char *)GetData(); 
 550 bool wxStringList::Delete(const wxChar 
*s
) 
 552     wxStringListNode 
*current
; 
 554     for ( current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 556         if ( wxStrcmp(current
->GetData(), s
) == 0 ) 
 567 void wxStringList::DoCopy(const wxStringList
& other
) 
 569     wxASSERT( GetCount() == 0 );    // this list must be empty before copying! 
 571     size_t count 
= other
.GetCount(); 
 572     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 574         Add(other
.Item(n
)->GetData()); 
 578 // Variable argument list, terminated by a zero 
 579 // Makes new storage for the strings 
 580 wxStringList::wxStringList (const wxChar 
*first
, ...) 
 582   DeleteContents(TRUE
); 
 589   const wxChar 
*s 
= first
; 
 594       s 
= va_arg(ap
, const wxChar 
*); 
 597       if ((int)(long) s 
== 0) 
 607 // Only makes new strings if arg is TRUE 
 608 wxChar 
**wxStringList::ListToArray(bool new_copies
) const 
 610     wxChar 
**string_array 
= new wxChar 
*[GetCount()]; 
 611     wxStringListNode 
*node 
= GetFirst(); 
 612     for (size_t i 
= 0; i 
< GetCount(); i
++) 
 614         wxChar 
*s 
= node
->GetData(); 
 616             string_array
[i
] = copystring(s
); 
 619         node 
= node
->GetNext(); 
 625 // Checks whether s is a member of the list 
 626 bool wxStringList::Member(const wxChar 
*s
) const 
 628     for ( wxStringListNode 
*node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 630         const wxChar 
*s1 
= node
->GetData(); 
 631         if (s 
== s1 
|| wxStrcmp (s
, s1
) == 0) 
 638 static int LINKAGEMODE
 
 639 wx_comparestrings(const void *arg1
, const void *arg2
) 
 641   wxChar 
**s1 
= (wxChar 
**) arg1
; 
 642   wxChar 
**s2 
= (wxChar 
**) arg2
; 
 644   return wxStrcmp (*s1
, *s2
); 
 647 // Sort a list of strings - deallocates old nodes, allocates new 
 648 void wxStringList::Sort() 
 650     size_t N 
= GetCount(); 
 651     wxChar 
**array 
= new wxChar 
*[N
]; 
 652     wxStringListNode 
*node
; 
 655     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 657         array
[i
++] = node
->GetData(); 
 660     qsort (array
, N
, sizeof (wxChar 
*), wx_comparestrings
); 
 663     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 664         node
->SetData( array
[i
++] );