/* Super fast sort program.
   whereas slow methods like quicksort/mergesort use O(n * log n) methods,
   radixsort is a true O(n) method. Especially for large textfiles, it is a
   LOT faster than other sorters (a log order of magnitude ;-).
   Radixsort uses a 256 buckets at each level to put the strings in. arrays
   of buckets are only allocated when the number of strings left to sort is
   large.
   Radix.e reads from a file, and outputs to stdout.
*/

MODULE 'tools/file', 'tools/exceptions'

DEF rad1:PTR TO LONG,radsize:PTR TO LONG

OBJECT str
  next,data
ENDOBJECT

PROC main() HANDLE
  DEF m,l,n,list
  m,l:=readfile(arg)
  n:=countstrings(m,l)
  list:=stringsinfilenolist(m,l,n)
  doradix(NEW rad1[256],NEW radsize[256],list,n)
  restradix(rad1,radsize)
EXCEPT
  report_exception()
ENDPROC

PROC doradix(table:PTR TO LONG,size:PTR TO LONG,str:PTR TO LONG,num)
  DEF a,s,c
  FOR a:=1 TO num
    s:=str[]++
    c:=s[]
    table[c]:=NEW [table[c],s]:str
    size[c]:=size[c]+1
  ENDFOR
ENDPROC

PROC restradix(table:PTR TO LONG,size:PTR TO LONG,level=1)
  DEF a
  FOR a:=0 TO 255 DO recradix(table[]++,size[]++,level)
ENDPROC

PROC recradix(l:PTR TO str,num,level)
  DEF tab:PTR TO LONG,size:PTR TO LONG,s,c,temp:PTR TO str
  IF num
    IF num<20
      straight(l,num)
    ELSE
      NEW tab[256],size[256]
      WHILE l
        s:=l.data
        temp:=l
        l:=l.next
        c:=s[level]
        temp.next:=tab[c]
        tab[c]:=temp
        size[c]:=size[c]+1
      ENDWHILE
      restradix(tab,size,level+1)
      END tab[256],size[256]
    ENDIF
  ENDIF
ENDPROC

PROC straight(l:PTR TO str,num)			-> sort these with a silly method
  DEF a,tl:PTR TO str,best:PTR TO str,fbest
  fbest:=[NIL,[$7F7F7F7F,$7F7F7F7F,$7F7F7F7F,0]:LONG]:str
  FOR a:=1 TO num
    tl:=l
    best:=fbest
    WHILE tl
      IF tl.data THEN IF OstrCmp(best.data,tl.data)=-1 THEN best:=tl
      tl:=tl.next
    ENDWHILE
    IF best<>fbest
      PutStr(best.data)
      FputC(stdout,"\n")
      best.data:=NIL
    ENDIF
  ENDFOR
ENDPROC

PROC stringsinfilenolist(mem,len,max)	-> to eliminate 32k strings boundary
  DEF list:PTR TO LONG,l
  NEW list[max]
  MOVE.L list,A1
  MOVE.L max,D3
  MOVE.L mem,A0
  MOVE.L A0,D1
  ADD.L  len,D1
  MOVEQ  #0,D0
  MOVEQ  #10,D2
stringsl:
  CMP.L  D3,D0
  BPL.S  done
  ADDQ.L #1,D0
  MOVE.L A0,(A1)+
findstringl:
  CMP.B  (A0)+,D2
  BNE.S  findstringl
  CLR.B  -1(A0)
  CMPA.L D1,A0
  BMI.S  stringsl
done:
  MOVE.L D0,l
ENDPROC list,l
