This repository has been archived on 2024-12-16. You can view files and clone it, but cannot push or open issues or pull requests.
CodeBlocksPortable/WATCOM/samples/cplbexam/contain/alloctor.cpp

252 lines
6.2 KiB
C++

#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 single linked list.
//
// On a 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();
}