1 //////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/list.cpp 
   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 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  38 // ============================================================================= 
  40 // ============================================================================= 
  42 // ----------------------------------------------------------------------------- 
  44 // ----------------------------------------------------------------------------- 
  45 wxListKey wxDefaultListKey
; 
  47 bool wxListKey::operator==(wxListKeyValue value
) const 
  52             wxFAIL_MSG(wxT("bad key type.")); 
  53             // let compiler optimize the line above away in release build 
  54             // by not putting return here... 
  57             return wxStrcmp(m_key
.string
, value
.string
) == 0; 
  60             return m_key
.integer 
== value
.integer
; 
  64 // ----------------------------------------------------------------------------- 
  66 // ----------------------------------------------------------------------------- 
  68 wxNodeBase::wxNodeBase(wxListBase 
*list
, 
  69                        wxNodeBase 
*previous
, wxNodeBase 
*next
, 
  70                        void *data
, const wxListKey
& key
) 
  74     m_previous 
= previous
; 
  77     switch ( key
.GetKeyType() ) 
  83             m_key
.integer 
= key
.GetNumber(); 
  87             // to be free()d later 
  88             m_key
.string 
= wxStrdup(key
.GetString()); 
  92             wxFAIL_MSG(wxT("invalid key type")); 
  96         previous
->m_next 
= this; 
  99         next
->m_previous 
= this; 
 102 wxNodeBase::~wxNodeBase() 
 104     // handle the case when we're being deleted from the list by the user (i.e. 
 105     // not by the list itself from DeleteNode) - we must do it for 
 106     // compatibility with old code 
 107     if ( m_list 
!= NULL 
) 
 109         if ( m_list
->m_keyType 
== wxKEY_STRING 
) 
 114         m_list
->DetachNode(this); 
 118 int wxNodeBase::IndexOf() const 
 120     wxCHECK_MSG( m_list
, wxNOT_FOUND
, wxT("node doesn't belong to a list in IndexOf")); 
 122     // It would be more efficient to implement IndexOf() completely inside 
 123     // wxListBase (only traverse the list once), but this is probably a more 
 124     // reusable way of doing it. Can always be optimized at a later date (since 
 125     // IndexOf() resides in wxListBase as well) if efficiency is a problem. 
 127     wxNodeBase 
*prev 
= m_previous
; 
 129     for( i 
= 0; prev
; i
++ ) 
 131         prev 
= prev
->m_previous
; 
 137 // ----------------------------------------------------------------------------- 
 139 // ----------------------------------------------------------------------------- 
 141 void wxListBase::Init(wxKeyType keyType
) 
 144   m_nodeLast 
= (wxNodeBase 
*) NULL
; 
 150 wxListBase::wxListBase(size_t count
, void *elements
[]) 
 154   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 160 void wxListBase::DoCopy(const wxListBase
& list
) 
 162     wxASSERT_MSG( !list
.m_destroy
, 
 163                   wxT("copying list which owns it's elements is a bad idea") ); 
 165     m_destroy 
= list
.m_destroy
; 
 166     m_keyType 
= list
.m_keyType
; 
 168     m_nodeLast 
= (wxNodeBase 
*) NULL
; 
 175                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 177                     key 
= node
->GetKeyInteger(); 
 178                     Append(key
, node
->GetData()); 
 186                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 188                     key 
= node
->GetKeyString(); 
 189                     Append(key
, node
->GetData()); 
 196                 for ( wxNodeBase 
*node 
= list
.GetFirst(); node
; node 
= node
->GetNext() ) 
 198                     Append(node
->GetData()); 
 204     wxASSERT_MSG( m_count 
== list
.m_count
, _T("logic error in wxList::DoCopy") ); 
 207 wxListBase::~wxListBase() 
 209   wxNodeBase 
*each 
= m_nodeFirst
; 
 210   while ( each 
!= NULL 
) 
 212       wxNodeBase 
*next 
= each
->GetNext(); 
 218 wxNodeBase 
*wxListBase::AppendCommon(wxNodeBase 
*node
) 
 223         m_nodeLast 
= m_nodeFirst
; 
 227         m_nodeLast
->m_next 
= node
; 
 236 wxNodeBase 
*wxListBase::Append(void *object
) 
 238     // all objects in a keyed list should have a key 
 239     wxCHECK_MSG( m_keyType 
== wxKEY_NONE
, (wxNodeBase 
*)NULL
, 
 240                  wxT("need a key for the object to append") ); 
 242     // we use wxDefaultListKey even though it is the default parameter value 
 243     // because gcc under Mac OS X seems to miscompile this call otherwise 
 244     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     // wxDefaultListKey: see comment in Append() above 
 296     wxNodeBase 
*node 
= CreateNode(prev
, next
, object
, wxDefaultListKey
); 
 312 wxNodeBase 
*wxListBase::Item(size_t n
) const 
 314     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 322     wxFAIL_MSG( wxT("invalid index in wxListBase::Item") ); 
 324     return (wxNodeBase 
*)NULL
; 
 327 wxNodeBase 
*wxListBase::Find(const wxListKey
& key
) const 
 329     wxASSERT_MSG( m_keyType 
== key
.GetKeyType(), 
 330                   wxT("this list is not keyed on the type of this key") ); 
 332     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 334         if ( key 
== current
->m_key 
) 
 341     return (wxNodeBase 
*)NULL
; 
 344 wxNodeBase 
*wxListBase::Find(const void *object
) const 
 346     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 348         if ( current
->GetData() == object 
) 
 353     return (wxNodeBase 
*)NULL
; 
 356 int wxListBase::IndexOf(void *object
) const 
 358     wxNodeBase 
*node 
= Find( object 
); 
 360     return node 
? node
->IndexOf() : wxNOT_FOUND
; 
 363 void wxListBase::DoDeleteNode(wxNodeBase 
*node
) 
 366     if ( m_keyType 
== wxKEY_STRING 
) 
 368         free(node
->m_key
.string
); 
 376     // so that the node knows that it's being deleted by the list 
 381 wxNodeBase 
*wxListBase::DetachNode(wxNodeBase 
*node
) 
 383     wxCHECK_MSG( node
, NULL
, wxT("detaching NULL wxNodeBase") ); 
 384     wxCHECK_MSG( node
->m_list 
== this, NULL
, 
 385                  wxT("detaching node which is not from this list") ); 
 388     wxNodeBase 
**prevNext 
= node
->GetPrevious() ? &node
->GetPrevious()->m_next
 
 390     wxNodeBase 
**nextPrev 
= node
->GetNext() ? &node
->GetNext()->m_previous
 
 393     *prevNext 
= node
->GetNext(); 
 394     *nextPrev 
= node
->GetPrevious(); 
 398     // mark the node as not belonging to this list any more 
 404 bool wxListBase::DeleteNode(wxNodeBase 
*node
) 
 406     if ( !DetachNode(node
) ) 
 414 bool wxListBase::DeleteObject(void *object
) 
 416     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 418         if ( current
->GetData() == object 
) 
 429 void wxListBase::Clear() 
 431     wxNodeBase 
*current 
= m_nodeFirst
; 
 434         wxNodeBase 
*next 
= current
->GetNext(); 
 435         DoDeleteNode(current
); 
 440     m_nodeLast 
= (wxNodeBase 
*)NULL
; 
 445 void wxListBase::ForEach(wxListIterateFunction F
) 
 447     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 449         (*F
)(current
->GetData()); 
 453 void *wxListBase::FirstThat(wxListIterateFunction F
) 
 455     for ( wxNodeBase 
*current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 457         if ( (*F
)(current
->GetData()) ) 
 458             return current
->GetData(); 
 461     return (wxNodeBase 
*)NULL
; 
 464 void *wxListBase::LastThat(wxListIterateFunction F
) 
 466     for ( wxNodeBase 
*current 
= GetLast(); current
; current 
= current
->GetPrevious() ) 
 468         if ( (*F
)(current
->GetData()) ) 
 469             return current
->GetData(); 
 472     return (wxNodeBase 
*)NULL
; 
 475 // (stefan.hammes@urz.uni-heidelberg.de) 
 477 // function for sorting lists. the concept is borrowed from 'qsort'. 
 478 // by giving a sort function, arbitrary lists can be sorted. 
 480 // - put wxObject pointers into an array 
 481 // - sort the array with qsort 
 482 // - put back the sorted wxObject pointers into the list 
 484 // CAVE: the sort function receives pointers to wxObject pointers (wxObject **), 
 485 //       so dereference right! 
 487 //   int listcompare(const void *arg1, const void *arg2) 
 489 //      return(compare(**(wxString **)arg1, 
 490 //                     **(wxString **)arg2)); 
 497 //     list.Append(new wxString("DEF")); 
 498 //     list.Append(new wxString("GHI")); 
 499 //     list.Append(new wxString("ABC")); 
 500 //     list.Sort(listcompare); 
 503 void wxListBase::Sort(const wxSortCompareFunction compfunc
) 
 505     // allocate an array for the wxObject pointers of the list 
 506     const size_t num 
= GetCount(); 
 507     void **objArray 
= new void *[num
]; 
 508     void **objPtr 
= objArray
; 
 510     // go through the list and put the pointers into the array 
 512     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 514         *objPtr
++ = node
->GetData(); 
 518     qsort((void *)objArray
,num
,sizeof(wxObject 
*), 
 520         (int (__cdecl 
*)(const void *,const void *)) 
 524     // put the sorted pointers back into the list 
 526     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 528         node
->SetData(*objPtr
++); 
 535 void wxListBase::Reverse() 
 537     wxNodeBase
* node 
= m_nodeFirst
; 
 542         // swap prev and next pointers 
 544         node
->m_next 
= node
->m_previous
; 
 545         node
->m_previous 
= tmp
; 
 547         // this is the node that was next before swapping 
 551     // swap first and last node 
 552     tmp 
= m_nodeFirst
; m_nodeFirst 
= m_nodeLast
; m_nodeLast 
= tmp
; 
 555 void wxListBase::DeleteNodes(wxNodeBase
* first
, wxNodeBase
* last
) 
 557     wxNodeBase
* node 
= first
; 
 561         wxNodeBase
* next 
= node
->GetNext(); 
 567 // ============================================================================ 
 568 // compatibility section from now on 
 569 // ============================================================================ 
 571 #ifdef wxLIST_COMPATIBILITY 
 573 // ----------------------------------------------------------------------------- 
 574 // wxList (a.k.a. wxObjectList) 
 575 // ----------------------------------------------------------------------------- 
 577 IMPLEMENT_DYNAMIC_CLASS(wxList
, wxObject
) 
 579 wxList::wxList( int key_type 
) 
 580     : wxObjectList( (wxKeyType
)key_type 
) 
 584 void wxObjectListNode::DeleteData() 
 586     delete (wxObject 
*)GetData(); 
 589 // ---------------------------------------------------------------------------- 
 591 // ---------------------------------------------------------------------------- 
 593 static inline wxChar
* MYcopystring(const wxChar
* s
) 
 595     wxChar
* copy 
= new wxChar
[wxStrlen(s
) + 1]; 
 596     return wxStrcpy(copy
, s
); 
 599 IMPLEMENT_DYNAMIC_CLASS(wxStringList
, wxObject
) 
 601 // instead of WX_DEFINE_LIST(wxStringListBase) we define this function 
 603 void wxStringListNode::DeleteData() 
 605     delete [] (char *)GetData(); 
 608 bool wxStringList::Delete(const wxChar 
*s
) 
 610     wxStringListNode 
*current
; 
 612     for ( current 
= GetFirst(); current
; current 
= current
->GetNext() ) 
 614         if ( wxStrcmp(current
->GetData(), s
) == 0 ) 
 625 void wxStringList::DoCopy(const wxStringList
& other
) 
 627     wxASSERT( GetCount() == 0 );    // this list must be empty before copying! 
 629     size_t count 
= other
.GetCount(); 
 630     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 632         Add(other
.Item(n
)->GetData()); 
 636 wxStringList::wxStringList() 
 638     DeleteContents(true); 
 641 // Variable argument list, terminated by a zero 
 642 // Makes new storage for the strings 
 643 wxStringList::wxStringList (const wxChar 
*first
, ...) 
 645   DeleteContents(true); 
 652   const wxChar 
*s 
= first
; 
 657       // icc gives this warning in its own va_arg() macro, argh 
 659     #pragma warning(push) 
 660     #pragma warning(disable: 1684) 
 663       s 
= va_arg(ap
, const wxChar 
*); 
 676 // Only makes new strings if arg is true 
 677 wxChar 
**wxStringList::ListToArray(bool new_copies
) const 
 679     wxChar 
**string_array 
= new wxChar 
*[GetCount()]; 
 680     wxStringListNode 
*node 
= GetFirst(); 
 681     for (size_t i 
= 0; i 
< GetCount(); i
++) 
 683         wxChar 
*s 
= node
->GetData(); 
 685             string_array
[i
] = MYcopystring(s
); 
 688         node 
= node
->GetNext(); 
 694 // Checks whether s is a member of the list 
 695 bool wxStringList::Member(const wxChar 
*s
) const 
 697     for ( wxStringListNode 
*node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 699         const wxChar 
*s1 
= node
->GetData(); 
 700         if (s 
== s1 
|| wxStrcmp (s
, s1
) == 0) 
 708 extern "C" int __cdecl
 
 710 extern "C" int LINKAGEMODE
 
 713 wx_comparestrings(const void *arg1
, const void *arg2
) 
 715   wxChar 
**s1 
= (wxChar 
**) arg1
; 
 716   wxChar 
**s2 
= (wxChar 
**) arg2
; 
 718   return wxStrcmp (*s1
, *s2
); 
 721 // Sort a list of strings - deallocates old nodes, allocates new 
 722 void wxStringList::Sort() 
 724     size_t N 
= GetCount(); 
 725     wxChar 
**array 
= new wxChar 
*[N
]; 
 726     wxStringListNode 
*node
; 
 729     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 731         array
[i
++] = node
->GetData(); 
 734     qsort (array
, N
, sizeof (wxChar 
*), wx_comparestrings
); 
 737     for ( node 
= GetFirst(); node
; node 
= node
->GetNext() ) 
 738         node
->SetData( array
[i
++] ); 
 743 wxNode 
*wxStringList::Add(const wxChar 
*s
) 
 745     return (wxNode 
*)wxStringListBase::Append(MYcopystring(s
)); 
 748 wxNode 
*wxStringList::Prepend(const wxChar 
*s
) 
 750     return (wxNode 
*)wxStringListBase::Insert(MYcopystring(s
)); 
 753 #endif // wxLIST_COMPATIBILITY 
 755 #else // wxUSE_STL = 1 
 757     #include "wx/listimpl.cpp" 
 758     WX_DEFINE_LIST(wxObjectList
) 
 760 // with wxUSE_STL wxStringList contains wxString objects, not pointers 
 761 void wxStringListBase::DeleteFunction( _WX_DELETEFUNCTIONCONST wxString 
WXUNUSED(X
) )