|
|
/*_________________________________________________________________*
| | | MODULE | | | | HSORT | | (C) Copyright Microsoft Corp 1988 | | 10 March 1988 | | | | FUNCTION | | | | Sorting functions required by linker. | | | | DEFINES | | | | void AllocSortBuffer(unsigned max, int AOrder) | | RBTYPE ExtractMin(unsigned n) | | void FreeSortBuffer(void) | | void InitSort(RBTYPE **buf, WORD *base1, WORD *lim1, | | WORD *base2, WORD *lim2 ) | | RBTYPE GetSymPtr(unsigned n) | | void Store(RBTYPE element) | | | | USES | | | | cmpf global pointer to comparing function | | AREASORT area in virtual memory where sort buffer is | | extended | | | | CHANGES | | | | symMac global counter of sorted symbols | | | | MODIFICATION HISTORY | | | | 88/03/10 Wieslaw Kalkus Initial version | | | | | | | |_________________________________________________________________| * */
#include <minlit.h> /* Types and constants */
#include <bndtrn.h> /* Basic type & const declarations */
#include <bndrel.h> /* Types and constants */
#include <lnkio.h> /* Linker I/O definitions */
#include <lnkmsg.h> /* Error messages */
#include <extern.h> /* External declarations */
#define VMBuffer(x) (RBTYPE *)mapva((long)(AREASORT+((long)(x)*sizeof(RBTYPE))),FALSE)
#define SORTDEBUG FALSE
LOCAL WORD LastInBuf; /* Last element in sort buffer */ LOCAL RBTYPE *SortBuffer; /* Sort buffer allocated on near heap */ LOCAL FTYPE fVMReclaim; /* TRUE if VM page buffers reclaimed */ LOCAL FTYPE fInMemOnly; /* TRUE if not using VM for sort buffer */ LOCAL FTYPE fFirstTime = (FTYPE) TRUE; LOCAL WORD SortIndex = 0; LOCAL int (NEAR *TestFun)(RBTYPE *arg1, RBTYPE *arg2); LOCAL int (NEAR *TestFunS)(RBTYPE *arg1, RBTYPE *arg2);
/*
* LOCAL FUNCTION PROTOTYPES */
LOCAL void NEAR SiftDown(unsigned n); LOCAL void NEAR SiftUp(unsigned n); LOCAL int NEAR AscendingOrder(RBTYPE *arg1, RBTYPE *arg2); LOCAL int NEAR DescendingOrder(RBTYPE *arg1, RBTYPE *arg2);
/*
* DEBUGING FUNCTIONS */
#if SORTDEBUG
LOCAL void NEAR DumpSortBuffer(unsigned max, int faddr); LOCAL void NEAR DumpElement(unsigned el, int faddr); LOCAL void NEAR CheckSortBuffer(unsigned n, unsigned max);
LOCAL void NEAR CheckSortBuffer(unsigned root, unsigned max) { DWORD c; RBTYPE child[2]; RBTYPE parent; RBTYPE *VMp;
c = root << 1;
if (c > (long) max) return;
/* c is the left child of root */
if (c + 1 <= (long) max) { /* c + 1 is the right child of root */
if (c > LastInBuf) { /* Fetch element from virtual memory */ VMp = VMBuffer(c); child[0] = *VMp; VMp = VMBuffer(c + 1); child[1] = *VMp; } else { child[0] = SortBuffer[c]; if (c + 1 > LastInBuf) { VMp = VMBuffer(c + 1); child[1] = *VMp; } else child[1] = SortBuffer[c+1]; }
} else { /* only left child of root */
if (c > LastInBuf) { /* Fetch element from virtual memory */ VMp = VMBuffer(c); child[0] = *VMp; } else child[0] = SortBuffer[c]; }
if (root > LastInBuf) { VMp = VMBuffer(root); parent = *VMp; } else parent = SortBuffer[root];
if (!(*TestFun)(&parent, &child[0])) { fprintf(stdout, "\r\nBAD sort buffer --> root = %u; left child = %lu \r\n", root, c); DumpElement(root, cmpf == FGtAddr); DumpElement(c, cmpf == FGtAddr); }
if (c + 1 < (long) max) { if (!(*TestFun)(&parent, &child[1])) { fprintf(stdout, "\r\nBAD sort buffer --> root = %u; right child = %lu \r\n", root, c+1); DumpElement(root, cmpf == FGtAddr); DumpElement(c+1, cmpf == FGtAddr); } } CheckSortBuffer((unsigned) c, max); if (c + 1 < (long) max) CheckSortBuffer((unsigned) c+1, max);
return; }
LOCAL void NEAR DumpSortBuffer(unsigned max, int faddr) {
unsigned x;
for (x = 1; x <= max; x++) { fprintf(stdout, "SortBuffer[%u] = ", x); DumpElement(x, faddr); fprintf(stdout, " \r\n"); } }
LOCAL void NEAR DumpElement(unsigned el, int faddr) {
unsigned i; RBTYPE *VMp; RBTYPE symp; AHTEPTR hte; APROPNAMEPTR prop; char name[40]; union { long vptr; /* Virtual pointer */ BYTE far *fptr; /* Far pointer */ struct { unsigned short offset; /* Offset value */ unsigned short seg; } /* Segmnet value */ ptr; } pointer; /* Different ways to describe pointer */
if (el > LastInBuf) { VMp = VMBuffer(el); symp = *VMp; } else symp = SortBuffer[el];
pointer.fptr = (BYTE far *) symp;
if(pointer.ptr.seg) /* If resident - segment value != 0 */ picur = 0; /* Picur not valid */ else pointer.fptr = (BYTE far *) mapva(AREASYMS + (pointer.vptr << SYMSCALE),FALSE); /* Fetch from virtual memory */
if (faddr) /* If buffer sorted by addresses */ { prop = (APROPNAMEPTR ) pointer.fptr; while (prop->an_attr != ATTRNIL) { pointer.fptr = (BYTE far *) prop->an_next;
if(pointer.ptr.seg) /* If resident - segment value != 0 */ picur = 0; /* Picur not valid */ else pointer.fptr = (BYTE far *) mapva(AREASYMS + (pointer.vptr << SYMSCALE),FALSE); /* Fetch from virtual memory */ prop = (APROPNAMEPTR ) pointer.fptr; } }
hte = (AHTEPTR ) pointer.fptr;
for (i = 0; i < B2W(hte->cch[0]); i++) name[i] = hte->cch[i+1]; name[i] = '\0'; fprintf(stdout, " %s ", name); }
#endif
#if AUTOVM
/*
* A sorting algorithm: * * for i := 1 to SymMax do * begin * { Insert element } * SortBuffer[i] = pointer-to-symbol; * SiftUp(i); * end * * for i := SymMax downto 2 do * begin * { Extract min element } * Do-what-you-want-with SortBuffer[1] element; * Swap(SortBuffer[1], SortBuffer[i]); * SiftDown(i - 1); * end */
/*_________________________________________________________________*
| | | NAME | | | | SiftUp | | | | INPUT | | | | Actual size of sorting heap. | | | | FUNCTION | | | | Placing an arbitrary element in SortBuffer[n] when | | SortBuffer[n-1] has a heap property will probably not | | yield the property heap(1, n) for the SortBuffer; | | establishing this property is the job of procedure SiftUp. | | | | RETURNS | | | | Nothing. | | | |_________________________________________________________________| * */
LOCAL void NEAR SiftUp(unsigned n)
{ unsigned i; unsigned p; RBTYPE child; RBTYPE parent; RBTYPE *VMp;
/*
* Precondition: SortBuffer has property heap(1, n-1) and n > 0 */
i = n;
for (;;) { /*
* Loop invariant condition: SortBuffer has property heap(1, n) * except perhaps between "i" and its parent. */
if (i == 1) return; /* POSTCONDITION: SortBuffer HAS PROPERTY HEAP(1, N). */
p = i >> 1; /* p = i div 2 */
if (i > LastInBuf) { /* Fetch element from virtual memory */ VMp = VMBuffer(i); child = *VMp; } else child = SortBuffer[i];
if (p > LastInBuf) { /* Fetch element from virtual memory */ VMp = VMBuffer(p); parent = *VMp; } else parent = SortBuffer[p];
if ((*TestFun)(&parent, &child)) break;
/* swap(p, i) */
if (p > LastInBuf) { VMp = VMBuffer(p); *VMp = child; markvp(); } else SortBuffer[p] = child;
if (i > LastInBuf) { /* Fetch element from virtual memory */ VMp = VMBuffer(i); *VMp = parent; markvp(); } else SortBuffer[i] = parent;
#if SORTDEBUG
fprintf(stdout, " \r\nSIFTUP - swap "); DumpElement(p, cmpf == FGtAddr); fprintf(stdout, " with "); DumpElement(i, cmpf == FGtAddr); fprintf(stdout, " \r\n"); #endif
i = p; } /* POSTCONDITION: SortBuffer HAS PROPERTY HEAP(1, N). */ return; }
/*_________________________________________________________________*
| | | NAME | | | | SiftDown | | | | INPUT | | | | Actual size of sorting heap. | | | | FUNCTION | | | | Assigning a new value to SortBuffer[1] leaves the | | SortBuffer[2 ... n] with heap property. Procedure | | SiftDown makes heap(SortBuffer[1 ... n]) true. | | | | RETURNS | | | | Nothing. | | | |_________________________________________________________________| * */
LOCAL void NEAR SiftDown(unsigned n) { DWORD i; DWORD c; RBTYPE child[2]; RBTYPE parent; RBTYPE *VMp;
/*
* Precondition: SortBuffer has property heap(2, n) and n > 0 */
i = 1L;
for (;;) { /*
* Loop invariant condition: SortBuffer has property heap(1, n) * except perhaps between "i" and its (0, 1 or 2) children. */
c = i << 1;
if (c > (DWORD) n) break;
/* c is the left child of i */
if (c + 1 <= (DWORD) n) { /* c + 1 is the right child of i */
if (c > LastInBuf) { /* Fetch element from virtual memory */ VMp = VMBuffer(c); child[0] = *VMp; VMp = VMBuffer(c + 1); child[1] = *VMp; } else { child[0] = SortBuffer[c]; if (c + 1 > LastInBuf) { VMp = VMBuffer(c + 1); child[1] = *VMp; } else child[1] = SortBuffer[c+1]; }
if ((*TestFunS)(&child[1], &child[0])) { c++; child[0] = child[1]; } } else { /* only left child of i */
if (c > LastInBuf) { /* Fetch element from virtual memory */ VMp = VMBuffer(c); child[0] = *VMp; } else child[0] = SortBuffer[c]; }
/* c is the least child of i */
if (i > LastInBuf) { VMp = VMBuffer(i); parent = *VMp; } else parent = SortBuffer[i];
if ((*TestFun)(&parent, &child[0])) break;
/* swap(p, i) */
if (i > LastInBuf) { VMp = VMBuffer(i); *VMp = child[0]; markvp(); } else SortBuffer[i] = child[0];
if (c > LastInBuf) { VMp = VMBuffer(c); *VMp = parent; markvp(); } else SortBuffer[c] = parent;
#if SORTDEBUG
fprintf(stdout, " \r\nSIFTDOWN - swap "); DumpElement(i, cmpf == FGtAddr); fprintf(stdout, " with "); DumpElement(c, cmpf == FGtAddr); fprintf(stdout, " \r\n"); #endif
i = c; }
/* POSTCONDITION: SortBuffer HAS PROPERTY HEAP(1, N). */
return; }
#endif
LOCAL int NEAR AscendingOrder(RBTYPE *arg1, RBTYPE *arg2) { return((*cmpf)(arg1, arg2) <= 0); }
LOCAL int NEAR DescendingOrder(RBTYPE *arg1, RBTYPE *arg2) { return((*cmpf)(arg1, arg2) >= 0); }
LOCAL int NEAR AscendingOrderSharp(RBTYPE *arg1, RBTYPE *arg2) { return((*cmpf)(arg1, arg2) < 0); }
LOCAL int NEAR DescendingOrderSharp(RBTYPE *arg1, RBTYPE *arg2) { return((*cmpf)(arg1, arg2) > 0); }
/*_________________________________________________________________*
| | | NAME | | | | ExtractMin | | | | INPUT | | | | Actual size of sorting heap. | | | | FUNCTION | | | | Get smallest element from SortBuffer and reheap if | | neccesary. Function takes into account fact that | | SortBuffer can be allocated only in "real" memory and if | | this is true, than QUICKSORT is used instead of HEAPSORT. | | | | RETURNS | | | | Pointer to smallest element from SortBuffer. | | | |_________________________________________________________________| * */
RBTYPE NEAR ExtractMin(unsigned n) {
RBTYPE *VMp; RBTYPE RetVal;
if (fInMemOnly) { if (fFirstTime) { /* First time called - sort buffer */
qsort(SortBuffer, symMac, sizeof(RBTYPE), (int (__cdecl *)(const void *, const void *)) cmpf); fFirstTime = FALSE; }
RetVal = SortBuffer[SortIndex++];
if (SortIndex >= symMac) { /* Last element extracted - reset flags and counters */
fFirstTime = (FTYPE) TRUE; SortIndex = 0; } } #if AUTOVM
else { RetVal = SortBuffer[1];
#if SORTDEBUG
fprintf(stdout, " \r\nAFTER EXTRACTING element "); DumpElement(1, cmpf == FGtAddr); #endif
if (n > LastInBuf) { VMp = VMBuffer(n); SortBuffer[1] = *VMp; } else SortBuffer[1] = SortBuffer[n];
SiftDown(n - 1);
#if SORTDEBUG
fprintf(stdout, "\r\nVerifying Sort Buffer - size = %u ", n-1); CheckSortBuffer(1,n-1); #endif
} #endif
return(RetVal); }
/*_________________________________________________________________*
| | | NAME | | | | Store | | | | INPUT | | | | Element to be put in SortBuffer | | | | FUNCTION | | | | Put element into SortBuffer and reheap if neccesary. | | Function takes into account fact that SortBuffer can be | | allocated only in "real" memory. | | | | RETURNS | | | | Nothing. | | | |_________________________________________________________________| * */
void NEAR Store(RBTYPE element) {
RBTYPE *VMp;
#if AUTOVM
if (fInMemOnly) { SortBuffer[symMac++] = element; } else { symMac++; if (symMac > LastInBuf) { VMp = VMBuffer(symMac); *VMp = element; markvp(); } else SortBuffer[symMac] = element;
#if SORTDEBUG
fprintf(stdout, " \r\nAFTER ADDING element "); DumpElement(symMac, cmpf == FGtAddr); #endif
SiftUp(symMac);
#if SORTDEBUG
fprintf(stdout, "\r\nVerifying Sort Buffer - size = %u ", symMac); CheckSortBuffer(1,symMac); #endif
} #else
SortBuffer[symMac++] = element; #endif
return; }
/*_________________________________________________________________*
| | | NAME | | | | InitSort | | | | INPUT | | | | Nothing. | | | | FUNCTION | | | | Initialize global variables used by INCREMENTAL module. | | Function takes into account fact that SortBuffer can be | | allocated only in "real" memory and if this is true than | | QUICKSORT instead of HEAPSORT to sort the SortBuffer. | | | | RETURNS | | | | Nothing. | | | |_________________________________________________________________| * */
void NEAR InitSort(RBTYPE **buf, WORD *base1, WORD *lim1, WORD *base2, WORD *lim2 ) {
RBTYPE *VMp; RBTYPE first, last; unsigned n, lx;
if (fInMemOnly) { /* SortBuffer allocated only in "real" memory - use QUICKSORT */
qsort(SortBuffer, symMac, sizeof(RBTYPE), (int (__cdecl *)(const void *, const void *)) cmpf); *base1 = 0; *lim1 = symMac; *base2 = symMac + 1; *lim2 = symMac + 1; } #if AUTOVM
else { /* SortBuffer allocated in "real" and "virtual" memory - use HEAPSORT */
for (n = 1, lx = symMac; lx > 2; n++, lx--) { if (lx > LastInBuf) { VMp = VMBuffer(lx); last = *VMp; } else last = SortBuffer[lx];
first = SortBuffer[1]; SortBuffer[1] = last;
if (lx > LastInBuf) { *VMp = first; markvp(); } else SortBuffer[lx] = first;
SiftDown(lx - 1); }
first = SortBuffer[1]; SortBuffer[1] = SortBuffer[2]; SortBuffer[2] = first; *base1 = 1; *lim1 = (symMac < LastInBuf) ? symMac + 1 : LastInBuf + 1; *base2 = *lim1; *lim2 = symMac + 1; } #endif
*buf = SortBuffer; }
#if AUTOVM
/*_________________________________________________________________*
| | | NAME | | | | GetSymPtr | | | | INPUT | | | | Index in SortBuffer. | | | | FUNCTION | | | | Get element from "virtual" portion of SortBuffer. | | | | RETURNS | | | | Retrieved element. | | | |_________________________________________________________________| * */
RBTYPE NEAR GetSymPtr(unsigned n) { RBTYPE *VMp; RBTYPE RetVal;
VMp = VMBuffer(n); RetVal = *VMp; return(RetVal); }
#endif
/*_________________________________________________________________*
| | | NAME | | | | AllocSortBuffer | | | | INPUT | | | | Max number of elements to be sorted and sorting order flag.| | | | FUNCTION | | | | Allocate space for SortBuffer and set pointer to test | | function accordingly to sorting order flag. | | | | RETURNS | | | | Nothing. | | | |_________________________________________________________________| * */
void NEAR AllocSortBuffer(unsigned max, int AOrder) {
extern short pimac; unsigned long SpaceAvail; unsigned long SpaceNeeded; unsigned long VMBufferSize;
/*
* Determine how much space is available on near heap and how much * we need. Assume ascending sort order. Set number of elements * in "real" portion of SortBuffer. */
SpaceNeeded = (long)(max + 1) * sizeof(RBTYPE); LastInBuf = (WORD) max; fInMemOnly = (FTYPE) TRUE; TestFun = AscendingOrder; TestFunS = AscendingOrderSharp; #if OSMSDOS AND AUTOVM
SpaceAvail = _memmax();
if (SpaceNeeded > SpaceAvail) { /*
* We need more than there is available - try deallocate * VM page buffers */
if (pimac > 8) { /* For perfomance reasons we need at least 8 page buffer */
VMBufferSize = 8 * PAGLEN;
/* Cleanup near heap by relaiming all virtual memory page buffers */
FreeMem(ReclaimVM(MAXBUF * PAGLEN)); } else VMBufferSize = 0;
/* Check how much is now available */
SpaceAvail = _memmax() - VMBufferSize;
if (SpaceNeeded > SpaceAvail) fInMemOnly = FALSE; /* Sorting buffer will be split between "real" and "virtual" memory */ else SpaceAvail = SpaceNeeded;
/* Calculate how many elements can go into "real" part of SortBuffer */
LastInBuf = (unsigned)SpaceAvail / sizeof(RBTYPE);
/* Allocate space for SortBuffer */
SortBuffer = (RBTYPE *) GetMem(LastInBuf * sizeof(RBTYPE));
LastInBuf--; fVMReclaim = (FTYPE) TRUE;
/*
* If descending sort order was requested and SortBuffer is split * between "real" and "virtual" memory change test function. */
if (!fInMemOnly && !AOrder) { TestFun = DescendingOrder; TestFunS = DescendingOrderSharp; }
return; } #endif
/* There is space available so take it. */
SortBuffer = (RBTYPE *) GetMem((unsigned)SpaceNeeded); fVMReclaim = FALSE; return; }
/*_________________________________________________________________*
| | | NAME | | | | FreeSortBuffer | | | | INPUT | | | | Nothing. | | | | FUNCTION | | | | Free space allocated for SortBuffer and if neccesary | | perform near heap cleanup by reclaiming all VM | | page buffers. | | | | RETURNS | | | | Nothing. | | | |_________________________________________________________________| * */
void NEAR FreeSortBuffer(void) { extern short pimac, pimax;
if (SortBuffer != NULL) FFREE(SortBuffer); }
|