]> git.saurik.com Git - wxWidgets.git/blame - src/common/list.cpp
no message
[wxWidgets.git] / src / common / list.cpp
CommitLineData
fd3f686c 1////////////////////////////////////////////////////////////////////////////////
c801d85f
KB
2// Name: list.cpp
3// Purpose: wxList implementation
4// Author: Julian Smart
fd3f686c 5// Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added
c801d85f
KB
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
fd3f686c
VZ
9// Licence: wxWindows license
10////////////////////////////////////////////////////////////////////////////////
c801d85f 11
fd3f686c
VZ
12// =============================================================================
13// declarations
14// =============================================================================
15
16// -----------------------------------------------------------------------------
17// headers
18// -----------------------------------------------------------------------------
c801d85f
KB
19#ifdef __GNUG__
20#pragma implementation "list.h"
21#endif
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
fd3f686c 27 #pragma hdrstop
c801d85f
KB
28#endif
29
fd3f686c
VZ
30#include <stdarg.h>
31#include <stdlib.h>
32#include <string.h>
33
c801d85f 34#ifndef WX_PRECOMP
fd3f686c
VZ
35 #include "wx/defs.h"
36 #include "wx/list.h"
37 #include "wx/utils.h" // for copystring() (beurk...)
c801d85f
KB
38#endif
39
40// Sun CC compatibility (interference with xview/pkg.h, apparently...)
41#if defined(SUN_CC) && defined(__XVIEW__)
fd3f686c
VZ
42 #undef va_start
43 #undef va_end
44 #undef va_arg
45 #undef va_list
c801d85f
KB
46#endif
47
fd3f686c
VZ
48// =============================================================================
49// implementation
50// =============================================================================
c801d85f 51
ff528365
VZ
52// -----------------------------------------------------------------------------
53// wxListKey
54// -----------------------------------------------------------------------------
55
56bool wxListKey::operator==(wxListKeyValue value) const
57{
58 switch ( m_keyType )
59 {
60 default:
61 wxFAIL_MSG("bad key type.");
62 // let compiler optimize the line above away in release build
63 // by not putting return here...
64
65 case wxKEY_STRING:
66 return strcmp(m_key.string, value.string) == 0;
67
68 case wxKEY_INTEGER:
69 return m_key.integer == value.integer;
70 }
71}
72
fd3f686c
VZ
73// -----------------------------------------------------------------------------
74// wxNodeBase
75// -----------------------------------------------------------------------------
c801d85f 76
fd3f686c
VZ
77wxNodeBase::wxNodeBase(wxListBase *list,
78 wxNodeBase *previous, wxNodeBase *next,
79 void *data, const wxListKey& key)
c801d85f 80{
fd3f686c
VZ
81 m_list = list;
82 m_data = data;
83 m_previous = previous;
84 m_next = next;
85
86 switch ( key.GetKeyType() )
87 {
88 case wxKEY_NONE:
89 break;
90
91 case wxKEY_INTEGER:
92 m_key.integer = key.GetNumber();
93 break;
94
95 case wxKEY_STRING:
96 // to be free()d later
97 m_key.string = strdup(key.GetString());
98 break;
99
100 default:
101 wxFAIL_MSG("invalid key type");
102 }
103
104 if ( previous )
105 previous->m_next = this;
106
107 if ( next )
108 next->m_previous = this;
109}
c801d85f 110
fd3f686c
VZ
111wxNodeBase::~wxNodeBase()
112{
113 // handle the case when we're being deleted from the list by the user (i.e.
114 // not by the list itself from DeleteNode) - we must do it for
115 // compatibility with old code
116 if ( m_list != NULL )
117 {
118 m_list->DetachNode(this);
119 }
c801d85f
KB
120}
121
fd3f686c
VZ
122// -----------------------------------------------------------------------------
123// wxListBase
124// -----------------------------------------------------------------------------
125
126void wxListBase::Init(wxKeyType keyType = wxKEY_NONE)
c801d85f 127{
fd3f686c
VZ
128 m_nodeFirst =
129 m_nodeLast = (wxNodeBase *) NULL;
130 m_count = 0;
131 m_destroy = FALSE;
132 m_keyType = keyType;
133}
c801d85f 134
fd3f686c
VZ
135wxListBase::wxListBase(size_t count, void *elements[])
136{
137 Init();
c801d85f 138
fd3f686c
VZ
139 for ( size_t n = 0; n < count; n++ )
140 {
141 Append(elements[n]);
142 }
c801d85f
KB
143}
144
fd3f686c 145void wxListBase::DoCopy(const wxListBase& list)
c801d85f 146{
fd3f686c
VZ
147 wxASSERT_MSG( !list.m_destroy,
148 "copying list which owns it's elements is a bad idea" );
c801d85f 149
fd3f686c
VZ
150 m_count = list.m_count;
151 m_destroy = list.m_destroy;
152 m_keyType = list.m_keyType;
153 m_nodeFirst =
154 m_nodeLast = (wxNodeBase *) NULL;
c801d85f 155
fd3f686c
VZ
156 for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() )
157 {
158 Append(node);
159 }
c801d85f
KB
160}
161
fd3f686c 162wxListBase::~wxListBase()
c801d85f 163{
fd3f686c
VZ
164 wxNodeBase *each = m_nodeFirst;
165 while ( each != NULL )
166 {
167 wxNodeBase *next = each->GetNext();
168 DoDeleteNode(each);
169 each = next;
170 }
c801d85f
KB
171}
172
fd3f686c 173wxNodeBase *wxListBase::AppendCommon(wxNodeBase *node)
c801d85f 174{
fd3f686c
VZ
175 if ( !m_nodeFirst )
176 {
177 m_nodeFirst = node;
178 m_nodeLast = m_nodeFirst;
179 }
180 else
181 {
182 m_nodeLast->m_next = node;
183 m_nodeLast = node;
184 }
185
186 m_count++;
187
188 return node;
c801d85f
KB
189}
190
fd3f686c 191wxNodeBase *wxListBase::Append(void *object)
c801d85f 192{
fd3f686c
VZ
193 // all objects in a keyed list should have a key
194 wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL,
195 "need a key for the object to append" );
c801d85f 196
fd3f686c
VZ
197 wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object);
198
199 return AppendCommon(node);
c801d85f
KB
200}
201
fd3f686c 202wxNodeBase *wxListBase::Append(long key, void *object)
c801d85f 203{
fd3f686c
VZ
204 wxCHECK_MSG( (m_keyType == wxKEY_INTEGER) ||
205 (m_keyType == wxKEY_NONE && m_count == 0),
206 (wxNodeBase *)NULL,
207 "can't append object with numeric key to this list" );
208
209 wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key);
210 return AppendCommon(node);
c801d85f
KB
211}
212
fd3f686c 213wxNodeBase *wxListBase::Append (const char *key, void *object)
c801d85f 214{
fd3f686c
VZ
215 wxCHECK_MSG( (m_keyType == wxKEY_STRING) ||
216 (m_keyType == wxKEY_NONE && m_count == 0),
217 (wxNodeBase *)NULL,
218 "can't append object with string key to this list" );
219
220 wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key);
221 return AppendCommon(node);
222}
c801d85f 223
fd3f686c
VZ
224wxNodeBase *wxListBase::Insert(wxNodeBase *position, void *object)
225{
226 // all objects in a keyed list should have a key
227 wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL,
228 "need a key for the object to insert" );
c801d85f 229
ff528365
VZ
230 wxCHECK_MSG( !position || position->m_list == this, (wxNodeBase *)NULL,
231 "can't insert before a node from another list" );
232
233 // previous and next node for the node being inserted
234 wxNodeBase *prev, *next;
fd3f686c 235 if ( position )
ff528365 236 {
fd3f686c 237 prev = position->GetPrevious();
ff528365
VZ
238 next = position;
239 }
240 else
241 {
242 // inserting in the beginning of the list
243 prev = (wxNodeBase *)NULL;
244 next = m_nodeFirst;
245 }
c801d85f 246
ff528365 247 wxNodeBase *node = CreateNode(prev, next, object);
fd3f686c 248 if ( !m_nodeFirst )
c801d85f 249 {
fd3f686c 250 m_nodeLast = node;
c801d85f 251 }
c801d85f 252
fd3f686c 253 if ( prev == NULL )
c801d85f 254 {
fd3f686c 255 m_nodeFirst = node;
c801d85f 256 }
c801d85f 257
fd3f686c
VZ
258 m_count++;
259
c801d85f
KB
260 return node;
261}
262
fd3f686c 263wxNodeBase *wxListBase::Item(size_t n) const
c801d85f 264{
fd3f686c 265 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
c801d85f 266 {
fd3f686c
VZ
267 if ( n-- == 0 )
268 {
269 return current;
270 }
c801d85f 271 }
c801d85f 272
fd3f686c 273 wxFAIL_MSG( "invalid index in wxListBase::Item" );
c801d85f 274
fd3f686c 275 return NULL;
c801d85f
KB
276}
277
fd3f686c 278wxNodeBase *wxListBase::Find(const wxListKey& key) const
c801d85f 279{
fd3f686c
VZ
280 wxASSERT_MSG( m_keyType == key.GetKeyType(),
281 "this list is not keyed on the type of this key" );
c801d85f 282
fd3f686c
VZ
283 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
284 {
285 if ( key == current->m_key )
286 {
287 return current;
288 }
289 }
c801d85f 290
fd3f686c
VZ
291 // not found
292 return (wxNodeBase *)NULL;
c801d85f
KB
293}
294
fd3f686c 295wxNodeBase *wxListBase::Find(void *object) const
c801d85f 296{
fd3f686c 297 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
c801d85f 298 {
fd3f686c
VZ
299 if ( current->GetData() == object )
300 return current;
c801d85f 301 }
fd3f686c
VZ
302
303 // not found
304 return (wxNodeBase *)NULL;
c801d85f
KB
305}
306
fd3f686c 307void wxListBase::DoDeleteNode(wxNodeBase *node)
c801d85f 308{
fd3f686c
VZ
309 // free node's data
310 if ( m_keyType == wxKEY_STRING )
c801d85f 311 {
fd3f686c 312 free(node->m_key.string);
c801d85f 313 }
c801d85f 314
fd3f686c 315 if ( m_destroy )
c801d85f 316 {
fd3f686c 317 node->DeleteData();
c801d85f 318 }
c801d85f 319
fd3f686c 320 delete node;
c801d85f
KB
321}
322
fd3f686c 323wxNodeBase *wxListBase::DetachNode(wxNodeBase *node)
c801d85f 324{
fd3f686c
VZ
325 wxCHECK_MSG( node, NULL, "detaching NULL wxNodeBase" );
326 wxCHECK_MSG( node->m_list == this, NULL,
327 "detaching node which is not from this list" );
c801d85f 328
fd3f686c
VZ
329 // update the list
330 wxNodeBase **prevNext = node->GetPrevious() ? &node->GetPrevious()->m_next
331 : &m_nodeFirst;
332 wxNodeBase **nextPrev = node->GetNext() ? &node->GetNext()->m_previous
333 : &m_nodeLast;
c801d85f 334
fd3f686c
VZ
335 *prevNext = node->GetNext();
336 *nextPrev = node->GetPrevious();
c801d85f 337
fd3f686c 338 m_count--;
c801d85f 339
fd3f686c
VZ
340 // mark the node as not belonging to this list any more
341 node->m_list = NULL;
c801d85f 342
fd3f686c 343 return node;
c801d85f
KB
344}
345
fd3f686c 346bool wxListBase::DeleteNode(wxNodeBase *node)
c801d85f 347{
fd3f686c
VZ
348 if ( !DetachNode(node) )
349 return FALSE;
350
351 DoDeleteNode(node);
352
353 return TRUE;
c801d85f
KB
354}
355
fd3f686c 356bool wxListBase::DeleteObject(void *object)
c801d85f 357{
fd3f686c
VZ
358 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
359 {
360 if ( current->GetData() == object )
361 {
362 DeleteNode(current);
363 return TRUE;
364 }
365 }
366
367 // not found
368 return FALSE;
c801d85f
KB
369}
370
fd3f686c
VZ
371
372void wxListBase::Clear()
c801d85f 373{
fd3f686c
VZ
374 wxNodeBase *current = m_nodeFirst;
375 while ( current )
c801d85f 376 {
fd3f686c
VZ
377 wxNodeBase *next = current->GetNext();
378 DoDeleteNode(current);
379 current = next;
c801d85f 380 }
fd3f686c
VZ
381
382 m_nodeFirst =
383 m_nodeLast = (wxNodeBase *)NULL;
384
385 m_count = 0;
c801d85f
KB
386}
387
fd3f686c 388void wxListBase::ForEach(wxListIterateFunction F)
c801d85f 389{
fd3f686c
VZ
390 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
391 {
392 (*F)(current->GetData());
c801d85f
KB
393 }
394}
fd3f686c
VZ
395
396void *wxListBase::FirstThat(wxListIterateFunction F)
c801d85f 397{
fd3f686c
VZ
398 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
399 {
400 if ( (*F)(current->GetData()) )
401 return current->GetData();
c801d85f 402 }
fd3f686c
VZ
403
404 return (wxNodeBase *)NULL;
c801d85f 405}
fd3f686c
VZ
406
407void *wxListBase::LastThat(wxListIterateFunction F)
c801d85f 408{
fd3f686c
VZ
409 for ( wxNodeBase *current = GetLast(); current; current = current->GetPrevious() )
410 {
411 if ( (*F)(current->GetData()) )
412 return current->GetData();
c801d85f 413 }
fd3f686c
VZ
414
415 return (wxNodeBase *)NULL;
c801d85f
KB
416}
417
418// (stefan.hammes@urz.uni-heidelberg.de)
419//
420// function for sorting lists. the concept is borrowed from 'qsort'.
421// by giving a sort function, arbitrary lists can be sorted.
422// method:
423// - put wxObject pointers into an array
424// - sort the array with qsort
425// - put back the sorted wxObject pointers into the list
426//
427// CAVE: the sort function receives pointers to wxObject pointers (wxObject **),
428// so dereference right!
429// EXAMPLE:
430// int listcompare(const void *arg1, const void *arg2)
431// {
432// return(compare(**(wxString **)arg1,
433// **(wxString **)arg2));
434// }
435//
436// void main()
fd3f686c
VZ
437// {
438// wxListBase list;
c801d85f
KB
439//
440// list.Append(new wxString("DEF"));
441// list.Append(new wxString("GHI"));
442// list.Append(new wxString("ABC"));
443// list.Sort(listcompare);
444// }
445
fd3f686c 446void wxListBase::Sort(const wxSortCompareFunction compfunc)
c801d85f 447{
fd3f686c
VZ
448 // allocate an array for the wxObject pointers of the list
449 const size_t num = GetCount();
450 void **objArray = new void *[num];
451 void **objPtr = objArray;
452
453 // go through the list and put the pointers into the array
454 wxNodeBase *node;
455 for ( node = GetFirst(); node; node = node->Next() )
456 {
457 *objPtr++ = node->Data();
458 }
459
460 // sort the array
461 qsort((void *)objArray,num,sizeof(wxObject *),compfunc);
462
463 // put the sorted pointers back into the list
464 objPtr = objArray;
465 for ( node = GetFirst(); node; node = node->Next() )
466 {
467 node->SetData(*objPtr++);
468 }
469
470 // free the array
471 delete[] objArray;
c801d85f
KB
472}
473
fd3f686c
VZ
474// -----------------------------------------------------------------------------
475// wxList (a.k.a. wxObjectList)
476// -----------------------------------------------------------------------------
c801d85f 477
fd3f686c 478void wxObjectListNode::DeleteData()
c801d85f 479{
fd3f686c 480 delete (wxObject *)GetData();
c801d85f
KB
481}
482
fd3f686c
VZ
483// -----------------------------------------------------------------------------
484// wxStringList
485// -----------------------------------------------------------------------------
486
487// instead of WX_DEFINE_LIST(wxStringListBase) we define this function
488// ourselves
489void wxStringListNode::DeleteData()
341287bf 490{
fd3f686c 491 delete [] (char *)GetData();
341287bf
JS
492}
493
db9504c5
VZ
494void wxStringList::DoCopy(const wxStringList& other)
495{
496 wxASSERT( GetCount() == 0 ); // this list must be empty before copying!
497
498 size_t count = other.GetCount();
499 for ( size_t n = 0; n < count; n++ )
500 {
501 Add(other.Item(n)->GetData());
502 }
503}
504
c801d85f
KB
505// Variable argument list, terminated by a zero
506// Makes new storage for the strings
fd3f686c 507wxStringList::wxStringList (const char *first, ...)
c801d85f 508{
fd3f686c 509 if ( !first )
c801d85f
KB
510 return;
511
512 va_list ap;
fd3f686c 513 va_start(ap, first);
c801d85f 514
fd3f686c 515 const char *s = first;
c801d85f 516 for (;;)
fd3f686c
VZ
517 {
518 Add(s);
519
520 s = va_arg(ap, const char *);
521 // if (s == NULL)
2049ba38 522#ifdef __WXMSW__
c801d85f
KB
523 if ((int) s == 0)
524#else
525 if ((long) s == 0)
526#endif
fd3f686c
VZ
527 break;
528 }
c801d85f 529
fd3f686c 530 va_end(ap);
341287bf
JS
531}
532
fd3f686c
VZ
533// Only makes new strings if arg is TRUE
534char **wxStringList::ListToArray(bool new_copies) const
341287bf 535{
fd3f686c
VZ
536 char **string_array = new char *[GetCount()];
537 wxStringListNode *node = GetFirst();
538 for (size_t i = 0; i < GetCount(); i++)
c801d85f 539 {
fd3f686c
VZ
540 char *s = node->GetData();
541 if ( new_copies )
542 string_array[i] = copystring(s);
543 else
544 string_array[i] = s;
545 node = node->GetNext();
c801d85f 546 }
c801d85f 547
fd3f686c 548 return string_array;
c801d85f
KB
549}
550
fd3f686c
VZ
551// Checks whether s is a member of the list
552bool wxStringList::Member(const char *s) const
c801d85f 553{
fd3f686c 554 for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() )
c801d85f 555 {
fd3f686c
VZ
556 const char *s1 = node->GetData();
557 if (s == s1 || strcmp (s, s1) == 0)
558 return TRUE;
c801d85f 559 }
fd3f686c
VZ
560
561 return FALSE;
c801d85f
KB
562}
563
fd3f686c
VZ
564static int
565wx_comparestrings(const void *arg1, const void *arg2)
c801d85f
KB
566{
567 char **s1 = (char **) arg1;
568 char **s2 = (char **) arg2;
569
570 return strcmp (*s1, *s2);
571}
572
573// Sort a list of strings - deallocates old nodes, allocates new
fd3f686c 574void wxStringList::Sort()
c801d85f 575{
fd3f686c
VZ
576 size_t N = GetCount();
577 char **array = new char *[N];
c801d85f 578
fd3f686c
VZ
579 size_t i = 0;
580 for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() )
c801d85f 581 {
fd3f686c 582 array[i++] = node->GetData();
c801d85f 583 }
341287bf 584
fd3f686c 585 qsort (array, N, sizeof (char *), wx_comparestrings);
341287bf
JS
586 Clear();
587
fd3f686c
VZ
588 for (i = 0; i < N; i++)
589 Append (array[i]);
341287bf 590
fd3f686c 591 delete[]array;
341287bf
JS
592}
593