Files
wxWidgets/src/common/list.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

767 lines
18 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// Name: src/common/list.cpp
// Purpose: wxList implementation
// Author: Julian Smart
// Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added
// Created: 04/01/98
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
////////////////////////////////////////////////////////////////////////////////
// =============================================================================
// declarations
// =============================================================================
// -----------------------------------------------------------------------------
// headers
// -----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifndef WX_PRECOMP
#include "wx/list.h"
#include "wx/crt.h"
#endif
#if !wxUSE_STD_CONTAINERS
// =============================================================================
// implementation
// =============================================================================
// -----------------------------------------------------------------------------
// wxListKey
// -----------------------------------------------------------------------------
wxListKey wxDefaultListKey;
bool wxListKey::operator==(wxListKeyValue value) const
{
switch ( m_keyType )
{
default:
wxFAIL_MSG(wxT("bad key type."));
// let compiler optimize the line above away in release build
// by not putting return here...
case wxKEY_STRING:
return *m_key.string == *value.string;
case wxKEY_INTEGER:
return m_key.integer == value.integer;
}
}
// -----------------------------------------------------------------------------
// wxNodeBase
// -----------------------------------------------------------------------------
wxNodeBase::wxNodeBase(wxListBase *list,
wxNodeBase *previous, wxNodeBase *next,
void *data, const wxListKey& key)
{
m_list = list;
m_data = data;
m_previous = previous;
m_next = next;
switch ( key.GetKeyType() )
{
case wxKEY_NONE:
break;
case wxKEY_INTEGER:
m_key.integer = key.GetNumber();
break;
case wxKEY_STRING:
// to be free()d later
m_key.string = new wxString(key.GetString());
break;
default:
wxFAIL_MSG(wxT("invalid key type"));
}
if ( previous )
previous->m_next = this;
if ( next )
next->m_previous = this;
}
wxNodeBase::~wxNodeBase()
{
// handle the case when we're being deleted from the list by the user (i.e.
// not by the list itself from DeleteNode) - we must do it for
// compatibility with old code
if ( m_list != NULL )
{
if ( m_list->m_keyType == wxKEY_STRING )
{
delete m_key.string;
}
m_list->DetachNode(this);
}
}
int wxNodeBase::IndexOf() const
{
wxCHECK_MSG( m_list, wxNOT_FOUND, wxT("node doesn't belong to a list in IndexOf"));
// It would be more efficient to implement IndexOf() completely inside
// wxListBase (only traverse the list once), but this is probably a more
// reusable way of doing it. Can always be optimized at a later date (since
// IndexOf() resides in wxListBase as well) if efficiency is a problem.
int i;
wxNodeBase *prev = m_previous;
for( i = 0; prev; i++ )
{
prev = prev->m_previous;
}
return i;
}
// -----------------------------------------------------------------------------
// wxListBase
// -----------------------------------------------------------------------------
void wxListBase::Init(wxKeyType keyType)
{
m_nodeFirst =
m_nodeLast = NULL;
m_count = 0;
m_destroy = false;
m_keyType = keyType;
}
wxListBase::wxListBase(size_t count, void *elements[])
{
Init();
for ( size_t n = 0; n < count; n++ )
{
Append(elements[n]);
}
}
void wxListBase::DoCopy(const wxListBase& list)
{
wxASSERT_MSG( !list.m_destroy,
wxT("copying list which owns it's elements is a bad idea") );
m_destroy = list.m_destroy;
m_keyType = list.m_keyType;
m_nodeFirst =
m_nodeLast = NULL;
switch (m_keyType)
{
case wxKEY_INTEGER:
{
for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() )
{
Append(node->GetKeyInteger(), node->GetData());
}
break;
}
case wxKEY_STRING:
{
for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() )
{
Append(node->GetKeyString(), node->GetData());
}
break;
}
default:
{
for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() )
{
Append(node->GetData());
}
break;
}
}
wxASSERT_MSG( m_count == list.m_count, wxT("logic error in wxList::DoCopy") );
}
wxListBase::~wxListBase()
{
wxNodeBase *each = m_nodeFirst;
while ( each != NULL )
{
wxNodeBase *next = each->GetNext();
DoDeleteNode(each);
each = next;
}
}
wxNodeBase *wxListBase::AppendCommon(wxNodeBase *node)
{
if ( !m_nodeFirst )
{
m_nodeFirst = node;
m_nodeLast = m_nodeFirst;
}
else
{
m_nodeLast->m_next = node;
m_nodeLast = node;
}
m_count++;
return node;
}
wxNodeBase *wxListBase::Append(void *object)
{
// all objects in a keyed list should have a key
wxCHECK_MSG( m_keyType == wxKEY_NONE, NULL,
wxT("need a key for the object to append") );
// we use wxDefaultListKey even though it is the default parameter value
// because gcc under Mac OS X seems to miscompile this call otherwise
wxNodeBase *node = CreateNode(m_nodeLast, NULL, object,
wxDefaultListKey);
return AppendCommon(node);
}
wxNodeBase *wxListBase::Append(long key, void *object)
{
wxCHECK_MSG( (m_keyType == wxKEY_INTEGER) ||
(m_keyType == wxKEY_NONE && m_count == 0),
NULL,
wxT("can't append object with numeric key to this list") );
wxNodeBase *node = CreateNode(m_nodeLast, NULL, object, key);
return AppendCommon(node);
}
wxNodeBase *wxListBase::Append (const wxString& key, void *object)
{
wxCHECK_MSG( (m_keyType == wxKEY_STRING) ||
(m_keyType == wxKEY_NONE && m_count == 0),
NULL,
wxT("can't append object with string key to this list") );
wxNodeBase *node = CreateNode(m_nodeLast, NULL, object, key);
return AppendCommon(node);
}
wxNodeBase *wxListBase::Insert(wxNodeBase *position, void *object)
{
// all objects in a keyed list should have a key
wxCHECK_MSG( m_keyType == wxKEY_NONE, NULL,
wxT("need a key for the object to insert") );
wxCHECK_MSG( !position || position->m_list == this, NULL,
wxT("can't insert before a node from another list") );
// previous and next node for the node being inserted
wxNodeBase *prev, *next;
if ( position )
{
prev = position->GetPrevious();
next = position;
}
else
{
// inserting in the beginning of the list
prev = NULL;
next = m_nodeFirst;
}
// wxDefaultListKey: see comment in Append() above
wxNodeBase *node = CreateNode(prev, next, object, wxDefaultListKey);
if ( !m_nodeFirst )
{
m_nodeLast = node;
}
if ( prev == NULL )
{
m_nodeFirst = node;
}
m_count++;
return node;
}
wxNodeBase *wxListBase::Item(size_t n) const
{
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
{
if ( n-- == 0 )
{
return current;
}
}
wxFAIL_MSG( wxT("invalid index in wxListBase::Item") );
return NULL;
}
wxNodeBase *wxListBase::Find(const wxListKey& key) const
{
wxASSERT_MSG( m_keyType == key.GetKeyType(),
wxT("this list is not keyed on the type of this key") );
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
{
if ( key == current->m_key )
{
return current;
}
}
// not found
return NULL;
}
wxNodeBase *wxListBase::Find(const void *object) const
{
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
{
if ( current->GetData() == object )
return current;
}
// not found
return NULL;
}
int wxListBase::IndexOf(void *object) const
{
wxNodeBase *node = Find( object );
return node ? node->IndexOf() : wxNOT_FOUND;
}
void wxListBase::DoDeleteNode(wxNodeBase *node)
{
// free node's data
if ( m_keyType == wxKEY_STRING )
{
free(node->m_key.string);
}
if ( m_destroy )
{
node->DeleteData();
}
// so that the node knows that it's being deleted by the list
node->m_list = NULL;
delete node;
}
wxNodeBase *wxListBase::DetachNode(wxNodeBase *node)
{
wxCHECK_MSG( node, NULL, wxT("detaching NULL wxNodeBase") );
wxCHECK_MSG( node->m_list == this, NULL,
wxT("detaching node which is not from this list") );
// update the list
wxNodeBase **prevNext = node->GetPrevious() ? &node->GetPrevious()->m_next
: &m_nodeFirst;
wxNodeBase **nextPrev = node->GetNext() ? &node->GetNext()->m_previous
: &m_nodeLast;
*prevNext = node->GetNext();
*nextPrev = node->GetPrevious();
m_count--;
// mark the node as not belonging to this list any more
node->m_list = NULL;
return node;
}
bool wxListBase::DeleteNode(wxNodeBase *node)
{
if ( !DetachNode(node) )
return false;
DoDeleteNode(node);
return true;
}
bool wxListBase::DeleteObject(void *object)
{
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
{
if ( current->GetData() == object )
{
DeleteNode(current);
return true;
}
}
// not found
return false;
}
void wxListBase::Clear()
{
wxNodeBase *current = m_nodeFirst;
while ( current )
{
wxNodeBase *next = current->GetNext();
DoDeleteNode(current);
current = next;
}
m_nodeFirst =
m_nodeLast = NULL;
m_count = 0;
}
void wxListBase::ForEach(wxListIterateFunction F)
{
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
{
(*F)(current->GetData());
}
}
void *wxListBase::FirstThat(wxListIterateFunction F)
{
for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
{
if ( (*F)(current->GetData()) )
return current->GetData();
}
return NULL;
}
void *wxListBase::LastThat(wxListIterateFunction F)
{
for ( wxNodeBase *current = GetLast(); current; current = current->GetPrevious() )
{
if ( (*F)(current->GetData()) )
return current->GetData();
}
return NULL;
}
// (stefan.hammes@urz.uni-heidelberg.de)
//
// function for sorting lists. the concept is borrowed from 'qsort'.
// by giving a sort function, arbitrary lists can be sorted.
// method:
// - put wxObject pointers into an array
// - sort the array with qsort
// - put back the sorted wxObject pointers into the list
//
// CAVE: the sort function receives pointers to wxObject pointers (wxObject **),
// so dereference right!
// EXAMPLE:
// int listcompare(const void *arg1, const void *arg2)
// {
// return(compare(**(wxString **)arg1,
// **(wxString **)arg2));
// }
//
// void main()
// {
// wxListBase list;
//
// list.Append(new wxString("DEF"));
// list.Append(new wxString("GHI"));
// list.Append(new wxString("ABC"));
// list.Sort(listcompare);
// }
void wxListBase::Sort(const wxSortCompareFunction compfunc)
{
// allocate an array for the wxObject pointers of the list
const size_t num = GetCount();
void **objArray = new void *[num];
void **objPtr = objArray;
// go through the list and put the pointers into the array
wxNodeBase *node;
for ( node = GetFirst(); node; node = node->GetNext() )
{
*objPtr++ = node->GetData();
}
// sort the array
qsort((void *)objArray,num,sizeof(wxObject *),
#ifdef __WXWINCE__
(int (__cdecl *)(const void *,const void *))
#endif
compfunc);
// put the sorted pointers back into the list
objPtr = objArray;
for ( node = GetFirst(); node; node = node->GetNext() )
{
node->SetData(*objPtr++);
}
// free the array
delete[] objArray;
}
void wxListBase::Reverse()
{
wxNodeBase* node = m_nodeFirst;
wxNodeBase* tmp;
while (node)
{
// swap prev and next pointers
tmp = node->m_next;
node->m_next = node->m_previous;
node->m_previous = tmp;
// this is the node that was next before swapping
node = tmp;
}
// swap first and last node
tmp = m_nodeFirst; m_nodeFirst = m_nodeLast; m_nodeLast = tmp;
}
void wxListBase::DeleteNodes(wxNodeBase* first, wxNodeBase* last)
{
wxNodeBase* node = first;
while (node != last)
{
wxNodeBase* next = node->GetNext();
DeleteNode(node);
node = next;
}
}
// ============================================================================
// compatibility section from now on
// ============================================================================
#ifdef wxLIST_COMPATIBILITY
// -----------------------------------------------------------------------------
// wxList (a.k.a. wxObjectList)
// -----------------------------------------------------------------------------
wxList::wxList( int key_type )
: wxObjectList( (wxKeyType)key_type )
{
}
void wxObjectListNode::DeleteData()
{
delete (wxObject *)GetData();
}
// ----------------------------------------------------------------------------
// wxStringList
// ----------------------------------------------------------------------------
static inline wxChar* MYcopystring(const wxChar* s)
{
wxChar* copy = new wxChar[wxStrlen(s) + 1];
return wxStrcpy(copy, s);
}
// instead of WX_DEFINE_LIST(wxStringListBase) we define this function
// ourselves
void wxStringListNode::DeleteData()
{
delete [] (char *)GetData();
}
bool wxStringList::Delete(const wxChar *s)
{
wxStringListNode *current;
for ( current = GetFirst(); current; current = current->GetNext() )
{
if ( wxStrcmp(current->GetData(), s) == 0 )
{
DeleteNode(current);
return true;
}
}
// not found
return false;
}
void wxStringList::DoCopy(const wxStringList& other)
{
wxASSERT( GetCount() == 0 ); // this list must be empty before copying!
size_t count = other.GetCount();
for ( size_t n = 0; n < count; n++ )
{
Add(other.Item(n)->GetData());
}
}
wxStringList::wxStringList()
{
DeleteContents(true);
}
// Variable argument list, terminated by a zero
// Makes new storage for the strings
wxStringList::wxStringList (const wxChar *first, ...)
{
DeleteContents(true);
if ( !first )
return;
va_list ap;
va_start(ap, first);
const wxChar *s = first;
for (;;)
{
Add(s);
// icc gives this warning in its own va_arg() macro, argh
#ifdef __INTELC__
#pragma warning(push)
#pragma warning(disable: 1684)
#endif
s = va_arg(ap, const wxChar *);
#ifdef __INTELC__
#pragma warning(pop)
#endif
if ( !s )
break;
}
va_end(ap);
}
// Only makes new strings if arg is true
wxChar **wxStringList::ListToArray(bool new_copies) const
{
wxChar **string_array = new wxChar *[GetCount()];
wxStringListNode *node = GetFirst();
for (size_t i = 0; i < GetCount(); i++)
{
wxChar *s = node->GetData();
if ( new_copies )
string_array[i] = MYcopystring(s);
else
string_array[i] = s;
node = node->GetNext();
}
return string_array;
}
// Checks whether s is a member of the list
bool wxStringList::Member(const wxChar *s) const
{
for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() )
{
const wxChar *s1 = node->GetData();
if (s == s1 || wxStrcmp (s, s1) == 0)
return true;
}
return false;
}
#ifdef __WXWINCE__
extern "C"
{
static int __cdecl
#else
extern "C"
{
static int LINKAGEMODE
#endif
wx_comparestrings(const void *arg1, const void *arg2)
{
wxChar **s1 = (wxChar **) arg1;
wxChar **s2 = (wxChar **) arg2;
return wxStrcmp (*s1, *s2);
}
} // end of extern "C" (required because of GCC Bug c++/33078
// Sort a list of strings - deallocates old nodes, allocates new
void wxStringList::Sort()
{
size_t N = GetCount();
wxChar **array = new wxChar *[N];
wxStringListNode *node;
size_t i = 0;
for ( node = GetFirst(); node; node = node->GetNext() )
{
array[i++] = node->GetData();
}
qsort (array, N, sizeof (wxChar *), wx_comparestrings);
i = 0;
for ( node = GetFirst(); node; node = node->GetNext() )
node->SetData( array[i++] );
delete [] array;
}
wxNode *wxStringList::Add(const wxChar *s)
{
return (wxNode *)(wxStringListBase::Node *)
wxStringListBase::Append(MYcopystring(s));
}
wxNode *wxStringList::Prepend(const wxChar *s)
{
return (wxNode *)(wxStringListBase::Node *)
wxStringListBase::Insert(MYcopystring(s));
}
#endif // wxLIST_COMPATIBILITY
#else // wxUSE_STD_CONTAINERS = 1
#include "wx/listimpl.cpp"
WX_DEFINE_LIST(wxObjectList)
// with wxUSE_STD_CONTAINERS wxStringList contains wxString objects, not pointers
void _WX_LIST_HELPER_wxStringListBase::DeleteFunction( wxString WXUNUSED(X) )
{
}
_WX_LIST_HELPER_wxStringListBase::BaseListType _WX_LIST_HELPER_wxStringListBase::EmptyList;
#endif // !wxUSE_STD_CONTAINERS