#include <math.h>
#include <malloc.h>
#include "ssort.h"

void sort(void *v[],                 /* An array of pointers to */
	                             /* data structures to be sorted */
	  long n,                    /* Number of elements in array */
	  double (*comp)(void *,void *) /* Pointer to comparison */
	  )                          /* function */
{
  int exp;         /* To be assign such that $2^(exp-1)<n<=2^exp$ */
  int counter;     /* counter to give us the correct gap at each */
		   /* stage in the algorithm */
  long *gaps;      /* \texttt{gaps} is to be an array of longs of length */
                   /* `\texttt{exp}'.  In it will be stored the distances */
		   /* between numbers which will be k-sorted as */
		   /* we go through the shell sort */
                   /* (see Knuth V3, pp83-95) */
  long gap,i,j,k;
  void *temp;


/* frexp stores the next power of two above n in exp.  
   e.g. n=23 gives exp=5, since $2^4=16<23$ and $2^5=32>23$.*/
  frexp((double) n,&exp);

/* allocate memory for gaps to be an array of longs of 
   length exp. */
  gaps = (long *)malloc(exp*sizeof(long));
  *gaps=1;

/* calculate the gaps in the shell sort using the 
   formula $9.4^i-9.2^i$ for even locations in gaps and 
   $4.4^i-6.2^i+1$ for odd locations.  Also set the 
   counter for gaps. */
  for (i=1; (gaps[2*i] = 9*((1<<2*i)-(1<<i))+1)<(n/6); ++i)
    gaps[2*i-1] = 4*(1<<2*i)-6*(1<<i)+1;

  gaps[2*i-1] = 4*(1<<2*i)-6*(1<<i)+1;
  counter=2*i;

/* This bit here is the actual shell sort sorting 
   algorithm.  The procedure is standard. */
  for (gap = gaps[counter]; counter-- >= 0; gap=gaps[counter])
    for (i = 0; i<gap; i++)
      for (j=0; j<(n-gap-i); j+=gap){
	if((*comp)(v[j+i],v[j+gap+i])<0){
	  temp=v[j+gap+i];
	  for(k=j+i;k>=0 && (*comp)(v[k],temp)<0;k-=gap)
	    v[k+gap]=v[k];
	  v[k+gap]=temp;
	}
      }
  free((void *)gaps);
}
