;/* IL_SORT.ASM
;
COMMENT ~ 

PDC Prolog 3.31 & Visual Prolog 4/5(tm) ASSEMBLY LANGUAGE EXTENSIONS
====================================================================

	Ultra-fast SORTING PREDICATES for Integer-Lists:
        ------------------------------------------------

GLOBAL PREDICATES
  unsigned il_sort(IL) 	   -(i) language c
  unsigned il_sortndup(IL) -(i) language c


% Visual/PDC PROLOG NOTES
% %%%%%%%%%%%%%%%%%%%%%%%
%
%  These predicates are incredibly fast, and of 'linear complexity'
%  (proportional to N, where N is the number of list-elements).
%
%  The algorithm used in the ASSEMBLY source-code of these predicates
%  is a variant of Radix-Sort, probably the fastest Sort in the world.
%
%  The second predicate also eliminates duplicates from the list while
%  sorting it, and is slightly faster than the first.



%========================================================================
~

; Visual/PDC Prolog Memory-Allocation Functions:
	extrn _MEM_MarkGStack:far
	extrn _MEM_AllocGStack:far
	extrn _MEM_ReleaseGStack:far
	extrn _MEM_AdjustGStackAlloc:far

	IDEAL
	MODEL	large

	DATASEG

t512a	dw 256 dup (0)

	CODESEG

P386N

; ========================== LOCAL PROCEDURES: ==========================

PROC phase_1 near
	push	ds		;
	 cld			;forwards
; ***********************************************************************
; ***** PHASE 'ZERO': Clear the 512-byte-"HISTOGRAM table" (t512a): *****
; ***********************************************************************
	 mov	si,di		;make SI=offset_of_list
	 mov	ax,es		;
	 mov di,offset DS:t512a	;
	 mov	bx,ds		;	 
	 mov	ds,ax		;make DS:SI=list
	 mov	es,bx		;make ES:DI=local_table
	 mov	cx,128	;make cx=128 (times 4 this is 512)
	 xor	eax,eax	;use eax for clearing 512 bytes
	 mov	bx,di	;save table1_offset also in bx
	 rep	stosd	;clear 512 bytes in table1
	 mov	di,bx	;recover table-1 offset from bx
; ***********************************************************************
; *** PHASE ONE: Record a HISTOGRAM of hi-bytes occurrences in t512a: ***
; ***********************************************************************
	 xor	cx,cx		;number_of_elements_Counter
	 jmp short @@Nx1	;
; ===============================
@@EL1:	 inc	si		;
	 lodsb			;load hi-byte
	 xor	AL,128		;
	 mov	bl,al		;
	 xor	bh,bh	;prepare BX as an array-index-assistant
	 shl	bx,1	;times 2 (since words, not bytes)
MASM
	 mov dx,word ptr ES:[DI+BX]	;get current 'occurrences_number'
	 inc dx				;increase it
	 mov word ptr ES:[DI+BX],dx	;store the new value
IDEAL
	 inc	cx		;add 1 to Counter_of_elements
	 lodsw			;next pointer-offset in AX
	 mov	bx,ax		;also in BX
	 lodsw			;next pointer-segment in AX
	 mov 	ds,ax		;also in DS
	 mov	si,bx		;now offset also in SI
; ===============================
@@Nx1:	 lodsb		;load first byte of list-element
	 dec	al	;is list-element NORMAL? (=1)?
	 jz	@@EL1	;if so, continue loop,
	pop	ds	;
	ret
ENDP phase_1

; -----------------------------------------------------------------------


PROC phase_2 near
; ***********************************************************************
; **** PHASE TWO: Turn occurrence-numbers into "Hotel Reservations": ****
; ***********************************************************************
	 mov  si,di		;copy offset of table-1 also to SI
	 add  di,512		;make di=table2_offset (512 bytes later)
	 mov  dx,di		;put this also in DX
	 add  dx,512		;512 bytes later is 'tourist_buffer'
	 mov  ax,es		;
	 mov  ds,ax		;make table_segment = DS
	 xor  cl,cl		;clear CL to use it as an 'ASCII-counter'
	 jmp  short @@PH2	;go to middle of next loop
; ===============================
@@PH2a:	 stosw		;write (zero-)occurrences_number to table-2
	 inc  cl	;increment ascii-pointer;
	 jz @@PH2x	;when it becomes again zero (at ASCII 256), exit
; -------------------------------
@@PH2:	 lodsw		;load occurrences_number from table-1(histogram)
	 or ax,ax	;a zero?
         jz @@PH2a	;if so, write it as-it-is, and repeat
         xchg ax,dx	;else: swap {DX-occur/s_number,AX-DX}
	 stosw		;write DX (temporarily turned into AX),
	 xchg ax,dx	;then restore {DX,AX},
	 add dx,ax	;then add current_occurences_number to DX
	 inc cl		;then increment the ascii-pointer CL,
	 jnz @@PH2	;and till its 0 again repeat (256 times)
; ===============================
@@PH2x:  mov	cx,si	;
	 ret		;(now cx is table-2 offset, di is tourist_offset)
ENDP phase_2

; -----------------------------------------------------------------------


PROC phase_3 near
; ***********************************************************************
; *** PHASE THREE: Use "Hotel Reservations" to allocate tourists! :-) ***
; ***********************************************************************
	  jmp short @@Nx1	;
; ===============================
@@EL1:	  inc si
	  mov bl,byte ptr DS:SI	;load hi-byte of list into BL
	  xor	bl,128		;

	  xor bh,bh	;prepare BX as an array-index-assistant
	  shl bx,1	;times 2 (since words, not bytes)
	  mov di,cx	;put table2_offset in DI
	  dec si	;
MASM
	  mov di,word ptr ES:[DI+BX]	;load 'reservation_pointer' in DI
	  movsb				;copy byte from list to str_buf
	  inc	si			;advance once more
	  mov ax,di			;put the new DI in AX
	  mov di,cx			;put again in DI the table_offset
	  mov word ptr ES:[DI+BX],ax	;update the 'reservation_pointer'
IDEAL
	  lodsw			;next pointer-offset in AX
	  mov	dx,ax		;also in DX
	  lodsw			;next pointer-segment in AX
	  mov 	ds,ax		;also in DS
	  mov	si,dx		;now offset also in SI
; ===============================
@@Nx1:	  lodsb		;load first byte of list-element
	  dec	al	;is list-element NORMAL? (=1)?
	  jz	@@EL1	;if so, continue loop,
; =======================
	  ret
ENDP phase_3

; -----------------------------------------------------------------------

PROC phase_4a near
; ***********************************************************************
; **** Part of Phase_4_5 as well as Phase_4_5a (common code re-used) ****
; ***********************************************************************
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
; NOTE NOW: DS:SI = ES:SI ="local_binary_input", CX = number of elements,
; ES:DI = DS:DI =binary_output, AL="common character to write rightwards:
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
	     push  ax	;save ASCII-num. to write rightwards, temporarily
	      push di	;save the output_buffer_offset again, temporarily
	       push es	;save the output_buffer_segment
	        mov ax,ds	;
	        mov es,ax	;make ES=DS
	        mov di,dx	;use table2_offset as a "new destination"
	        mov bx,di	;save the table2-offset, also in bx
	        mov dx,cx	;save the "tourist group size" CX, in DX
	        mov cx,128	;use 128 (times 4 bytes) to clear table-2
	        xor eax,eax	;prepare empty register, to clear table-2
	        rep stosd	;clear 512 bytes (in table-2)
	        mov cx,dx	;recover CX (size of this group) from DX
	        mov di,bx	;recover table2_offset (DI) from bx
; ===============================
@@PH4d:	        lodsb		;load a byte from the "tourist_buffer"
	        mov	bl,al	;put it in BL
	        xor	bh,bh	;prepare BX as an array-index-assistant
	        shl	bx,1	;times 2 since words, not bytes
MASM
	        mov dx,word ptr ES:[DI+BX]	;get occurrences_number
	        inc	dx			;increment it once
	        mov word ptr ES:[DI+BX],dx	;store the new value
IDEAL
	        loop	@@PH4d	;repeat for all elements of this "group"
; ------------------------------> NOTE: di has remained unchanged!
	        mov	si,di	;now ES:SI=table2_start
	       pop	es	;recover binary_output_segment
	      pop       di	;recover binary_output_offset
	     pop        ax	;recover ASCII-byte to "write leftwards"
	     ret
ENDP phase_4a

; -----------------------------------------------------------------------

PROC phase_4_5 near
; ***********************************************************************
; *** PHASE FOUR: Return the "tourists" home... SORTED this time! :-) ***
; ***********************************************************************
; assumes: ES:DI=list(as output now),  DS:SI=table1(occurrences)
;	   DS:SI=table2(temporary), DS:[SI+1024]='tourist_buffer'
; =======================
        mov	dx,si	;copy offset of table-1 into DX
	add	dx,512	;now DX is offset of table-2(temporary)
	mov	bx,dx	;
	add	bx,512	;now BX is offset of 'tourist_buffer'
        push	dx	;save offset of table-2 in the stack
	 xor	cl,cl	;clear CL (to use it as "ASCII-counter")
; -----------------------------------------------------------------------
; NOW: si=occurrence_table_offset, dx=table2_offset, ES:DI=output_buffer,
;      bx=tourist_buffer_offset,   cl=ascii_counter (0..255, initially 0)
; =======================================================================	
	 inc	di		;increment list by 1 (skip first functor)
	 jmp short @@PH4m	;goto middle of next loop (the MAIN LOOP)
; -------------------------------
@@PH4:	 mov	dx,si	;save current_table1_offset inside DX
	 mov	si,bx	;put the current "tourist_offset" into SI
	 movsb		;copy 1 'tourist-byte' to "final output buffer",
	 mov	al,cl	;use as "companion-byte" the current ASCII-number
	 xor	al,128		;
	 stosb		;write this, too...
; =======================================
	 mov	eax,dword ptr ES:DI	;next list_offset_and_segment
	 mov	di,ax			;
	 shr	eax,16			;
	 mov	es,ax			;
	 inc	di			;skip list functor
; =======================================
	 mov	bx,si	;record the next output-pos. back into bx
	 mov	si,dx	;restore the table1_offset from DX, in SI
@@PH4b:	 inc	cl		;increment current ASCII-counter
	 jz short @@PH4x	;if again zero (i.e. 256) exit this loop!
; ======================================================================
; >>>>>>>>>>>>>>>> Middle of MAIN LOOP of "PHASE FOUR": &#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;
@@PH4m:	 lodsw		;(else) load the occurrences_number from table-1
	 or	ax,ax	;is it a zero?
	 jz	@@PH4b	;if so, no point in writing anything; just go on!
	 dec	ax	;else, one less (to "test for zero" more easily):
	 jz	@@PH4	;if 0 (i.e. a "lonely tourist") move the tourist!
; ====================== else, need to move en entire group of "tourists"
	pop	dx	;so.... recover start of table-2 (from the stack)
	push	dx	;and then save it again in the stack,
	 inc	 ax	;balance 'dec ax' so that ax="number_of_tourists"
	 push	 ax	;put this "tourist group"'s size :-) in the stack
	  push	 si	;save the current_offset of the occurrences_table
	   push  bx	;save the "tourist_buffer"'s offset in the stack,
	    push cx	;finally save the current "ASCII-counter" value,
	     xchg ax,cx	;swap ax (tourist_group_size) with CL (ascii-num)
	     mov  si,bx	;use the tourist_buffer offset as source-register
; ===============================
	     call phase_4a	;
; ===============================
; ***********************************************************************
; ************ PHASE FIVE (INNER LOOP within PHASE FOUR): ***************
; ***********************************************************************
; Now ds:si is a "local occurrence_table", ES:DI = original output_buffer
; and AL = "local common byte" (to write rightwards, after each element):
; =======================================================================
	     xor    cl,cl	;prepare CL as a 'local ascii-counter'
	     mov    ch,al	;move rightwardly_writeable char. to CH
	     XOR    CH,128	;
	     jmp short @@PH5	;jump to middle of next loop
; ===============================
@@PH5a:      inc    cl		;increment the 'local ascii-number', CL
	     jz     @@PH5b	;if reached 0 (i.e. 256) exit this loop!
; -------------------------------
@@PH5:	     lodsw		;(else) load "occurrences_number"
	     or     ax,ax	;is it a zero (i.e. no occurrences)?
	     jz     @@PH5a	;if so, don't write anything (but go on)
	     xchg   ax,cx	;now {AL,AH}=byte_pair, CX="occurrences"
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@@Ldump:     stosw		;write as many byte_pairs AS OCCURRENCES
	     mov ebx,dword ptr ES:DI	;
	     mov	di,bx		;
	     shr	ebx,16		;
	     mov	es,bx		;
             inc	di		;
	     loop	@@Ldump		;
;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;
	     mov    cx,ax	;restore CL=count,CH=char_right, from AX
	     inc    cl		;increment the "local ascii_counter", CL
	     jnz   @@PH5	;if not reached 0 (i.e. 256), repeat loop
; ///////////////////////////////////////////////////////////////////////
@@PH5b:	    pop  cx	;now retrieve the current "ASCII-Counter" value,
	   pop   bx	;and also recover the old "tourist_buffer_offset"
 	  pop    si	;and recover current offset of occurrences_table
	 pop	 ax	;also recover this "tourist group"'s size, in AX,
	 add	 bx,ax	;now add this to current offset of tourist_buffer
	 inc	 cl	;and finally increment the current ASCII-number,
	 jnz	 @@PH4m	;if not 0 (i.e.256) repeat PHASE FOUR's MAIN LOOP
; =======================================================================
@@PH4x:	pop	 cx	;balance the stack (for saving start of table-2)
	ret
ENDP phase_4_5

; -----------------------------------------------------------------------

PROC phase_4b near
; ***********************************************************************
; *********************** Part of Phase_nd_4_5  *************************
; ***********************************************************************
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
; NOTE NOW: DS:SI = ES:SI ="local_binary_input", CX = number of elements,
; ES:DI = DS:DI =binary_output, AL="common character to write rightwards:
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
	     push  ax	;save ASCII-num. to write rightwards, temporarily
	      push di	;save the output_buffer_offset again, temporarily
	       push es	;save the output_buffer_segment
	        mov ax,ds	;
	        mov es,ax	;make ES=DS
	        mov di,dx	;use table2_offset as a "new destination"
	        mov bx,di	;save the table2-offset, also in bx
	        mov dx,cx	;save the "tourist group size" CX, in DX
	        mov cx,64	;use 64 (times 4 bytes) to clear table-2
	        xor eax,eax	;prepare empty register, to clear table-2
	        rep stosd	;clear 256 bytes (in table-2)
	        mov cx,dx	;recover CX (size of this group) from DX
	        mov di,bx	;recover table2_offset (DI) from bx
; ===============================
@@PH4d:	        lodsb		;load a byte from the "tourist_buffer"
	        mov	bl,al	;put it in BL
	        xor	bh,bh	;prepare BX as an array-index-assistant
MASM
	        mov byte ptr ES:[DI+BX],al	;
IDEAL
	        loop	@@PH4d	;repeat for all elements of this "group"
; ------------------------------ NOTE: di has remained unchanged!
	        mov	si,di	;now ES:SI=table2_start
	       pop	es	;recover binary_output_segment
	      pop       di	;recover binary_output_offset
	     pop        ax	;recover ASCII-byte to "write leftwards"
	     ret
ENDP phase_4b

; -----------------------------------------------------------------------

PROC phase_nd_4_5 near
; ***********************************************************************
; *** PHASE FOUR: Return the "tourists" home... SORTED this time! :-) ***
; ***********************************************************************
; assumes: ES:DI=list(as output now),  DS:SI=table1(occurrences)
;	   DS:SI=table2(temporary), DS:[SI+1024]='tourist_buffer'
; =======================
	xor	edx,edx	;
        mov	dx,si	;copy offset of table-1 into DX
	add	dx,512	;now DX is offset of table-2(temporary)
	mov	bx,dx	;
	add	bx,512	;now BX is offset of 'tourist_buffer'
        push	dx	;save offset of table-2 in the stack
	 xor	cl,cl	;clear CL (to use it as "ASCII-counter")
; -----------------------------------------------------------------------
; NOW: si=occurrence_table_offset, dx=table2_offset, ES:DI=output_buffer,
;      bx=tourist_buffer_offset,   cl=ascii_counter (0..255, initially 0)
; =======================================================================	
	 inc	di		;increment list by 1 (skip first functor)
	 jmp short @@PH4m	;goto middle of next loop (the MAIN LOOP)
; -------------------------------
@@PH4:	 mov	dx,si	;save current_table1_offset inside DX
	 mov	si,bx	;put the current "tourist_offset" into SI
	 movsb		;copy 1 'tourist-byte' to "final output buffer",
	 mov	al,cl	;use as "companion-byte" the current ASCII-number
	 stosb		;write this, too...
; =======================================
	 mov	eax,dword ptr ES:DI	;next list_offset_and_segment
	 mov	di,ax			;
	 shr	eax,16			;
	 mov	es,ax			;
	 inc	di			;skip list functor
; =======================================
	 mov	bx,si	;record the next output-pos. back into bx
	 mov	si,dx	;restore the table1_offset from DX, in SI
	 ror	edx,16	;
	 inc	dx	;increment list-element counter
	 ror	edx,16	;
@@PH4b:	 inc	cl		;increment current ASCII-counter
	 jz short @@PH4x	;if again zero (i.e. 256) exit this loop!
; ======================================================================
; >>>>>>>>>>>>>>> Middle of MAIN LOOP of "PHASE FOUR": &#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;
@@PH4m:	 lodsw		;(else) load the occurrences_number from table-1
	 or	ax,ax	;is it a zero?
	 jz	@@PH4b	;if so, no point in writing anything; just go on!
	 dec	ax	;else, one less (to "test for zero" more easily):
	 jz	@@PH4	;if 0 (i.e. a "lonely tourist") move the tourist!
; ====================== else, need to move en entire group of "tourists"
	pop	dx	;so.... recover start of table-2 (from the stack)
	push	dx	;and then save it again in the stack,
	 inc	 ax	;balance 'dec ax' so that ax="number_of_tourists"
	 push	 ax	;put this "tourist group"'s size :-) in the stack
	  push	 si	;save the current_offset of the occurrences_table
	   push  bx	;save the "tourist_buffer"'s offset in the stack,
	    push cx	;finally save the current "ASCII-counter" value,
	     xchg ax,cx	;swap ax (tourist_group_size) with CL (ascii-num)
	     mov  si,bx	;use the tourist_buffer offset as source-register
; ===============================
	     call phase_4b	;
; ===============================
; ***********************************************************************
; ************ PHASE FIVE (INNER LOOP within PHASE FOUR): ***************
; ***********************************************************************
; Now ds:si is a "local occurrence_table", ES:DI = original output_buffer
; and AL = "local common byte" (to write rightwards, after each element):
; =======================================================================
	     xor    cl,cl	;prepare CL as a 'local ascii-counter'
	     mov    ah,al	;move rightwardly_writeable char. to AH
	     XOR    AH,128	;
	     jmp short @@PH5	;jump to middle of next loop
; ===============================
@@PH5a:      inc    cl		;increment the 'local ascii-number', CL
	     jz     @@PH5b	;if reached 0 (i.e. 256) exit this loop!
; -------------------------------
@@PH5:	     lodsb		;(else) load byte from table
	     or     al,al	;is it a zero (i.e. no occurrences)?
	     jz     @@PH5a	;if so, don't write anything (but go on)
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	     stosw		;write the byte_pair
	     mov ebx,dword ptr ES:DI	;
	     mov	di,bx		;
	     shr	ebx,16		;
	     mov	es,bx		;
             inc	di		;skip list_functor
	     ror	edx,16	;
	     inc	dx	;increment list-element counter
	     ror	edx,16	;
;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;&#lt;
	     inc    cl		;increment the "local ascii_counter", CL
	     jnz   @@PH5	;if not reached 0 (i.e. 256), repeat loop
; ///////////////////////////////////////////////////////////////////////
@@PH5b:	    pop  cx	;now retrieve the current "ASCII-Counter" value,
	   pop   bx	;and also recover the old "tourist_buffer_offset"
 	  pop    si	;and recover current offset of occurrences_table
	 pop	 ax	;also recover this "tourist group"'s size, in AX,
	 add	 bx,ax	;now add this to current offset of tourist_buffer
	 inc	 cl	;and finally increment the current ASCII-number,
	 jnz	 @@PH4m	;if not 0 (i.e.256) repeat PHASE FOUR's MAIN LOOP
; =======================================================================
@@PH4x:	pop  cx		;balance the stack (for saving start of table-2)
	dec  di		;go back to last list-functor
	mov  al,02h	;
	stosb		;mark end of list at that point
	ret
ENDP phase_nd_4_5


; ======================== PUBLIC PREDICATES: ==========================

	public	_il_sort		;-(i)

; Updates the input number-list 'destructively', overwriting old values.
; Uses temporary GStack-Memory Allocation. The number of temporary extra
; bytes required to sort a list of N numbers, is equal to N/2+1024. Note
; that for large N (e.g. 32000), this is almost N/2 (16000), i.e. 17024.

PROC _il_sort far
      ARG  ilist:dword
      ENTER 2,0
      push  ds
      push  si
      push  es
      push  di
; ===============================
      cld			;
      call _MEM_MarkGStack	;
      push	dx		;
       push	ax		;
; ===============================
        les di,[ilist]	;input-list..............................ARG-1
        push	es	;save segment of input in the stack
         push	di	;save offset  of input in the stack
; \\\\\\\\\\\\\\\\\\\\\\\
	  call	phase_1	;get length in CX, histogram in t512a(table)
	  mov	[bp-2],cx	;
; ///////////////////////
	  push	ds	;
	   push di	;
	    push cx		;save the length in the stack
	     add cx,1024	;add space for 2 temporary tables in it
	     push cx	;push it as a parameter (bytes to allocate)
	      call _MEM_AllocGStack	;allocate space in the GStack
	     pop	cx	;balance
             mov	di,ax	;put offset  of 'fresh' binary in DI
	     mov	bx,di	;copy it also to BX
             mov	es,dx	;put segment of 'fresh' binary in ES
            pop	dx		;recover number_of_elements, but in DX
	   pop	si		;recover start of t512a (dataseg-table)
	  pop	ds		;recover standard data_segment
	  mov	cx,128		;
	  rep   movsd		;copy t512a to new table-1 in GStack
	  mov	di,bx		;recover start of 'fresh' binary
	  mov	cx,dx	;put number_of_elements in CX
	  push	di	;save the temporary buffer offset in the stack
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
	   call phase_2		;
; ///////////////////////////////
	  pop	di		;
         pop	si		;recover offset  of input, but in SI
	pop	ds		;recover segment of input, but in DS
	push	di		;
	 call phase_3		;
; ///////////////////////////////
	pop	si	;recover the temporary buffer offset, but in SI
	mov	ax,es		;
	mov	ds,ax		;now DS:SI=temporary_buffer
	les	di,[ilist]	;and ES:DI=list(now as output)....ARG-1
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
	 call phase_4_5		;
; ///////////////////////////////
       pop	 ax		;recover offset  of GStack_array
      pop	 dx		;recover segment of GStack_array
      push	 dx		;push segment as parameter
       push	 ax		;push offset  as parameter
	call _MEM_ReleaseGStack	;Release temporary GStack-memory used
       pop	 cx		;balance the stack
      pop	 cx		;balance the stack
; -------------------------------
      mov	 ax,[bp-2]	;return number of elements
; ===============================
      pop	di
      pop	es
      pop	si
      pop	ds
      LEAVE
      ret
ENDP _il_sort

; -----------------------------------------------------------------------

	public	_il_sortndup		;-(i)

; Same as 'il_sort/1', but removes from the list all duplicate elements.
; Also slightly faster than 'il_sort/1', as a result.

PROC _il_sortndup far
      ARG  ilist:dword
      ENTER 0,0
      push  ds
      push  si
      push  es
      push  di
; ===============================
      cld			;
      call _MEM_MarkGStack	;
      push	dx		;
       push	ax		;
; ===============================
        les di,[ilist]	;input-list..............................ARG-1
        push	es	;save segment of input in the stack
         push	di	;save offset  of input in the stack
; \\\\\\\\\\\\\\\\\\\\\\\
	  call	phase_1	;get length in CX, histogram in t512a(table)
; ///////////////////////
	  push	ds	;
	   push di	;
	    push cx		;save the length in the stack
	     add cx,1024	;add space for 2 temporary tables in it
	     push cx	;push it as a parameter (bytes to allocate)
	      call _MEM_AllocGStack	;allocate space in the GStack
	     pop	cx	;balance
             mov	di,ax	;put offset  of 'fresh' binary in DI
	     mov	bx,di	;copy it also to BX
             mov	es,dx	;put segment of 'fresh' binary in ES
            pop	dx		;recover number_of_elements, but in DX
	   pop	si		;recover start of t512a (dataseg-table)
	  pop	ds		;recover standard data_segment
	  mov	cx,128		;
	  rep   movsd		;copy t512a to new table-1 in GStack
	  mov	di,bx		;recover start of 'fresh' binary
	  mov	cx,dx	;put number_of_elements in CX
	  push	di	;save the temporary buffer offset in the stack
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
	   call phase_2		;
; ///////////////////////////////
	  pop	di		;
         pop	si		;recover offset  of input, but in SI
	pop	ds		;recover segment of input, but in DS
	push	di		;
	 call phase_3		;
; ///////////////////////////////
	pop	si	;recover the temporary buffer offset, but in SI
	mov	ax,es		;
	mov	ds,ax		;now DS:SI=temporary_buffer
	les	di,[ilist]	;and ES:DI=list(now as output)....ARG-1
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
	 call phase_nd_4_5	;
; ///////////////////////////////
       pop	 ax		;recover offset  of GStack_array
      pop	 dx		;recover segment of GStack_array
      push	 dx		;push segment as parameter
       push	 ax		;push offset  as parameter
	call _MEM_ReleaseGStack	;Release temporary GStack-memory used
       pop	 cx		;balance the stack
      pop	 cx		;balance the stack
; ===============================
      ror	edx,16	;
      mov	ax,dx	;return number of list-elements
; =======================
      pop	di
      pop	es
      pop	si
      pop	ds
      LEAVE
      ret
ENDP _il_sortndup

	END		;*/


ifndef include_defs
CONSTANTS
 test_il_tobin = 1

include ".\\AUXPREDS.DOM"

GLOBAL PREDICATES
 unsigned il_sort(IL) -(i) language c
 unsigned il_sortndup(IL) -(i) language c

include ".\\AUXPREDS.INC"

PREDICATES
 do_il_sort(INTEGER)

GOAL
 do_il_sort(1), do_il_sort(2), do_il_sort(3), do_il_sort(4).
enddef

PREDICATES
 fill_random(unsigned,CHAR,binary)
 write_array(CHAR,unsigned,unsigned,binary)
 showbinx(unsigned,unsigned,binary)
	showelement(INTEGER,INTEGER)
 mywritef(CHAR,CHAR,CHAR)

CLAUSES
 do_il_sort(1):- attribute(A), rep, attribute(79),
	write("testing:  unsigned il_sort(ilist) -(i)\n"), attribute(14),
	write("\n\nHow many numbers in the array?\n-> "), attribute(15),
	readint(N), fill_random(N,'n',Bin1), il_tobin(ILx,Bin1),
	attribute(14), write("input-list:\n",ILx), nl, Nx=il_sort(ILx),
	write("SORTED list:\n",ILx,"\n\nNumber of elements=",Nx), nl,
	attribute(A), pkey, !.

 do_il_sort(2):- attribute(A), rep, attribute(79),
	write("testing:  unsigned il_sort(ilist) -(i)\n"), attribute(14),
	write("\nHow many numbers in the array?\n-> "),
	readint(N), fill_random(N,'n',Bin1), il_tobin(ILx,Bin1),
	NN=N+N, openwrite(output,"il_sort.RAW"), writedevice(output),
	write_array('\n',0,NN,Bin1), closefile(output),
	system("LIST il_sort.RAW"), il_sort(ILx), il_tobin(ILx,0,Bin1),
	openwrite(output,"il_sort.SRT"), writedevice(output),
	write_array('\n',0,NN,Bin1), closefile(output),
	system("LIST il_sort.SRT"), attribute(A), pkey, !.

 do_il_sort(3):- attribute(A), unread_str("[3,2,5,-12,4,5,9,8,4,-12,1,3]"),
	rep, attribute(79),
	write("testing:  unsigned il_sortndup(ilist) -(i)\n"),
	attribute(14), prompt(0,"\nGive a list of numbers:\n",Istr),
	term_str(il,L,Istr), NewN=il_sortndup(L), nl, attribute(14),
	write("This list, after sorting and removing duplicates is:\n   "),
	attribute(15), write(L), write("\n\nNew Number of elements=",NewN),
	attribute(A), nl, pkey, !.

 do_il_sort(4):- attribute(A), rep, attribute(79),
	write("testing:  unsigned il_sortndup(ilist) -(i)\n"), attribute(14),
	write("\nHow many numbers in the array?\n-> "), attribute(15),
	readint(N), fill_random(N,'n',Bin1), il_tobin(ILx,Bin1),
	NN=N+N, openwrite(output,"il_sort.RAW"), writedevice(output),
	write_array('\n',0,NN,Bin1), closefile(output),
	system("LIST il_sort.RAW"), New=il_sortndup(ILx), il_tobin(ILx,0,Bin1),
	openwrite(output,"il_sort.SRT"), writedevice(output),
	New2=New+New, write_array('\n',0,New2,Bin1), closefile(output),
	system("LIST il_sort.SRT"), nl, attribute(A), pkey, !.

 fill_random(NumW,'s',Bin):- bitleft(NumW,1,NumW2), Bin=makebinary(NumW2),
	BC=makebinary(2), setwordentry(BC,0,0), rep,
	P=getwordentry(BC,0), random(26,Byte1a), random(26,Byte2a),
	Byte1=Byte1a+65, Byte2=Byte2a+97,
	setbyteentry(Bin,P,Byte1), P2=P+1, setbyteentry(Bin,P2,Byte2),
	P3=P2+1, setwordentry(BC,0,P3), P3>=NumW2, !.

 fill_random(NumW,'n',Bin):- bitleft(NumW,1,NumW2), Bin=makebinary(NumW2),
	BC=makebinary(2), setwordentry(BC,0,0), rep,
	P=getwordentry(BC,0), random(Real), RND=cast(unsigned,Real*65535),
	setwordentry(Bin,P,RND), PP=P+1, setwordentry(BC,0,PP), PP>=NumW, !.

 write_array('\0',Startbyte,Numbytes,Bin):-
	bitright(Startbyte,1,Start), bitright(Numbytes,1,NumW),
	Bc=makebinary(2), write("&#lt; "), setwordentry(Bc,0,Start), 
	getbacktrack(LP), rep, P1=getwordentry(Bc,0),
	Word1=getwordentry(Bin,P1), P2=P1+1,
	write(Word1,' '), setwordentry(Bc,0,P2),
	P2>=NumW, cutbacktrack(LP), write('>'),	!.

 write_array('\n',Startbyte,Numbytes,Bin):- Bc=makebinary(2), 
	bitright(Startbyte,1,Start), bitright(Numbytes,1,NumW),
	setwordentry(Bc,0,Start),
	rep, P1=getwordentry(Bc,0), W1=getwordentry(Bin,P1), P2=P1+1,
	W1a=cast(integer,W1),
	writef("%6\n",W1a), setwordentry(Bc,0,P2), P2>=NumW, !.

 write_array(SepC,Startbyte,Numbytes,Bin):- 
	Bc=makebinary(2), write('&#lt;'), setwordentry(Bc,0,Startbyte),
	getbacktrack(LP), rep, P1=getwordentry(Bc,0),
	Byte1=getbyteentry(Bin,P1), P2=P1+1, Byte2=getbyteentry(Bin,P2),
	mywritef(Byte1,Byte2,SepC), Q=P2+1, setwordentry(Bc,0,Q),
	Q>=NumBytes, cutbacktrack(LP), write('>'), !.

  mywritef(Byte1,Byte2,'\1'):- Byte1>&#lt;0, Byte2>&#lt;0,
	writef("%c%c",Byte1,Byte2), !.
  mywritef(Byte1,Byte2,'\1'):- Byte1>&#lt;0, Byte2=0,
	writef("%c%c",Byte1,'.'), !.
  mywritef(Byte1,Byte2,'\1'):- Byte2>&#lt;0, Byte1=0,
	writef("%c%c",'.',Byte2), !.
  mywritef(_,_,'\1'):- writef(".."), !.
  mywritef(Byte1,Byte2,SepC):- Byte1>&#lt;0, Byte2>&#lt;0,
	writef("%c%c%c",Byte1,Byte2,SepC),  !;
	Byte1=0,  Byte2=0, write("__%",SepC), !;
	Byte1>&#lt;0, Byte2=0, writef("%c_%",Byte1,SepC), !;
	Byte2>&#lt;0, Byte1=0, writef("%c_%",Byte2,SepC), !.

  showbinx(Start,End,Bi):- BC=makebinary(2),
	setwordentry(BC,0,Start), rep, P=getwordentry(BC,0),
	Byte1=getbyteentry(Bi,P), P2=P+1, Byte2=getbyteentry(Bi,P2),
	E=Byte1+(256*Byte2), Pee=(P-Start)/2, showelement(Pee,E),
	P3=P2+1, setwordentry(BC,0,P3), P3>=End, !.

  showelement(_,0):- !.
  showelement(P,N):- writef("%c=%,",P,N), !./


Back to ASM-Library Index
Author's home page


Stathis Services Ltd (Office Automation): http://www.stathis.com