  def literal "%1"

  def buffer string

  def bufptr strptr


  macro SetBufMem( v,n,  ,de,le)
  ==============================
  #ifndef v##_buffer
    buffer v##_buffer
  #endif 
  int le=len(v##_buffer)
  int de=n-le
  if de>0
    v##_buffer += nuls(de)
  elseif de<0
    v##_buffer = left( v##_buffer,le+de )
  end if
  @v=bufptr(v##_buffer)
  end macro


  macro FillBytes(name,count,value)
  =================================
  addr rsi,name
  mov rcx,count
  (
   dec rcx
   jl exit
   mov byte [rsi],value
   inc rsi
   repeat
  )
  end macro


  macro Swap(a,b,    c)
  =====================
  typeof(a) c=a
  a=b
  b=c
  end macro


  macro LimitMin(a,m)
  ===================
  if a<m then a=m
  end macro


  macro LimitMax(a,m)
  ===================
  if a>m then a=m
  end macro


  macro LimitMinMax(a,n,m)
  ========================
  if a<n then
    a=n
  elseif a>m then
    a=m
  end if
  end macro
 

  def Stride
  ==========
  @%1+=sizeof %1
  end def


  def CreateStatic
  ================
  dim %1 %2
  #ifdef %1.___
    ? %2 = @%1_table
  #endif
  #ifdef %1.constructor
    %2.constructor(%3)
  #endif
  end def

  def CreateDynamic
  =================
  dim %1 * %2
  if @%2 then freememory @%2
  @%2=getmemory sizeof %1
  #ifdef %1.___
    ? %2 = @%1_table
  #endif
  #ifdef %1.constructor
    %2.constructor(%3)
  #endif
  end def


  def DestroyStatic
  =================
  #ifdef %1.destructor
    %1.destructor
  #endif
  end def


  def DestroyDynamic
  ==================
  #ifdef %1.destructor
    %1.destructor
  #endif
  if @%1 then freeMemory @%1
  @%1=null
  end def

  'DYNAMIC MEMBER ARRAYS
  '
  'class cc
  'MemberArray bb mm
  'method Members(int n)
  ' MemberRedim bb mm(n)
  'end method
  'method constructor()
  ' Members 100
  'end method
  'method destructor()
  ' Members 0
  'end method
  'end class
  '
  def MemberArray
  ===============
  'class members:
  %1 * %2
  int  %2_count
  end def
  '
  def MemberRedim
  ===============
  ' requires these class members:
  ' %1 * %2
  ' int  %2_count
  scope
  bstring %2_buf
  ? %2_buf = @ %2
  int %2_i
  int %2_st=sizeof(%1)
  int %2_lq = (%3) * %2_st
  int %2_le=len(%2_buf)
  int %2_de=%2_lq-%2_le
  if %2_de>0
    %2_buf += nuls(%2_de) : @ %2 = ? %2_buf
    %1 %2_p at @%2 + %2_count * %2_st
    for %2_i=1 to %2_de step %2_st
      #ifdef %2.___
        ? %2_p.___=@%1_table
      #endif
      #ifdef %2.constructor
        %2_p.constructor
      #endif
      stride %2_p
    next
  elseif %2_de<0
    #ifdef %2.destructor
      %1 %2_p at @%2 + %2_count * %2_st
      for %2_i=1 to -%2_de step %2_st
        %2_p.destructor : #show stride %2_p
      next
    #endif
    %2_buf = left( %2_buf, %2_le + %2_de )
    @ %2 = ? %2_buf
  end if
  %2_count=%3
  if %2_count=0
    freememory  @%2
    @2=null
  end if
  end scope
  end def


  def RedimArray
  ================
  #ifndef %2
    dim static string %2_buffer = ""
    dim static int %2_count
    dim static %1 byref %2
  #endif
  dim sys %2_lq = (%3) * sizeof(%1)
  SetBufMem(%2, %2_lq)
  %2_count=%3
  end def


  macro CountArray(v,n)
  =====================
  #ifndef n
    #ifdef v##_count
      int n=v##_count
    #else
      int n=countof v
    #endif
  #endif
  end macro


  macro ApplyToArray(v,f,n,  m,w)
  ===============================
  countArray v,n
  typeof v *w = @v
  int m=n
  while m--
    f w
    stride w
  wend
  end macro


  def DotCompo
  ============
    %1.%2
  end def


  macro ApplyMethodToArray(v,f,n,  m,w)
  =====================================
  countArray v,n
  typeof v *w = @v
  int m=n
  while m--
    dotCompo w f
    stride w
  wend
  end macro


  macro AppendBuffer(b,t,ob,  lb,ls,  s)
  ======================================
  #ifndef b
    static string b
  #endif
  #ifndef ob
    static int ob
  #endif
  string s=t 'supports string expressions
  int lb=len(b)
  int ls=len(s)
  if ob+ls>lb then
    b+=nuls(0x1000+ls*4)
  end if
  mid(b,ob+1,s) : ob+=ls
  end macro 


  macro ListArray(v,f,n,ix,   b,s,ob,c,m,w,x)
  ===========================================
  scope
  indexbase 1
  int c
  string s,b
  int c,m,ob
  m=n
  typeof v *w = @v
  #ifdef ix 'DATA INDEXER
    typeof ix *x =@ix
    while m--
      c++
      @w=@v[x]
      s = c  chr(9)  w  chr(13,10)
      appendBuffer b,s,ob
      stride x
    wend
  #else
    countArray v,n
    while m--
      c++
      s = c  chr(9)  w  chr(13,10)
      appendBuffer b,s,ob,lb,ls
      stride w
    wend
  #endif
  f left b,ob
  b="" : s=""
  end scope
  end macro


'float v={10.5,20,30,40,50}
'applyToArray v, madd1
'ListArray    v, print


'bottom-up Merge-sort procedure
===============================
macro mergeSort(
  idx,ct,cp, 'params
  src,dest,stp,sw,kk,bi,bj,ej,ed,ni,nj,sx,dj,sd 'encapsulated
  )
'
' idx        index array must have ct*2 elements
' ct         element count
' cp         comparator callback/macro
'
sys src             ' index offset for elements to be compared
sys dest            ' index offset for merged ordered elements
sys stp             ' merge group size X sizeof idx element
sys sw              ' flag to select from second group instead of first
sys kk              ' element counter
sys bi              ' base for first group
sys bj              ' base for second group
sys ej              ' boundary for second group
sys ed              ' source data boundary
typeof idx * ni     ' position for first compare element
typeof idx * nj     ' position for second compare element
typeof idx * dj     ' destination for element
%=  sx=sizeof idx   'element size
sys sd=ct*sx        'size of index data (bytes)
'
src=@idx
dest=sd+@idx
stp=sx 'INITIAL STRIDE IS SIZE OF IDX ELEMENT
do 'MERGING LOOP
  if stp>=sd then
    if src<>@idx then 'COPY INDEX VALUES BACK TO BASE
      copy @idx, @idx+sd, sd
    end if
    exit do 'DONE
  end if
  kk=0
  bi=src : bj=bi+stp : ej=bj+stp
  @ni=bi : @nj=bj
  ed=src+sd 'DATA BOUNDARY
  LimitMax ej,ed
  @dj=dest-sx
  stp+=stp 'DOUBLE STRIDE FOR EACH MERGE 8,16,32 ...
  do 'NEXT MERGING PASS
    if kk>=ct then exit do 'ALL ELEMENTS PROCESSED
    stride dj : kk++ 'NEXT DESTINATION POSITION
    retest:
    if @ni>=bj then
      if @nj>=ej then 'MOVE TO NEXT GROUP
        bi+=stp : bj+=stp : ej+=stp
        @ni=bi : @nj=bj
        LimitMax ej,ed 'LIMIT EJ TO BOUNDARY ed
        goto retest
      else
        dj=nj : stride nj : continue do 'PICK FROM SECOND GROUP
      end if
    elseif @nj>=ej then
      dj=ni : stride ni : continue do 'PICK FROM FIRST GROUP
    end if
    'COMPARE BEFORE PICKING
    sw=0
    cp sw, ni, nj 'COMPARE PROCEDURE
    if sw then dj=nj : stride nj else dj=ni : stride ni
  end do
  swap src,dest 'SWAP SOURCE/DESTINATION IDX BASES
end do
end macro


  macro NewSortIndex(idx,ct,cf,filt,comp,  i,f,x)
  ===============================================
  'idx            index name
  'ct             count of items
  'cf             resulting count of filtered items
  'filt  optional filter procedure for selecting items
  'comp  optional comparison procedure for sorting items
  '
  int *idx 'create the index file
  int cf   'filtered data counter
  if @idx then freememory @idx 'check for re-use
  cf=0                         'clear counter
  @idx=getMemory 2*(ct)*sizeof int
  scope
    int x at @idx  'idx strider
    int i          'iterator
    int f          'filter flag
    for i=1 to ct
      f=0
      #ifdef filt
        filt f,i
      #else
        f=1
      #endif
      if f then x=i : stride x : cf++
    next
  end scope
  #ifdef comp
    mergeSort idx,cf,comp
  #endif
  end macro


  macro NewSortedData(a,b,idx,ct,  i,j)
  =====================================
  typeof(b) *a
  if @a then freememory @a
  @a=getMemory ct*sizeof b
  scope
    indexbase 1
    int i,j
    for i=1 to ct
      j=idx[i]
      a[i]=b[j]
    next
  end scope
  end macro


  def DelDynamicArray if @%1 then freememory @%1 : @%1=0
  def DelSortIndex  DelDynamicArray %1
  def DelSortedData DelDynamicArray %1


  macro Encounters(v,ct,act,  a,b,e)
  ==================================
  '
  'permutations of pairs of elements in an array
  'v    array of elements
  'ct   count of elements
  'act  action to be performed with the selected pair
  '
  typeof v *a,*b
  sys e
  e=(ct-1) * sizeof v + @v
  @a=@v
  while @a<e
    @b=@a
    while @b<e
      @b+=sizeof b
      act a,b
    wend
    @a+=sizeof a
  wend
  end macro


  macro Touch(xd,yd,r1,r2,act,    xx,yy,rr,dd)
  ============================================
  '
  '2 objects may come into contact on an xy 2d plane
  'xd   difference in x coordinates
  'yd   difference in y coordinates
  'r1   touch radius of object 1
  'r2   touch radius of object 2
  'act  action to perform when contact is made
  '
  float rr=r1+r2
  float xx = abs(xd)
  if xx<=rr then
    float yy = abs(yd)
    if yy<=rr then
      float dd=xx*xx+yy*yy 'distance squared
      rr*=rr
      if dd<=rr then
        act
      end if
    end if
  end if
  end macro
