You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
706 lines
25 KiB
706 lines
25 KiB
;----------------------M O D U L E H E A D E R----------------------------;
|
|
; ;
|
|
; Module Name: SORT.ASM ;
|
|
; ;
|
|
; History: SORT.C ;
|
|
; Created by Charles Whitmer 12/30/1986 ;
|
|
; Modified by Mitchel B. London 08/05/1987 ;
|
|
; ;
|
|
; SORT.ASM - translation of SORT.C ;
|
|
; CreateModule David Weise ;
|
|
; Other Modules Amit Chatterjee 08/09/1988 ;
|
|
; ;
|
|
; Copyright (c) 1985 - 1988 Microsoft Corporation ;
|
|
; ;
|
|
; General Description: ;
|
|
; ;
|
|
; The SORT module creates and maintains a tree of nodes, each node ;
|
|
; having a KEY value and a TAG field. The KEY field is used to or- ;
|
|
; -ganize the tree into a heap. ;
|
|
; The heap tree is implemented using an array, where if ;
|
|
; parent node occurs in position i, its left child will be at index ;
|
|
; (2 * i) and the right chaild at index (2 * i + 1). ;
|
|
; The Module ensures that at any instant, the root node ;
|
|
; of any subtree has the least key value in the subtree. ;
|
|
; First few positions in the array are used for storing ;
|
|
; a header for the tree. ;
|
|
; ;
|
|
; SubModules: ;
|
|
; ;
|
|
; 1. CreatePQ: ;
|
|
; Allocates space for the heaptree and its header ;
|
|
; and initializes the header. ;
|
|
; 2. InsertPQ: ;
|
|
; Inserts a node into the heap ensuring that the heap ;
|
|
; property is not violated. ;
|
|
; 3. MinPQ: ;
|
|
; Returns the tag value associated with the lowest ;
|
|
; key in the heap. (node is not deleted) ;
|
|
; 4. ExtractPQ: ;
|
|
; Return the tag value associated with the lowest key ;
|
|
; in the heap and deletes the node. The heap is then ;
|
|
; reconstructed with the remaining nodes. ;
|
|
; 5. DeletePQ: ;
|
|
; Deletes the entire heap by freeing the allocated ;
|
|
; area. ;
|
|
; 6. SizePQ: ;
|
|
; Increases the size of the heap by adding space ;
|
|
; for a requested number of entries ;
|
|
; Heap Data Structure: ;
|
|
; ;
|
|
; The heap data structure has two parts, a header and a set of nodes and ;
|
|
; these are blocked one after the other. ;
|
|
; The header maintains: ;
|
|
; (i) A pointer to the next available node slot ;
|
|
; relative to start of the node area ;
|
|
; (ii) A pointer to the first valid node slot ;
|
|
; node slots between the header and this pointer ;
|
|
; are actually deleted nodes ;
|
|
; (iii) A pointer past the last allocated node slot ;
|
|
; (iv) A last key value, which either holds the largest;
|
|
; key value as long as the nodes are sequentially ;
|
|
; ordered, or a very large value to indicate there;
|
|
; is no sequential ordering ;
|
|
; ;
|
|
; ---------------- ;
|
|
; | INDEX | ---- Pointer to next available node slot ;
|
|
; ---------------- ;
|
|
; | MAXENTRY | ---- Pointer past last allocated node slot ;
|
|
; ---------------- ;
|
|
; START | LASTKEY | ---- Aslong as possible holds max key ;
|
|
; NODE | START | ---- pointer to first active node slot ;
|
|
; ---------------- ;
|
|
; | KEY | ---- Node 1. ;
|
|
; | TAG | ;
|
|
; //---------------// ;
|
|
; | KEY | ---- Last allocated node slot ;
|
|
; | TAG | ;
|
|
; ---------------- ;
|
|
; ;
|
|
; All pointers to nodes are relative to node 1 (pointer to node 1 is ZERO) ;
|
|
;----------------------------------------------------------------------------;
|
|
;----------------------------------------------------------------------------;
|
|
; Include File Section and definitions: ;
|
|
; ;
|
|
|
|
.xlist
|
|
include cmacros.inc
|
|
include gdimacro.inc
|
|
include gdimem.inc
|
|
.286p
|
|
.list
|
|
|
|
START equ SIZE PQ - SIZE ENTRY ; The header includes Node 0
|
|
|
|
VERYLARGE equ 4000h ; assumed to be larger than any key
|
|
PQERROR equ -1 ; return value on error
|
|
TRUE equ 1
|
|
FALSE equ 0
|
|
|
|
Entry struc
|
|
e_key dw ? ; key value of node
|
|
e_tag dw ? ; corresponding tag value
|
|
Entry ends
|
|
|
|
PQ struc ; HEAP Header Structure + Start Node
|
|
pq_index dw ?
|
|
pq_maxentry dw ? ; excludes START NODE
|
|
pq_lastkey dw ?
|
|
pq_start dw ?
|
|
PQ ends
|
|
|
|
|
|
externFP GlobalLock
|
|
externFP GlobalUnlock
|
|
externFP GlobalReAlloc
|
|
externFP GlobalFree
|
|
externFP GlobalAlloc ; Defined in HELPER.ASM
|
|
|
|
createSeg _SORT,SORT,byte,public,CODE
|
|
sBegin SORT
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
; ;
|
|
;CreatePQ: ;
|
|
; Inputs: ;
|
|
; Max Number of entries the tree will hold ;
|
|
; Outputs: ;
|
|
; HANDLE to Heap -- if creation successful ;
|
|
; PQERROR if failure ;
|
|
; Registers Preserved: ;
|
|
; DI,SI ;
|
|
; ;
|
|
; -by- David Weise [davidw] ;
|
|
; ;
|
|
;-----------------------------------------------------------------------------;
|
|
|
|
assumes cs,SORT
|
|
assumes ds,nothing
|
|
|
|
cProc farGDIGlobalAlloc,<FAR,PUBLIC>
|
|
|
|
parmd amount
|
|
cBegin
|
|
cCall GlobalAlloc,<GMEM_MOVEABLE+GMEM_SHARE,amount>
|
|
cEnd
|
|
|
|
cProc CreatePQ,<FAR,PUBLIC,NODATA>,<di,si>
|
|
parmW cEntries
|
|
|
|
cBegin
|
|
mov ax,cEntries ; max no of nodes the tree will hold
|
|
shl ax,1
|
|
shl ax,1 ; ax <---- ax * SIZE ENTRY
|
|
.errnz (SIZE ENTRY - 4)
|
|
mov si,ax ; save number of bytes in node array
|
|
add ax, SIZE PQ ; size of header including NODE 0
|
|
xor dx,dx
|
|
cCall farGDIGlobalAlloc,<dx,ax>
|
|
mov bx,ax ; Handle returned
|
|
dec ax ; set to -1 if handle returned == 0
|
|
.errnz (-1 - PQERROR)
|
|
or bx,bx ; test for succesfull memory allocation
|
|
jz cPQ_Done ; error return.
|
|
push bx
|
|
cCall GlobalLock,<bx> ; lock handle get back segment
|
|
pop bx
|
|
mov es,dx
|
|
mov di,ax ; es:di points to start of structure
|
|
|
|
; now initialize the header part of the structure with values
|
|
; si has size of the node array
|
|
|
|
stosw ; index set to zero
|
|
.errnz (0 - pq_index)
|
|
mov ax,si ; pointer past end of node array
|
|
stosw ; max no of entries
|
|
.errnz (2 - pq_maxentry)
|
|
xor ax,ax ; last key = 0, as heap empty
|
|
stosw
|
|
.errnz (4 - pq_lastkey)
|
|
stosw ; START = 0, implies no deleted slot
|
|
.errnz (6 - pq_start)
|
|
|
|
push bx
|
|
cCall GlobalUnlock,<bx> ; unlock the handle to heap
|
|
pop ax ; return the handle
|
|
|
|
cPQ_Done:
|
|
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
; ;
|
|
; InsertPQ: ;
|
|
; Inputs: ;
|
|
; hPQ -- handle to heap structure segment ;
|
|
; tag -- tag value for new node ;
|
|
; key -- key value for new node ;
|
|
; Outputs: ;
|
|
; return TRUE if insertion was successful ;
|
|
; return PQERROR if heap was already packed ;
|
|
; Preserves: ;
|
|
; DS,SI ;
|
|
; ;
|
|
; -by- Amit Chatterjee [amitc] Tue Aug 9 10:45:25 ;
|
|
;-----------------------------------------------------------------------------
|
|
|
|
assumes cs,SORT
|
|
assumes ds,nothing
|
|
|
|
cProc InsertPQ,<FAR,PUBLIC,NODATA>,<di,si>
|
|
parmW hPQ
|
|
parmW tag
|
|
parmW key
|
|
|
|
cBegin
|
|
mov di,hPQ
|
|
cCall GlobalLock,<di> ; lock heap and get back segment addres
|
|
or ax,dx ; Invalid handle causes zero return
|
|
jz Ins_Cant_Proceed
|
|
mov es,dx
|
|
xor si,si ; offset in segment always zero
|
|
mov ax,es:[si] ; pointer to next available slot
|
|
sub ax,es:[si].pq_start ; convert it relative to 1st active node
|
|
cmp ax,es:[si].pq_maxentry ; compare with pointer past last slot
|
|
jb Insertion_Possible
|
|
cCall GlobalUnlock,<di>
|
|
Ins_Cant_Proceed:
|
|
mov ax,PQERROR ; error return
|
|
jmp cInsert_Done
|
|
|
|
Insertion_Possible:
|
|
push es ; HEAP structure segment
|
|
smov es,ds ; save local segment in es
|
|
pop ds ; change DS to heap segment
|
|
mov ax,[si].pq_index ; next available slot in node area
|
|
cmp ax,[si].pq_maxentry
|
|
jb Enough_Space_Atend ; insertion possible w/o compaction
|
|
|
|
; Deleted nodes exist near the head of the tree, compaction necessary
|
|
call CompactList ; removes all deleted elements
|
|
|
|
; LASTKEY still holds the max key value in the tree
|
|
|
|
Enough_Space_Atend:
|
|
mov bx,[si].pq_index ; pointer to next available slot
|
|
mov dx,bx ; save value in register
|
|
add bx,SIZE PQ ; area for header
|
|
mov ax,tag
|
|
mov [si][bx].e_tag,ax ; insert new tag and key
|
|
mov ax,key
|
|
mov [si][bx].e_key,ax ; key in ax will be used below
|
|
mov bx,dx ; bx points to last occupied slot
|
|
add dx,SIZE ENTRY ; available slot points to next node
|
|
mov [si].pq_index,dx ; save in the structure
|
|
|
|
; Now test whether the heap property is valid still.
|
|
; ax has key, dx has pointer to next slot after addition
|
|
; bx points to last valid node
|
|
|
|
cmp ax,[si].pq_lastkey ; compare with new key
|
|
jb Heap_Violated
|
|
mov [si].pq_lastkey,ax ; new key is the largest key in tree
|
|
jmp short Heap_Restructured ; Insertion over
|
|
|
|
comment ~
|
|
|
|
node i has lchild at 2*i and rchild at 2*i+1. But we maintain their
|
|
address relative to start of node array. [ie node 1 has addr 0,
|
|
node 2 has 4, node 3 12 and so on.]
|
|
so if x happens to be the address of a node, the address of its
|
|
parent is (x/2 -2) AND 0fffch.
|
|
if x is the address of a parent, the address of its lchild is 2*x + 4
|
|
and that of its rchild is 2*x + 8
|
|
|
|
end comment ~
|
|
|
|
Heap_Violated:
|
|
call CompactList ; make sure heap is compacted first!
|
|
mov [si].pq_lastkey,VERYLARGE ; to imply heap nolonger seq. ordered
|
|
mov bx,[si].pq_index ; bx = offset of inserted elem.
|
|
sub bx,SIZE ENTRY
|
|
|
|
Heap_Walk_Loop:
|
|
cmp bx,[si].pq_start ; traversed to top of heap ?
|
|
jz Heap_Restructured
|
|
mov cx,bx
|
|
shr cx,1 ; cx points to parent of current node
|
|
dec cx
|
|
dec cx
|
|
and cx,0fffch ; refer to comment above
|
|
.errnz (SIZE ENTRY - 4)
|
|
|
|
; Test whether current node has to move up or not, if not it resets carry
|
|
; else it swaps the two nodes and sets carry
|
|
|
|
call TestShuffle
|
|
mov bx,cx ; next node to inspect ifnec. is parent
|
|
jc Heap_Walk_Loop
|
|
|
|
Heap_Restructured:
|
|
smov ds,es ; get back own segment in ds
|
|
cCall GlobalUnlock,<di> ; di still has the handle
|
|
mov ax,di ; return true
|
|
|
|
cInsert_Done:
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
; TestShuffle: ;
|
|
; ;
|
|
; Takes as input the node addresses of a parent and on of it's childs. If the;
|
|
; key of the parent is >= key of the child, it returns with carry clear, else;
|
|
; it swaps the two nodes and returns with carry set. ;
|
|
; ;
|
|
; bx has current node address in HEAP, relative to start NODE 1 ;
|
|
; cx has address of parent node of bx ;
|
|
; ;
|
|
; -by- Amit Chatterjee [amitc] Tue Aug 9 12:00:00 ;
|
|
;-----------------------------------------------------------------------------;
|
|
|
|
cProc TestShuffle,<NEAR,PUBLIC>,<si,di>
|
|
|
|
cBegin
|
|
lea di,[si][SIZE PQ] ; di points to node 1
|
|
add di,cx ; di points to parent
|
|
lea si,[bx].SIZE PQ ; si points to child node
|
|
mov ax,[si].e_key ; childs key
|
|
cmp ax,[di].e_key ; key of parent
|
|
jb Nodes_Tobe_Swapped
|
|
;
|
|
; Carry cleared by comparision, use for return
|
|
;
|
|
jmp short TestShuffle_Ret
|
|
|
|
Nodes_Tobe_Swapped:
|
|
;
|
|
; Carry has been set by comparision, use for return
|
|
;
|
|
xchg ax,[di].e_key
|
|
mov [si].e_key,ax
|
|
mov ax,[si].e_tag
|
|
xchg ax,[di].e_tag
|
|
mov [si].e_tag,ax ; swap complete
|
|
TestShuffle_Ret:
|
|
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
; MinPQ: ;
|
|
; Inputs: ;
|
|
; hPQ -- Handle to the heap structure ;
|
|
; Outputs: ;
|
|
; minimum tag value in the tree or PQERROR(if invalid handle) ;
|
|
; ;
|
|
; Calls Local Procedure GetMinPQ. ;
|
|
; GetMinPQ takes the handle and a flag as parameter. ;
|
|
; If the flag is TRUE, the node with the least key is deleted ;
|
|
; GetMinPQ also returns the tag value of least key in AX ;
|
|
; ;
|
|
; ;
|
|
; -by- Amit Chatterjee [amitc] Tue Aug 9 12:46:10 ;
|
|
;-----------------------------------------------------------------------------;
|
|
|
|
assumes cs,SORT
|
|
assumes ds,nothing
|
|
|
|
cProc MinPQ,<FAR,PUBLIC,NODATA>
|
|
; parmW hPQ
|
|
|
|
cBegin nogen
|
|
|
|
mov cl,FALSE ; to imply node not to be deleted
|
|
jmpnext ; fall through trick, refer cmacros
|
|
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
; ExtractPQ: ;
|
|
; Inputs: ;
|
|
; hPQ -- Handle to the heap structure ;
|
|
; Outputs: ;
|
|
; minimum tag value if heap handle is valid and heap not empty ;
|
|
; return PQERROR otherwise ;
|
|
; The node with min key is deleted ;
|
|
; Calls Local Procedure GetMinPQ ;
|
|
; ;
|
|
; -by- Amit Chatterjee [amitc] Tue Aug 9 12:54:00 ;
|
|
;-----------------------------------------------------------------------------;
|
|
|
|
assumes cs,SORT
|
|
assumes ds,nothing
|
|
|
|
cProc ExtractPQ,<FAR,PUBLIC,NODATA>
|
|
; parmW hPQ
|
|
|
|
|
|
cBegin nogen
|
|
|
|
mov cl,TRUE ; to imply that node to be deleted
|
|
jmpnext stop ; fall through trick, refer cmacros
|
|
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
; GetMinPQ: ;
|
|
; ;
|
|
; One of the inputs is a flag. If the flag is FALSE it simply returns the tag ;
|
|
; associated with the lease key value in the heap. If the flag is TRUE besides;
|
|
; returnning the above tag value it also deletes the node. ;
|
|
; ;
|
|
; ;
|
|
; hPQ --- handle of HEAP segment ;
|
|
; cl --- Deletion Flag ( Delete node if TRUE) ;
|
|
; ;
|
|
; -by- Amit Chatterjee [amitc] Tue Aug 9 13:00:00 ;
|
|
;-----------------------------------------------------------------------------;
|
|
|
|
cProc GetMinPQ,<FAR,PUBLIC,NODATA>,<di,si>
|
|
parmW hPQ
|
|
cBegin
|
|
mov di,hPQ
|
|
push cx ; save flag
|
|
cCall GlobalLock,<di>
|
|
pop cx ; get back flag into cl
|
|
or dx,ax ; invalid handle implies zero return
|
|
jz Min_Cant_Proceed
|
|
mov es,dx
|
|
mov si,ax ; ds:si points to heap start
|
|
mov bx,es:[si].pq_start ; pointer to 1st. available slot
|
|
cmp bx,es:[si].pq_index ; empty if equal to next available node
|
|
jb Heap_Not_Empty
|
|
cCall GlobalUnlock,<di>
|
|
|
|
Min_Cant_Proceed:
|
|
mov ax,PQERROR
|
|
jmp cGetMin_Done ; error return
|
|
|
|
; bx still has [si].pq_start
|
|
|
|
Heap_Not_Empty:
|
|
push es ; save heap segment
|
|
smov es,ds ; save local segment is es
|
|
pop ds ; ds:si points to start of heap
|
|
lea dx,[si][SIZE PQ]
|
|
add dx,bx ; points past deleted nodes
|
|
xchg di,dx ; save di in dx and use dx's value
|
|
mov ax,[di].e_tag ; get the tag associated with least key
|
|
xchg di,dx ; get back values
|
|
or cl,cl ; test for bl = FALSE
|
|
.errnz (0 - FALSE)
|
|
jnz Delete_Node ; TRUE implies get tag and delete node
|
|
jmp cGetMin_Ret ; return after unlocking heap
|
|
|
|
Delete_Node:
|
|
|
|
; bx retains [si].start
|
|
|
|
add bx,SIZE ENTRY ; one more node deleted
|
|
cmp bx,[si].pq_index ; is tree empty ?
|
|
jb Tree_Not_Empty
|
|
xor cx,cx
|
|
mov [si].pq_lastkey,cx ; initialize for empty tree
|
|
mov [si].pq_start,cx ; initialize for empty tree
|
|
mov [si].pq_index,cx
|
|
jmp cGetMin_Ret ; return after unlocking heap
|
|
|
|
Tree_Not_Empty:
|
|
|
|
; ax has return tag value
|
|
; bx has [si].pq_start + SIZE ENTRY
|
|
|
|
cmp [si].pq_lastkey,VERYLARGE ; implies keys in random order
|
|
jae Min_Restructure_Heap ; maybe restructuring necessary
|
|
mov [si].pq_start,bx ; updates past deleted entry
|
|
jmp cGetMin_Ret
|
|
|
|
Min_Restructure_Heap:
|
|
|
|
; dx still has offset to NODE 1, because
|
|
; if LASTKEY = VERYLARGE, pq_start has to be zero
|
|
|
|
push ax ; save return tag value
|
|
mov bx,dx ; offset to first active node
|
|
xchg di,dx ; get pointer into di ,save di
|
|
add di,[si].pq_index ; dx points to next available slot
|
|
sub di,SIZE ENTRY ; point to last filled node
|
|
mov ax,di ; last node being moved upfront
|
|
sub ax,SIZE PQ ; point ax one node ahead of last
|
|
mov [si].pq_index,ax ; update it
|
|
mov cx,[di].e_key
|
|
mov [bx].e_key,cx ; move from last position to NODE 1
|
|
mov cx,[di].e_tag
|
|
mov [bx].e_tag,cx
|
|
xchg di,dx ; restore di,dx
|
|
xor cx,cx ; start traversing heap from root
|
|
|
|
|
|
Min_Traverse_Heap:
|
|
mov bx,cx
|
|
shl bx,1
|
|
add bx,SIZE ENTRY ; bx has left child addr of parent in cx
|
|
cmp bx,[si].pq_index ; compare with next available slot
|
|
jae Min_Heap_Fixed ; heap restored
|
|
push cx ; save current parent
|
|
mov cx,bx ; have lchild in cx
|
|
add cx,SIZE ENTRY ; cx now get address of rchild
|
|
cmp cx,[si].pq_index ; test against last node
|
|
jae Right_Child_Not_Present
|
|
call GetLesserChild ; gets child with lesser key in bx
|
|
|
|
Right_Child_Not_Present:
|
|
pop cx ; get back parent
|
|
;
|
|
; cx has node number of parent node and bx has node no of child node with
|
|
; least key. If parents key value is greater it should be swapped
|
|
;
|
|
call TestShuffle
|
|
|
|
; swaps the two nodes if necessary.
|
|
|
|
mov cx,bx ; lesser child is next parent
|
|
jmp Min_Traverse_Heap
|
|
|
|
Min_Heap_Fixed:
|
|
pop ax ; get back return tag value
|
|
cGetMin_Ret:
|
|
push ax ; save return value
|
|
smov ds,es ; get back own ds
|
|
cCall GlobalUnlock,<di> ; unlock heap
|
|
pop ax ; get back return value
|
|
cGetMin_Done:
|
|
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
; GetLesserChild: ;
|
|
; ;
|
|
; Given two child node numbers, it returns the child which has a lesser key ;
|
|
; ;
|
|
; cx has RCHILD NODE address ;
|
|
; bx has LCHILD NODE address ;
|
|
; si points to start of heap ;
|
|
; will return node address of lesser child in bx ;
|
|
; ;
|
|
; -by- Amit Chatterjee [amitc] Tue Aug 9 13:50 ;
|
|
;-----------------------------------------------------------------------------;
|
|
|
|
|
|
cProc GetLesserChild,<NEAR,PUBLIC,NODATA>,<di,si>
|
|
|
|
cBegin
|
|
lea di,[si][SIZE PQ] ; dx now points to NODE 1
|
|
mov si,di ; si also points to start of NODE 1
|
|
add di,cx ; di get address of rchild
|
|
mov ax,[si+bx].e_key ; rchilds key
|
|
cmp ax,[di].e_key ; compare with rchild
|
|
jb Right_Child_Lesser ; bx still has the correct child no.
|
|
mov bx,cx ; get RCHILD address into bx
|
|
Right_Child_Lesser:
|
|
|
|
cEnd
|
|
;
|
|
;-----------------------------------------------------------------------------;
|
|
; DeletePQ: ;
|
|
; Inputs: ;
|
|
; hPQ --- handle to a heap structure ;
|
|
; OutPuts: nothing ;
|
|
; Preserves: DI ;
|
|
; ;
|
|
; -by- Amit Chatterjee [amitc] Tue Aug 9 14:15:45 ;
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
assumes cs,SORT
|
|
assumes ds,nothing
|
|
|
|
cProc DeletePQ,<FAR,PUBLIC,NODATA>
|
|
parmW hPQ
|
|
|
|
cBegin
|
|
cCall GlobalFree,<hPQ> ; free the handle
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
;SizePQ: ;
|
|
; Input: ;
|
|
; hPQ --- Handle to a heap structure ;
|
|
; entry --- number of nodes by which heap is to be expanded ;
|
|
; Output: ;
|
|
; Returns the total number of node slots in new heap, if successful
|
|
; else return PQERROR ;
|
|
; ;
|
|
; -by- Amit Chatterjee [amitc] Tue Aug 9 14:31:40 ;
|
|
;-----------------------------------------------------------------------------
|
|
|
|
assumes cs,SORT
|
|
assumes ds,nothing
|
|
|
|
cProc SizePQ,<FAR,PUBLIC,NODATA>,<si,di>
|
|
parmW hPQ
|
|
parmW cEntry
|
|
|
|
cBegin
|
|
mov di,hPQ
|
|
cCall GlobalLock,<di> ; lock to get back segment address
|
|
or ax,dx ; Invalid handle implies NULL return
|
|
jz Siz_Cant_Proceed
|
|
mov es,dx
|
|
xor si,si ; offset will always be zro
|
|
mov ax,cEntry ; additional nodes
|
|
or ax,ax ; if zero return original numof nodes
|
|
jnz Size_Tobe_Increased
|
|
mov ax,es:[si].pq_maxentry ; offset past last node
|
|
shr ax,1
|
|
shr ax,1 ; ax <--- ax / SIZE ENTRY
|
|
.errnz (SIZE ENTRY - 4)
|
|
jmp short cSize_Ret ; return after unlocking handle
|
|
|
|
Size_Tobe_Increased:
|
|
shl ax,1
|
|
shl ax,1 ; ax <-- ax * SIZE ENTRY, = extra bytes
|
|
.errnz (SIZE ENTRY - 4)
|
|
add ax,es:[si].pq_maxentry ; number of byte for new node array
|
|
cmp ax,es:[si].pq_index ; next available slot
|
|
jae Valid_Increase
|
|
mov ax,PQERROR ; error code
|
|
jmp short cSize_Ret ; return after releasing handle
|
|
|
|
Valid_Increase:
|
|
push ax ; save number of bytes in node block
|
|
add ax,SIZE PQ ; size of header
|
|
push ax
|
|
cCall GlobalUnlock,<di> ; unlock handle
|
|
xor dx,dx ; high word for size
|
|
pop ax ; get back size
|
|
cCall GlobalReAlloc,<di,dx,ax,GMEM_MOVEABLE>
|
|
or ax,ax
|
|
jz Siz_Cant_Proceed
|
|
mov di,ax ; new handle
|
|
cCall GlobalLock,<ax> ; lock it
|
|
mov es,dx ; set new segment
|
|
pop cx ; get back total no of nodes into cx
|
|
jmp short Reloc_Successful
|
|
Siz_Cant_Proceed:
|
|
pop cx ; balance stack
|
|
dec ax
|
|
.errnz (-1 - PQERROR)
|
|
jmp short cSize_End
|
|
|
|
Reloc_Successful:
|
|
mov es:[si].pq_maxentry,cx ; total number of slots now
|
|
shr cx,1
|
|
shr cx,1 ; no of nodes = bytes / SIZE ENTRY
|
|
.errnz (SIZE ENTRY - 4)
|
|
mov ax,cx ; return value
|
|
cSize_Ret:
|
|
cCall GlobalUnlock,<di>
|
|
cSize_End:
|
|
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
;CompactList: ;
|
|
; Input: ;
|
|
; ds:si --- pointer to heap structure ;
|
|
; Output: ;
|
|
; all deleted elements are removed from heap structure ;
|
|
; Registers trashed:
|
|
; AX,BX,CX,DX
|
|
;
|
|
; -by- Ken Sykes [kensy] Tue Nov 12 1991 10:20:00am ;
|
|
;-----------------------------------------------------------------------------
|
|
|
|
CompactList proc near
|
|
mov ax,[si].pq_index ; next available slot in node area
|
|
sub ax,[si].pq_start ; ax had pointer to available slot
|
|
mov [si].pq_index,ax ; next available slot will come up
|
|
lea dx,[si][SIZE PQ] ; points to NODE 1
|
|
mov ax,[si].pq_start ; pointer to 1st active node rel to 1
|
|
add ax,dx ; ax has offset to first valid node.
|
|
mov bx,ax
|
|
mov cx,[si].pq_maxentry ; pointer past end of node slots
|
|
sub cx,[si].pq_start ; pointer to strt of active block
|
|
shr cx,1 ; will do a REP MOVSW
|
|
.errnz (1 and SIZE ENTRY)
|
|
push es ; es has local segment
|
|
smov es,ds ; moth es ds point to heap segment
|
|
push si
|
|
push di ; save start to heap and its handle
|
|
mov si,bx ; si points to start of valid nodes
|
|
mov di,dx ; dx points to node 1
|
|
cld
|
|
rep movsw ; Compacted
|
|
pop di
|
|
pop si
|
|
pop es ; restore local segment in es
|
|
mov [si].pq_start,cx ; after compaction deleted nodes = 0
|
|
ret
|
|
CompactList endp
|
|
|
|
;-----------------------------------------------------------------------------;
|
|
|
|
sEnd SORT
|
|
|
|
end
|