4b123bb9cc
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3345 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
660 lines
14 KiB
C++
660 lines
14 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: No names yet.
|
|
// Purpose: Contrib. demo
|
|
// Author: Aleksandras Gluchovas
|
|
// Modified by:
|
|
// Created: 27/09/98
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) Aleskandars Gluchovas
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef __WXSTLAC_G__
|
|
#define __WXSTLAC_G__
|
|
|
|
#include <stddef.h>
|
|
#include <sys/types.h>
|
|
#include <memory.h>
|
|
#include <limits.h>
|
|
#include <new>
|
|
|
|
|
|
// the below macro used internally (see actual interface after this macro)
|
|
|
|
// arguments:
|
|
//
|
|
// ARG_IS_UNIQUE
|
|
// ASSOC_CONT_CLASS_NAME
|
|
//
|
|
// ARG_VALUE_TYPE
|
|
// ARG_KEY_TYPE
|
|
// ARG_ACTUAL_VALUE_TYPE
|
|
//
|
|
// _KEY_NAME
|
|
// _VALUE_NAME
|
|
//
|
|
// _X_KEY_NAME
|
|
// _X_VALUE_NAME
|
|
//
|
|
// _INSERT_METHOD_DEFINITION
|
|
|
|
#define __DEFINE_ASOC_CLASS( ARG_IS_UNIQUE, \
|
|
FUNCTOR,\
|
|
ASSOC_CONT_CLASS_NAME, \
|
|
ARG_VALUE_TYPE, \
|
|
ARG_KEY_TYPE, \
|
|
ARG_ACTUAL_VALUE_TYPE, \
|
|
_KEY_NAME, \
|
|
_VALUE_NAME, \
|
|
_X_KEY_NAME, \
|
|
_X_VALUE_NAME, \
|
|
_INSERT_METHOD_DEFINITION \
|
|
) class \
|
|
ASSOC_CONT_CLASS_NAME\
|
|
{\
|
|
protected:\
|
|
\
|
|
public:\
|
|
typedef ARG_VALUE_TYPE value_type;\
|
|
typedef ARG_KEY_TYPE key_type;\
|
|
typedef ARG_ACTUAL_VALUE_TYPE actual_value_type;\
|
|
\
|
|
typedef value_type* pointer;\
|
|
typedef value_type& reference;\
|
|
\
|
|
typedef const value_type& const_reference;\
|
|
\
|
|
typedef FUNCTOR key_compare;\
|
|
typedef key_compare Compare;\
|
|
\
|
|
protected:\
|
|
\
|
|
struct tree_node \
|
|
{\
|
|
tree_node* mpParent;\
|
|
tree_node* mpLeft;\
|
|
tree_node* mpRight;\
|
|
\
|
|
value_type mData;\
|
|
};\
|
|
\
|
|
typedef tree_node* node_ref_type;\
|
|
\
|
|
node_ref_type mpRoot;\
|
|
node_ref_type mpLeftMost;\
|
|
node_ref_type mpRightMost;\
|
|
\
|
|
node_ref_type mpFreeListHead;\
|
|
int mKeyIsUnique;\
|
|
\
|
|
key_compare mCmpFunctorObj;\
|
|
\
|
|
public:\
|
|
\
|
|
static inline node_ref_type next( node_ref_type pNode )\
|
|
{\
|
|
if ( pNode->mpRight ) \
|
|
{\
|
|
pNode = pNode->mpRight;\
|
|
\
|
|
while ( pNode->mpLeft ) pNode = pNode->mpLeft;\
|
|
\
|
|
return pNode;\
|
|
}\
|
|
else\
|
|
if ( pNode->mpParent )\
|
|
{\
|
|
if ( pNode == pNode->mpParent->mpLeft )\
|
|
\
|
|
return pNode->mpParent;\
|
|
\
|
|
pNode = pNode->mpParent;\
|
|
\
|
|
node_ref_type prevNode = pNode;\
|
|
pNode = pNode->mpParent;\
|
|
\
|
|
while(pNode)\
|
|
{\
|
|
if ( pNode->mpRight &&\
|
|
pNode->mpRight != prevNode\
|
|
) return pNode;\
|
|
\
|
|
prevNode = pNode;\
|
|
pNode= pNode->mpParent;\
|
|
}\
|
|
\
|
|
return 0;\
|
|
}\
|
|
else\
|
|
return 0;\
|
|
}\
|
|
\
|
|
static inline node_ref_type prev( node_ref_type pNode )\
|
|
{\
|
|
if ( pNode->mpLeft ) \
|
|
{\
|
|
pNode = pNode->mpLeft;\
|
|
\
|
|
while ( pNode->mpRight ) pNode = pNode->mpRight;\
|
|
\
|
|
return pNode;\
|
|
}\
|
|
else\
|
|
if ( pNode->mpParent )\
|
|
{\
|
|
if ( pNode == pNode->mpParent->mpRight )\
|
|
return pNode->mpParent;\
|
|
\
|
|
pNode = pNode->mpParent;\
|
|
\
|
|
node_ref_type prevNode = pNode;\
|
|
pNode = pNode->mpParent;\
|
|
\
|
|
while(pNode)\
|
|
{\
|
|
if ( pNode->mpLeft &&\
|
|
pNode->mpLeft != prevNode\
|
|
) return pNode;\
|
|
\
|
|
prevNode = pNode;\
|
|
pNode= pNode->mpParent;\
|
|
}\
|
|
\
|
|
return 0;\
|
|
}\
|
|
else \
|
|
return 0;\
|
|
}\
|
|
\
|
|
protected:\
|
|
\
|
|
inline int are_equel( const key_type& x, const key_type& y ) const\
|
|
{\
|
|
mCmpFunctorObj(x,y);\
|
|
return ( !mCmpFunctorObj(x,y) && !mCmpFunctorObj(y,x) );\
|
|
}\
|
|
\
|
|
inline int is_less( const key_type& x, const key_type& y ) const\
|
|
{\
|
|
return mCmpFunctorObj(x,y);\
|
|
}\
|
|
\
|
|
static inline const actual_value_type& value( node_ref_type pNode )\
|
|
{\
|
|
return pNode->_VALUE_NAME;\
|
|
}\
|
|
\
|
|
static inline const key_type& key( node_ref_type pNode )\
|
|
{\
|
|
return pNode->_KEY_NAME;\
|
|
}\
|
|
\
|
|
inline node_ref_type AllocNode() \
|
|
{ \
|
|
if ( mpFreeListHead ) \
|
|
{\
|
|
node_ref_type pFreeNode = mpFreeListHead;\
|
|
mpFreeListHead = mpFreeListHead->mpLeft;\
|
|
\
|
|
return pFreeNode;\
|
|
}\
|
|
else\
|
|
{\
|
|
char* pHeapBlock = new char[sizeof(tree_node)];\
|
|
\
|
|
return (node_ref_type)pHeapBlock;\
|
|
}\
|
|
}\
|
|
\
|
|
inline void DestroyFreeList()\
|
|
{\
|
|
while ( mpFreeListHead )\
|
|
{\
|
|
node_ref_type tmp = mpFreeListHead;\
|
|
mpFreeListHead = mpFreeListHead->mpLeft;\
|
|
\
|
|
delete [](char*)tmp;\
|
|
}\
|
|
}\
|
|
\
|
|
inline void RecycleNode( node_ref_type pNode ) \
|
|
{\
|
|
pNode->mpLeft = mpFreeListHead;\
|
|
mpFreeListHead = pNode;\
|
|
}\
|
|
\
|
|
inline node_ref_type do_insert(const value_type& x = value_type() )\
|
|
{\
|
|
node_ref_type pNewNode = AllocNode();\
|
|
\
|
|
pNewNode->mpParent = \
|
|
pNewNode->mpLeft =\
|
|
pNewNode->mpRight = 0;\
|
|
\
|
|
node_ref_type pCurrent = mpRoot;\
|
|
node_ref_type pParent = 0;\
|
|
\
|
|
while (pCurrent) \
|
|
{\
|
|
if ( mKeyIsUnique && are_equel( _X_KEY_NAME, key(pCurrent) ) )\
|
|
{\
|
|
RecycleNode(pNewNode);\
|
|
return 0;\
|
|
}\
|
|
\
|
|
pParent = pCurrent;\
|
|
\
|
|
pCurrent = is_less( _X_KEY_NAME, key(pCurrent) ) \
|
|
? pCurrent->mpLeft \
|
|
: pCurrent->mpRight;\
|
|
}\
|
|
\
|
|
pNewNode->mpParent = pParent;\
|
|
\
|
|
if(pParent)\
|
|
\
|
|
if( is_less(_X_KEY_NAME, key(pParent) ) )\
|
|
\
|
|
pParent->mpLeft = pNewNode;\
|
|
else\
|
|
pParent->mpRight = pNewNode;\
|
|
else\
|
|
mpRoot = pNewNode;\
|
|
\
|
|
new ( &pNewNode->_KEY_NAME ) key_type(_X_KEY_NAME);\
|
|
new ( &pNewNode->_VALUE_NAME ) actual_value_type(_X_VALUE_NAME);\
|
|
\
|
|
if ( prev(pNewNode) == 0 ) mpLeftMost = pNewNode;\
|
|
if ( next(pNewNode) == 0 ) mpRightMost = pNewNode;\
|
|
\
|
|
return pNewNode;\
|
|
}\
|
|
\
|
|
friend class iterator;\
|
|
\
|
|
public:\
|
|
\
|
|
class iterator;\
|
|
class const_iterator;\
|
|
\
|
|
class iterator \
|
|
{\
|
|
public:\
|
|
node_ref_type mpNode;\
|
|
friend class CONT_CLASS_NAME;\
|
|
friend class const_iterator;\
|
|
friend class const_reverse_iterator;\
|
|
\
|
|
inline iterator( node_ref_type pNode )\
|
|
{\
|
|
mpNode = pNode;\
|
|
}\
|
|
\
|
|
public:\
|
|
inline iterator() {}\
|
|
inline int operator==( const iterator& rhs ) const { return (mpNode == rhs.mpNode); }\
|
|
inline int operator!=( const iterator& rhs ) const { return (mpNode != rhs.mpNode); }\
|
|
\
|
|
inline iterator( const iterator& other )\
|
|
{\
|
|
mpNode = other.mpNode;\
|
|
}\
|
|
\
|
|
inline const iterator& operator=( const iterator& other )\
|
|
{\
|
|
mpNode = other.mpNode;\
|
|
return *this;\
|
|
}\
|
|
\
|
|
inline const iterator& operator--() \
|
|
{\
|
|
mpNode = ASSOC_CONT_CLASS_NAME::prev(mpNode);\
|
|
return *this;\
|
|
}\
|
|
\
|
|
inline iterator operator--(int)\
|
|
{\
|
|
iterator tmp = *this;\
|
|
mpNode = ASSOC_CONT_CLASS_NAME::prev(mpNode);\
|
|
return tmp;\
|
|
}\
|
|
\
|
|
inline const iterator& operator++() \
|
|
{\
|
|
mpNode = ASSOC_CONT_CLASS_NAME::next(mpNode);\
|
|
return *this;\
|
|
}\
|
|
\
|
|
inline iterator operator++(int)\
|
|
{\
|
|
iterator tmp = *this;\
|
|
mpNode = ASSOC_CONT_CLASS_NAME::next(mpNode);\
|
|
return tmp;\
|
|
}\
|
|
\
|
|
inline reference operator*() const { return mpNode->mData; }\
|
|
};\
|
|
\
|
|
\
|
|
class const_iterator \
|
|
{\
|
|
public:\
|
|
node_ref_type mpNode;\
|
|
friend class CONT_CLASS_NAME;\
|
|
friend class const_reverse_iterator;\
|
|
\
|
|
inline const_iterator( node_ref_type pNode )\
|
|
{\
|
|
mpNode = pNode;\
|
|
}\
|
|
\
|
|
public:\
|
|
inline const_iterator() {}\
|
|
\
|
|
inline int operator==( const const_iterator& rhs ) const { return (mpNode == rhs.mpNode); }\
|
|
inline int operator!=( const const_iterator& rhs ) const { return (mpNode != rhs.mpNode); }\
|
|
\
|
|
inline const_iterator( const iterator& other )\
|
|
{\
|
|
mpNode = other.mpNode;\
|
|
}\
|
|
\
|
|
inline const_iterator( const const_iterator& other )\
|
|
{\
|
|
mpNode = other.mpNode;\
|
|
}\
|
|
\
|
|
inline const const_iterator& operator=( const const_iterator& other )\
|
|
{\
|
|
mpNode = other.mpNode;\
|
|
return *this;\
|
|
}\
|
|
\
|
|
inline const const_iterator& operator--() \
|
|
{\
|
|
mpNode = ASSOC_CONT_CLASS_NAME::prev(mpNode);\
|
|
return *this;\
|
|
}\
|
|
\
|
|
inline const_iterator operator--(int)\
|
|
{\
|
|
const_iterator tmp = *this;\
|
|
mpNode = ASSOC_CONT_CLASS_NAME::prev(mpNode);\
|
|
return tmp;\
|
|
}\
|
|
\
|
|
inline const const_iterator& operator++() \
|
|
{\
|
|
mpNode = ASSOC_CONT_CLASS_NAME::next(mpNode);\
|
|
return *this;\
|
|
}\
|
|
\
|
|
inline const_iterator operator++(int)\
|
|
{\
|
|
const_iterator tmp = *this;\
|
|
mpNode = ASSOC_CONT_CLASS_NAME::next(mpNode);\
|
|
return tmp;\
|
|
}\
|
|
\
|
|
inline const_reference operator*() const { return mpNode->mData; }\
|
|
};\
|
|
\
|
|
public:\
|
|
\
|
|
inline ASSOC_CONT_CLASS_NAME( key_compare cmpFunctorObj = key_compare(),\
|
|
int keyIsUnique = ARG_IS_UNIQUE )\
|
|
: mpFreeListHead( 0 ),\
|
|
mKeyIsUnique( keyIsUnique ),\
|
|
mCmpFunctorObj( cmpFunctorObj )\
|
|
{\
|
|
mpLeftMost = 0;\
|
|
mpRightMost = 0;\
|
|
mpRoot = 0;\
|
|
}\
|
|
\
|
|
inline ~ASSOC_CONT_CLASS_NAME() \
|
|
{ \
|
|
erase( begin(), end() ); \
|
|
\
|
|
DestroyFreeList();\
|
|
}\
|
|
\
|
|
inline iterator begin() { return mpLeftMost; }\
|
|
inline iterator end() { return 0; }\
|
|
\
|
|
inline const_iterator begin() const { return mpLeftMost; }\
|
|
inline const_iterator end() const { return 0; }\
|
|
\
|
|
inline iterator lower_bound( const key_type& x )\
|
|
{ \
|
|
node_ref_type pCurrent = mpRoot;\
|
|
\
|
|
while( pCurrent )\
|
|
{\
|
|
node_ref_type pParent = pCurrent;\
|
|
\
|
|
if( are_equel( x, key(pCurrent) ) )\
|
|
\
|
|
return (pCurrent);\
|
|
else\
|
|
pCurrent = is_less( x, key(pCurrent) ) \
|
|
? pCurrent->mpLeft \
|
|
: pCurrent->mpRight;\
|
|
\
|
|
if ( !pCurrent ) return (pParent);\
|
|
}\
|
|
\
|
|
return begin();\
|
|
}\
|
|
\
|
|
inline const_iterator lower_bound( const key_type& x ) const\
|
|
\
|
|
{ return const_iterator( lower_bound(x).mpNode ); }\
|
|
\
|
|
inline iterator upper_bound( const key_type& x )\
|
|
{\
|
|
node_ref_type pCurrent = mpRoot;\
|
|
\
|
|
while( pCurrent )\
|
|
{\
|
|
node_ref_type pParent = pCurrent;\
|
|
\
|
|
if( are_equel( x, key(pCurrent) ) )\
|
|
\
|
|
return (pCurrent);\
|
|
else\
|
|
pCurrent = is_less( x, key(pCurrent) ) \
|
|
? pCurrent->mpLeft \
|
|
: pCurrent->mpRight;\
|
|
\
|
|
if ( !pCurrent ) return next(pParent);\
|
|
}\
|
|
\
|
|
return end();\
|
|
}\
|
|
\
|
|
inline iterator find( const key_type& x ) const\
|
|
{\
|
|
node_ref_type pCurrent = mpRoot;\
|
|
\
|
|
while( pCurrent )\
|
|
{\
|
|
if( are_equel( x, key(pCurrent) ) )\
|
|
\
|
|
return (pCurrent);\
|
|
else\
|
|
pCurrent = is_less( x, key(pCurrent) ) \
|
|
? pCurrent->mpLeft \
|
|
: pCurrent->mpRight;\
|
|
}\
|
|
\
|
|
return iterator(0);\
|
|
}\
|
|
\
|
|
inline actual_value_type& operator[]( const key_type x ) const\
|
|
\
|
|
{ return find(x).mpNode->_VALUE_NAME; }\
|
|
\
|
|
inline void erase(iterator first, iterator last)\
|
|
{\
|
|
if ( first.mpNode == 0 ) return;\
|
|
\
|
|
while( first != last ) \
|
|
{\
|
|
iterator next = first;\
|
|
++next;\
|
|
erase( first );\
|
|
first = next;\
|
|
}\
|
|
}\
|
|
\
|
|
inline void erase(iterator position)\
|
|
{\
|
|
if ( position.mpNode == 0 ) return;\
|
|
\
|
|
node_ref_type pZ = position.mpNode;\
|
|
node_ref_type pX, pY;\
|
|
\
|
|
if ( pZ == mpLeftMost ) mpLeftMost = next(pZ);\
|
|
if ( pZ == mpRightMost ) mpRightMost = prev( pZ );\
|
|
\
|
|
if ( !pZ->mpLeft || !pZ->mpRight )\
|
|
\
|
|
pY = pZ;\
|
|
else \
|
|
{\
|
|
pY = pZ->mpRight;\
|
|
\
|
|
while (pY->mpLeft) \
|
|
\
|
|
pY = pY->mpLeft;\
|
|
}\
|
|
\
|
|
if ( pY->mpLeft)\
|
|
\
|
|
pX = pY->mpLeft;\
|
|
else\
|
|
pX = pY->mpRight;\
|
|
\
|
|
if ( pX ) pX->mpParent = pY->mpParent;\
|
|
\
|
|
if (pY->mpParent)\
|
|
\
|
|
if (pY == pY->mpParent->mpLeft )\
|
|
\
|
|
pY->mpParent->mpLeft = pX;\
|
|
else\
|
|
pY->mpParent->mpRight = pX;\
|
|
else\
|
|
mpRoot = pX;\
|
|
\
|
|
node_ref_type toRemove = 0;\
|
|
\
|
|
if (pY != pZ) {\
|
|
\
|
|
pY->mpLeft = pZ->mpLeft;\
|
|
\
|
|
if (pY->mpLeft) pY->mpLeft->mpParent = pY;\
|
|
\
|
|
pY->mpRight = pZ->mpRight;\
|
|
\
|
|
if ( pY->mpRight ) \
|
|
\
|
|
pY->mpRight->mpParent = pY;\
|
|
\
|
|
pY->mpParent = pZ->mpParent;\
|
|
\
|
|
if (pZ->mpParent)\
|
|
\
|
|
if (pZ == pZ->mpParent->mpLeft)\
|
|
\
|
|
pZ->mpParent->mpLeft = pY;\
|
|
else\
|
|
pZ->mpParent->mpRight = pY;\
|
|
else\
|
|
mpRoot = pY;\
|
|
\
|
|
toRemove = pZ;\
|
|
} \
|
|
else \
|
|
toRemove = pY;\
|
|
\
|
|
\
|
|
RecycleNode( toRemove );\
|
|
}\
|
|
\
|
|
_INSERT_METHOD_DEFINITION\
|
|
}
|
|
|
|
// do not undefine ___WXSTL_COMMA, where associated containers are defined!
|
|
// (it is used as workaround for constraints of C-Preprocessor's nested macros)
|
|
|
|
#define ___WXSTL_COMMA ,
|
|
|
|
#define __DEFINE_MAP(ARG_IS_UNIQUE, KEY_TYPE, VAL_TYPE, FUNCTOR ) __DEFINE_ASOC_CLASS( ARG_IS_UNIQUE,\
|
|
FUNCTOR,\
|
|
__WXSTLMAP_##KEY_TYPE##VAL_TYPE##ARG_IS_UNIQUE, \
|
|
struct key_value_pair { KEY_TYPE first ; \
|
|
VAL_TYPE second;\
|
|
key_value_pair() {}\
|
|
key_value_pair( const KEY_TYPE& key ___WXSTL_COMMA const VAL_TYPE& value ) \
|
|
: first(key) ___WXSTL_COMMA second( value ) {} \
|
|
} , \
|
|
KEY_TYPE,\
|
|
VAL_TYPE,\
|
|
mData.first, mData.second, x.first, x.second, \
|
|
struct insert_result_iterator\
|
|
{\
|
|
iterator first;\
|
|
int second;\
|
|
};\
|
|
inline insert_result_iterator insert( const value_type& x )\
|
|
{\
|
|
insert_result_iterator result;\
|
|
\
|
|
result.first = do_insert(x);\
|
|
result.second = ( result.first == end() ) ? 0 : 1;\
|
|
\
|
|
return result;\
|
|
} )
|
|
|
|
#define __DEFINE_SET(ARG_IS_UNIQUE, KEY_TYPE, FUNCTOR ) __DEFINE_ASOC_CLASS( ARG_IS_UNIQUE,\
|
|
FUNCTOR,\
|
|
__WXSTLSET_##TYPE##ARG_IS_UNIQUE, \
|
|
KEY_TYPE,\
|
|
KEY_TYPE,\
|
|
KEY_TYPE,\
|
|
mData, mData, x, x, \
|
|
struct insert_result_iterator\
|
|
{\
|
|
iterator first;\
|
|
int second;\
|
|
};\
|
|
inline insert_result_iterator insert( const value_type& x )\
|
|
{\
|
|
insert_result_iterator result;\
|
|
\
|
|
result.first = do_insert(x);\
|
|
result.second = ( result.first == end() ) ? 0 : 1;\
|
|
\
|
|
return result;\
|
|
} )
|
|
|
|
// helper macros to create functor objects for associative containers of the given type
|
|
|
|
#define LESS_THEN_FUNCTOR(TYPE) struct \
|
|
{ inline int operator()(const TYPE& x, const TYPE& y ) const { return x < y; } }
|
|
|
|
#define GREATER_THEN_FUNCTOR(TYPE) struct \
|
|
{ inline int operator()(const TYPE& x, const TYPE& y ) const { return x > y; } }
|
|
|
|
// functor argument should be created using the two above macros
|
|
// or passing own class with method "operator()(const TYPE&,cosnt TYPE&)" defined in it
|
|
|
|
#define WXSTL_MAP( KEY_TYPE, VALUE_TYPE, FUNCTOR ) __DEFINE_MAP( 1 ,KEY_TYPE, VALUE_TYPE, FUNCTOR)
|
|
#define WXSTL_MULTIMAP( KEY_TYPE, VALUE_TYPE, FUNCTOR ) __DEFINE_MAP( 0 ,KEY_TYPE, VALUE_TYPE, FUNCTOR)
|
|
#define WXSTL_SET( KEY_TYPE, FUNCTOR ) __DEFINE_SET( 1 ,KEY_TYPE, FUNCTOR )
|
|
#define WXSTL_MULTISET( KEY_TYPE, FUNCTOR ) __DEFINE_SET( 0 ,KEY_TYPE, FUNCTOR )
|
|
|
|
#endif
|