added sorted arrays: they automatically sort items on insertion (using user

provided compare function) and binary search in Index(). Using them in
situations where Index() performance is important brings 30%-40% performance
boost.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@280 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1998-07-16 17:29:46 +00:00
parent 400735a8fa
commit 3bfa440288
2 changed files with 149 additions and 35 deletions

View File

@@ -2,7 +2,7 @@
// Name: dynarray.h
// Purpose: auto-resizable (i.e. dynamic) array support
// Author: Vadim Zeitlin
// Modified by:
// Modified by:
// Created: 12.09.97
// RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
@@ -17,9 +17,9 @@
#endif
#include "wx/defs.h"
#include "wx/utils.h"
#include "wx/debug.h"
/** @name Dynamic arrays and lists
/** @name Dynamic arrays and lists
@memo Arrays which grow on demand and do range checking (only in debug)
*/
//@{
@@ -30,7 +30,7 @@
/**
the initial size by which an array/list grows when an element is added
default value avoids allocate one or two bytes when the array is created
default value avoids allocate one or two bytes when the array is created
which is rather inefficient
*/
#define WX_ARRAY_DEFAULT_INITIAL_SIZE (16)
@@ -41,7 +41,7 @@
/**
callback compare function for quick sort
must return -1, 0 or +1 if pItem1 <, = or > pItem2
must return negative value, 0 or positive value if pItem1 <, = or > pItem2
*/
#ifdef __VISUALC__
@@ -56,9 +56,9 @@ typedef int (CMPFUNC_CONV *CMPFUNC)(const void* pItem1, const void* pItem2);
base class managing data having size of type 'long' (not used directly)
NB: for efficiency this often used class has no virtual functions (hence no
VTBL), even dtor is <B>not</B> virtual. If used as expected it won't
create any problems because ARRAYs from DEFINE_ARRAY have no dtor at all,
so it's not too important if it's not called (this happens when you cast
VTBL), even dtor is <B>not</B> virtual. If used as expected it won't
create any problems because ARRAYs from DEFINE_ARRAY have no dtor at all,
so it's not too important if it's not called (this happens when you cast
"SomeArray *" as "BaseArray *" and then delete it)
@memo Base class for template array and list classes
@@ -102,7 +102,7 @@ public:
//@}
protected:
// these methods are protected because if they were public one could
// these methods are protected because if they were public one could
// mistakenly call one of them instead of DEFINE_ARRAY's or LIST's
// type safe methods
@@ -123,10 +123,14 @@ protected:
@return index of the first item matched or NOT_FOUND
@see NOT_FOUND
*/
int Index (long lItem, bool bFromEnd = FALSE) const;
int Index(long lItem, bool bFromEnd = FALSE) const;
/// search for an item using binary search in a sorted array
int Index(long lItem, CMPFUNC fnCompare);
/// add new element at the end
void Add (long lItem);
/// add new element at given position
void Add(long lItem);
/// add item assuming the array is sorted with fnCompare function
void Add(long lItem, CMPFUNC fnCompare);
/// add new element at given position (it becomes Item[uiIndex])
void Insert(long lItem, uint uiIndex);
/// remove first item matching this value
void Remove(long lItem);
@@ -135,7 +139,7 @@ protected:
//@}
/// sort array elements using given compare function
void Sort(CMPFUNC fCmp);
void Sort(CMPFUNC fnCompare);
private:
void Grow(); // makes array bigger if needed
@@ -153,7 +157,7 @@ private:
// ----------------------------------------------------------------------------
// This macro generates a new array class. It is intended for storage of simple
// types of sizeof()<=sizeof(long) or pointers if sizeof(pointer)<=sizeof(long)
//
//
// NB: it has only inline functions => takes no space at all
// ----------------------------------------------------------------------------
#define _WX_DEFINE_ARRAY(T, name) \
@@ -193,6 +197,60 @@ public: \
void Sort(CMPFUNC##T fCmp) { wxBaseArray::Sort((CMPFUNC)fCmp); } \
}
// ----------------------------------------------------------------------------
// This is the same as the previous macro, but it defines a sorted array.
// Differences:
// 1) it must be given a COMPARE function in ctor which takes 2 items of type
// T* and should return -1, 0 or +1 if the first one is less/greater
// than/equal to the second one.
// 2) the Add() method inserts the item in such was that the array is always
// sorted (it uses the COMPARE function)
// 3) it has no Sort() method because it's always sorted
// 4) Index() method is much faster (the sorted arrays use binary search
// instead of linear one), but Add() is slower.
//
// Summary: use this class when the speed of Index() function is important, use
// the normal arrays otherwise.
//
// NB: it has only inline functions => takes no space at all
// ----------------------------------------------------------------------------
#define _WX_DEFINE_SORTED_ARRAY(T, name) \
typedef int (CMPFUNC_CONV *SCMPFUNC##T)(T pItem1, T pItem2); \
class name : public wxBaseArray \
{ \
public: \
name(SCMPFUNC##T fn) \
{ wxASSERT( sizeof(T) <= sizeof(long) ); m_fnCompare = fn; } \
\
name& operator=(const name& src) \
{ ((wxBaseArray *)this)->operator=((const wxBaseArray&)src); \
m_fnCompare = src.m_fnCompare; \
return *this; } \
\
T& operator[](uint uiIndex) const \
{ return (T&)(wxBaseArray::Item(uiIndex)); } \
T& Item(uint uiIndex) const \
{ return (T&)(wxBaseArray::Item(uiIndex)); } \
T& Last() const \
{ return (T&)(wxBaseArray::Item(Count() - 1)); } \
\
int Index(T Item) const \
{ return wxBaseArray::Index((long)Item, (CMPFUNC)m_fnCompare); }\
\
void Add(T Item) \
{ wxBaseArray::Add((long)Item, (CMPFUNC)m_fnCompare); } \
\
void Remove(uint uiIndex) { wxBaseArray::Remove(uiIndex); } \
void Remove(T Item) \
{ int iIndex = Index(Item); \
wxCHECK2_MSG( iIndex != NOT_FOUND, return, \
"removing inexisting element in wxArray::Remove" ); \
wxBaseArray::Remove((uint)iIndex); } \
\
private: \
SCMPFUNC##T m_fnCompare; \
}
// ----------------------------------------------------------------------------
// see WX_DECLARE_LIST and WX_DEFINE_LIST
// ----------------------------------------------------------------------------
@@ -238,7 +296,7 @@ private: \
}
// ----------------------------------------------------------------------------
/** @name Macros for definition of dynamic arrays and lists
/** @name Macros for definition of dynamic arrays and lists
These macros are ugly (especially if you look in the sources ;-), but they
allow us to define 'template' classes without actually using templates.
@@ -247,7 +305,7 @@ private: \
Range checking is performed in debug build for both arrays and lists. Type
checking is done at compile-time. Warning: arrays <I>never</I> shrink, they
only grow, so loading 10 millions in an array only to delete them 2 lines
below is <I>not</I> recommended. However, it does free memory when it's
below is <I>not</I> recommended. However, it does free memory when it's
destroyed, so if you destroy array also, it's ok.
*/
// ----------------------------------------------------------------------------
@@ -264,6 +322,14 @@ private: \
*/
#define WX_DEFINE_ARRAY(T, name) typedef T _A##name; \
_WX_DEFINE_ARRAY(_A##name, name)
/**
This macro does the same as WX_DEFINE_ARRAY except that the array will be
sorted with the specified compare function.
*/
#define WX_DEFINE_SORTED_ARRAY(T, name) typedef T _A##name; \
_WX_DEFINE_SORTED_ARRAY(_A##name, name)
/**
This macro generates a new list class which owns the objects it contains,
i.e. it will delete them when it is destroyed. An element is of type T*,
@@ -290,11 +356,11 @@ private: \
<BR>
NB1: Base type T should have an accessible copy ctor if Add(T&) is used,
<BR>
NB2: Never ever cast a list to it's base type: as dtor is <B>not</B> virtual
NB2: Never ever cast a list to it's base type: as dtor is <B>not</B> virtual
it will provoke memory leaks
<BR>
<BR>
some functions of this class are not inline, so it takes some space to
some functions of this class are not inline, so it takes some space to
define new class from this template.
@memo declare list class 'name' containing elements of type 'T'
@@ -313,7 +379,7 @@ private: \
This is necessary because at the moment of DEFINE_LIST class element_type
must be fully defined (i.e. forward declaration is not enough), while
DECLARE_LIST may be done anywhere. The separation of two allows to break
cicrcular dependencies with classes which have member variables of list
cicrcular dependencies with classes which have member variables of list
type.
@memo define (must include listimpl.cpp!) list class 'name'

View File

@@ -2,7 +2,7 @@
// Name: dynarray.cpp
// Purpose: implementation of wxBaseArray class
// Author: Vadim Zeitlin
// Modified by:
// Modified by:
// Created: 12.09.97
// RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
@@ -26,6 +26,7 @@
#include "wx/dynarray.h"
#include <stdlib.h>
#include <string.h> // for memmove
#ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
@@ -57,34 +58,32 @@ wxBaseArray::wxBaseArray()
// copy ctor
wxBaseArray::wxBaseArray(const wxBaseArray& src)
{
m_uiSize = src.m_uiSize;
m_uiSize = // not src.m_uiSize to save memory
m_uiCount = src.m_uiCount;
if ( m_uiSize != 0 )
if ( m_uiSize != 0 ) {
m_pItems = new long[m_uiSize];
memcpy(m_pItems, src.m_pItems, m_uiCount*sizeof(long));
}
else
m_pItems = NULL;
if ( m_uiCount != 0 )
memcpy(m_pItems, src.m_pItems, m_uiCount*sizeof(long));
}
// copy operator
// assignment operator
wxBaseArray& wxBaseArray::operator=(const wxBaseArray& src)
{
DELETEA(m_pItems);
m_uiSize = src.m_uiSize;
m_uiSize = // not src.m_uiSize to save memory
m_uiCount = src.m_uiCount;
if ( m_uiSize != 0 )
if ( m_uiSize != 0 ) {
m_pItems = new long[m_uiSize];
memcpy(m_pItems, src.m_pItems, m_uiCount*sizeof(long));
}
else
m_pItems = NULL;
if ( m_uiCount != 0 )
memcpy(m_pItems, src.m_pItems, m_uiCount*sizeof(long));
return *this;
}
@@ -124,7 +123,7 @@ wxBaseArray::~wxBaseArray()
// clears the list
void wxBaseArray::Clear()
{
m_uiSize =
m_uiSize =
m_uiCount = 0;
DELETEA(m_pItems);
@@ -169,6 +168,28 @@ int wxBaseArray::Index(long lItem, bool bFromEnd) const
return NOT_FOUND;
}
// search for an item in a sorted array (binary search)
int wxBaseArray::Index(long lItem, CMPFUNC fnCompare)
{
uint i,
lo = 0,
hi = m_uiCount;
int res;
while ( lo < hi ) {
i = (lo + hi)/2;
res = (*fnCompare)((const void *)lItem, (const void *)m_pItems[i]);
if ( res < 0 )
hi = i;
else if ( res > 0 )
lo = i + 1;
else
return i;
}
return NOT_FOUND;
}
// add item at the end
void wxBaseArray::Add(long lItem)
{
@@ -176,6 +197,33 @@ void wxBaseArray::Add(long lItem)
m_pItems[m_uiCount++] = lItem;
}
// add item assuming the array is sorted with fnCompare function
void wxBaseArray::Add(long lItem, CMPFUNC fnCompare)
{
uint i,
lo = 0,
hi = m_uiCount;
int res;
while ( lo < hi ) {
i = (lo + hi)/2;
res = (*fnCompare)((const void *)lItem, (const void *)m_pItems[i]);
if ( res < 0 )
hi = i;
else if ( res > 0 )
lo = i + 1;
else {
lo = hi = i;
break;
}
}
wxASSERT( lo == hi ); // I hope I got binary search right :-)
Insert(lItem, lo);
}
// add item at the given position
void wxBaseArray::Insert(long lItem, uint uiIndex)
{
@@ -183,7 +231,7 @@ void wxBaseArray::Insert(long lItem, uint uiIndex)
Grow();
memmove(&m_pItems[uiIndex + 1], &m_pItems[uiIndex],
memmove(&m_pItems[uiIndex + 1], &m_pItems[uiIndex],
(m_uiCount - uiIndex)*sizeof(long));
m_pItems[uiIndex] = lItem;
m_uiCount++;
@@ -194,7 +242,7 @@ void wxBaseArray::Remove(uint uiIndex)
{
wxCHECK_RET( uiIndex <= m_uiCount, "bad index in wxArray::Remove" );
memmove(&m_pItems[uiIndex], &m_pItems[uiIndex + 1],
memmove(&m_pItems[uiIndex], &m_pItems[uiIndex + 1],
(m_uiCount - uiIndex - 1)*sizeof(long));
m_uiCount--;
}
@@ -204,7 +252,7 @@ void wxBaseArray::Remove(long lItem)
{
int iIndex = Index(lItem);
wxCHECK_RET( iIndex != NOT_FOUND,
wxCHECK_RET( iIndex != NOT_FOUND,
"removing inexistent item in wxArray::Remove" );
Remove((uint)iIndex);