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 
   9 // Licence:     wxWindows licence 
  10 //////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================= 
  14 // ============================================================================= 
  16 // ----------------------------------------------------------------------------- 
  18 // ----------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "list.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  42 // ============================================================================= 
  44 // ============================================================================= 
  46 // ----------------------------------------------------------------------------- 
  48 // ----------------------------------------------------------------------------- 
  49 wxListKey wxDefaultListKey
; 
  51 bool wxListKey::operator==(wxListKeyValue value
) const 
  56             wxFAIL_MSG(wxT("bad key type.")); 
  57             // let compiler optimize the line above away in release build 
  58             // by not putting return here... 
  61             return wxStrcmp(m_key
.string
, value
.string
) == 0; 
  64             return m_key
.integer 
== value
.integer
; 
  68 // ----------------------------------------------------------------------------- 
  70 // ----------------------------------------------------------------------------- 
  72 wxNodeBase::wxNodeBase(wxListBase 
*list
, 
  73                        wxNodeBase 
*previous
, wxNodeBase 
*next
, 
  74                        void *data
, const wxListKey
& key
) 
  78     m_previous 
= previous
; 
  81     switch ( key
.GetKeyType() ) 
  87             m_key
.integer 
= key
.GetNumber(); 
  91             // to be free()d later 
  92             m_key
.string 
= wxStrdup(key
.GetString()); 
  96             wxFAIL_MSG(wxT("invalid key type")); 
 100         previous
->m_next 
= this; 
 103         next
->m_previous 
= this; 
 106 wxNodeBase::~wxNodeBase() 
 108     // handle the case when we're being deleted from the list by the user (i.e. 
 109     // not by the list itself from DeleteNode) - we must do it for 
 110     // compatibility with old code 
 111     if ( m_list 
!= NULL 
) 
 113         if ( m_list
->m_keyType 
== wxKEY_STRING 
) 
 118         m_list
->DetachNode(this); 
 122 int wxNodeBase::IndexOf() const 
 124     wxCHECK_MSG( m_list
, wxNOT_FOUND
, wxT("node doesn't belong to a list in IndexOf")); 
 126     // It would be more efficient to implement IndexOf() completely inside 
 127     // wxListBase (only traverse the list once), but this is probably a more 
 128     // reusable way of doing it. Can always be optimized at a later date (since 
 129     // IndexOf() resides in wxListBase as well) if efficiency is a problem. 
 131     wxNodeBase 
*prev 
= m_previous
; 
 133     for( i 
= 0; prev
; i
++ ) 
 135         prev 
= prev
->m_previous
; 
 141 // ----------------------------------------------------------------------------- 
 143 // ----------------------------------------------------------------------------- 
 145 void wxListBase::Init(wxKeyType keyType
) 
 148   m_nodeLast 
= (wxNodeBase 
*) NULL
; 
 154 wxListBase::wxListBase(size_t count
, void *elements
[]) 
 158   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 164 void wxListBase::DoCopy(const wxListBase
& list
) 
 166     wxASSERT_MSG( !list
.m_destroy
, 
 167                   wxT("copying list which owns it's elements is a bad idea") ); 
 169     m_destroy 
= list
.m_destroy
; 
 170     m_keyType 
= list
.m_keyType
; 
 172     m_nodeLast 
= (wxNodeBase 
*) NULL
; 
 179                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 181                     key 
= node
->GetKeyInteger(); 
 182                     Append(key
, node
->GetData()); 
 190                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 192                     key 
= node
->GetKeyString(); 
 193                     Append(key
, node
->GetData()); 
 200                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 202                     Append(node
->GetData()); 
 208     wxASSERT_MSG( m_count 
== list
.m_count
, _T("logic error in wxList::DoCopy") ); 
 211 wxListBase::~wxListBase() 
 213   wxNodeBase 
*each 
= m_nodeFirst
; 
 214   while ( each 
!= NULL 
) 
 216       wxNodeBase 
*next 
= each
->GetNext(); 
 222 wxNodeBase 
*wxListBase::AppendCommon(wxNodeBase 
*node
) 
 227         m_nodeLast 
= m_nodeFirst
; 
 231         m_nodeLast
->m_next 
= node
; 
 240 wxNodeBase 
*wxListBase::Append(void *object
) 
 242     // all objects in a keyed list should have a key 
 243     wxCHECK_MSG( m_keyType 
== wxKEY_NONE
, (wxNodeBase 
*)NULL
, 
 244                  wxT("need a key for the object to append") ); 
 246     // we use wxDefaultListKey even though it is the default parameter value 
 247     // because gcc under Mac OS X seems to miscompile this call otherwise 
 248     wxNodeBase 
*node 
= CreateNode(m_nodeLast
, (wxNodeBase 
*)NULL
, object
, 
 251     return AppendCommon(node
); 
 254 wxNodeBase 
*wxListBase::Append(long key
, void *object
) 
 256     wxCHECK_MSG( (m_keyType 
== wxKEY_INTEGER
) || 
 257                  (m_keyType 
== wxKEY_NONE 
&& m_count 
== 0), 
 259                  wxT("can't append object with numeric key to this list") ); 
 261     wxNodeBase 
*node 
= CreateNode(m_nodeLast
, (wxNodeBase 
*)NULL
, object
, key
); 
 262     return AppendCommon(node
); 
 265 wxNodeBase 
*wxListBase::Append (const wxChar 
*key
, void *object
) 
 267     wxCHECK_MSG( (m_keyType 
== wxKEY_STRING
) || 
 268                  (m_keyType 
== wxKEY_NONE 
&& m_count 
== 0), 
 270                  wxT("can't append object with string key to this list") ); 
 272     wxNodeBase 
*node 
= CreateNode(m_nodeLast
, (wxNodeBase 
*)NULL
, object
, key
); 
 273     return AppendCommon(node
); 
 276 wxNodeBase 
*wxListBase::Insert(wxNodeBase 
*position
, void *object
) 
 278     // all objects in a keyed list should have a key 
 279     wxCHECK_MSG( m_keyType 
== wxKEY_NONE
, (wxNodeBase 
*)NULL
, 
 280                  wxT("need a key for the object to insert") ); 
 282     wxCHECK_MSG( !position 
|| position
->m_list 
== this, (wxNodeBase 
*)NULL
, 
 283                  wxT("can't insert before a node from another list") ); 
 285     // previous and next node for the node being inserted 
 286     wxNodeBase 
*prev
, *next
; 
 289         prev 
= position
->GetPrevious(); 
 294         // inserting in the beginning of the list 
 295         prev 
= (wxNodeBase 
*)NULL
; 
 299     // wxDefaultListKey: see comment in Append() above 
 300     wxNodeBase 
*node 
= CreateNode(prev
, next
, object
, wxDefaultListKey
); 
 316 wxNodeBase 
*wxListBase::Item(size_t n
) const 
 318     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 326     wxFAIL_MSG( wxT("invalid index in wxListBase::Item") ); 
 328     return (wxNodeBase 
*)NULL
; 
 331 wxNodeBase 
*wxListBase::Find(const wxListKey
& key
) const 
 333     wxASSERT_MSG( m_keyType 
== key
.GetKeyType(), 
 334                   wxT("this list is not keyed on the type of this key") ); 
 336     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 338         if ( key 
== current
->m_key 
) 
 345     return (wxNodeBase 
*)NULL
; 
 348 wxNodeBase 
*wxListBase::Find(const void *object
) const 
 350     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 352         if ( current
->GetData() == object 
) 
 357     return (wxNodeBase 
*)NULL
; 
 360 int wxListBase::IndexOf(void *object
) const 
 362     wxNodeBase 
*node 
= Find( object 
); 
 364     return node 
? node
->IndexOf() : wxNOT_FOUND
; 
 367 void wxListBase::DoDeleteNode(wxNodeBase 
*node
) 
 370     if ( m_keyType 
== wxKEY_STRING 
) 
 372         free(node
->m_key
.string
); 
 380     // so that the node knows that it's being deleted by the list 
 385 wxNodeBase 
*wxListBase::DetachNode(wxNodeBase 
*node
) 
 387     wxCHECK_MSG( node
, NULL
, wxT("detaching NULL wxNodeBase") ); 
 388     wxCHECK_MSG( node
->m_list 
== this, NULL
, 
 389                  wxT("detaching node which is not from this list") ); 
 392     wxNodeBase 
**prevNext 
= node
->GetPrevious() ? &node
->GetPrevious()->m_next
 
 394     wxNodeBase 
**nextPrev 
= node
->GetNext() ? &node
->GetNext()->m_previous
 
 397     *prevNext 
= node
->GetNext(); 
 398     *nextPrev 
= node
->GetPrevious(); 
 402     // mark the node as not belonging to this list any more 
 408 bool wxListBase::DeleteNode(wxNodeBase 
*node
) 
 410     if ( !DetachNode(node
) ) 
 418 bool wxListBase::DeleteObject(void *object
) 
 420     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 422         if ( current
->GetData() == object 
) 
 433 void wxListBase::Clear() 
 435     wxNodeBase 
*current 
= m_nodeFirst
; 
 438         wxNodeBase 
*next 
= current
->GetNext(); 
 439         DoDeleteNode(current
); 
 444     m_nodeLast 
= (wxNodeBase 
*)NULL
; 
 449 void wxListBase::ForEach(wxListIterateFunction F
) 
 451     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 453         (*F
)(current
->GetData()); 
 457 void *wxListBase::FirstThat(wxListIterateFunction F
) 
 459     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 461         if ( (*F
)(current
->GetData()) ) 
 462             return current
->GetData(); 
 465     return (wxNodeBase 
*)NULL
; 
 468 void *wxListBase::LastThat(wxListIterateFunction F
) 
 470     for ( wxNodeBase 
*current 
= GetLast(); current
; current 
= current
->GetPrevious() ) 
 472         if ( (*F
)(current
->GetData()) ) 
 473             return current
->GetData(); 
 476     return (wxNodeBase 
*)NULL
; 
 479 // (stefan.hammes@urz.uni-heidelberg.de) 
 481 // function for sorting lists. the concept is borrowed from 'qsort'. 
 482 // by giving a sort function, arbitrary lists can be sorted. 
 484 // - put wxObject pointers into an array 
 485 // - sort the array with qsort 
 486 // - put back the sorted wxObject pointers into the list 
 488 // CAVE: the sort function receives pointers to wxObject pointers (wxObject **), 
 489 //       so dereference right! 
 491 //   int listcompare(const void *arg1, const void *arg2) 
 493 //      return(compare(**(wxString **)arg1, 
 494 //                     **(wxString **)arg2)); 
 501 //     list.Append(new wxString("DEF")); 
 502 //     list.Append(new wxString("GHI")); 
 503 //     list.Append(new wxString("ABC")); 
 504 //     list.Sort(listcompare); 
 507 void wxListBase::Sort(const wxSortCompareFunction compfunc
) 
 509     // allocate an array for the wxObject pointers of the list 
 510     const size_t num 
= GetCount(); 
 511     void **objArray 
= new void *[num
]; 
 512     void **objPtr 
= objArray
; 
 514     // go through the list and put the pointers into the array 
 516     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 518         *objPtr
++ = node
->GetData(); 
 522     qsort((void *)objArray
,num
,sizeof(wxObject 
*), 
 524         (int (__cdecl 
*)(const void *,const void *)) 
 528     // put the sorted pointers back into the list 
 530     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 532         node
->SetData(*objPtr
++); 
 539 void wxListBase::Reverse() 
 541     wxNodeBase
* node 
= m_nodeFirst
; 
 546         // swap prev and next pointers 
 548         node
->m_next 
= node
->m_previous
; 
 549         node
->m_previous 
= tmp
; 
 551         // this is the node that was next before swapping 
 555     // swap first and last node 
 556     tmp 
= m_nodeFirst
; m_nodeFirst 
= m_nodeLast
; m_nodeLast 
= tmp
; 
 559 void wxListBase::DeleteNodes(wxNodeBase
* first
, wxNodeBase
* last
) 
 561     wxNodeBase
* node 
= first
; 
 565         wxNodeBase
* next 
= node
->GetNext(); 
 571 // ============================================================================ 
 572 // compatibility section from now on 
 573 // ============================================================================ 
 575 #ifdef wxLIST_COMPATIBILITY 
 577 // ----------------------------------------------------------------------------- 
 578 // wxList (a.k.a. wxObjectList) 
 579 // ----------------------------------------------------------------------------- 
 581 IMPLEMENT_DYNAMIC_CLASS(wxList
, wxObject
) 
 583 wxList::wxList( int key_type 
) 
 584     : wxObjectList( (wxKeyType
)key_type 
) 
 588 void wxObjectListNode::DeleteData() 
 590     delete (wxObject 
*)GetData(); 
 593 // ---------------------------------------------------------------------------- 
 595 // ---------------------------------------------------------------------------- 
 597 static inline wxChar
* MYcopystring(const wxString
& s
) 
 599     wxChar
* copy 
= new wxChar
[s
.length() + 1]; 
 600     return wxStrcpy(copy
, s
.c_str()); 
 603 static inline wxChar
* MYcopystring(const wxChar
* s
) 
 605     wxChar
* copy 
= new wxChar
[wxStrlen(s
) + 1]; 
 606     return wxStrcpy(copy
, s
); 
 609 IMPLEMENT_DYNAMIC_CLASS(wxStringList
, wxObject
) 
 611 // instead of WX_DEFINE_LIST(wxStringListBase) we define this function 
 613 void wxStringListNode::DeleteData() 
 615     delete [] (char *)GetData(); 
 618 bool wxStringList::Delete(const wxChar 
*s
) 
 620     wxStringListNode 
*current
; 
 622     for ( current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 624         if ( wxStrcmp(current
->GetData(), s
) == 0 ) 
 635 void wxStringList::DoCopy(const wxStringList
& other
) 
 637     wxASSERT( GetCount() == 0 );    // this list must be empty before copying! 
 639     size_t count 
= other
.GetCount(); 
 640     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 642         Add(other
.Item(n
)->GetData()); 
 646 wxStringList::wxStringList() 
 648     DeleteContents(true); 
 651 // Variable argument list, terminated by a zero 
 652 // Makes new storage for the strings 
 653 wxStringList::wxStringList (const wxChar 
*first
, ...) 
 655   DeleteContents(true); 
 662   const wxChar 
*s 
= first
; 
 667       s 
= va_arg(ap
, const wxChar 
*); 
 670       if ((int)(long) s 
== 0) 
 680 // Only makes new strings if arg is true 
 681 wxChar 
**wxStringList::ListToArray(bool new_copies
) const 
 683     wxChar 
**string_array 
= new wxChar 
*[GetCount()]; 
 684     wxStringListNode 
*node 
= GetFirst(); 
 685     for (size_t i 
= 0; i 
< GetCount(); i
++) 
 687         wxChar 
*s 
= node
->GetData(); 
 689             string_array
[i
] = MYcopystring(s
); 
 692         node 
= node
->GetNext(); 
 698 // Checks whether s is a member of the list 
 699 bool wxStringList::Member(const wxChar 
*s
) const 
 701     for ( wxStringListNode 
*node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 703         const wxChar 
*s1 
= node
->GetData(); 
 704         if (s 
== s1 
|| wxStrcmp (s
, s1
) == 0) 
 712 extern "C" int __cdecl
 
 714 extern "C" int LINKAGEMODE
 
 717 wx_comparestrings(const void *arg1
, const void *arg2
) 
 719   wxChar 
**s1 
= (wxChar 
**) arg1
; 
 720   wxChar 
**s2 
= (wxChar 
**) arg2
; 
 722   return wxStrcmp (*s1
, *s2
); 
 725 // Sort a list of strings - deallocates old nodes, allocates new 
 726 void wxStringList::Sort() 
 728     size_t N 
= GetCount(); 
 729     wxChar 
**array 
= new wxChar 
*[N
]; 
 730     wxStringListNode 
*node
; 
 733     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 735         array
[i
++] = node
->GetData(); 
 738     qsort (array
, N
, sizeof (wxChar 
*), wx_comparestrings
); 
 741     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 742         node
->SetData( array
[i
++] ); 
 747 wxNode 
*wxStringList::Add(const wxChar 
*s
) 
 749     return (wxNode 
*)wxStringListBase::Append(MYcopystring(s
)); 
 752 wxNode 
*wxStringList::Prepend(const wxChar 
*s
) 
 754     return (wxNode 
*)wxStringListBase::Insert(MYcopystring(s
)); 
 757 #endif // wxLIST_COMPATIBILITY 
 759 #else // wxUSE_STL = 1 
 761     #include <wx/listimpl.cpp> 
 762     WX_DEFINE_LIST(wxObjectList
); 
 764 // with wxUSE_STL wxStringList contains wxString objects, not pointers 
 765 void wxStringListBase::DeleteFunction( const wxString X 
)