windows-nt/Source/XPSP1/NT/sdktools/link16/hsort.c

951 lines
32 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*_________________________________________________________________*
| |
| 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);
}