/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename :: ODYNARR.CPP
//Description :: Dynamic Array object
#include
#include
#include
//--------- BEGIN OF FUNCTION DynArray Constructor -------//
//
// eleSize = size of each element
// [int] blockNum = number of entity of each block of element
// increased ( default : 30 )
DynArray::DynArray(int eleSize,int blockNum)
{
ele_size = eleSize;
block_num = blockNum;
body_buf = mem_add( ele_size*block_num );
cur_pos=0;
last_ele=0;
ele_num= block_num;
sort_offset = -1;
}
//----------- END OF FUNCTION DynArray Constructor -----//
//--------- BEGIN OF FUNCTION DynArray Destructor ------//
DynArray::~DynArray()
{
mem_del( body_buf );
}
//---------- END OF FUNCTION DynArray Destructor --------//
//--------- BEGIN OF FUNCTION DynArray::resize ---------//
//
// change the size of the storage block - this will always be an increase
//
void DynArray::resize( int newNum )
{
//-------------------------------------------------------//
//
// The Mem::resize() and realloc() may not function properly in
// some case when the memory block has a considerable size.
//
// Calling function resize_keep_data will do additional effort
// to preserve the original data.
//
//-------------------------------------------------------//
body_buf = mem_resize( body_buf, newNum*ele_size ); // give both the original data size and the new data size
ele_num = newNum;
}
//--------- END OF FUNCTION DynArray::resize -----------//
//--------- BEGIN OF FUNCTION DynArray::zap ---------//
//
// Zap the whole dynamic array, clear all elements
//
// [int] resizeFlag - whether resize the array to its initial size
// or keep its current size.
// (default:1)
//
void DynArray::zap(int resizeFlag)
{
if( resizeFlag )
{
if( ele_num != block_num ) // if the current record no. is already block_num, no resizing needed
{
ele_num = block_num;
body_buf = mem_resize(body_buf, ele_size*ele_num );
}
}
cur_pos=0;
last_ele=0;
}
//--------- END OF FUNCTION DynArray::zap -----------//
//---------- BEGIN OF FUNCTION DynArray::linkin -----------//
//
// Link a record at the END of the array
//
// WARNING : After calling linkin() all pointers to the linklist body
// should be updated, because mem_resize() will move the body memory
//
void DynArray::linkin(void* ent)
{
last_ele++;
cur_pos=last_ele;
if ( last_ele > ele_num ) // not enough empty element left to hold the new entity
resize( ele_num + block_num );
if ( ent )
memcpy(body_buf+(cur_pos-1)*ele_size, ent, ele_size );
else
*(body_buf+(cur_pos-1)*ele_size) = NULL;
}
//---------- END OF FUNCTION DynArray::linkin ------------//
//---------- BEGIN OF FUNCTION DynArray::linkin_unique -----------//
//
// Linkin - unique mode. If duplicated, don't link into the array.
//
void DynArray::linkin_unique(void* ent)
{
int i;
for( i=0 ; i ele_num ) // not enough empty element left to hold the new entity
resize( ele_num + block_num );
memmove( body_buf+cur_pos*ele_size,body_buf+(cur_pos-1)*ele_size, (last_ele-cur_pos)*ele_size );
if ( ent )
memcpy(body_buf+(cur_pos-1)*ele_size, ent, ele_size );
else
*(body_buf+(cur_pos-1)*ele_size) = NULL;
}
//---------- END OF FUNCTION DynArray::insert ------------//
//---------- BEGIN OF FUNCTION DynArray::insert_at -----------//
//
// Link into the position BEFORE the current one
//
// Warning : DynArrayB (version B) can't use this function
//
// insertPos - the recno to insert the new entity.
// ent - pointer to the record entity. If NULL, blank record.
//
void DynArray::insert_at(int insertPos, void* ent)
{
if( size()==0 || insertPos>last_ele )
{
linkin(ent);
return;
}
err_when( insertPos<1 || insertPos > last_ele );
last_ele++;
if ( last_ele > ele_num ) // not enough empty element left to hold the new entity
resize( ele_num + block_num );
memmove( body_buf+insertPos*ele_size, body_buf+(insertPos-1)*ele_size, (last_ele-insertPos)*ele_size );
if ( ent )
memcpy(body_buf+(insertPos-1)*ele_size, ent, ele_size );
else
*(body_buf+(insertPos-1)*ele_size) = NULL;
}
//---------- END OF FUNCTION DynArray::insert_at ------------//
//----------- BEGIN OF FUNCTION DynArray::linkout ---------//
//
// Linkout the current object and then point to next object
//
// [int] delPos = the position (recno) of the item to be deleted
// ( default : recno() current record no. )
//
void DynArray::linkout(int delPos)
{
if( delPos < 0 )
delPos = cur_pos;
if( delPos == 0 || delPos > last_ele )
return;
if( delPos != last_ele )
memmove( body_buf+(delPos-1)*ele_size, body_buf+delPos*ele_size, (last_ele-delPos)*ele_size );
last_ele--;
if( cur_pos > last_ele )
cur_pos = last_ele;
if ( last_ele < ele_num - block_num*2 ) // shrink the size if two empty block of element are left
resize( ele_num - block_num );
}
//------------ END OF FUNCTION DynArray::linkout ----------//
//---------- BEGIN OF FUNCTION DynArray::update ---------//
//
// bodyPtr = the pointer to the content body
// [int] recNo = no. of the record to be updated
// ( default : current record no. )
//
void DynArray::update(void* bodyPtr, int recNo)
{
if( recNo < 0 )
recNo = cur_pos;
if( recNo <= 0 )
return;
if( bodyPtr )
memcpy(body_buf+(recNo-1)*ele_size, bodyPtr, ele_size );
else
*(body_buf+(recNo-1)*ele_size) = NULL;
}
//----------- END OF FUNCTION DynArray::update ---------//
//---------- BEGIN OF FUNCTION DynArray::add_blank -----------//
//
// Add a specified number of blank records at the END of the array
//
// blankNum = no. of blank records
//
void DynArray::add_blank(int blankNum)
{
cur_pos=last_ele+1;
last_ele+=blankNum;
if ( last_ele > ele_num ) // not enough empty element left to hold the new entity
resize( last_ele+block_num );
memset( body_buf+(cur_pos-1)*ele_size, 0, blankNum*ele_size );
}
//---------- END OF FUNCTION DynArray::add_blank ------------//
//------ BEGIN OF FUNCTION DynArray::scan_whole ----------//
//
// Description : scan a sorted or unsorted link list for matching
// the Whole Structure
//
// Syntax : scan()
//
// = pointer to the data structure
//
// Return : 0 if not found
// if found, return the position found
//
int DynArray::scan_whole(void* structPtr)
{
for ( cur_pos=1 ; cur_pos<=last_ele ; cur_pos++ )
{
if( memcmp( structPtr, get(), ele_size ) == 0 )
return cur_pos;
}
return 0;
}
//-------- END OF FUNCTION DynArray::scan_whole ----------//
//------ BEGIN OF FUNCTION DynArray::scan ----------//
//
// Description : scan a sorted or unsorted link list for matching
// the specified element in the structure
//
// Syntax : scan(,,,[int])
//
// = the data to be scanned for
// = the offset of the structure containing the variable to be compared
// = the type of the variable in the structure
// 'C' = char[]
// 'P' = char*
// 'd' = double
// 'i' = integer
// 'c' = char
// [int] = restore the original position ( default : FALSE )
//
// Return : 0 if not found
// if found, return the position found
//
int DynArray::scan(void* varChar,int varOff,char varType,int restPos)
{
int oldPos,ret;
oldPos = cur_pos;
for ( cur_pos=1 ; cur_pos<=last_ele ; cur_pos++ )
{
if ( compare(varChar,varOff,varType) )
{
ret = cur_pos;
if (restPos)
cur_pos = oldPos;
return ret;
}
}
return 0;
}
//-------- END OF FUNCTION DynArray::scan ----------//
//------- BEGIN OF FUNCTION DynArray::compare --------//
//
// = the character string to be scanned for
// = the offset of the structure containing the variable to be compared
// = the type of the variable in the structure
// 'C' = char[]
// 'P' = char*
// 'd' = double
// 'i' = integer
// 'c' = char
int DynArray::compare(void* varChar,int varOff,char varType)
{
char *bodyPtr,*bodyStr;
bodyPtr = (char*) get();
switch( varType )
{
case 'C' :
case 'P' :
if ( varType == 'C' )
bodyStr = bodyPtr + varOff;
else
bodyStr = *( (char**)(bodyPtr+varOff) );
if( bodyStr == (char*) varChar ) // the pointer is the same
return 1;
else
return m.str_cmp(bodyStr, (char*) varChar); // m1strcmp with exact set off
case 'c' :
return *(bodyPtr + varOff ) == *((char*)varChar);
case 'i' :
return *((int*)(bodyPtr+varOff)) == *((int*)varChar);
case 'd' :
return *((double*)(bodyPtr+varOff)) == *((double*)varChar);
}
return NULL;
}
//-------- END OF FUNCTION DynArray::compare ----------//
//---------- BEGIN OF FUNCTION DynArray::clean_up --------------//
//
// Description : clear up the whole dynamic array
//
// Syntax : clean_up()
//
// = the array of offset of the char*
//
void DynArray::clean_up(int *stringOffset)
{
if ( stringOffset )
{
int i;
for ( i = 0 ; i writeFile = the pointer to the writing file
//
// Return : 1 - write successfully
// 0 - writing error
//
int DynArray::write_file(File* filePtr)
{
if( !filePtr->file_write( this, sizeof(DynArray) ) )
return 0;
if( last_ele > 0 )
{
if( !filePtr->file_write( body_buf, ele_size*last_ele ) )
return 0;
}
return 1;
}
//------------- End of function DynArray::write_file --------------//
//---------- Begin of function DynArray::read_file -------------//
//
// Read a saved dynamic array from file, it must be saved with write_file()
//
// readFile = the pointer to the writing file
//
// Return : 1 - read successfully
// 0 - writing error
//
int DynArray::read_file(File* filePtr)
{
char* bodyBuf = body_buf; // preserve body_buf which has been allocated
if( !filePtr->file_read( this, sizeof(DynArray) ) )
return 0;
body_buf = mem_resize( bodyBuf, ele_num*ele_size );
if( last_ele > 0 )
{
if( !filePtr->file_read( body_buf, ele_size*last_ele ) )
return 0;
}
start(); // go top
return 1;
}
//------------- End of function DynArray::read_file --------------//
//--------- Begin of function DynArray::init_sort ---------//
//
// Initialize sorting parameters before using linkin_sort & resort
//
// sortOffset : offset of the sorting variable
// sortType : SORT_CHAR_PTR =
// SORT_CHAR_STR =
// SORT_INT =
// SORT_SHORT =
// SORT_CHAR =
//
void DynArray::init_sort(int sortOffset, char sortType)
{
sort_offset = sortOffset;
sort_type = sortType;
}
//----------- End of function DynArray::init_sort ---------//
//------ BEGIN OF FUNCTION DynArray::linkin_sort_scan_from_bottom ----------//
//
// Description : linkin a entry to a sorted link list
//
// Note : init_sort() must be called first, before using sorting function
// Warning : DynArrayB (version B) can't use this function
//
// Syntax : linkin_sort_scan_from_bottom(,,)
//
// = the structure buffer pointer
//
// Note : use DynArray::seek() to search quickly if the whole DynArray is
// built up with linkin_sort_scan_from_bottom()
//
// WARNING : After calling linkin() all pointers to the linklist body
// should be updated, because mem_resize() will move the body memory
//
void DynArray::linkin_sort_scan_from_bottom(void* varPtr)
{
err_when( sort_offset < 0 );
int cmpRet;
char* varData,*bodyChar;
for( int recNo=last_ele ; recNo>0 ; recNo-- )
{
//-------- comparsion ---------//
switch( sort_type )
{
case SORT_INT: //
cmpRet = *((int*)((char*)varPtr+sort_offset)) >
*((int*)((char*)get()+sort_offset));
break;
case SORT_SHORT: //
cmpRet = *((short*)((char*)varPtr+sort_offset)) >
*((short*)((char*)get()+sort_offset));
break;
case SORT_CHAR: //
cmpRet = *((char*)((char*)varPtr+sort_offset)) >
*((char*)((char*)get()+sort_offset));
break;
case SORT_CHAR_PTR: //
varData = *( (char**)((char*)varPtr + sort_offset) );
bodyChar = *( (char**)((char*)get() + sort_offset) );
err_when( !varData || !bodyChar );
cmpRet = strcmp( varData, bodyChar );
break;
case SORT_CHAR_STR: //
varData = (char*)varPtr + sort_offset ;
bodyChar = (char*)get() + sort_offset ;
err_when( !varData || !bodyChar );
cmpRet = strcmp( varData, bodyChar );
break;
}
//---- if equal then linkin -----------//
if( cmpRet >= 0 )
{
insert_at( last_ele+1, varPtr) ;
return;
}
}
insert_at( 1, varPtr); // insert at the top
}
//--------- END OF FUNCTION DynArray::linkin_sort_scan_from_bottom ---------//
/* this function has bugs and is commented out.
//------ BEGIN OF FUNCTION DynArray::linkin_sort ----------//
//
// Description : linkin a entry to a sorted link list
//
// Note : init_sort() must be called first, before using sorting function
// Warning : DynArrayB (version B) can't use this function
//
// Syntax : linkin_sort(,,)
//
// = the structure buffer pointer
//
// Note : use DynArray::seek() to search quickly if the whole DynArray is
// built up with linkin_sort()
//
// WARNING : After calling linkin() all pointers to the linklist body
// should be updated, because mem_resize() will move the body memory
//
void DynArray::linkin_sort(void* varPtr)
{
err_when( sort_offset < 0 );
register int jumpStep,cmpRet;
char* lastVar,*lastVar2;
char* varData,*bodyChar;
jumpStep=last_ele/2+1;
go(jumpStep);
lastVar = lastVar2 = NULL;
//------- for binary comparsion linkin_sort -------------//
for (;; )
{
//-------- comparsion ---------//
switch( sort_type )
{
case 'I':
cmpRet = *((int*)((char*)varPtr+sort_offset)) ==
*((int*)((char*)get()+sort_offset));
break;
case 'P': // char*
varData = *( (char**)((char*)varPtr + sort_offset) );
bodyChar = *( (char**)((char*)get() + sort_offset) );
err_when( !varData || !bodyChar );
cmpRet = strcmp( varData, bodyChar );
break;
case 'C':
varData = (char*)varPtr + sort_offset ;
bodyChar = (char*)get() + sort_offset ;
err_when( !varData || !bodyChar );
cmpRet = strcmp( varData, bodyChar );
break;
}
//---- if equal then linkin -----------//
if ( cmpRet ==0 )
{
linkin(varPtr) ;
break;
}
//----- reach the end of the binary tree ----//
if ( lastVar2 == bodyChar )
{
if ( cmpRet < 0 )
bkwd();
linkin(varPtr);
break;
}
//----- search through the binary tree -----//
if ( jumpStep%2 == 1 )
jumpStep=jumpStep/2+1;
else
jumpStep/=2;
if ( jumpStep < 1 )
jumpStep = 1;
if ( cmpRet < 0 )
jump( -jumpStep );
else
jump( jumpStep );
lastVar2 = lastVar;
lastVar = bodyChar;
}
}
//--------- END OF FUNCTION DynArray::linkin_sort ---------//
//---------- Begin of function DynArray::resort -------------//
//
// When the content of a sorted recno is updated,
// call this function for renewing the sorting order
//
// resortRecno = the pointer to the writing file
//
void DynArray::resort(int resortRecno)
{
linkin_sort(get(resortRecno)); // linkin the record for a second time, for sorting
go(resortRecno); // delete the original record
linkout(resortRecno);
}
//------------- End of function DynArray::resort --------------//
*/