diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Wasabi/bfc/ptrlist.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Wasabi/bfc/ptrlist.cpp')
-rw-r--r-- | Src/Wasabi/bfc/ptrlist.cpp | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/Src/Wasabi/bfc/ptrlist.cpp b/Src/Wasabi/bfc/ptrlist.cpp new file mode 100644 index 00000000..32015dcb --- /dev/null +++ b/Src/Wasabi/bfc/ptrlist.cpp @@ -0,0 +1,330 @@ +#include "ptrlist.h" +#include <bfc/bfc_assert.h> + +// if this symbol is enabled, do sanity checking in a bunch of methods +//#define DO_VERIFY_PTRLIST + +#if defined(ASSERTS_ENABLED) && defined(DO_VERIFY_PTRLIST) +#define VERIFY_PTRLIST verify() +#else +#define VERIFY_PTRLIST +#endif + +#ifdef _DEBUG +int ptrlist_totalnitems = 0; +#endif + +PtrListRoot::PtrListRoot( int initial_size ) +{ + nitems = nslots = 0; + items = NULL; + //FG>why? we might as well save initial_size*4 bytes if nobody inserts anything in the list, no? + //BU No. initial_size defaults to 0 and therefore no memory is actually + //allocated in a typical construction. But, sometimes you want to start with + //a specific size, generally when you know the exact size you want, + //so that you can avoid REALLOCs when you initially populate the list. + //FG>Ah, makes sense. + setMinimumSize( initial_size ); +} + +PtrListRoot::PtrListRoot( const PtrListRoot *from ) +{ + nitems = nslots = 0; + items = NULL; + copyFrom( from ); +} + +PtrListRoot::~PtrListRoot() +{ + removeAll(); +} + +void PtrListRoot::copyFrom( const PtrListRoot *from ) +{ + ASSERT( from != NULL ); + + removeAll(); + appendFrom( from ); + VERIFY_PTRLIST; +} + +void PtrListRoot::appendFrom( const PtrListRoot *from ) +{ + ASSERT( from != NULL ); + + int n = from->getNumItems(); + + if ( n <= 0 ) + return; + + void **mem = from->getItemList(); + + ASSERT( mem != NULL ); // can't be NULL if getNumItems() >= 1 + + setMinimumSize( getNumItems() + n ); + MEMCPY( items + getNumItems(), from->getItemList(), sizeof( void * ) * n ); + nitems += n; +#ifdef _DEBUG + ptrlist_totalnitems += n; +#endif + VERIFY_PTRLIST; +} + +void PtrListRoot::setMinimumSize( int _nslots ) +{ + ASSERT( _nslots >= 0 ); +#ifdef DECREASE_PTRLISTS_SIZE + if ( _nslots + 2 * DEF_PTRLIST_INCREMENT < nslots ) + { + nslots = ( ( _nslots / DEF_PTRLIST_INCREMENT ) + 2 ) * DEF_PTRLIST_INCREMENT; + items = (void **) REALLOC( items, sizeof( void * ) * nslots ); + } +#endif + if ( _nslots == 0 || _nslots <= nslots ) + return; + + nslots = _nslots; + + if ( items ) + items = (void **) REALLOC( items, sizeof( void * ) * nslots ); + else + items = (void **) MALLOC( sizeof( void * ) * nslots ); + + VERIFY_PTRLIST; +} + +int PtrListRoot::getNumItems() const +{ + return nitems; +} + +void *PtrListRoot::enumItem( int n ) const +{ + if ( items == NULL || n < 0 || n >= nitems ) + return NULL; + + return items[ n ]; +} + +void *PtrListRoot::addItem( void *item, int pos, int increment ) +{ + ASSERT( increment > 0 ); + ASSERTPR( item != NULL, "can't put NULLs into ptrlists" ); + ASSERT( nitems <= nslots ); + +#ifdef DECREASE_PTRLISTS_SIZE + // expand or shrink as necessary + if ( items == NULL || nslots == nitems ) + setMinimumSize( nslots + increment ); + else + setMinimumSize( nitems ); +#else + // expand if necessary + if ( items == NULL || nslots == nitems ) + setMinimumSize( nslots + increment ); +#endif + + items[ nitems++ ] = item; + + if ( pos != PTRLIST_POS_LAST ) + moveItem( nitems - 1, pos ); + + VERIFY_PTRLIST; + +#ifdef _DEBUG + ptrlist_totalnitems++; +#endif + + return item; +} + +// replace what's in the slot with the new value +void *PtrListRoot::setItem( void *item, int pos ) +{ + ASSERT( nitems >= pos ); + items[ pos ] = item; + VERIFY_PTRLIST; + return item; +} + +void PtrListRoot::reverse() +{ + if ( nitems <= 1 ) + return; + + MemBlock<void *> block( nitems, items ); + void **blockmem = block.getMemory(); + + for ( int i = 0, j = nitems - 1; j >= 0; i++, j-- ) + { + items[ i ] = blockmem[ j ]; + } +} + +void PtrListRoot::moveItem( int from, int to ) +{ + if ( from == to ) + return; + + void *ptr = items[ from ]; + + if ( nitems > from + 1 ) // if moving from the end, there is nothing to shift behind our src position + { + //IMPORTANT note for future ports: This assumes MEMCPY accepts overlapping segments. + MEMCPY( &items[ from ], &items[ from + 1 ], ( nitems - from ) * sizeof( void * ) ); + } + + if ( to > from ) + to--; + + if ( nitems > to ) // if moving to the end, there is nothing to shift behind our target position + MEMCPY( &items[ to + 1 ], &items[ to ], ( nitems - to - 1 ) * sizeof( void * ) ); + + items[ to ] = ptr; + VERIFY_PTRLIST; +} + +int PtrListRoot::removeItem( void *item ) +{ + int c = 0; + + if ( item == NULL || items == NULL || nitems <= 0 ) + return 0; + + // count occurences of item in items, remember the first one + void **p = items; + int first = -1; + + for ( int i = 0; i < nitems; i++, p++ ) + { + if ( *p == item ) + { + if ( c++ == 0 ) + first = i; + } + } + + // if we found one, remove it + if ( c > 0 ) + { + removeByPos( first ); // delByPos is faaast + c--; // decrease count + } + + VERIFY_PTRLIST; + + return c; // returns how many occurences of this item left +} + +void PtrListRoot::removeEveryItem( void *item ) +{ + while ( removeItem( item ) ); + VERIFY_PTRLIST; +} + +void PtrListRoot::removeByPos( int pos ) +{ + if ( pos < 0 || pos >= nitems ) + return; //JC + + --nitems; +#ifdef _DEBUG + ptrlist_totalnitems--; +#endif + + if ( pos == nitems ) + return; // last one? nothing to copy over + + MEMCPY( items + pos, items + ( pos + 1 ), sizeof( void * ) * ( nitems - pos ) ); // CT:not (nitems-(pos+1)) as nitems has been decremented earlier +#ifdef DECREASE_PTRLISTS_SIZE + // shrink if necessary + setMinimumSize( nitems ); +#endif + VERIFY_PTRLIST; +} + +void PtrListRoot::removeLastItem() +{ + if ( nitems == 0 || items == NULL ) return; + nitems--; // hee hee +#ifdef _DEBUG + ptrlist_totalnitems--; +#endif +#ifdef DECREASE_PTRLISTS_SIZE + // shrink if necessary + setMinimumSize( nitems ); +#endif + VERIFY_PTRLIST; +} + +void PtrListRoot::removeAll() +{ + FREE( items ); items = NULL; +#ifdef _DEBUG + ptrlist_totalnitems -= nitems; +#endif +#ifdef DECREASE_PTRLISTS_SIZE + // shrink if necessary + setMinimumSize( nitems ); +#endif + nitems = 0; + nslots = 0; + VERIFY_PTRLIST; +} + +void PtrListRoot::freeAll() +{ + for ( int i = 0; i < nitems; i++ ) //JC + if ( items ) FREE( items[ i ] ); + + removeAll(); + VERIFY_PTRLIST; +} + +int PtrListRoot::searchItem( void *item ) const +{ + for ( int i = 0; i < nitems; i++ ) + if ( items[ i ] == item ) + return i; + return -1; +} + +void PtrListRoot::verify() +{ +#ifdef DO_VERIFY_PTRLIST + ASSERT( nitems >= 0 ); + ASSERT( nslots >= 0 ); + ASSERT( nitems <= nslots ); +#endif +} + +#if 0 +int PtrListRoot::bsearchItem( void *item ) const +{ + // do binary search + if ( nitems == 0 || items == NULL ) return -1; + + int bot = 0, top = nitems - 1, mid; + + for ( int c = 0; c < nitems + 16; c++ ) + { + if ( bot > top ) return -1; + mid = ( bot + top ) / 2; + if ( item == items[ mid ] ) return mid; + if ( item < items[ mid ] ) top = mid - 1; + else bot = mid + 1; + } + ASSERTPR( 0, "binary search fucked up" ); + return -1; +} +#endif + +void PtrListRoot::purge() +{ + ASSERT( nitems == 0 ); + if ( items != NULL ) + { + FREE( items ); + items = NULL; + } +} |