Developers Heaven Forum
Desktop Programming => HLA => Topic started by: David on August 17, 2012, 02:48:57 AM
-
This space is designated to hold a library of HLA vector and HLA list functions ... similar to the Cvec/Cvec2 and Clist/Clist2 library of functions available here...
http://developers-heaven.net/forum/index.php?topic=2580.0
For some example programs that demo the use of these HLA vector and list containers with their push_back, (and list push_front, and vector reserve) ... and merge sort, insert sort, find, erase, and unique functions ... see this next link ...
http://developers-heaven.net/forum/index.php?topic=2599.0
The first set of vector and list functions, permit just one type of vector or list in a program. These pairs of include files are named:
The first pair is:
"vector_func's.hhf"
"vector.hhf"
If you include file "vector_func's.hhf" to get access to the sort, etc... functions, that file FIRSTLY includes file "vector.hhf", which firstly includes file "stdlib.hhf"
The next pair is:
"sllist_func's.hhf"
"sllist.hhf"
If you include file "sllist_func's.hhf" to get access to the sort, etc... functions, that file FIRSTLY includes file "sllist.hhf", which firstly includes file "stdlib.hhf"
Note: see the vector2/sllist2 .hhf files at the bottom also ... linked here ...
http://developers-heaven.net/forum/index.php?topic=2600.msg2978#msg2978
-
The vector pair:
"vector.hhf"
// vector.hhf // 2012-08-21 //
#includeOnce( "stdlib.hhf" )
// NB!!! the record Rec must be defined before including this file
// ALSO the type pRec: pointer to Rec;
// ALSO ... the procedure freeRec( pr: pRec );
/* // for example ... //
procedure freeRec( pr: pRec in eax ); @nodisplay;
begin freeRec;
free( (type Rec [eax]).str );
end freeRec;
*/
? @nodisplay:= true; // All procedures have @nodisplay 'as default' now.
#if( !@defined( InitCap ) )
const
InitCap: uns32 := 8;
#endif
type
Vec: record
ary: pRec;
capacity: uns32;
size: uns32;
endrecord;
procedure initVec( var v: Vec );
begin initVec;
push( ebx );
mov( v, ebx );
mov( 0, (type Vec [ebx]).ary );
mov( 0, (type Vec [ebx]).capacity );
mov( 0, (type Vec [ebx]).size );
pop( ebx );
end initVec;
// double capacity ...
procedure enlargeVec( var v: Vec );
begin enlargeVec;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
if( (type Vec [ebx]).capacity != 0 ) then // i.e. if capacity not zero
shl( 1, (type Vec [ebx]).capacity ); // double capacity
else; // set initial capacity
mov( mov( InitCap, eax ), (type Vec [ebx]).capacity );
endif;
//mov( (type Vec [ebx]).elen, ecx );
intmul( @size(Rec), (type Vec [ebx]).capacity, ecx );
if( (type dword (type Vec [ebx]).ary) ) then mem.realloc( (type Vec [ebx]).ary, ecx );
else mem.alloc( ecx );
endif;
mov( eax, (type Vec [ebx]).ary );
pop( ecx ); pop( ebx ); pop( eax );
end enlargeVec;
// if size == capacity then enlarge ...
procedure push_backVec( var v: Vec; var r: Rec );
begin push_backVec;
//push( ebx ); push( ecx ); push( esi ); push( edi ); // caller must preserve if needed
// if size == capacity then enlarge/double capacity ...
mov( v, ebx );
mov( (type Vec [ebx]).size, ecx );
if( ecx == (type Vec [ebx]).capacity ) then
enlargeVec( (type Vec [ebx]) );
endif;
// ok ... now append (copy) of new rec ...
mov( r, esi ); // get address of new Rec into esi ...
//mov( (type Vec [ebx]).size, edi );
intmul( @size(Rec), (type Vec [ebx]).size, edi );
add( (type Vec [ebx]).ary, edi ); // get offset into edi
// get num bytes to copy in ecx ...
mov( @size(Rec), ecx );
rep.movsb();
inc( (type Vec [ebx]).size ); // update size
//pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end push_backVec;
procedure reserveVec( var v: Vec; newCap: uns32 );
begin reserveVec;
push( eax ); push( ebx );
mov( newCap, eax );
mov( v, ebx );
if( eax > (type Vec [ebx]).capacity ) then
mov( eax, (type Vec [ebx]).capacity );
intmul( @size(Rec), eax ); // num new bytes in eax
if( (type dword (type Vec [ebx]).ary) ) then
mem.realloc( (type Vec [ebx]).ary, eax );
else
mem.alloc( eax );
endif;
mov( eax, (type Vec [ebx]).ary ); // update new ary pointer
endif;
pop( ebx ); pop( eax );
end reserveVec;
procedure clearVec( var v: Vec );
begin clearVec;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
mov( (type Vec[ebx]).size, ecx );
for( dec( ecx ); (type int32 ecx) >= 0; dec( ecx ) ) do
intmul( @size(Rec), ecx, eax );
add( (type Vec [ebx]).ary, eax );
freeRec( eax ); // recall this procedure 'freeRec' must be defined
// along with type Rec, BEFORE including this file
endfor;
mem.free( (type Vec [ebx]).ary );
initVec( (type Vec [ebx]) );
pop( ecx ); pop( ebx ); pop( eax );
end clearVec;
-
"vector_func's.hhf"
// vector_func's.hhf // 2012-08-21 //
#includeOnce ( "vector.hhf" )
type
pVec: pointer to Vec;
#if( !@defined( pMyCmp ) )
static
pMyCmp: procedure( a: dword in esi; b: dword in edi ); @returns( "eax" );
#endif
// re. isort ... note: cmp func is a < b
// re. msort ... note: cmp func is a <= b
procedure isortVec( var v: Vec );
static
rcmp: Rec;
tmpReg: dword;
begin isortVec;
push( eax ); push( ebx ); push( ecx ); push( edx ); push( esi ); push( edi );
//int i, j; // i in eax, j in edx
// start with an array of just the first 2 elements (if exists) ...
// for( i = 1; i < cv->size; ++i )
cld();
mov( v, ebx );
for( mov( 1, eax ); eax < (type Vec [ebx]).size; inc( eax ) ) do
// update this cmp Rec on each outer loop
//memcpy( &cmp, &cv->ary[i], sizeof(Rec) );
mov( &rcmp, edi );
intmul( @size(Rec), eax, esi );
add( (type Vec [ebx]).ary, esi );
mov( @size(Rec), ecx ); // get # bytes to copy in a Rec ... into ecx
rep.movsb(); // ok ... got copy into rcmp ...
// get index of element just to the left of the above 'cmp' to start comparisons
mov( eax, edx ); // j = i
dec( edx ); // --j // i.e. j = i-1; //
while( (type int32 edx) >= 0 ) do // while( j >= 0 && myCmp(&cmp, &cv->ary[j]) < 0 )
intmul( @size(Rec), edx, edi ); // get offset into edi ..
add( (type Vec [ebx]).ary, edi );
mov( &rcmp, esi );
//breakif( !pMyCmp(esi, edi) ); // 'copy up' // but first ...
mov( eax, tmpReg ); // get copy of loop counter in eax
pMyCmp( esi, edi );
if( eax ) then
mov( tmpReg, eax );
else
mov( tmpReg, eax );
break;
endif;
// Now ... 'copy up' ...
//memcpy( &cv->ary[j+1], &cv->ary[j], sizeof(Rec) );
intmul( @size(Rec), edx, esi );
add( (type Vec [ebx]).ary, esi );
mov( esi, edi );
add( @size(Rec), edi ); // to inc( j ) add size //
mov( @size(Rec), ecx ); // get # bytes to copy in a Rec into ecx
rep.movsb();
dec( edx ); //--j; // --j to prepare for next inner loop
endwhile;
// insert pointer at index j+1 (since j was decremented above ...
//memcpy( &cv->ary[j+1], &cmp, sizeof(Rec) );
inc( edx ); // ++j
mov( &rcmp, esi );
intmul( @size(Rec), edx, edi );
add( (type Vec [ebx]).ary, edi );
mov( @size(Rec), ecx ); // get # bytes to copy in a Rec into ecx
rep.movsb();
endfor;
pop( edi ); pop( esi ); pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end isortVec; // size hasn't changed ...
////////////////////////////////////////////////////////////////////////////
// re. msort ... note: cmp func is a <= b
procedure mergeVec( pv: pVec in ebx; bot: int32; top: int32; ptmp: pVec in edx );
var
mid: int32; // set to (bot+top)/2
sz: int32; // set to top-bot+1 // size of the range to be merged
j: int32;
tmpReg: dword;
begin mergeVec;
//push( eax ); push( ecx ); push( esi ); push( edi );
//int mid = (bot+top)/2;
mov( top, eax );
add( bot, eax );
shr( 1, eax ); // divide by 2
mov( eax, mid );
//int sz = top - bot + 1; // size of the range to be merged
mov( top, eax );
sub( bot, eax );
inc( eax );
mov( eax, sz );
mov( 0, j ); // int j = 0; // next open index in tmp
mov( bot, eax ); // int h1 = bot; // next index to consider in 1st half
mov( mid, ecx ); // int h2 = mid + 1; // next index to consider in 2nd half
inc( ecx );
// while indexes h1 and h2 are not past their ends ...
cld();
while( eax <= mid && ecx <= top ) do // while( h1 <= mid && h2 <= top )
// move the smaller element into the tmp vec 'next' ...
// if( myCmp( &(cv->ary[h1]), &(cv->ary[h2]) ) <= 0 )
intmul( @size(Rec), eax, esi );
add( (type Vec [ebx]).ary, esi );
intmul( @size(Rec), ecx, edi );
add( (type Vec [ebx]).ary, edi );
mov( eax, tmpReg );
pMyCmp( esi, edi ); // if( myCmp(...) <= 0 )
if( eax ) then // if( myCmp(...) <= 0 )
//tmp->ary[j++] = cv->ary[h1++];
mov( tmpReg, eax ); // restore eax
intmul( @size(Rec), eax, esi );
add( (type Vec [ebx]).ary, esi );
intmul( @size(Rec), j, edi );
add( (type Vec [edx]).ary, edi );
mov( ecx, tmpReg );
mov( @size(Rec), ecx );
rep.movsb(); // tmp->ary[j++] = cv->ary[h1++];
mov( tmpReg, ecx );
inc( eax ); // ++h1
inc( j );
else
//tmp->ary[j++] = cv->ary[h2++];
mov( tmpReg, eax ); // restore eax
intmul( @size(Rec), ecx, esi ); // ecx holds h2
add( (type Vec [ebx]).ary, esi );
intmul( @size(Rec), j, edi );
add( (type Vec [edx]).ary, edi );
mov( ecx, tmpReg );
mov( @size(Rec), ecx );
rep.movsb(); // tmp->ary[j++] = cv->ary[h2++];
mov( tmpReg, ecx );
inc( ecx ); // ++h2
inc( j );
endif;
endwhile;
// Note: only one (at most) of the two 'while's' below is executed ...
//while( h1 <= mid ) // copy any remaining entries (1st half)
//tmp->ary[j++] = cv->ary[h1++];
while( eax <= mid ) do
intmul( @size(Rec), eax, esi );
add( (type Vec [ebx]).ary, esi );
intmul( @size(Rec), j, edi );
add( (type Vec [edx]).ary, edi );
mov( ecx, tmpReg );
mov( @size(Rec), ecx );
rep.movsb(); // tmp->ary[j++] = cv->ary[h1++];
mov( tmpReg, ecx );
inc( eax ); // ++h1
inc( j );
endwhile;
//while( h2 <= top ) // copy any remaining entries (2nd half)
//tmp->ary[j++] = cv->ary[h2++];
while( ecx <= top ) do
intmul( @size(Rec), ecx, esi );
add( (type Vec [ebx]).ary, esi );
intmul( @size(Rec), j, edi );
add( (type Vec [edx]).ary, edi );
mov( ecx, tmpReg );
mov( @size(Rec), ecx );
rep.movsb(); // tmp->ary[j++] = cv->ary[h2++];
mov( tmpReg, ecx );
inc( ecx ); // ++h2
inc( j );
endwhile;
//for( j = 0; j < sz; ++j ) // copy back sorted tmp vec...
//cv->ary[bot+j] = tmp->ary[j];
mov( (type Vec [edx]).ary, esi );
//mov( bot, edi );
intmul( @size(Rec), bot, edi );
add( (type Vec [ebx]).ary, edi );
//mov( sz, ecx );
intmul( @size(Rec), sz, ecx );
rep.movsb();
/*
for( mov( 0, ecx ); ecx < sz; inc( ecx ) ) do
intmul( @size(Rec), ecx, esi );
add( (type Vec [edx]).ary, esi );
mov( bot, eax );
add( ecx, eax );
intmul( @size(Rec), eax, edi );
add( (type Vec [ebx]).ary, edi );
mov( ecx, tmpReg );
mov( @size(Rec), ecx );
rep.movsb(); // cv->ary[bot+j] = tmp->ary[j];
mov( tmpReg, ecx );
endfor;
*/
//pop( edi ); pop( esi ); pop( ecx ); pop( eax );
end mergeVec;
procedure my_msortVec( pv: pVec in ebx; bot: int32; top: int32; ptmp: pVec in edx );
var
mid: int32;
begin my_msortVec;
mov( top, eax );
if( bot < eax ) then
add( bot, eax ); // NOW EAX HOLDS top + bot
shr( 1, eax ); // divide by 2 ...
mov( eax, mid ); // mid = ( bot + top ) / 2;
my_msortVec( ebx, bot, mid, edx ); // sort the first half ...
inc( mid ); // now mid = mid +1
my_msortVec( ebx, mid, top, edx ); // and the second half
mergeVec( ebx, bot, top, edx ); // now merge 2 sorted chunks
endif;
end my_msortVec;
procedure msortVec( var v: Vec );
var
Rega: dword;
Regb: dword;
Regc: dword;
Regd: dword;
Regesi: dword;
Regedi: dword;
tmp: Vec;
begin msortVec;
mov( eax, Rega ); mov( ebx, Regb ); mov( ecx, Regc ); mov( edx, Regd );
mov( esi, Regesi ); mov( edi, Regedi );
mov( v, ebx );
mov( (type Vec [ebx]).size, eax );
if( eax > 1 ) then
initVec( tmp );
reserveVec( tmp, eax ); // Note: resets cap... BUT tmp size still 0
dec( eax );
lea( edx, tmp ); // get address of new tmp Vec into edx ...
my_msortVec( ebx, 0, eax, edx );
// NOW done ... BUT only free ary mem that held copies of pointers
mem.free( tmp.ary );
endif;
mov( Regedi, edi ); mov( Regesi, esi );
mov( Regd, edx ); mov( Regc, ecx ); mov( Regb, ebx ); mov( Rega, eax );
end msortVec;
// returns index if string present, else -1 ...
procedure findVec( var v: Vec; var r: Rec ); @returns( "eax" );
begin findVec;
push( ebx ); push( ecx ); push( esi ); push( edi );
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec [ebx]).size; inc( ecx ) ) do
//if( myCmp(&cv->ary[i], r) == 0 )
intmul( @size(Rec), ecx, esi );
add( (type Vec [ebx]).ary, esi );
mov( r, edi );
pMyCmp( esi, edi ); // need an 'eq' cmp here ...
breakif( eax ); // i.e. break if equal ...
endfor;
// now check loop end condition ...
if( ecx != (type Vec [ebx]).size ) then
mov( ecx, eax ); // found
else
mov( -1, eax ); // NOT found
endif;
pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end findVec;
// if int index valid, erases element there ...
procedure eraseVec( var v: Vec; index: uns32 in eax );
var
tmpReg: dword;
begin eraseVec;
push( ebx ); push( ecx ); push( esi ); push( edi );
mov( v, ebx );
if( (type int32 eax) >= 0 && (type int32 eax) < (type Vec [ebx]).size ) then
mov( eax, tmpReg );
intmul( @size(Rec), eax );
add( (type Vec [ebx]).ary, eax );
//freeVrec( &(cv->ary[index]) );
freeRec( eax ); // must pass in eax, needed here if dynamic memory
mov( tmpReg, eax );
//if( index < cv->size-1 )
//memcpy(&cv->ary[index], &cv->ary[index+1], (cv->size-1-index)*sizeof(Rec));
mov( (type Vec [ebx]).size, ecx );
dec( ecx ); // ecx holds size-1
if( eax < ecx ) then
sub( eax, ecx ); // ecx now holds (cv->size-1-index)
intmul( @size(Rec), ecx ); // ecx now holds bytes to copy ...
intmul( @size(Rec), eax, edi );
add( (type Vec [ebx]).ary, edi );
mov( edi, esi );
add( @size(Rec), esi );
rep.movsb();
endif;
// now update size and return by reference (since address passed in)
dec( (type Vec [ebx]).size );
else
mov( (type Vec [ebx]).size, ecx );
dec( ecx ); // ecx holds size-1
stdout.put( nl, "ERROR! Index ", index, " out of range 0..", (type int32 ecx), nl);
endif;
pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end eraseVec;
#if ( false )
// isort ///////////////////////////////////////////////////////////////////
void isortCvec( Cvec* cv, int (*myCmp) (const Rec* a, const Rec* b) )
{
int i, j;
Rec cmp;
for( i = 1; i < cv->size; ++i ) /* start with an array of just the first 2 elements (if exists) */
{
memcpy( &cmp, &cv->ary[i], sizeof(Rec) ); /* get new cmp on each outer loop */
j = i-1; /* get index of element just to the left of 'cmp' to start comparisons */
while( j >= 0 && myCmp(&cmp, &cv->ary[j]) < 0 )
{
memcpy( &cv->ary[j+1], &cv->ary[j], sizeof(Rec) ); /* 'copy up' */
--j; /* decrement j in preparation for next inner loop ... */
}
memcpy( &cv->ary[j+1], &cmp, sizeof(Rec) ); /* insert cmp at index j+1
(since j was decremented above) */
}
cv->isSorted = 1;
} /* size hasn't changed ... */
// msort ///////////////////////////////////////////////////////////////////
void mergeCvec( Cvec* cv, int bot, int top, Cvec* tmp,
int (*myCmp) (const Rec* a, const Rec* b) )
{
int mid = (bot+top)/2;
int sz = top - bot + 1; // size of the range to be merged
int j = 0; // next open index in tmp
int h1 = bot; // next index to consider in the 1st half
int h2 = mid + 1; // next index to consider in the 2nd half
// while indexes h1 and h2 are not past their ends ...
while( h1 <= mid && h2 <= top )
{ // move the smaller element into the tmp vec next ...
if( myCmp( &(cv->ary[h1]), &(cv->ary[h2]) ) <= 0 )
tmp->ary[j++] = cv->ary[h1++];
else
tmp->ary[j++] = cv->ary[h2++];
}
// Note: only one of the two 'while's' below is executed ...
while( h1 <= mid ) // copy any remaining entries (1st half)
tmp->ary[j++] = cv->ary[h1++];
while( h2 <= top ) // copy any remaining entries (2nd half)
tmp->ary[j++] = cv->ary[h2++];
for( j = 0; j < sz; ++j ) // copy back sorted tmp vec...
cv->ary[bot+j] = tmp->ary[j];
}
void my_msortCvec( Cvec* cv, int bot, int top, Cvec* tmp,
int (*myCmp) (const Rec* a, const Rec* b) )
{
if( bot == top ) return;
else
{
int mid = ( bot + top ) / 2;
my_msortCvec( cv, bot, mid, tmp, myCmp ); // sort the first ...
my_msortCvec( cv, mid+1, top, tmp, myCmp ); // and the second half
mergeCvec( cv, bot, top, tmp, myCmp ); // now merge 2 sorted chunks
}
}
/* *NOTE* Calling msortCvec sets the returned by ref Cvec to *** isSorted *** */
void msortCvec( Cvec* cv, int (*myCmp) (const Rec* a, const Rec* b) )
{
if( cv->size > 1 )
{
Cvec tmp;
initCvec( &tmp );
reserveCvec( &tmp, cv->size ); /* Note: resets cap, BUT size still 0 */
my_msortCvec( cv, 0, cv->size-1, &tmp, myCmp );
cv->isSorted = 1;
free( tmp.ary ); /* only free ary mem that held copies of pointers */
}
}
// find ////////////////////////////////////////////////////////////////////
/* returns index if string present, else -1 */
int findCvec( Cvec* cv, const Rec* r, int (*myCmp) (const Rec* a, const Rec* b) )
{
int i;
for( i = 0; i < cv->size; ++i )
if( myCmp(&cv->ary[i], r) == 0 ) return i;
/* else if reach here ... */
return -1;
}
// erase ///////////////////////////////////////////////////////////////////
/* if int index valid, erases element there */
void eraseCvec( Cvec* cv, int index )
{
//int i;
if( index < 0 || index >= cv->size )
{ printf( "\nERROR! Index %d out of range 0..%d\n", index, cv->size-1 );
return; }
freeVrec( &(cv->ary[index]) ); /* needed here for dynamic memory types */
/* copy each (set of pointers above) down one index */
//for( i = index; i < cv->size-1; ++i )
//memcpy(&cv->ary[i], &cv->ary[i+1], sizeof(Rec));
if( index < cv->size-1 )
memcpy(&cv->ary[index], &cv->ary[index+1], (cv->size-1-index)*sizeof(Rec));
/* now update size and return (by reference, since address passed in) */
-- cv->size;
}
#endif
-
The list pair:
"sllist.hhf"
// sllist.hhf // 2012-08-16 //
// using NNode to avoid conflict with Node
// using SLList to avoid conflict with List
#includeOnce( "stdlib.hhf" )
// NB!!! the record NNode must be defined before including this file
// ALSO the type pNNode: pointer to NNode;
? @nodisplay:= true; // all procedures have @nodisplay 'as default' now
type
SLList: record
head: pNNode;
tail: pNNode;
size: uns32;
endrecord;
procedure initSLList( var lst: SLList );
begin initSLList;
push( ebx );
mov( lst, ebx );
mov( 0, (type SLList [ebx]).head );
mov( 0, (type SLList [ebx]).tail );
mov( 0, (type SLList [ebx]).size );
pop( ebx );
end initSLList;
procedure push_frontSLList( var lst: SLList; var n: NNode );
begin push_frontSLList;
//push( ebx ); push( ecx ); push( esi ); push( edi ); // caller must preserve as needed
cld();
mem.alloc( @size(NNode) );
mov( eax, edi );
mov( n, esi ); // get address of new NNode into esi ...
// get num bytes to copy in ecx ...
mov( @size(NNode), ecx );
rep.movsb();
// ok ... now prepend (copy) of new NNode ...
mov( lst, ebx );
if( (type SLList [ebx]).size != 0 ) then // not empty
mov( mov( (type SLList [ebx]).head, ecx ), (type NNode [eax]).next );
mov( eax, (type SLList [ebx]).head );
else
mov( 0, (type NNode [eax]).next );
mov( eax, (type SLList [ebx]).tail );
mov( eax, (type SLList [ebx]).head );
endif;
inc( (type SLList [ebx]).size ); // update size
//pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end push_frontSLList;
procedure push_backSLList( var lst: SLList; var n: NNode );
begin push_backSLList;
// push( ebx ); push( ecx ); push( esi ); push( edi ); // caller must preserve as needed
cld();
mem.alloc( @size(NNode) );
mov( eax, edi );
mov( n, esi ); // get address of new NNode into esi ...
// get num bytes to copy in ecx ...
mov( @size(NNode), ecx );
rep.movsb();
mov( 0, (type NNode [eax]).next );
// ok ... now append (copy) of new rec ...
mov( lst, ebx );
if( (type SLList [ebx]).size != 0 ) then // not empty
mov( (type SLList [ebx]).tail, ecx );
mov( eax, (type NNode [ecx]).next ); // now 'next' updated
mov( eax, (type SLList [ebx]).tail );
else
mov( eax, (type SLList [ebx]).tail );
mov( eax, (type SLList [ebx]).head );
endif;
inc( (type SLList [ebx]).size ); // update size
// pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end push_backSLList;
procedure clearSLList( var v: SLList );
begin clearSLList;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
mov( (type SLList[ebx]).head, ecx );
while( ecx != 0 ) do
mov( ecx, eax );
mov( (type NNode [ecx]).next, ecx );
freeNNode( eax ); // recall this procedure 'freeNNode' must be defined
// along with type NNode, BEFORE including this file
mem.free( eax );
endwhile;
initSLList( (type SLList [ebx]) );
pop( ecx ); pop( ebx ); pop( eax );
end clearSLList;
-
"sllist_func's.hhf"
// sllist_func's.hhf // // 2012-08-16 //
#includeOnce( "sllist.hhf" )
type
pSLList: pointer to SLList;
#if( !@defined( pMyCmp ) )
static
pMyCmp: procedure( a: dword in esi; b: dword in edi ); @returns( "eax" );
#endif
// re. isort ... note: cmp func is a <= b (for list, ALSO same as for msort)
// re. msort ... note: cmp func is a <= b
// pass in the address of the SLList and the new Node to insert ...
procedure insert_sortedSLList( var lst: SLList; pn: pNNode in eax );
//var
//head: pNNode; // esi
var
reg32: dword;
begin insert_sortedSLList;
push( ebx ); push( esi ); push( edi );
//pList head;
//if( !isSortedSLList( list, myCmp )) msortSLList( list, myCmp );
//head = list->start;
mov( lst, ebx );
mov( (type SLList [ebx]).head, esi );
mov( eax , edi );
// firstly, we handle most common case where 'n' is NOT the first Node
//if( head != NULL && myCmp( n, head ) >= 0 ) // NEED >=
if( esi && pMyCmp( esi, edi ) ) then
// so search the linked list for the right location
//pList cur = head;
//while( cur->next != NULL && myCmp( cur->next, n ) <= 0 )
mov( esi, reg32 );
mov( (type NNode [esi]).next, esi );
//while( esi && pmyCmp( esi, edi ) ) do
forever
if( !esi || !pMyCmp( esi, edi ) ) then
//cur = cur->next;
mov( reg32, esi );
break;
else
mov( esi, reg32 );
mov( (type NNode [esi]).next, esi );
endif;
endfor;
//if( cur == list->end ) list->end = n;
if( esi == (type SLList [ebx]).tail ) then
mov( edi, (type SLList [ebx]).tail );
endif;
//n->next = cur->next;
mov( (type NNode [esi]).next, (type NNode [edi]).next );
//cur->next = n;
mov( edi, (type NNode [esi]).next );
// list->start = head; // unchanged //
//++ list->size;
inc( (type SLList [ebx]).size );
else // if we reach here, this IS the first node ...
//n->next = head; // so set this node in first position
mov( (type SLList [ebx]).head, (type NNode [edi]).next );
//list->start = n;
mov( edi, (type SLList [ebx]).head );
//++ list->size;
inc( (type SLList [ebx]).size );
if( (type SLList [ebx]).size == 1 ) then
// list->end = n;
mov( edi, (type SLList [ebx]).tail );
endif;
endif;
pop( edi ); pop( esi ); pop( ebx );
end insert_sortedSLList;
//void isortSLList( SLList* list, int (*myCmp) (const pList r1, const pList r2) )
procedure isortSLList( var lst: SLList );
var
nSLList: SLList;
//cur: pNNode; // eax
//nextNode: pNNode; // ecx
begin isortSLList;
push( eax ); push( ebx ); push( ecx );
initSLList( nSLList );
mov( lst, ebx );
//for( cur = list->start; cur != NULL; cur = nextNode )
for( mov( (type SLList [ebx]).head, eax ); eax; mov( ecx, eax ) ) do
//nextNode = cur->next; // get copy here before next is changed below
mov( (type NNode [eax]).next, ecx );
//insert_sortedSLList( &nSLList, cur, myCmp ); // 'cur' already is a Node pointer
insert_sortedSLList( nSLList, eax );
endfor;
// now ... update old list with new front and back ...
//list->start = nSLList.start;
mov( nSLList.head, (type SLList [ebx]).head );
//list->end = nSLList.end;
mov( nSLList.tail, (type SLList [ebx]).tail );
// size hasn't changed
pop( ecx ); pop( ebx ); pop( eax );
end isortSLList;
// merge two sorted SLLists with heads 'a' and 'b' ... in sorted order
procedure mergeSLLists(var a: SLList; var b: SLList ); @returns( "eax" ); // new head
var
newMergedHead: dword;
//sorted: dword; // use ebx // using edx now ..
begin mergeSLLists;
//push( ebx ); push( esi ); push( edi ); // using edx instead of ebx here now
//pList sorted, new_merged_head;
mov( a, eax );
mov( (type SLList [eax]).head, esi );
mov( b, eax );
mov( (type SLList [eax]).head, edi );
//if( a->start == NULL ) return b->start;
//if( b->start == NULL ) return a->start;
if( !esi ) then mov( edi, newMergedHead );
elseif( !edi ) then mov( esi, newMergedHead );
else
//if( myCmp(a->start, b->start) <= 0 )
if( pMyCmp( esi, edi ) ) then
//sorted = a->start;
//a->start = a->start->next;
mov( esi, edx );
mov( (type NNode [esi]).next, esi );
else
//sorted = b->start;
//b->start = b->start->next;
mov( edi, edx );
mov( (type NNode [edi]).next, edi );
endif;
//new_merged_head = sorted;
mov( edx, newMergedHead );
// now ...
//while( a->start != NULL && b->start != NULL )
while( esi && edi ) do
//if( myCmp(a->start, b->start) <= 0 )
if( pMyCmp( esi, edi ) ) then
//sorted->next = a->start;
mov( esi, (type NNode [edx]).next );
//sorted = a->start;
mov( esi, edx );
//a->start = a->start->next;
mov( (type NNode [esi]).next, esi );
else
//sorted->next = b->start;
mov( edi, (type NNode [edx]).next );
//sorted = b->start;
mov( edi, edx );
//b->start = b->start->next;
mov( (type NNode [edi]).next, edi );
endif;
endwhile;
// and finally ...
//if( a->start != NULL )
if( esi ) then
//sorted->next = a->start;
mov( esi, (type NNode [edx]).next );
//else if( b->start != NULL )
elseif( edi ) then
//sorted->next = b->start;
mov( edi, (type NNode [edx]).next );
endif;
endif;
mov( newMergedHead, eax );
//pop( edi ); pop( esi ); pop( ebx );
end mergeSLLists;
// a recursive mergesort ...
procedure mergesortSLList( var lst: SLList );
var
// cur: pNNode; // ecx
a: SLList;
b: SLList;
begin mergesortSLList;
push( ebx );
//push( ecx ); push( edx );
//pList cur = list->start;
mov( lst, ebx );
mov( (type SLList [ebx]).head, ecx );
mov( ecx, a.head );
//SLList a, b;
// base case is a SLList of length 0 or 1 ...
//if ((cur == NULL) || (cur->next == NULL)) return;
if( a.head != 0 /*&& b.head != 0*/ ) then
mov( (type NNode [ecx]).next, b.head );
if( b.head != 0 ) then
// split SLList into 'a' and 'b' sublists ...
//a.start = cur;
//b.start = cur->next; // both these lines done above
while( b.head != 0 /*&& ( b.start->next != NULL)*/ ) do
mov( b.head, edx );
mov( (type NNode [edx]).next, edx );
breakif( !edx );
//cur = cur->next;
mov( (type NNode [ecx]).next, ecx );
//b.start = b.start->next->next;
mov( (type NNode [edx]).next, b.head );
endwhile;
//b.start = cur->next;
mov( (type NNode [ecx]).next, b.head );
//cur->next = NULL; // SLList divided into 2 roughly equal parts now
mov( 0, (type NNode [ecx]).next );
// recursively sort the sublists ...
mergesortSLList( a );
mergesortSLList( b );
// merge the two sorted SLLists together ...
//list->start = mergeSLLists(&a, &b, myCmp);
mergeSLLists( a, b ); // returns new merged head in eax
mov( eax, (type SLList [ebx]).head );
endif;;
endif;
//pop( edx ); pop( ecx );
pop( ebx );
end mergesortSLList;
procedure update_endSLList( var lst: SLList ); // after sort
begin update_endSLList;
//push( ebx ); push( ecx );
mov( lst, ebx );
if( (type SLList [ebx]).size > 1 ) then
//pList cur;
//for( cur = list->start; cur->next != NULL; cur = cur->next ) ;
//list->end = cur;
//list->end->next = NULL; // this line NOT-needed/redundant
mov( (type SLList [ebx]).head, ecx );
while( (type NNode [ecx]).next != 0 ) do mov( (type NNode [ecx]).next, ecx ); endwhile;
mov( ecx, (type SLList [ebx]).tail );
endif;
//pop( ecx ); pop( ebx );
end update_endSLList;
procedure msortSLList( var lst: SLList );
var
Rega: dword;
Regb: dword;
Regc: dword;
Regd: dword;
Regesi: dword;
Regedi: dword;
begin msortSLList;
mov( eax, Rega ); mov( ebx, Regb ); mov( ecx, Regc ); mov( edx, Regd );
mov( esi, Regesi ); mov( edi, Regedi );
mov( lst, ebx );
mergesortSLList( (type SLList [ebx]) );
//mov( lst, ebx );
update_endSLList( (type SLList [ebx]) );
mov( Regedi, edi ); mov( Regesi, esi );
mov( Regd, edx ); mov( Regc, ecx ); mov( Regb, ebx ); mov( Rega, eax );
end msortSLList;
// returns pointer if present, else returns 0
procedure findSLList( var lst: SLList; var nn: NNode ); @returns( "eax" );
begin findSLList;
push( ebx ); push( esi ); push( edi );
//pList p;
mov( lst, ebx );
mov( nn, edi );
//for( p = cl->start; p != NULL; p = p->next )
for( mov( (type SLList [ebx]).head, esi ); esi; mov( (type NNode [esi]).next, esi ) ) do
//if( myCmp(p, pr) == 0 ) return p;
pMyCmp( esi, edi ); // returns eax = 1 if found, else 0
if( eax ) then
mov( esi, eax );
break;
endif;
endfor;
// if not found above, eax is already 0
pop( edi ); push( esi ); push( ebx );
end findSLList;
procedure eraseSLList( var lst: SLList; pn: pNNode in eax ); // if pn valid, erase element there
//var
//prev: pNNode; // use edx
begin eraseSLList;
push( ebx ); push( ecx ); push( edx );
//pList prev = NULL, cur = cl->start;
mov( 0, edx );
mov( lst, ebx );
for( mov( (type SLList [ebx]).head, ecx ); ecx && ecx != eax; mov( (type NNode [ecx]).next, ecx ) ) do
//prev = cur;
mov( ecx, edx );
endfor;
if( ecx ) then
if( edx ) then // case of NOT FIRST element
//prev->next = cur->next;
mov( (type NNode [ecx]).next, (type NNode [edx]).next );
else // case of IS FIRST element
//cl->start = cl->start->next;
mov( (type NNode [ecx]).next, (type SLList [ebx]).head );
endif;
//if( cur == cl->end ) cl->end = prev; /* case of IS LAST element*/
if( ecx == (type SLList [ebx]).tail ) then
mov( edx, (type SLList [ebx]).tail );
endif;
freeNNode( ecx ); // needed here for types like dynamic C strings, etc
mem.free( ecx ); // free memory for dynamic Node ...
// now update size and return (by reference, since address passed in)
//-- cl->size;
dec( (type SLList [ebx]).size );
else
stdout.puts( nl "eraseSLList ERROR! Pointer NOT found ..." );
endif;
pop( edx ); pop( ecx ); pop( ebx );
end eraseSLList;
#if( !@defined( chrIsInStr ) )
// returns *POSITION* 1..n (POS = INDEX+1) or 0 if NOT found //
procedure chrIsInStr( c: char in al; s: string ); @returns( "eax" );
begin chrIsInStr;
str.chpos( s, al );
inc( eax );
end chrIsInStr;
#endif
procedure splitSLList( var sll: SLList; s: string; delims: string );
var
myNNode: NNode;
reg32: dword;
i: uns32;
begin splitSLList;
push( eax ); push( ebx ); push( ecx ); push( edx );
mov( sll, ebx );
mov( s, ecx ); // ecx holds start address ...
forever
while( chrIsInStr( (type char [ecx]), delims ) ) do
inc( ecx );
endwhile;
breakif( (type char [ecx]) == 0 ); // since 'empty' string
mov( ecx, edx );
inc( edx ); // edx holds address one past end of 'word' ...
mov( (type char [edx]), al );
while( al && !chrIsInStr( al, delims ) ) do
inc( edx );
mov( (type char [edx]), al );
endwhile;
mov( edx, reg32 ); // save a copy of 'end' in reg32 ...
sub( ecx, edx ); // edx holds 'len of next word'
mov( ecx, i );
mov( s, eax );
sub( eax, i ); // i is index to start
str.a_substr( s, i, edx ); // start, len
mov( eax, myNNode.nval );
push_backSLList( (type SLList [ebx]), myNNode );
mov( reg32, ecx ); // update (next) start pointer ecx ...
endfor;
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end splitSLList;
procedure uniqueSLList( var lst: SLList );
begin uniqueSLList;
push( eax ); push( ebx ); push( esi ); push( edi );
//pList p = c->start;
mov( lst, ebx );
mov( (type SLList [ebx]).head, esi ); // esi holds cur NNode address
if( esi ) then
//while( p->next != NULL )
while( (type NNode [esi]).next != 0 ) do
//if( myCmp(p, p->next) == 0 )
mov( (type NNode [esi]).next, edi );
if( pMyCmp( esi, edi ) ) then // if equal then ...
//pList tmp = p->next;
mov( edi, eax ); // eax is tmp copy ...
//p->next = p->next->next;
mov( (type NNode [edi]).next, edi ); // now advance edi ...
mov( edi, (type NNode [esi]).next );
freeNNode( eax ); // needed here for types like dynamic Cstrings, etc
mem.free( eax );
//-- c->size;
dec( (type SLList [ebx]).size );
else
//p = p->next;
mov( edi, esi ); // mov esi up since not equal ...
endif;
endwhile;
update_endSLList( (type SLList [ebx]) ) ; // update end ...
endif;
pop( edi ); pop( esi ); pop( ebx ); pop( eax );
end uniqueSLList;
-
Now the FILE read functions, that permit reading in an HLA string of any length, restricted only by the amount of remaining available memory ...
These include files are named:
"readLine.hhf"
Called like this: (similar to getline in C++)
while( readLine( fin, lineStr ) ) do
// process lineStr
endwhile;
and
"readWord.hhf"
Called like this:
while( readWord( fin, wordStr, delimitersStr ) ) do
// process wordStr
endwhile;
// readLine.hhf // 2012-08-11 //
#includeOnce( "stdlib.hhf" )
#if( !@defined( InitStrCap ) )
const
InitStrCap: uns32 := 1024;
#endif
// expects an unitialized string to be passed in ...
procedure readLine( fin:dword; var line:string ); @nodisplay; @returns("eax");
var
cap: dword;
sTmp: string;
begin readLine;
push( ebx ); push( ecx );
mov( InitStrCap, eax );
mov( eax, cap );
str.alloc( eax );
mov( eax, ebx );
mov( 0, ecx ); // and ... ecx tracks size
if( !fileio.eof( fin ) ) then
while( !fileio.eof( fin ) ) do
fileio.getc( fin );
if( al == stdio.cr ) then // Windows #13 #10
fileio.getc( fin );
break; // eat #10
elseif( al == stdio.eoln ) then // Linux, etc ?
break;
endif;
if( ecx == cap ) then // size == cap, so realloc into cap x2 memory
shl( 1, cap ); // cap gets x2 (doubled)...
mov( ecx, (type str.strRec [ebx]).length );
mov( 0, (type char [ebx+ecx+1]) );
push( eax ); // preserve char in al ...
str.realloc( ebx, cap );
mov( eax, ebx ); // Ok ... now NEW string in ebx ..
pop( eax ); // restore char in al in eax
endif;
mov( al, [ebx + ecx] );
inc( ecx );
endwhile;
mov( ecx, (type str.strRec [ebx]).length );
mov( 0, (type char [ebx+ecx]) );
mov( ebx, sTmp ); // get a copy of address ...
str.a_cpy( ebx ); // new 'right sized' string now in eax
mov( line, ebx );
mov( eax, [ebx] ); // so can return by ref new string
str.free( sTmp );
else
str.free( ebx ); // prevent 'memory leak'
mov( 0, eax ); // AT eof NOW, so return 'zero'
endif;
pop( ecx ); pop( ebx );
end readLine;
And ...
// readLineConsole.hhf // 2012-08-22 //
#includeOnce( "stdlib.hhf" )
#if( !@defined( InitCap ) )
const
InitCap: uns32 := 256;
#endif
procedure readLineConsole; @nodisplay; @returns( "eax" );
var
cap: uns32;
begin readLineConsole;
push( ebx ); push( ecx );
mov( 0, ecx ); // ecx tracks size ...
mov( ecx, cap );
forever
if( ecx == cap ) then
if( ecx != 0 ) then
shl( 1, cap ); // double cap
str.realloc( ebx, cap );
else
mov( InitCap, cap );
str.alloc( cap );
endif;
mov( eax, ebx );
endif;
stdin.getc();
breakif( al == stdio.eoln );
mov( al, [ebx+ecx] );
inc( ecx );
endfor;
mov( 0, (type byte [ebx+ecx]) ); // 0 terminate
mov( ecx, (type str.strRec [ebx]).length ); // update size
str.a_cpy( ebx ); // returns 'right size capacity' string in eax ...
str.free( ebx ); // can eliminate this 'tmp' string now ...
pop( ecx ); pop( ebx );
end readLineConsole;
-
"readWord.hhf"
// readWord.hhf // 2012-08-11 //
#includeOnce( "stdlib.hhf" )
#if( !@defined( InitStrCap ) )
const
InitStrCap: uns32 := 32;
#endif
/*
#if( !@defined( chrIsInStr ) )
// returns *POSITION* 1..n (POS = INDEX+1) or 0 if NOT found //
procedure chrIsInStr( c: char in al; s: string ); @returns( "eax" );
begin chrIsInStr;
str.chpos( s, al );
inc( eax );
end chrIsInStr;
#endif
*/
// expects an unitialized string to be passed in ...
procedure readWord( fin:dword; var line:string; delims: string ); @nodisplay; @returns("eax");
var
cap: dword;
sTmp: string;
c: char;
begin readWord;
push( ebx ); push( ecx );
mov( 0, ecx ); // using ecx to track size ...
mov( InitStrCap, eax );
mov( eax, cap );
str.alloc( eax );
mov( eax, ebx );
// firstly ... skip over any leading delimit char's ...
while( !fileio.eof( fin ) ) do
fileio.getc( fin );
mov( al, c );
//breakif( !chrIsInStr( al, delims ) );
str.chpos( delims, al );
if( eax == -1 ) then
// ok ... we have a good char in c ...
mov( c, al ); // restore good char value to al ...
mov( al, [ebx + ecx] );
inc( ecx );
break;
endif;
endwhile;
// now ... get rest of word ... (if any)
while( !fileio.eof( fin ) ) do
fileio.getc( fin );
mov( al, c );
//breakif( chrIsInStr( al, delims ) );
str.chpos( delims, al );
breakif( eax != -1 );
if( ecx == cap ) then // size == cap, so realloc into cap x2 memory
shl( 1, cap ); // cap gets x2 (doubled)...
mov( ecx, (type str.strRec [ebx]).length );
mov( 0, (type char [ebx+ecx+1]) );
str.realloc( ebx, cap );
mov( eax, ebx ); // Ok ... now NEW string in ebx ..
endif;
mov( c, al ); // restore good char value to al ...
mov( al, [ebx + ecx] );
inc( ecx );
endwhile;
if( !ecx && fileio.eof( fin ) ) then // if eof and empty line ...
str.free( ebx );
mov( 0, eax );
else
mov( ecx, (type str.strRec [ebx]).length );
mov( 0, (type char [ebx+ecx]) );
mov( ebx, sTmp ); // get a copy of address ...
str.a_cpy( ebx ); // new 'right sized' string now in eax
mov( line, ebx );
mov( eax, [ebx] ); // so can return by ref new string
str.free( sTmp );
endif;
pop( ecx ); pop( ebx );
end readWord;
And ...
// readWordConsole.hhf // 2012-08-27 //
#includeOnce( "stdlib.hhf" )
#if( !@defined( InitStrCap ) )
const
InitStrCap: uns32 := 32;
#endif
/*
#if( !@defined( chrIsInStr ) )
// returns *POSITION* 1..n (POS = INDEX+1) or 0 if NOT found //
procedure chrIsInStr( c: char in al; s: string ); @returns( "eax" );
begin chrIsInStr;
str.chpos( s, al );
inc( eax );
end chrIsInStr;
#endif
*/
// expects an unitialized string to be passed in ...
procedure readWordConsole( var line:string; delims: string ); @nodisplay; @returns("eax");
var
cap: dword;
sTmp: string;
c: char;
begin readWordConsole;
push( ebx ); push( ecx );
mov( 0, ecx ); // using ecx to track size ...
mov( InitStrCap, eax );
mov( eax, cap );
str.alloc( eax );
mov( eax, ebx );
// firstly ... skip over any leading delimit char's ...
forever
stdin.getc();
mov( al, c );
if( al != stdio.eoln ) then
str.chpos( delims, al );
if( eax == -1 ) then
// ok ... we have a good char in c ...
mov( c, al ); // restore good char value to al ...
mov( al, [ebx + ecx] );
inc( ecx );
break;
endif;
endif;
endfor;
// now ... get rest of word ... (if any)
forever
stdin.getc();
breakif( al == stdio.eoln );
mov( al, c );
str.chpos( delims, al );
breakif( eax != -1 );
if( ecx == cap ) then // size == cap, so realloc into cap x2 memory
shl( 1, cap ); // cap gets x2 (doubled)...
mov( ecx, (type str.strRec [ebx]).length );
mov( 0, (type char [ebx+ecx+1]) );
str.realloc( ebx, cap );
mov( eax, ebx ); // Ok ... now NEW string in ebx ..
endif;
mov( c, al ); // restore good char value to al ...
mov( al, [ebx + ecx] );
inc( ecx );
endfor;
mov( ecx, (type str.strRec [ebx]).length );
mov( 0, (type char [ebx+ecx]) );
mov( ebx, sTmp ); // get a copy of address ...
str.a_cpy( ebx ); // new 'right sized' string now in eax
mov( line, ebx );
mov( eax, [ebx] ); // so can return by ref new string
str.free( sTmp );
pop( ecx ); pop( ebx );
end readWordConsole;
-
This second set of vector and list functions, permit any number of types of vector or list in a program. These pairs of include files are named:
The first pair is:
"vector2_func's.hhf"
"vector2.hhf"
If you include file "vector2_func's.hhf" to get access to the sort, etc... functions, that file FIRSTLY includes file "vector2.hhf", which firstly includes file "stdlib.hhf"
The next pair is:
"sllist2_func's.hhf"
"sllist2.hhf"
If you include file "sllist2_func's.hhf" to get access to the sort, etc... functions, that file FIRSTLY includes file "sllist2.hhf", which firstly includes file "stdlib.hhf"
-
The vector2 pair:
"vector2.hhf"
// vector2.hhf // 2012-08-15 //
#includeOnce( "stdlib.hhf" )
? @nodisplay:= true; // All procedures have @nodisplay 'as default' now.
#if( !@defined( InitCap ) )
const
InitCap: uns32 := 8;
#endif
// Recall needs a procedure like freeRec( pr: dword in eax );
// so can pass proc address to pFreeRec used below ...
/* // for example ... //
procedure freeRec( pr: dword in eax ); @nodisplay; @noframes;
begin freeRec;
free( (type Rec eax).str );
ret();
end freeRec;
*/
// get a (static) procedure pointer
static
pFreeRec: procedure( a: dword in eax );
type
Vec: record
ary: dword;
capacity: uns32;
size: uns32;
elen: uns32;
endrecord;
procedure initVec( var v: Vec; eln: uns32 );
begin initVec;
push( ebx );
mov( v, ebx );
mov( 0, (type Vec [ebx]).ary );
mov( 0, (type Vec [ebx]).capacity );
mov( 0, (type Vec [ebx]).size );
mov( eln, (type Vec [ebx]).elen );
pop( ebx );
end initVec;
// double capacity ...
procedure enlargeVec( var v: Vec );
begin enlargeVec;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
if( (type Vec [ebx]).capacity != 0 ) then // i.e. if capacity not zero
shl( 1, (type Vec [ebx]).capacity ); // double capacity
else; // set initial capacity
mov( mov( InitCap, eax ), (type Vec [ebx]).capacity );
endif;
mov( (type Vec [ebx]).elen, ecx );
intmul( (type Vec [ebx]).capacity, ecx );
if( (type Vec [ebx]).ary ) then mem.realloc( (type Vec [ebx]).ary, ecx );
else mem.alloc( ecx );
endif;
mov( eax, (type Vec [ebx]).ary );
pop( ecx ); pop( ebx ); pop( eax );
end enlargeVec;
// if size == capacity then enlarge ...
procedure push_backVec( var v: Vec; pr: dword );
begin push_backVec;
//push( ebx ); push( ecx ); push( esi ); push( edi ); // caller must preserve if needed
// if size == capacity then enlarge/double capacity ...
mov( v, ebx );
mov( (type Vec [ebx]).size, ecx );
if( ecx == (type Vec [ebx]).capacity ) then
enlargeVec( (type Vec [ebx]) );
endif;
// ok ... now append (copy) of new rec ...
mov( pr, esi ); // get address of new Rec into esi ...
mov( (type Vec [ebx]).size, edi );
intmul( (type Vec [ebx]).elen, edi );
add( (type Vec [ebx]).ary, edi ); // get offset into edi
// get num bytes to copy in ecx ...
mov( (type Vec [ebx]).elen, ecx );
rep.movsb();
inc( (type Vec [ebx]).size ); // update size
//pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end push_backVec;
procedure reserveVec( var v: Vec; newCap: uns32 );
begin reserveVec;
push( eax ); push( ebx );
mov( newCap, eax );
mov( v, ebx );
if( eax > (type Vec [ebx]).capacity ) then
mov( eax, (type Vec [ebx]).capacity );
intmul( (type Vec [ebx]).elen, eax ); // num new bytes in eax
if( (type Vec [ebx]).ary ) then
mem.realloc( (type Vec [ebx]).ary, eax );
else
mem.alloc( eax );
endif;
mov( eax, (type Vec [ebx]).ary ); // update new ary pointer
endif;
pop( ebx ); pop( eax );
end reserveVec;
procedure clearVec( var v: Vec );
static
rsize: uns32;
begin clearVec;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
mov( (type Vec [ebx]).elen, rsize );
mov( (type Vec[ebx]).size, ecx );
if( (type Vec [ebx]).ary ) then // if was allocated some memory ...
for( dec( ecx ); (type int32 ecx) >= 0; dec( ecx ) ) do
mov( ecx, eax );
intmul( rsize, eax );
add( (type Vec [ebx]).ary, eax );
pFreeRec( eax ); // recall some procedure 'freeRec' must be defined
// along with some type Rec, BEFORE including this file
endfor;
mem.free( (type Vec [ebx]).ary );
endif;
initVec( (type Vec [ebx]), 0 );
pop( ecx ); pop( ebx ); pop( eax );
end clearVec;
-
"vector2_func's.hhf"
// vector2_func's.hhf // 2012-08-15 //
#includeOnce ( "vector2.hhf" )
type
pVec: pointer to Vec;
#if( !@defined( pMyCmp ) )
static
pMyCmp: procedure( a: dword in esi; b: dword in edi ); @returns( "eax" );
#endif
// re. isort ... note: cmp func is a < b (for vector)
// re. msort ... note: cmp func is a <= b
procedure isortVec( var v: Vec );
static
tmpReg: dword;
var
rsize: uns32;
prcmp: dword;
begin isortVec;
push( eax ); push( ebx ); push( ecx ); push( edx ); push( esi ); push( edi );
//int i, j; // i in eax, j in edx
// start with an array of just the first 2 elements (if exists) ...
// for( i = 1; i < cv->size; ++i )
cld();
mov( v, ebx );
mov( (type Vec [ebx]).elen, rsize );
mem.alloc( rsize );
mov( eax, prcmp );
for( mov( 1, eax ); eax < (type Vec [ebx]).size; inc( eax ) ) do
// update this cmp Rec on each outer loop
//memcpy( &cmp, &cv->ary[i], sizeof(Rec) );
mov( prcmp, edi );
mov( eax, esi );
intmul( rsize, esi );
add( (type Vec [ebx]).ary, esi );
mov( rsize, ecx ); // get # bytes to copy in a Rec ... into ecx
rep.movsb(); // ok ... got copy into rcmp ...
// get index of element just to the left of the above 'cmp' to start comparisons
mov( eax, edx ); // j = i
dec( edx ); // --j // i.e. j = i-1; //
while( (type int32 edx) >= 0 ) do // while( j >= 0 && myCmp(&cmp, &cv->ary[j]) < 0 )
mov( edx, edi );
intmul( rsize, edi ); // get offset into edi ..
add( (type Vec [ebx]).ary, edi );
mov( prcmp, esi );
//breakif( !pMyCmp(esi, edi) ); // 'copy up' // but first ...
mov( eax, tmpReg ); // get copy of loop counter in eax
pMyCmp( esi, edi );
if( eax ) then
mov( tmpReg, eax );
else
mov( tmpReg, eax );
break;
endif;
// Now ... 'copy up' ...
//memcpy( &cv->ary[j+1], &cv->ary[j], sizeof(Rec) );
mov( edx, esi );
intmul( rsize, esi );
add( (type Vec [ebx]).ary, esi );
mov( esi, edi );
add( rsize, edi ); // to inc( j ) add size //
mov( rsize, ecx ); // get # bytes to copy in a Rec into ecx
rep.movsb();
dec( edx ); //--j; // --j to prepare for next inner loop
endwhile;
// insert pointer at index j+1 (since j was decremented above ...
//memcpy( &cv->ary[j+1], &cmp, sizeof(Rec) );
inc( edx ); // ++j
mov( prcmp, esi );
mov( edx, edi );
intmul( rsize, edi );
add( (type Vec [ebx]).ary, edi );
mov( rsize, ecx ); // get # bytes to copy in a Rec into ecx
rep.movsb();
endfor;
pop( edi ); pop( esi ); pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end isortVec; // size hasn't changed ...
////////////////////////////////////////////////////////////////////////////
// re. msort ... note: cmp func is a <= b
procedure mergeVec( pv: pVec in ebx; bot: int32; top: int32; ptmp: pVec in edx );
var
mid: int32; // set to (bot+top)/2
sz: int32; // set to top-bot+1 // size of the range to be merged
j: int32;
tmpReg: dword;
rsize: uns32;
begin mergeVec;
//push( eax ); push( ecx ); push( esi ); push( edi ); // NOTE: all 6 reg's preserved by msortVec
//int mid = (bot+top)/2;
mov( top, eax );
add( bot, eax );
shr( 1, eax ); // divide by 2
mov( eax, mid );
//int sz = top - bot + 1; // size of the range to be merged
mov( top, eax );
sub( bot, eax );
inc( eax );
mov( eax, sz );
mov( 0, j ); // int j = 0; // next open index in tmp
mov( bot, eax ); // int h1 = bot; // next index to consider in 1st half
mov( mid, ecx ); // int h2 = mid + 1; // next index to consider in 2nd half
inc( ecx );
mov( (type Vec [ebx]).elen, rsize );
// while indexes h1 and h2 are not past their ends ...
cld();
while( eax <= mid && ecx <= top ) do // while( h1 <= mid && h2 <= top )
// move the smaller element into the tmp vec 'next' ...
// if( myCmp( &(cv->ary[h1]), &(cv->ary[h2]) ) <= 0 )
mov( eax, esi );
intmul( rsize, esi );
add( (type Vec [ebx]).ary, esi );
mov( ecx, edi );
intmul( rsize, edi );
add( (type Vec [ebx]).ary, edi );
mov( eax, tmpReg );
pMyCmp( esi, edi ); // if( myCmp(...) <= 0 )
if( eax ) then // if( myCmp(...) <= 0 )
//tmp->ary[j++] = cv->ary[h1++];
mov( tmpReg, eax ); // restore eax
mov( eax, esi );
intmul( rsize, esi );
add( (type Vec [ebx]).ary, esi );
mov( j, edi );
intmul( rsize, edi );
add( (type Vec [edx]).ary, edi );
mov( ecx, tmpReg );
mov( rsize, ecx );
rep.movsb(); // tmp->ary[j++] = cv->ary[h1++];
mov( tmpReg, ecx );
inc( eax ); // ++h1
inc( j );
else
//tmp->ary[j++] = cv->ary[h2++];
mov( tmpReg, eax ); // restore eax
mov( ecx, esi );
intmul( rsize, esi ); // ecx holds h2
add( (type Vec [ebx]).ary, esi );
mov( j, edi );
intmul( rsize, edi );
add( (type Vec [edx]).ary, edi );
mov( ecx, tmpReg );
mov( rsize, ecx );
rep.movsb(); // tmp->ary[j++] = cv->ary[h2++];
mov( tmpReg, ecx );
inc( ecx ); // ++h2
inc( j );
endif;
endwhile;
// Note: only one (at most) of the two 'while's' below is executed ...
//while( h1 <= mid ) // copy any remaining entries (1st half)
//tmp->ary[j++] = cv->ary[h1++];
while( eax <= mid ) do
mov( eax, esi );
intmul( rsize, esi );
add( (type Vec [ebx]).ary, esi );
mov( j, edi );
intmul( rsize, edi );
add( (type Vec [edx]).ary, edi );
mov( ecx, tmpReg );
mov( rsize, ecx );
rep.movsb(); // tmp->ary[j++] = cv->ary[h1++];
mov( tmpReg, ecx );
inc( eax ); // ++h1
inc( j );
endwhile;
//while( h2 <= top ) // copy any remaining entries (2nd half)
//tmp->ary[j++] = cv->ary[h2++];
while( ecx <= top ) do
mov( ecx, esi );
intmul( rsize, esi );
add( (type Vec [ebx]).ary, esi );
mov( j, edi );
intmul( rsize, edi );
add( (type Vec [edx]).ary, edi );
mov( ecx, tmpReg );
mov( rsize, ecx );
rep.movsb(); // tmp->ary[j++] = cv->ary[h2++];
mov( tmpReg, ecx );
inc( ecx ); // ++h2
inc( j );
endwhile;
//for( j = 0; j < sz; ++j ) // copy back sorted tmp vec...
//cv->ary[bot+j] = tmp->ary[j];
mov( (type Vec [edx]).ary, esi );
mov( bot, edi );
intmul( rsize, edi );
add( (type Vec [ebx]).ary, edi );
mov( sz, ecx );
intmul( rsize, ecx );
rep.movsb();
/*
for( mov( 0, ecx ); ecx < sz; inc( ecx ) ) do
mov( ecx, esi );
intmul( rsize, esi );
add( (type Vec [edx]).ary, esi );
mov( bot, eax );
add( ecx, eax );
mov( eax, edi );
intmul( rsize, edi );
add( (type Vec [ebx]).ary, edi );
mov( ecx, tmpReg );
mov( rsize, ecx );
rep.movsb(); // cv->ary[bot+j] = tmp->ary[j];
mov( tmpReg, ecx );
endfor;
*/
//pop( edi ); pop( esi ); pop( ecx ); pop( eax );
end mergeVec;
procedure my_msortVec( pv: pVec in ebx; bot: int32; top: int32; ptmp: pVec in edx );
var
mid: int32;
begin my_msortVec;
mov( top, eax );
if( bot < eax ) then
add( bot, eax ); // NOW EAX HOLDS top + bot
shr( 1, eax ); // divide by 2 ...
mov( eax, mid ); // mid = ( bot + top ) / 2;
my_msortVec( ebx, bot, mid, edx ); // sort the first half ...
inc( mid ); // now mid = mid +1
my_msortVec( ebx, mid, top, edx ); // and the second half
mergeVec( ebx, bot, top, edx ); // now merge 2 sorted chunks
endif;
end my_msortVec;
procedure msortVec( var v: Vec );
var
Rega: dword;
Regb: dword;
Regc: dword;
Regd: dword;
Regesi: dword;
Regedi: dword;
tmp: Vec;
begin msortVec;
mov( eax, Rega ); mov( ebx, Regb ); mov( ecx, Regc ); mov( edx, Regd );
mov( esi, Regesi ); mov( edi, Regedi );
mov( v, ebx );
mov( (type Vec [ebx]).size, eax );
if( eax > 1 ) then
initVec( tmp, (type Vec [ebx]).elen );
reserveVec( tmp, eax ); // Note: resets cap... BUT tmp size still 0
dec( eax );
lea( edx, tmp ); // get address of new tmp Vec into edx ...
my_msortVec( ebx, 0, eax, edx );
// NOW done ... BUT only free ary mem that held copies of pointers
mem.free( tmp.ary );
endif;
mov( Regedi, edi ); mov( Regesi, esi );
mov( Regd, edx ); mov( Regc, ecx ); mov( Regb, ebx ); mov( Rega, eax );
end msortVec;
// returns index if string present, else -1 ...
procedure findVec( var v: Vec; pr: dword ); @returns( "eax" );
begin findVec;
push( ebx ); push( ecx ); push( esi ); push( edi );
mov( v, ebx );
for( mov( 0, ecx ); ecx < (type Vec [ebx]).size; inc( ecx ) ) do
//if( myCmp(&cv->ary[i], r) == 0 )
mov( ecx, esi );
intmul( (type Vec [ebx]).elen, esi );
add( (type Vec [ebx]).ary, esi );
mov( pr, edi );
pMyCmp( esi, edi ); // need an 'eq' cmp here ...
breakif( eax ); // i.e. break if equal ...
endfor;
// now check loop end condition ...
if( ecx != (type Vec [ebx]).size ) then
mov( ecx, eax ); // found
else
mov( -1, eax ); // NOT found
endif;
pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end findVec;
// if int index valid, erases element there ...
procedure eraseVec( var v: Vec; index: int32 in eax );
var
tmpReg: dword;
rsize: uns32;
begin eraseVec;
push( ebx ); push( ecx ); push( esi ); push( edi );
mov( v, ebx );
mov( (type Vec [ebx]).elen, rsize );
if( (type int32 eax) >= 0 && (type int32 eax) < (type Vec [ebx]).size ) then
mov( eax, tmpReg );
intmul( rsize, eax );
add( (type Vec [ebx]).ary, eax );
pFreeRec( eax ); // must pass in eax, needed here if dynamic memory
mov( tmpReg, eax );
//if( index < cv->size-1 )
//memcpy(&cv->ary[index], &cv->ary[index+1], (cv->size-1-index)*sizeof(Rec));
mov( (type Vec [ebx]).size, ecx );
dec( ecx ); // ecx holds size-1
if( eax < ecx ) then
sub( eax, ecx ); // ecx now holds (cv->size-1-index)
intmul( rsize, ecx ); // ecx now holds bytes to copy ...
mov( eax, edi );
intmul( rsize, edi );
add( (type Vec [ebx]).ary, edi );
mov( edi, esi );
add( rsize, esi );
rep.movsb();
endif;
// now update size and return by reference (since address passed in)
dec( (type Vec [ebx]).size );
else
mov( (type Vec [ebx]).size, ecx );
dec( ecx ); // ecx holds size-1
stdout.put( nl, "ERROR! Index ", index, " out of range 0..", (type int32 ecx), nl);
endif;
pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end eraseVec;
/*
void uniqueCvec( Cvec* cv, int (*myCmp) (const void* a, const void* b),
void (*freeVrec) (void* el) )
{
int i = 0, j = 1;
if( !isSortedCvec( cv, myCmp ) )
msortCvec( cv, myCmp, freeVrec ); // first make sure, sorted order
for( ; j < cv->size ; ++j )
{
if( myCmp( (cv->ary + i*cv->elen), (cv->ary + j*cv->elen) ) != 0 )
{
++i;
if( i != j ) memcpy( (cv->ary + cv->elen*i), (cv->ary + cv->elen*j),
cv->elen );
}
else freeVrec( cv->ary + cv->elen*j );
}
cv->size = ++i;
}
*/
// Adapted from the above 'C' language algorithim ...
procedure xDuplicates( var v: Vec );
var
k: uns32;
begin xDuplicates;
push( ebx );
mov( v, ebx );
if( (type Vec [ebx]).size > 1 ) then // Note: need size > 1 to enter this block ...
push( eax ); push( ecx ); push( esi ); push( edi );
cld(); // re. rep.movsb() ...
mov( 0, k );
for( mov( 1, ecx ); ecx < (type Vec [ebx]).size; inc( ecx) ) do
//mov( @size(MyContact), (type Vec [ebx]).elen ); // ......................debugging //
mov( (type Vec [ebx]).elen, edi );
intmul( k, edi );
add( (type Vec [ebx]).ary, edi );
// edi holds offset into LAST LOWER UNIQUE record compared
mov( (type Vec [ebx]).elen, esi );
stdout.put( "esi = ", esi, ", edi = ", edi, nl );
intmul( ecx, esi );
stdout.put( "esi = ", esi, ", edi = ", edi, nl );
add( (type Vec [ebx]).ary, esi );
// esi now holds offset into this 'i'
//if (a[k] != a[i])
//if( str.ine( MyBBook.theName[edi], MyBBook.theName[esi] ) ) then
stdout.put( "esi = ", esi, ", edi = ", edi, nl );
pMyCmp( esi, edi );
if( !eax ) then // uses eax ...
inc( k ); // k=k+1; get ready for next pair of '(k,i)' to compare
add( (type Vec [ebx]).elen, edi ); // now edi holds offset for (k+1)
if( k != ecx ) then // i.e. if ( (k+1) != i ) then ...
push( ecx ); // preserve ecx counter ...
//mov( MyBBook.theName[esi], MyBBook.theName[edi] ); // copy this new
//mov( MyBBook.thePhone[esi], MyBBook.thePhone[edi] );
mov( (type Vec [ebx]).elen, ecx );
rep.movsb();
pop( ecx );
endif;
else // a[k]=a[i], SO THEN goto next 'i', (i.e. ecx), but still same old 'k' though.
// ok to free this 'i' record since = the 'k' record below
//str.free( MyBBook.thePhone[esi] ); // ok to free these strings
//str.free( MyBBook.theName[esi] );
mov( esi, eax );
pFreeRec( eax );
endif;
endfor;
inc( k );
mov( k, (type Vec [ebx]).size );
pop( edi ); pop( esi ); pop( ecx ); pop( eax );
endif;
pop( ebx );
end xDuplicates;
-
The list2 pair:
"sllist2.hhf"
// sllist2.hhf // 2012-08-15 //
// using NNode to avoid conflict with Node
// using SLList to avoid conflict with List
#includeOnce( "stdlib.hhf" )
// NB!!! the record NNode must be defined before including this file
// ALSO the type pNNode: pointer to NNode;
? @nodisplay:= true; // all procedures have @nodisplay 'as default' now
type
NNode: record
nval: dword;
next: pointer to NNode;
endrecord;
pNNode: pointer to NNode;
type
SLList: record
head: pNNode;
tail: pNNode;
size: uns32;
endrecord;
static
pFreeNNode: procedure( pn: pNNode in eax );
procedure initSLList( var lst: SLList );
begin initSLList;
push( eax ); push( ebx );
mov( lst, ebx );
mov( 0, (type SLList [ebx]).head );
mov( 0, (type SLList [ebx]).tail );
mov( 0, (type SLList [ebx]).size );
pop( ebx ); pop( eax );
end initSLList;
procedure push_frontSLList( var lst: SLList; var n: NNode );
begin push_frontSLList;
//push( ebx ); push( ecx ); push( esi ); push( edi ); // caller must preserve if needed
cld();
mem.alloc( @size(NNode) );
mov( eax, edi );
mov( n, esi ); // get address of new NNode into esi ...
// get num bytes to copy in ecx ...
mov( @size(NNode), ecx );
rep.movsb();
// ok ... now prepend (copy) of new rec ...
mov( lst, ebx );
if( (type SLList [ebx]).size != 0 ) then // not empty
mov( mov( (type SLList [ebx]).head, ecx ), (type NNode [eax]).next );
mov( eax, (type SLList [ebx]).head );
else
mov( 0, (type NNode [eax]).next );
mov( eax, (type SLList [ebx]).tail );
mov( eax, (type SLList [ebx]).head );
endif;
inc( (type SLList [ebx]).size ); // update size
//pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end push_frontSLList;
procedure push_backSLList( var lst: SLList; var n: NNode );
begin push_backSLList;
//push( ebx ); push( ecx ); push( esi ); push( edi ); // caller must preserve if needed
cld();
mem.alloc( @size(NNode) );
mov( eax, edi );
mov( n, esi ); // get address of new Rec into esi ...
// get num bytes to copy in ecx ...
mov( @size(NNode), ecx );
rep.movsb();
mov( 0, (type NNode [eax]).next );
// ok ... now append (copy) of new rec ...
mov( lst, ebx );
if( (type SLList [ebx]).size != 0 ) then // not empty
mov( (type SLList [ebx]).tail, ecx );
mov( eax, (type NNode [ecx]).next ); // now 'next' updated
mov( eax, (type SLList [ebx]).tail );
else
mov( eax, (type SLList [ebx]).tail );
mov( eax, (type SLList [ebx]).head );
endif;
inc( (type SLList [ebx]).size ); // update size
//pop( edi ); pop( esi ); pop( ecx ); pop( ebx );
end push_backSLList;
procedure clearSLList( var v: SLList );
begin clearSLList;
push( eax ); push( ebx ); push( ecx );
mov( v, ebx );
mov( (type SLList[ebx]).head, ecx );
while( ecx != 0 ) do
mov( ecx, eax );
mov( (type NNode [ecx]).next, ecx );
pFreeNNode( eax );
mem.free( eax );
endwhile;
initSLList( (type SLList [ebx]) );
pop( ecx ); pop( ebx ); pop( eax );
end clearSLList;
-
"sllist2_func's.hhf"
// sllist2_func's.hhf // // 2012-08-16 //
#includeOnce( "sllist2.hhf" )
type
pSLList: pointer to SLList;
#if( !@defined( pMyCmp ) )
static
pMyCmp: procedure( a: dword in esi; b: dword in edi ); @returns( "eax" );
#endif
// re. isort ... note: cmp func is a <= b (for list, ALSO same as for msort)
// re. msort ... note: cmp func is a <= b
// pass in the address of the SLList and the new Node to insert ...
procedure insert_sortedSLList( var lst: SLList; pn: pNNode in eax );
//var
//head: pNNode; // esi
var
reg32: dword;
begin insert_sortedSLList;
push( ebx ); push( esi ); push( edi );
//pList head;
//if( !isSortedSLList( list, myCmp )) msortSLList( list, myCmp );
//head = list->start;
mov( lst, ebx );
mov( (type SLList [ebx]).head, esi );
mov( eax , edi );
// firstly, we handle most common case where 'n' is NOT the first Node
//if( head != NULL && myCmp( n, head ) >= 0 ) // NEED >=
if( esi && pMyCmp( esi, edi ) ) then
// so search the linked list for the right location
//pList cur = head;
//while( cur->next != NULL && myCmp( cur->next, n ) <= 0 )
mov( esi, reg32 );
mov( (type NNode [esi]).next, esi );
//while( esi && pmyCmp( esi, edi ) ) do
forever
if( !esi || !pMyCmp( esi, edi ) ) then
//cur = cur->next;
mov( reg32, esi );
break;
else
mov( esi, reg32 );
mov( (type NNode [esi]).next, esi );
endif;
endfor;
//if( cur == list->end ) list->end = n;
if( esi == (type SLList [ebx]).tail ) then
mov( edi, (type SLList [ebx]).tail );
endif;
//n->next = cur->next;
mov( (type NNode [esi]).next, (type NNode [edi]).next );
//cur->next = n;
mov( edi, (type NNode [esi]).next );
// list->start = head; // unchanged //
//++ list->size;
inc( (type SLList [ebx]).size );
else // if we reach here, this IS the first node ...
//n->next = head; // so set this node in first position
mov( (type SLList [ebx]).head, (type NNode [edi]).next );
//list->start = n;
mov( edi, (type SLList [ebx]).head );
//++ list->size;
inc( (type SLList [ebx]).size );
if( (type SLList [ebx]).size == 1 ) then
// list->end = n;
mov( edi, (type SLList [ebx]).tail );
endif;
endif;
pop( edi ); pop( esi ); pop( ebx );
end insert_sortedSLList;
//void isortSLList( SLList* list, int (*myCmp) (const pList r1, const pList r2) )
procedure isortSLList( var lst: SLList );
var
nSLList: SLList;
//cur: pNNode; // eax
//nextNode: pNNode; // ecx
begin isortSLList;
push( eax ); push( ebx ); push( ecx );
initSLList( nSLList );
mov( lst, ebx );
//for( cur = list->start; cur != NULL; cur = nextNode )
for( mov( (type SLList [ebx]).head, eax ); eax; mov( ecx, eax ) ) do
//nextNode = cur->next; // get copy here before next is changed below
mov( (type NNode [eax]).next, ecx );
//insert_sortedSLList( &nSLList, cur, myCmp ); // 'cur' already is a Node pointer
insert_sortedSLList( nSLList, eax );
endfor;
// now ... update old list with new front and back ...
//list->start = nSLList.start;
mov( nSLList.head, (type SLList [ebx]).head );
//list->end = nSLList.end;
mov( nSLList.tail, (type SLList [ebx]).tail );
// size hasn't changed
pop( ecx ); pop( ebx ); pop( eax );
end isortSLList;
// merge two sorted SLLists with heads 'a' and 'b' ... in sorted order
procedure mergeSLLists(var a: SLList; var b: SLList ); @returns( "eax" ); // new head
var
newMergedHead: dword;
//sorted: dword; // use ebx // using edx now ..
begin mergeSLLists;
//push( ebx ); // using edx instead of ebx here now ...
//push( esi ); push( edi );
//pList sorted, new_merged_head;
mov( a, eax );
mov( (type SLList [eax]).head, esi );
mov( b, eax );
mov( (type SLList [eax]).head, edi );
//if( a->start == NULL ) return b->start;
//if( b->start == NULL ) return a->start;
if( !esi ) then mov( edi, newMergedHead );
elseif( !edi ) then mov( esi, newMergedHead );
else
//if( myCmp(a->start, b->start) <= 0 )
if( pMyCmp( esi, edi ) ) then
//sorted = a->start;
//a->start = a->start->next;
mov( esi, edx );
mov( (type NNode [esi]).next, esi );
else
//sorted = b->start;
//b->start = b->start->next;
mov( edi, edx );
mov( (type NNode [edi]).next, edi );
endif;
//new_merged_head = sorted;
mov( edx, newMergedHead );
// now ...
//while( a->start != NULL && b->start != NULL )
while( esi && edi ) do
//if( myCmp(a->start, b->start) <= 0 )
if( pMyCmp( esi, edi ) ) then
//sorted->next = a->start;
mov( esi, (type NNode [edx]).next );
//sorted = a->start;
mov( esi, edx );
//a->start = a->start->next;
mov( (type NNode [esi]).next, esi );
else
//sorted->next = b->start;
mov( edi, (type NNode [edx]).next );
//sorted = b->start;
mov( edi, edx );
//b->start = b->start->next;
mov( (type NNode [edi]).next, edi );
endif;
endwhile;
// and finally ...
//if( a->start != NULL )
if( esi ) then
//sorted->next = a->start;
mov( esi, (type NNode [edx]).next );
//else if( b->start != NULL )
elseif( edi ) then
//sorted->next = b->start;
mov( edi, (type NNode [edx]).next );
endif;
endif;
mov( newMergedHead, eax );
//pop( edi ); pop( esi );
//pop( ebx );
end mergeSLLists;
// a recursive mergesort ...
procedure mergesortSLList( var lst: SLList );
var
// cur: pNNode; // ecx
a: SLList;
b: SLList;
begin mergesortSLList;
push( ebx );
//push( ecx ); push( edx );
//pList cur = list->start;
mov( lst, ebx );
mov( (type SLList [ebx]).head, ecx );
mov( ecx, a.head );
//SLList a, b;
// base case is a SLList of length 0 or 1 ...
//if ((cur == NULL) || (cur->next == NULL)) return;
if( a.head != 0 /*&& b.head != 0*/ ) then
mov( (type NNode [ecx]).next, b.head );
if( b.head != 0 ) then
// split SLList into 'a' and 'b' sublists ...
//a.start = cur;
//b.start = cur->next; // both these lines done above
while( b.head != 0 /*&& ( b.start->next != NULL)*/ ) do
mov( b.head, edx );
mov( (type NNode [edx]).next, edx );
breakif( !edx );
//cur = cur->next;
mov( (type NNode [ecx]).next, ecx );
//b.start = b.start->next->next;
mov( (type NNode [edx]).next, b.head );
endwhile;
//b.start = cur->next;
mov( (type NNode [ecx]).next, b.head );
//cur->next = NULL; // SLList divided into 2 roughly equal parts now
mov( 0, (type NNode [ecx]).next );
// recursively sort the sublists ...
mergesortSLList( a );
mergesortSLList( b );
// merge the two sorted SLLists together ...
//list->start = mergeSLLists(&a, &b, myCmp);
mergeSLLists( a, b ); // returns new merged head in eax
mov( eax, (type SLList [ebx]).head );
endif;
endif;
//pop( edx ); pop( ecx );
pop( ebx );
end mergesortSLList;
procedure update_endSLList( var lst: SLList ); // after sort
begin update_endSLList;
//push( ebx ); push( ecx );
mov( lst, ebx );
if( (type SLList [ebx]).size > 1 ) then
//pList cur;
//for( cur = list->start; cur->next != NULL; cur = cur->next ) ;
//list->end = cur;
//list->end->next = NULL; // this line NOT-needed/redundant
mov( (type SLList [ebx]).head, ecx );
while( (type NNode [ecx]).next != 0 ) do mov( (type NNode [ecx]).next, ecx ); endwhile;
mov( ecx, (type SLList [ebx]).tail );
endif;
//pop( ecx ); pop( ebx );
end update_endSLList;
procedure msortSLList( var lst: SLList );
var
Rega: dword;
Regb: dword;
Regc: dword;
Regd: dword;
Regesi: dword;
Regedi: dword;
begin msortSLList;
mov( eax, Rega ); mov( ebx, Regb ); mov( ecx, Regc ); mov( edx, Regd );
mov( esi, Regesi ); mov( edi, Regedi );
mov( lst, ebx );
mergesortSLList( (type SLList [ebx]) );
//mov( lst, ebx );
update_endSLList( (type SLList [ebx]) );
mov( Regedi, edi ); mov( Regesi, esi );
mov( Regd, edx ); mov( Regc, ecx ); mov( Regb, ebx ); mov( Rega, eax );
end msortSLList;
// returns pointer if present, else returns 0
procedure findSLList( var lst: SLList; var nn: NNode ); @returns( "eax" );
begin findSLList;
push( ebx ); push( esi ); push( edi );
//pList p;
mov( lst, ebx );
mov( nn, edi );
//for( p = cl->start; p != NULL; p = p->next )
for( mov( (type SLList [ebx]).head, esi ); esi; mov( (type NNode [esi]).next, esi ) ) do
//if( myCmp(p, pr) == 0 ) return p;
pMyCmp( esi, edi ); // returns eax = 1 if found, else 0
if( eax ) then
mov( esi, eax );
break;
endif;
endfor;
// if not found above, eax is already 0
pop( edi ); push( esi ); push( ebx );
end findSLList;
procedure eraseSLList( var lst: SLList; pn: pNNode in eax ); // if pn valid, erase element there
//var
//prev: pNNode; // use edx
begin eraseSLList;
push( ebx ); push( ecx ); push( edx );
//pList prev = NULL, cur = cl->start;
mov( 0, edx );
mov( lst, ebx );
for( mov( (type SLList [ebx]).head, ecx ); ecx && ecx != eax; mov( (type NNode [ecx]).next, ecx ) ) do
//prev = cur;
mov( ecx, edx );
endfor;
if( ecx ) then
if( edx ) then // case of NOT FIRST element
//prev->next = cur->next;
mov( (type NNode [ecx]).next, (type NNode [edx]).next );
else // case of IS FIRST element
//cl->start = cl->start->next;
mov( (type NNode [ecx]).next, (type SLList [ebx]).head );
endif;
//if( cur == cl->end ) cl->end = prev; /* case of IS LAST element*/
if( ecx == (type SLList [ebx]).tail ) then
mov( edx, (type SLList [ebx]).tail );
endif;
pFreeNNode( ecx ); // needed here for types like dynamic C strings, etc
mem.free( ecx ); // free memory for dynamic Node ...
// now update size and return (by reference, since address passed in)
//-- cl->size;
dec( (type SLList [ebx]).size );
else
stdout.puts( nl "eraseSLList ERROR! Pointer NOT found ..." );
endif;
pop( edx ); pop( ecx ); pop( ebx );
end eraseSLList;
#if( !@defined( chrIsInStr ) )
// returns *POSITION* 1..n (POS = INDEX+1) or 0 if NOT found //
procedure chrIsInStr( c: char in al; s: string ); @returns( "eax" );
begin chrIsInStr;
str.chpos( s, al );
inc( eax );
end chrIsInStr;
#endif
procedure splitSLList( var sll: SLList; s: string; delims: string );
var
myNNode: NNode;
reg32: dword;
i: uns32;
begin splitSLList;
push( eax ); push( ebx ); push( ecx ); push( edx );
mov( sll, ebx );
mov( s, ecx ); // ecx holds start address ...
forever
while( chrIsInStr( (type char [ecx]), delims ) ) do
inc( ecx );
endwhile;
breakif( (type char [ecx]) == 0 ); // since 'empty' string
mov( ecx, edx );
inc( edx ); // edx holds address one past end of 'word' ...
mov( (type char [edx]), al );
while( al && !chrIsInStr( al, delims ) ) do
inc( edx );
mov( (type char [edx]), al );
endwhile;
mov( edx, reg32 ); // save a copy of 'end' in reg32 ...
sub( ecx, edx ); // edx holds 'len of next word'
mov( ecx, i );
mov( s, eax );
sub( eax, i ); // i is index to start
str.a_substr( s, i, edx ); // start, len
mov( eax, myNNode.nval );
push_backSLList( (type SLList [ebx]), myNNode );
mov( reg32, ecx ); // update (next) start pointer ecx ...
endfor;
pop( edx ); pop( ecx ); pop( ebx ); pop( eax );
end splitSLList;
procedure uniqueSLList( var lst: SLList );
begin uniqueSLList;
push( eax ); push( ebx ); push( esi ); push( edi );
//pList p = c->start;
mov( lst, ebx );
mov( (type SLList [ebx]).head, esi ); // esi holds cur NNode address
if( esi ) then
//while( p->next != NULL )
while( (type NNode [esi]).next != 0 ) do
//if( myCmp(p, p->next) == 0 )
mov( (type NNode [esi]).next, edi );
if( pMyCmp( esi, edi ) ) then // if equal then ...
//pList tmp = p->next;
mov( edi, eax ); // eax is tmp copy ...
//p->next = p->next->next;
mov( (type NNode [edi]).next, edi ); // now advance edi ...
mov( edi, (type NNode [esi]).next );
pFreeNNode( eax ); // needed here for types like dynamic Cstrings, etc
mem.free( eax );
//-- c->size;
dec( (type SLList [ebx]).size );
else
//p = p->next;
mov( edi, esi ); // mov esi up since not equal ...
endif;
endwhile;
update_endSLList( (type SLList [ebx]) ) ; // update end ...
endif;
pop( edi ); pop( esi ); pop( ebx ); pop( eax );
end uniqueSLList;