#include <iostream.h> #include <wclist.h> #include <wclistit.h> #include <wcskip.h> #include <wcskipit.h> #include <stdlib.h> #pragma warning 549 9 const int ElemsPerBlock = 50; // // Simple block allocation class. Allocate blocks for // ElemsPerBlock elements, and use part of the block for each // of the next ElemsPerBlock allocations, incrementing the // number allocated elements. Repeat, getting more blocks // as needed. // // Store the blocks in an intrusive singly linked list. // // On an element deallocation, assume we allocated the memory, // and just decrement the count of allocated elements. When // the count gets to zero, free all allocated blocks. // // This implementation assumes sizeof( char ) == 1. // class BlockAlloc { private: // the size of elements (in bytes) unsigned elem_size; // number of elements allocated unsigned num_allocated; // free space of this number of elements available in // first block unsigned num_free_in_block; // list of blocks used to store elements (block are chunks // of memory, pointed by (char *) pointers. WCPtrSList<char> block_list; // pointer to the first block in the list char *curr_block; public: inline BlockAlloc( unsigned size ) : elem_size( size ), num_allocated( 0 ) , num_free_in_block( 0 ) {}; inline ~BlockAlloc() { block_list.clearAndDestroy(); }; // get memory for an element using block allocation void *allocator( size_t elem_size ); // free memory for an element using block allocation and // deallocation void deallocator( void *old_ptr, size_t elem_size ); }; void *BlockAlloc::allocator( size_t size ) { // need a new block to perform allocation if( num_free_in_block == 0 ) { // allocate memory for ElemsPerBlock elements curr_block = new char[ size * ElemsPerBlock ]; if( curr_block == 0 ) { // allocation failed return( 0 ); } // add new block to beginning of list if( !block_list.insert( curr_block ) ) { // allocation of list element failed delete( curr_block ); return( 0 ); } num_free_in_block = ElemsPerBlock; } // curr block points to a block of memory with some free // memory num_allocated++; num_free_in_block--; // return pointer to a free part of the block, starting at // the end of the block return( curr_block + num_free_in_block * size ); } void BlockAlloc::deallocator( void *, size_t ) { // just decrement the count // don't free anything until all elements are deallocated num_allocated--; if( num_allocated == 0 ) { // all the elements allocated BlockAlloc object have // now been deallocated, free all the blocks block_list.clearAndDestroy(); num_free_in_block = 0; } } const unsigned NumTestElems = 200; // array with random elements static unsigned test_elems[ NumTestElems ]; static void fill_test_elems() { for( int i = 0; i < NumTestElems; i++ ) { test_elems[ i ] = rand(); } } void test_isv_list(); void test_val_list(); void test_val_skip_list(); void main() { fill_test_elems(); test_isv_list(); test_val_list(); test_val_skip_list(); } // An intrusive list class class isvInt : public WCSLink { public: static BlockAlloc memory_manage; int data; isvInt( int datum ) : data( datum ) {}; void *operator new( size_t size ) { return( memory_manage.allocator( size ) ); }; void operator delete( void *old, size_t size ) { memory_manage.deallocator( old, size ); }; }; // define static member data BlockAlloc isvInt::memory_manage( sizeof( isvInt ) ); void test_isv_list() { WCIsvSList<isvInt> list; for( int i = 0; i < NumTestElems; i++ ) { list.insert( new isvInt( test_elems[ i ] ) ); } WCIsvSListIter<isvInt> iter( list ); while( ++iter ) { cout << iter.current()->data << " "; } cout << "\n\n\n"; list.clearAndDestroy(); } // WCValSList<int> memory allocator/dealloctor support static BlockAlloc val_list_manager( WCValSListItemSize( int ) ); static void *val_list_alloc( size_t size ) { return( val_list_manager.allocator( size ) ); } static void val_list_dealloc( void *old, size_t size ) { val_list_manager.deallocator( old, size ); } // test WCValSList<int> void test_val_list() { WCValSList<int> list( &val_list_alloc, &val_list_dealloc ); for( int i = 0; i < NumTestElems; i++ ) { list.insert( test_elems[ i ] ); } WCValSListIter<int> iter( list ); while( ++iter ) { cout << iter.current() << " "; } cout << "\n\n\n"; list.clear(); } // skip list allocator dealloctors: just use allocator and // dealloctor functions on skip list elements with one and // two pointers (this will handle 94% of the elements) const int one_ptr_size = WCValSkipListItemSize( int, 1 ); const int two_ptr_size = WCValSkipListItemSize( int, 2 ); static BlockAlloc one_ptr_manager( one_ptr_size ); static BlockAlloc two_ptr_manager( two_ptr_size ); static void *val_skip_list_alloc( size_t size ) { switch( size ) { case one_ptr_size: return( one_ptr_manager.allocator( size ) ); case two_ptr_size: return( two_ptr_manager.allocator( size ) ); default: return( new char[ size ] ); } } static void val_skip_list_dealloc( void *old, size_t size ) { switch( size ) { case one_ptr_size: one_ptr_manager.deallocator( old, size ); break; case two_ptr_size: two_ptr_manager.deallocator( old, size ); break; default: delete old; break; } } // test WCValSkipList<int> void test_val_skip_list() { WCValSkipList<int> skiplist( WCSKIPLIST_PROB_QUARTER , WCDEFAULT_SKIPLIST_MAX_PTRS , &val_skip_list_alloc , &val_skip_list_dealloc ); for( int i = 0; i < NumTestElems; i++ ) { skiplist.insert( test_elems[ i ] ); } WCValSkipListIter<int> iter( skiplist ); while( ++iter ) { cout << iter.current() << " "; } cout << "\n\n\n"; skiplist.clear(); }