/***************************************************/
/*      sqsort  (stable qsort)     Version 2.1     */
/*                                                 */
/* by 河村 知行 (kawamura tomoyuki)    2021.11.5   */
/*             t-kawa@crux.ocn.ne.jp               */
/***************************************************/

// sqsort は timsortより高速で、安定・安全な比較ソートです（qsortを元にしています）
/* sqsortの概略
対象配列(ptr)と補助配列(ptr2)(ptrと同じ大きさ)の役目を入れ替えながらソートを行う。
条件が揃った場合は、ポインタ配列(ptr)と補助ポインタ配列(ptr2)による間接ソートに自動的に切り替わる。
以下のようにＡＢ2段階で要素を移動する。ここで「5」はピボット(分割要素)を表している。
        l             r                 l  r                      l  r
   ptr2:...............  →  ptr2:332223....77787  →  ptr2:332223....77787
   ptr :357358257257237  Ａ  ptr :5555...........  Ｂ  ptr :......5555.....
        m      M                      m
移動Ａで、ピボット及び比較値が同じ要素をptrの左端に集め、5より小さい要素をptr2の左端に集め、
5より大きい要素をptr2の右端に集める。このとき77787は初期順序の逆順になっている。
移動Ｂのとき、もしも5555が逆順ならば、移動Ｂ後に5555が正順になるように移動する。
移動Ｂ後の時点で5555はすでにソート完成状態の位置に収まっている。
次に332223の{先頭位置・末尾位置・正順逆順}をスタックに保存(PUSH)する。
これ以降、部分配列77787に対して同じ処理を繰り返す。部分配列長<=14なら挿入ソートを行う。
挿入ソート後は、スタックから{先頭位置・末尾位置・正順逆順}を取り出し(POP)て処理を続ける。
スタックが空になれば処理を終了する。
*/
#include <malloc.h>
#include <time.h>

///////////////////　要素の移動に関するもの　別なものに書き換え可能です　////////////////////////
#define  lli    long long int
#define  MV1(i) {                                 a [i] =        b [i];                  } 
#define  MV4(i) {                          ((int*)a)[i] = ((int*)b)[i];                  } 
#define  MV8(i) {                          ((lli*)a)[i] = ((lli*)b)[i];                  } 
#define  SW1(i) {char v; v =        a [i];        a [i] =        b [i];        b [i] = v;} 
#define  SW4(i) { int v; v = ((int*)a)[i]; ((int*)a)[i] = ((int*)b)[i]; ((int*)b)[i] = v;} 
#define  SW8(i) { lli v; v = ((lli*)a)[i]; ((lli*)a)[i] = ((lli*)b)[i]; ((lli*)b)[i] = v;} 

#define HIGHLOW(MOV,WS) {                                                               \
   if (high) {                                                                          \
     char *e = a + high;                                                                \
     do {MOV(0) MOV(1) MOV(2) MOV(3) MOV(4) MOV(5) MOV(6) MOV(7)  b += 8*WS; a += 8*WS; \
     }while (a < e);                                                                    \
   }                                                                                    \
   switch ((low) & 7) {                                                                 \
     case 7: MOV(6)                                                                     \
     case 6: MOV(5)                                                                     \
     case 5: MOV(4)                                                                     \
     case 4: MOV(3)                                                                     \
     case 3: MOV(2)                                                                     \
     case 2: MOV(1)                                                                     \
     case 1: MOV(0)                                                                     \
     case 0: {}                                                                         \
   }                                                                                    \
} 

#define ENINT(x)  ((char*)(x) - (char*)0)
static size_t high, low;

static void   mvfnc8  ( char *a, const char *b ) {        MV8(0)}
static void   mvfnc4  ( char *a, const char *b ) {        MV4(0)}
static void   mvfnc8n ( char *a, const char *b ) {HIGHLOW(MV8,8)}
static void   mvfnc4n ( char *a, const char *b ) {HIGHLOW(MV4,4)}
static void   mvfnc1n ( char *a, const char *b ) {HIGHLOW(MV1,1)}
static void (*mvfnc)  ( char *a, const char *b );
static void   swfnc8  ( char *a,       char *b ) {        SW8(0)}
static void   swfnc4  ( char *a,       char *b ) {        SW4(0)}
static void   swfnc8n ( char *a,       char *b ) {HIGHLOW(SW8,8)}
static void   swfnc4n ( char *a,       char *b ) {HIGHLOW(SW4,4)}
static void   swfnc1n ( char *a,       char *b ) {HIGHLOW(SW1,1)}
static void (*swfnc)  ( char *a,       char *b );

static void mmprepare( void *base, size_t siz ) {
 if       ((sizeof(lli)==8) && (ENINT(base)&(8-1))==0 && (siz&(8-1))==0) {
   high=(siz&(-64)); low=(siz&(64-1))/8;  mvfnc = (siz==8 ? mvfnc8 : mvfnc8n);
                                          swfnc = (siz==8 ? swfnc8 : swfnc8n);
 }else if ((sizeof(int)==4) && (ENINT(base)&(4-1))==0 && (siz&(4-1))==0) {
   high=(siz&(-32)); low=(siz&(32-1))/4;  mvfnc = (siz==4 ? mvfnc4 : mvfnc4n);
                                          swfnc = (siz==4 ? swfnc4 : swfnc4n);
 }else{                                                    
   high=(siz&( -8)); low=(siz&( 8-1))/1;  mvfnc = mvfnc1n;
                                          swfnc = swfnc1n;
 }
}
///////////////////　ここまでが要素の移動に関するもの　別なものに書き換え可能です　//////////////


///////////////////////////　ここから下は、ss18によるソートプログラムです　//////////////////////
typedef struct { char *stkL, *stkR; int stkRev; } stack_node;   /*L,Rを積むスタックの構造体*/
#define PUSH(sL,sR,Rev) {       top->stkL = (sL);  top->stkR = (sR);  top->stkRev = (Rev); ++top;}
#define  POP(sL,sR,Rev) {--top;   sL = top->stkL;    sR = top->stkR;    Rev = top->stkRev;       }

#define LT(a,b)  if ((t=CMP(a,b)) <  0) 
#define else_GT  else if (t > 0)

#define med3(a,b,c) (CMP(a,b)<=0 ? (CMP(b,c)<=0 ? b : (CMP(a,c)<=0 ? c : a)) : \
                                   (CMP(b,c)>=0 ? b : (CMP(a,c)<=0 ? a : c)) )
#define I(x)  {x+=Esiz;}  /*注目要素ｘを右へ１つ移動する*/
#define D(x)  {x-=Esiz;}  /*注目要素ｘを左へ１つ移動する*/
#define ASS_CNT(x) {}     /* {ass_cnt += (x);} などとすれば、要素の移動回数を計測できる*/


/////////////////////////////////　sqsortの変数の宣言部分のマクロ定義　/////////////////////////////
#define SORT_DECLARATION( SORT_TYPE )                                                              \
static int SORT_TYPE ( void *base, size_t nel, size_t size,  int (*cmp)(void *a, void *b) ) {      \
 char *l,*l0,*r,*r0,*L,*R; /* L〜Rをソート(右端を含む)。 l0〜l に小要素を移動する(右端を含まず) */ \
 char *ptr,*ptrE,*ptr2;    /* ptr,ptr2 は実際にソートする配列,補助配列を指す。                  */ \
 char *m,*m0,*M,*p;        /* m0〜mに同要素(ピボットとキー値が同じ要素)を移動する(右端を含まず) */ \
 int  t, rev;              /* tは作業用 　rev==0のときL〜R間は正順                              */ \
 size_t n, Z;              /* nはソート中の区間L〜Rの要素数   Zは配列・補助配列間の距離         */ \
 size_t rndm = (clock()) & 0x7FFFFFFFL; /* clock()を乱数発生器として使用。正整数を保証          */ \
 stack_node stack[40], *top = stack;    /* 現在のところは４０で十分                             */


/////////////////////////////////　sqsortの本体部分のマクロ定義　///////////////////////////////////
#define SORT_BODY( INS_END, C, S )                                                                 \
 ptrE = ptr + nel * Esiz;  /* ptrE は「L〜Rが対象配列・補助配列いずれにあるか」の判定に使用する*/  \
 L=ptr; R=&ptr[Esiz*(nel-1)]; rev=0;                                                               \
 goto LOOP;                                                                                        \
 /*ここまでは、sqsort_xxxの１回の呼び出しで１度だけ実行される。これ以降は繰り返し実行される。*/    \
                                                                                                   \
NXT:                                                                                               \
 if (stack == top) {goto FIN;} /*スタックが空になったとき終了する*/                                \
 POP(L,R,rev);                 /*スタックに積んである値を取り出す*/                                \
                                                                                                   \
LOOP:                                                                                              \
 if (R<L)  {                                         goto NXT; }  /*要素なし*/                     \
 if (L==R) {if (ptr<=L && L<ptrE) {} else {C(L-Z,L)} goto NXT; }  /*要素数１*/                     \
 /*上記(ptr<=L && L<ptrE)判定は L<ptr2 が普通だが、直接ソート時、ptr2<base のシステムも存在する*/  \
                                                                                                   \
 n = (R - L + Esiz) / Esiz;                                       /*要素数 n>=2*/                  \
                                                                                                   \
 if (n <= INS_END) { /*挿入ソート実行   結果はptr上に作る    n<=INS_ENDで挿入ソートに切り替わる*/  \
   if (ptr<=L && L<ptrE){ if (rev==0) {/*この４行でソートしたい要素をptr上に移動する(元順)*/ }     \
                          else        {l=L; r=R;   do {S(l,r) l+=Esiz; r-=Esiz;} while(l< r);}     \
   }else{                 if (rev==0) {l=L; p=L-Z; do {C(p,l) l+=Esiz; p+=Esiz;} while(l<=R);}     \
                          else        {l=L; p=R-Z; do {C(p,l) l+=Esiz; p-=Esiz;} while(l<=R);}     \
                          L-=Z; R-=Z;                                                              \
   }                                                                                               \
   for (r=L+Esiz; r <= R; r+=Esiz) {  /*ptr判定2種ｘrev判定2種で４種類の挿入ソートにするのが最速*/ \
     if (CMP(r-Esiz,r)<=0) continue;  /*これを実装してみたが、複雑すぎるので採用を見合わせた    */ \
     p=L+Z; C(p,r)  C(r,r-Esiz)       /*挿入する要素を一時的に p に保存する                     */ \
     for (l=r-Esiz-Esiz; L<=l && CMP(l,p)>0; l-=Esiz) C(l+Esiz,l)                                  \
     C(l+Esiz,p)                                                                                   \
   }                                                                                               \
   goto NXT;                                                                                       \
 }                                                                                                 \
                                                                                                   \
 if (ptr<=L && L<ptrE) {l=l0=L+Z; r=r0=R+Z; m=m0=L  ;} /* l:ピボットより小さい要素を次に置く場所*/ \
 else                  {l=l0=L  ; r=r0=R-Z; m=m0=L-Z;} /* r:ピボットより大きい要素を次に置く場所*/ \
                                                       /* m:ピボットと  同じ  要素を次に置く場所*/ \
 if (n <= 120) {                        /*３点処理             「120」は実験で得られた値        */ \
   M = L + Esiz * (n >> 1);             /*配列の中央位置を一時的にMにセットする                 */ \
   size_t rnd = rndm % ((n >> 1) - 2);  /*３点の内に定点が２点あると悪意のある配列が作れてしまう*/ \
   char *ll=L+rnd*Esiz, *rr=R-rnd*Esiz; /*悪意ある攻撃を無効化するため、２要素を乱数で選択      */ \
   M=med3(ll, M, rr);                   /*３点を比較して、Mにピボットをセットする               */ \
 }else{                                 /*９点処理    ９点内の近似的中央要素をMにセットする     */ \
   size_t u=n/9, q=(rndm%u)*Esiz, v=u*Esiz;  char *ll,*mm,*rr, *z1,*z2,*z3;                        \
   ll=(p=L+q); mm=(p+=v); rr=(p+=v); z1=med3(ll, mm, rr);                                          \
   ll=(p+= v); mm=(p+=v); rr=(p+=v); z2=med3(ll, mm, rr);                                          \
   ll=(p+= v); mm=(p+=v); rr=(p+ v); z3=med3(ll, mm, rr); M=med3(z1, z2, z3);                      \
 }                                                                                                 \
                                                                                                   \
 /*ピボットと比較して、小要素,大要素,同要素を l, r,m の位置に並べて行く。  mは常にptr上にある*/    \
 for (p=L; p<M;) {LT(p,M) {C(l,p) I(l)} else_GT {C(r,p) D(r)} else {C(m,p) I(m)} I(p)}             \
 C(m,p) M=m; I(m) I(p)                                                                             \
 for (  ; p<=R;) {LT(p,M) {C(l,p) I(l)} else_GT {C(r,p) D(r)} else {C(m,p) I(m)} I(p)}             \
 /*この時点で (l-l0)+(m-m0)+(r0-r)==n*Esiz になっている */                                         \
                                                                                                   \
 /*ピボット及び同要素(m0〜m)をptr上の最終位置に移動する。以降この要素を参照・移動することはない */ \
 if (rev==0) {                                                                                     \
   if (l0<l) { p=(l-l0)+m; do {D(m) D(p) C(p,m)} while (m0<m);}  /*m0〜mには少なくとも１個ある*/   \
 }else{ /* rev==1 */                                                                               \
   char *ll=l-Z;                                                                                   \
   if (m<=ll) {                                                                                    \
     p=ll; do {D(m) C(p,m) I(p)} while(m0<m);                                                      \
   }else{                                                                                          \
     for (M=m-Esiz, p=ll; p<M;) {S(p,M) I(p) D(M)}                                                 \
     for (p=m, m=ll; m0<m;) {D(m) C(p,m) I(p)}                                                     \
   }                                                                                               \
 }                                                                                                 \
                                                                                                   \
 /*ピボットより 小さい要素 と 大きい要素 を別々にソートする。要素数の少ない方からソートする。*/    \
 if (l-l0 <= r0-r) {PUSH(r+Esiz, r0, rev^1) L=l0;     R=l-Esiz;        } /*左から先にソートする*/  \
 else              {PUSH(l0, l-Esiz, rev  ) L=r+Esiz; R=r0;     rev^=1;} /*右から先にソートする*/  \
 goto LOOP;                                                                                        \
                                                                                                   \
FIN: /*スタックが空になったとき繰り返しを終了する*/


/////////////////////////////////　sqsortの終了部分のマクロ定義　///////////////////////////////////
#define SORT_FIN( WORK_AREA )   free( WORK_AREA ); return 0; }


//
/////////////////////　直接ソート用に 宣言・本体・終了の３つのマクロを展開　//////////////////////
#define C1(x,y)  {ASS_CNT(1) mvfnc(x,y);}
#define S1(x,y)  {ASS_CNT(2) swfnc(x,y);}
#define CMP(a,b)  cmp(a,b)
#define Esiz      size        /* Esiz は実際にソートされる配列の要素の大きさ*/

 SORT_DECLARATION( sort_direct )    /************* 直接 ソート の開始 *****************/

 ptr = base;
 ptr2 = malloc( nel * size );      //ptr2はソートのための補助配列
 if (ptr2 == NULL) {return -1;}    //直接ソートが不可なので、戻って間接ソートを試す
 Z = ptr2 - ptr;    //Zは２個の配列間の距離。正負両方あり。  変数Zの大きさはsizeof(char*)ほど必要
 mmprepare( base, size );

 SORT_BODY( 14, C1, S1 )            /* 「14」 は実験で得られた値 */

 SORT_FIN( ptr2 )                   /************* 直接 ソート の終了 *****************/


/////////////////////　ptr_t ソート用に 宣言・本体・終了の３つのマクロを展開　//////////////////////
#define C2(x,y) {ASS_CNT(1)                          *(char**)(x)=*(char**)(y);                   }
#define S2(x,y) {ASS_CNT(2) {char *tmp=*(char**)(x); *(char**)(x)=*(char**)(y); *(char**)(y)=tmp;}}
#undef  Esiz
#define Esiz  sizeof(char*)  /* Esiz は実際にソートされる配列の要素の大きさ*/

 SORT_DECLARATION( sort_ptr_t )     /************* ptr_t ソート の開始 *****************/

 ptr = base;
 ptr2 = malloc( nel * sizeof(char*) );   //ptr2はソートのための補助配列
 if (ptr2 == NULL) {return -1;}          //作業領域が確保できないので、ソートは失敗
 Z = ptr2 - ptr;    //Zは２個の配列間の距離。正負両方あり。  変数Zの大きさはsizeof(char*)ほど必要

 SORT_BODY( 18, C2, S2 )            /* 「18」 は実験で得られた値 */

 SORT_FIN( ptr2 )                   /************* ptr_t ソート の終了 *****************/


/////////////////////　間接ソート用に 宣言・本体・終了の３つのマクロを展開　////////////////////////
#undef  CMP
#define CMP(a,b)  cmp( *(void**)(a), *(void**)(b) )

 SORT_DECLARATION( sort_indirect )  /************* 間接 ソート の開始 *****************/

 Z = nel * sizeof(char*) ;                        //Zはポインタ配列１個のバイト数
 ptr = malloc( Z * 2 + (size > Z ? size-Z : 0 )); //２個のポインタ配列を同時に確保する
 if (ptr == NULL) {return -1;}                    //作業領域が確保できないので、ソートは失敗
 ptr2 = ptr + Z;   //ptrは実際にソートする配列。ptr2は補助配列。  Zは２個の配列間の距離。正の値のみ
 {
  void **tp=(void**)ptr; char *ip=base, *ip_end=(char*)base+nel*size;
  for (; ip<ip_end; ip+=size, tp++) *tp=(void*)ip;  //間接ソートの為、ポインタ配列ptrの要素をセット
 }

 SORT_BODY( 18, C2, S2 )            /* 「18」 は実験で得られた値 */

 // スタックが空になったとき、ポインタ配列を用いて、本来の配列の要素を移動してから終了する
 mmprepare( base, size );
 {void **tp;  char *ip, *kp, *tmp=ptr2; size_t i;
  // Knuth vol. 3 (2nd ed.) exercise 5.2-10.
  // tp[i]はループの糸口(先頭)を指す。ipは退避要素の元の位置,kpは空き地を指す
  for (tp = (void **)ptr, i = 0, ip = base; i < nel; i++, ip += size)
    if ((kp = tp[i]) != ip) {
      size_t j = i;
      char *jp = ip;
      C1(tmp, ip);
      do {
        size_t k = (kp - (char *) base) / size;
        tp[j] = jp;
        C1(jp, kp);
        j = k;
        jp = kp;
        kp = tp[k];
      }while (kp != ip);
      tp[j] = jp;
      C1(jp, tmp);
    }
 }

 SORT_FIN( ptr )                    /************* 間接 ソート の終了 *****************/



///////////////　ソートの入り口　直接ソート・ptr_tソート・間接ソートへ振り分ける　////////////////
int sqsort( void *base, size_t nel, size_t size,  int (*cmp)(void *a, void *b) )
    // base : ソートしようとする配列へのポインタ
    // nel  : 配列baseの要素数
    // size : 配列baseの要素の大きさ（バイト単位）
    // cmp  : 要素の大小比較をする関数へのポインタ     ★sqsort関数の戻り値　0:正常  -1:メモリ不足
{
 if (size == sizeof(char*) && (ENINT(base)&(sizeof(char*)-1)) == 0) goto ptr_type;
 if (size >= 520)                                                   goto indirect;
 if (size <   16)                                                   goto direct;
 if (nel  <   70)                                                   goto direct;

 // 直接ソートを選択するために必要なeqcntは、nelとsizeごとに変化する。実験によりeqcntの値を求めた。
 // 下はnel(10000000〜100) X size(16〜480)でのeqcntの必要値。eqcntがこの値以上で直接ソートを実行。
 // 下はnel塊 右の値はsize 16 24 32 40 48 56 64 72 80 88 96 104112120160200240280320360400440480
 static char eq_tab10M []={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 4, 4, 6,10,10,14,14};
 static char eq_tab4M  []={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,10,10,10,10,14,14,14,14};
 static char eq_tab2M  []={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4,14,14,14,14,14,33,33,33};
 static char eq_tab1M  []={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 6,14,14,14,14,14,33,33,33};
 static char eq_tab400K[]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2,14,14,33,33,33,33,33,33,33};
 static char eq_tab200K[]={ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 6,10,14,33,33,33,33,33,33,33,33};
 static char eq_tab100K[]={ 0, 1, 1, 1, 1, 2, 2, 2, 4, 6,10,10,14,14,33,33,33,33,33,33,33,33,33};
 static char eq_tab40K []={ 1, 1, 1, 1, 4,10,14,14,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33};
 static char eq_tab20K []={ 1, 1, 1, 2, 6,14,14,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33};
 static char eq_tab10K []={ 1, 1,14,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33};
 static char eq_tab4K  []={ 1, 1, 1, 1, 1, 1, 3,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33};
 static char eq_tab2K  []={ 1, 1, 1, 1, 1, 2, 3, 4, 4, 5, 6,10,10,14,33,33,33,33,33,33,33,33,33};
 static char eq_tab1K  []={ 1, 1, 1, 1, 1, 2, 3, 4, 4, 5, 6, 8,10,10,14,33,33,33,33,33,33,33,33};
 static char eq_tab400 []={ 1, 1, 1, 2, 2, 2, 4, 4, 5, 5, 6, 8,10,14,14,33,33,33,33,33,33,33,33};
 static char eq_tab200 []={ 1, 1, 1, 2, 2, 2, 4, 4, 4, 5, 5, 6, 8, 8,14,33,33,33,33,33,33,33,33};
 static char eq_tab100 []={ 2, 2, 2, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 8,10,33,33,33,33,33,33,33,33};
 static char*eq_tab;

 if      (nel <    150) eq_tab = eq_tab100 ;
 else if (nel <    300) eq_tab = eq_tab200 ;
 else if (nel <    700) eq_tab = eq_tab400 ;
 else if (nel <   1500) eq_tab = eq_tab1K  ;
 else if (nel <   3000) eq_tab = eq_tab2K  ;
 else if (nel <   7000) eq_tab = eq_tab4K  ;
 else if (nel <  15000) eq_tab = eq_tab10K ;
 else if (nel <  30000) eq_tab = eq_tab20K ;
 else if (nel <  70000) eq_tab = eq_tab40K ;
 else if (nel < 150000) eq_tab = eq_tab100K;
 else if (nel < 300000) eq_tab = eq_tab200K;
 else if (nel < 700000) eq_tab = eq_tab400K;
 else if (nel <1500000) eq_tab = eq_tab1M  ;
 else if (nel <3000000) eq_tab = eq_tab2M  ;
 else if (nel <7000000) eq_tab = eq_tab4M  ;
 else /*  nel>=7000000*/eq_tab = eq_tab10M ;

 //eq_tab[nel,size]の値を取り出す。eqcnt(0〜32)がこの値以上なら直接ソート,それ以外なら間接ソート
 {
  int eq_low = ( size < 120 ? eq_tab[(size-16)/8] : eq_tab[(size-120)/40+13] ); //eq_tabは左右２部制
  if (eq_low == 0 ) goto   direct;     // eqcntの値を計算するまでもなく eqcnt(0〜32) >= eq_low(0)
  if (eq_low == 33) goto indirect;     // eqcntの値を計算するまでもなく eqcnt(0〜32) <  eq_low(33)

#define VBUN 64          /* 比較する組(ペアー)の数の２倍==VBUN。     nel >= VBUN の必要あり。*/

  //適当な32組の要素を比較して、等しい組の数を eqcnt（同値キーの個数）とする。eqcnt==0〜32になる。
  int eqcnt=0; size_t vsize=(nel/VBUN)*size; size_t half=vsize*(VBUN/2); char *ip_end=base+half;
  for (char *ip=base; ip<ip_end; ip+=vsize) if ((*cmp)(ip,ip+half)==0) eqcnt++;

  if (eqcnt >= eq_low) goto direct; else goto indirect;
 }

 ptr_type: return sort_ptr_t   ( base, nel, size, cmp );                   //ptr_tソートの実行
   direct: if   ( sort_direct  ( base, nel, size, cmp ) == 0) {return 0;}  // 直接ソートの実行
 indirect: return sort_indirect( base, nel, size, cmp );                   // 間接ソートの実行
}
