added qse_awk_rtx_getrefvaltype()/qse_awk_rtx_getrefval()

finished asort() in awk
added qse_sortx()
This commit is contained in:
hyung-hwan 2019-05-07 07:22:55 +00:00
parent c3e30eaae4
commit 2ac2ad8200
6 changed files with 412 additions and 121 deletions

View File

@ -2958,6 +2958,21 @@ QSE_EXPORT qse_awk_int_t qse_awk_rtx_hashval (
qse_awk_val_t* v
);
/**
* The qse_awk_rtx_getrefvaltype() function returns the type of the value
* that the given reference points to.
*/
QSE_EXPORT qse_awk_val_type_t qse_awk_rtx_getrefvaltype (
qse_awk_rtx_t* rtx,
qse_awk_val_ref_t* ref
);
QSE_EXPORT qse_awk_val_t* qse_awk_rtx_getrefval (
qse_awk_rtx_t* rtx,
qse_awk_val_ref_t* ref
);
/**
* The qse_awk_rtx_setrefval() function changes the value
* of a variable referenced in \a ref.

View File

@ -55,10 +55,23 @@ typedef int (*qse_search_comper_t) (
void* ctx
);
/**
* The qse_search_comperx_t type defines a search callback function.
* It should return 0 on success and -1 on failure. the comparsion
* result must be put back into the variable pointed to by \a cv.
*/
typedef int (*qse_search_comperx_t) (
const void* ptr1,
const void* ptr2,
void* ctx,
int * cv
);
/**
* The qse_sort_comper_t type defines a sort callback function.
*/
typedef qse_search_comper_t qse_sort_comper_t;
typedef qse_search_comperx_t qse_sort_comperx_t;
#if defined(__cplusplus)
extern "C" {
@ -134,6 +147,14 @@ QSE_EXPORT void qse_qsort (
void* ctx
);
QSE_EXPORT int qse_qsortx (
void* base,
qse_size_t nmemb,
qse_size_t size,
qse_sort_comperx_t comper,
void* ctx
);
/**
* The qse_rand31() function implements Park-Miller's minimal standard

View File

@ -45,7 +45,7 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
*
* - v: value. pass it after normal evaluation.
* - r: pass a variable by reference
* - x: regular expression as it it. not evaluated as /rex/ ~ $0.
* - x: regular expression as it is. not evaluated as /rex/ ~ $0.
*
* If the first character of the specifer is 'R', all
* parameters are passed by reference regarless of the remaining
@ -67,7 +67,7 @@ static qse_awk_fnc_t sysfnctab[] =
{ {QSE_T("typename"), 8}, 0, { {1, 1, QSE_NULL}, fnc_typename, 0 }, QSE_NULL},
/* array sort */
{ {QSE_T("asort"), 5}, 0, { {1, 3, QSE_NULL}, fnc_asort, 0 }, QSE_NULL},
{ {QSE_T("asort"), 5}, 0, { {1, 3, QSE_T("rrv")}, fnc_asort, 0 }, QSE_NULL},
/* string functions */
{ {QSE_T("gsub"), 4}, 0, { {2, 3, QSE_T("xvr")}, qse_awk_fnc_gsub, 0 }, QSE_NULL},
@ -704,7 +704,6 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
a2 = (nargs >= 3)? qse_awk_rtx_getarg (rtx, 2): QSE_NULL;
a1_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, a1);
QSE_ASSERT (a1_vtype == QSE_AWK_VAL_REF);
str.ptr = qse_awk_rtx_getvalstr(rtx, a0, &str.len);
@ -714,7 +713,7 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
/* get the value from FS */
t1 = qse_awk_rtx_getgbl(rtx, QSE_AWK_GBL_FS);
t1_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, t1);
t1_vtype = QSE_AWK_RTX_GETVALTYPE(rtx, t1);
if (t1_vtype == QSE_AWK_VAL_NIL)
{
fs.ptr = QSE_T(" ");
@ -727,7 +726,7 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
}
else
{
fs.ptr = qse_awk_rtx_valtostrdup (rtx, t1, &fs.len);
fs.ptr = qse_awk_rtx_valtostrdup(rtx, t1, &fs.len);
if (fs.ptr == QSE_NULL) goto oops;
fs_free = (qse_char_t*)fs.ptr;
}
@ -801,15 +800,11 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
if (fs.len <= 1)
{
p = qse_awk_rtx_strxntok (rtx,
p, str.len, fs.ptr, fs.len, &tok);
p = qse_awk_rtx_strxntok(rtx, p, str.len, fs.ptr, fs.len, &tok);
}
else
{
p = qse_awk_rtx_strxntokbyrex (
rtx, str.ptr, org_len, p, str.len,
fs_rex, &tok, &errnum
);
p = qse_awk_rtx_strxntokbyrex(rtx, str.ptr, org_len, p, str.len, fs_rex, &tok, &errnum);
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
{
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
@ -848,7 +843,7 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
/*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/
qse_awk_rtx_freevalstr (rtx, a0, str.ptr);
if (fs_free) QSE_AWK_FREE (rtx->awk, fs_free);
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
if (fs_rex_free)
{
@ -870,7 +865,7 @@ oops:
/*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/
if (str.ptr) qse_awk_rtx_freevalstr (rtx, a0, str.ptr);
if (fs_free) QSE_AWK_FREE (rtx->awk, fs_free);
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
if (fs_rex_free)
{
@ -1531,31 +1526,58 @@ static int fnc_ismap (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
return 0;
}
static QSE_INLINE int asort_compare (const void* x1, const void* x2, void* ctx)
static QSE_INLINE int asort_compare (const void* x1, const void* x2, void* ctx, int* cv)
{
int n;
if (qse_awk_rtx_cmpval((qse_awk_rtx_t*)ctx, (qse_awk_val_t*)x1, (qse_awk_val_t*)x2, &n) <= -1) return -1;
return n;
if (qse_awk_rtx_cmpval((qse_awk_rtx_t*)ctx, *(qse_awk_val_t**)x1, *(qse_awk_val_t**)x2, &n) <= -1) return -1;
*cv = n;
return 0;
}
struct cud_t
{
qse_awk_rtx_t* rtx;
qse_awk_fun_t* fun;
};
static QSE_INLINE int asort_compare_ud (const void* x1, const void* x2, void* ctx, int* cv)
{
struct cud_t* cud = (struct cud_t*)ctx;
qse_awk_val_t* r, * args[2];
qse_awk_int_t rv;
args[0] = *(qse_awk_val_t**)x1;
args[1] = *(qse_awk_val_t**)x2;
r = qse_awk_rtx_callfun(cud->rtx, cud->fun, args, 2);
if (!r) return -1;
if (qse_awk_rtx_valtoint(cud->rtx, r, &rv) <= -1) return -1;
*cv = rv;
return 0;
}
static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
qse_size_t nargs;
qse_awk_val_t* a0, * a2;
qse_awk_val_t* a0, * a0_val, * a1, * a2;
qse_awk_val_type_t a0_type, v_type;
qse_awk_val_t* r, * rmap;
qse_awk_int_t rv = 0; /* as if no element in the map */
qse_awk_val_map_itr_t itr;
qse_awk_fun_t* fun;
qse_awk_fun_t* fun = QSE_NULL;
qse_size_t msz, i;
qse_awk_val_t** va;
int x;
nargs = qse_awk_rtx_getnargs(rtx);
a0 = qse_awk_rtx_getarg(rtx, 0);
a0_type = QSE_AWK_RTX_GETVALTYPE(rtx, a0);
QSE_ASSERT (a0_type == QSE_AWK_VAL_REF);
if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) != QSE_AWK_VAL_MAP)
v_type = qse_awk_rtx_getrefvaltype(rtx, (qse_awk_val_ref_t*)a0);
if (v_type != QSE_AWK_VAL_MAP)
{
if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_NIL)
if (v_type == QSE_AWK_VAL_NIL)
{
/* treat it as an empty value */
goto done;
@ -1565,7 +1587,14 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
return -1;
}
a0_val = qse_awk_rtx_getrefval(rtx, (qse_awk_val_ref_t*)a0);
QSE_ASSERT (QSE_AWK_RTX_GETVALTYPE(rtx, a0_val) == QSE_AWK_VAL_MAP);
if (nargs >= 2)
{
a1 = qse_awk_rtx_getarg(rtx, 1); /* destination map */
if (nargs >= 3)
{
a2 = qse_awk_rtx_getarg(rtx, 2);
if (QSE_AWK_RTX_GETVALTYPE(rtx, a2) != QSE_AWK_VAL_FUN)
@ -1582,13 +1611,19 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
return -1;
}
}
}
else
{
a1 = a0; /* let a0 be the destination. a0 is both source and destination */
}
if (!qse_awk_rtx_getfirstmapvalitr(rtx, a0, &itr)) goto done; /* map empty */
msz = qse_htb_getsize(((qse_awk_val_map_t*)a0)->map);
if (!qse_awk_rtx_getfirstmapvalitr(rtx, a0_val, &itr)) goto done; /* map empty */
msz = qse_htb_getsize(((qse_awk_val_map_t*)a0_val)->map);
QSE_ASSERT (msz > 0);
va = (qse_awk_val_t**)qse_awk_rtx_allocmem(rtx, msz * QSE_SIZEOF(qse_awk_val_t*));
va = (qse_awk_val_t**)qse_awk_rtx_allocmem(rtx, msz * QSE_SIZEOF(*va));
if (!va) return -1;
i = 0;
@ -1596,9 +1631,25 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
va[i++] = (qse_awk_val_t*)QSE_AWK_VAL_MAP_ITR_VAL(&itr);
}
while (qse_awk_rtx_getnextmapvalitr(rtx, a0, &itr));
while (qse_awk_rtx_getnextmapvalitr(rtx, a0_val, &itr));
qse_qsort (va, msz, QSE_SIZEOF(*va), asort_compare, rtx);
if (fun)
{
struct cud_t cud;
cud.rtx = rtx;
cud.fun = fun;
x = qse_qsortx(va, msz, QSE_SIZEOF(*va), asort_compare_ud, &cud);
}
else
{
x = qse_qsortx(va, msz, QSE_SIZEOF(*va), asort_compare, rtx);
}
if (x <= -1)
{
qse_awk_rtx_freemem (rtx, va);
return -1;
}
rmap = qse_awk_rtx_makemapval(rtx);
if (!rmap)
@ -1622,7 +1673,7 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
QSE_NULL
);
if (qse_awk_rtx_setmapvalfld (rtx, rmap, ridx, ridx_len, va[i]) == QSE_NULL)
if (qse_awk_rtx_setmapvalfld(rtx, rmap, ridx, ridx_len, va[i]) == QSE_NULL)
{
qse_awk_rtx_freeval (rtx, rmap, 0);
qse_awk_rtx_freemem (rtx, va);
@ -1630,30 +1681,13 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
}
}
{
#if 0
/* TODO: complete this function */
r = qse_awk_rtx_callfun(rtx, fun, valargs, nargs);
if (qse_awk_rtx_valtoint(rtx, r, &rv) <= -1) return -1;
if (rv > 0)
{
}
else if (rv < 0)
{
}
else
{
}
#endif
}
rv = msz;
qse_awk_rtx_freemem (rtx, va);
/* TODO: set the resulting map back to a0.
* or to a1 if a1 is given */
qse_awk_rtx_setretval (rtx, rmap);
return 0;
qse_awk_rtx_refupval (rtx, rmap);
x = qse_awk_rtx_setrefval (rtx, (qse_awk_val_ref_t*)a1, rmap);
qse_awk_rtx_refdownval (rtx, rmap);
if (x <= -1) return -1;
done:
r = qse_awk_rtx_makeintval(rtx, rv);

View File

@ -1650,7 +1650,7 @@ qse_awk_val_t* qse_awk_rtx_callfun (
}
else
{
/* thr return value captured in termination by exit()
/* the return value captured in termination by exit()
* is reference-counted up in capture_retval_on_exit().
* let's do the same thing for the return value normally
* returned. */
@ -5996,7 +5996,7 @@ static qse_awk_val_t* __eval_call (
}
/* push all arguments onto the stack */
nargs = argpusher (run, call, apdata);
nargs = argpusher(run, call, apdata);
if (nargs == (qse_size_t)-1)
{
UNWIND_RTX_STACK_BASE (run);
@ -6049,7 +6049,7 @@ static qse_awk_val_t* __eval_call (
{
run->errinf.num = QSE_AWK_ENOERR;
n = call->u.fnc.spec.impl (run, &call->u.fnc.info);
n = call->u.fnc.spec.impl(run, &call->u.fnc.info);
if (n <= -1)
{

View File

@ -1911,6 +1911,69 @@ qse_awk_int_t qse_awk_rtx_hashval (qse_awk_rtx_t* rtx, qse_awk_val_t* v)
return hv & ~(((qse_awk_uint_t)1) << ((QSE_SIZEOF(qse_awk_uint_t) * 8) - 1));
}
qse_awk_val_type_t qse_awk_rtx_getrefvaltype (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref)
{
/* return the type of the value that the reference points to */
switch (ref->id)
{
case QSE_AWK_VAL_REF_POS:
{
return QSE_AWK_VAL_STR;
}
case QSE_AWK_VAL_REF_GBL:
{
qse_size_t idx;
qse_awk_val_t* v;
idx = (qse_size_t)ref->adr;
v = RTX_STACK_GBL(rtx, idx);
return QSE_AWK_RTX_GETVALTYPE(rtx, v);
}
default:
{
qse_awk_val_t** xref = (qse_awk_val_t**)ref->adr;
qse_awk_val_t* v;
/* A reference value is not able to point to another
* refernce value for the way values are represented
* in QSEAWK */
v = *xref;
QSE_ASSERT (QSE_AWK_RTX_GETVALTYPE(rtx, v) != QSE_AWK_VAL_REF);
return QSE_AWK_RTX_GETVALTYPE(rtx, v);
}
}
}
qse_awk_val_t* qse_awk_rtx_getrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref)
{
switch (ref->id)
{
case QSE_AWK_VAL_REF_POS:
{
/* a positional doesn't contain a value. you should use qse_awk_rtx_valtoXXX()
* like qse_awk_rtx_valtostr(), qse_Awk_rtx_valtoint() */
return QSE_NULL;
}
case QSE_AWK_VAL_REF_GBL:
{
qse_size_t idx;
idx = (qse_size_t)ref->adr;
return RTX_STACK_GBL(rtx, idx);
}
default:
{
qse_awk_val_t** xref = (qse_awk_val_t**)ref->adr;
/* A reference value is not able to point to another
* refernce value for the way values are represented
* in QSEAWK */
QSE_ASSERT (QSE_AWK_RTX_GETVALTYPE (rtx, *xref)!= QSE_AWK_VAL_REF);
return *xref;
}
}
}
int qse_awk_rtx_setrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref, qse_awk_val_t* val)
{
qse_awk_val_type_t vtype = QSE_AWK_RTX_GETVALTYPE (rtx, val);
@ -2001,7 +2064,7 @@ int qse_awk_rtx_setrefval (qse_awk_rtx_t* rtx, qse_awk_val_ref_t* ref, qse_awk_v
qse_awk_val_type_t rref_vtype;
rref = (qse_awk_val_t**)ref->adr; /* old value pointer */
rref_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, *rref); /* old value type */
rref_vtype = QSE_AWK_RTX_GETVALTYPE(rtx, *rref); /* old value type */
if (vtype == QSE_AWK_VAL_MAP)
{
/* new value: map, old value: nil or map => ok */

View File

@ -64,8 +64,8 @@
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
#define swapcode(TYPE,parmi,parmj,n) { \
qse_size_t i = (n) / sizeof (TYPE); \
#define swapcode(TYPE,parmi,parmj,n) do { \
qse_size_t i = (n) / QSE_SIZEOF (TYPE); \
register TYPE *pi = (TYPE*)(parmi); \
register TYPE *pj = (TYPE*)(parmj); \
do { \
@ -73,29 +73,38 @@
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
}
} while(0)
#define SWAPINIT(a,size) \
swaptype = ((qse_byte_t*)a-(qse_byte_t*)0)%sizeof(long) || \
size % sizeof(long) ? 2 : size == sizeof(long)? 0 : 1;
static QSE_INLINE void swapfunc (
qse_byte_t* a, qse_byte_t* b, int n, int swaptype)
{
if (swaptype <= 1)
swapcode(long, a, b, n)
else
swapcode(qse_byte_t, a, b, n)
}
#define get_swaptype(a, elemsize) (((qse_byte_t*)(a) - (qse_byte_t*)0) % QSE_SIZEOF(long) || elemsize % QSE_SIZEOF(long)? 2 : elemsize == QSE_SIZEOF(long)? 0 : 1)
#define swap(a, b) \
if (swaptype == 0) { \
#define swap(a, b, elemsize) do { \
switch (swaptype) \
{ \
case 0: \
{ \
long t = *(long*)(a); \
*(long*)(a) = *(long*)(b); \
*(long*)(b) = t; \
} else swapfunc(a, b, size, swaptype)
break; \
} \
case 1: \
swapcode(long, a, b, elemsize); \
break; \
default: \
swapcode(qse_byte_t, a, b, elemsize); \
break; \
} \
} while(0)
#define vecswap(a,b,n) if ((n) > 0) swapfunc(a, b, n, swaptype)
#define vecswap(a,b,n) do { \
if ((n) > 0) \
{ \
if (swaptype <= 1) swapcode(long, a, b, n); \
else swapcode(qse_byte_t, a, b, n); \
} \
} while(0)
static QSE_INLINE qse_byte_t* med3 (qse_byte_t* a, qse_byte_t* b, qse_byte_t* c, qse_sort_comper_t comper, void* ctx)
{
@ -111,26 +120,48 @@ static QSE_INLINE qse_byte_t* med3 (qse_byte_t* a, qse_byte_t* b, qse_byte_t* c,
}
}
static QSE_INLINE qse_byte_t* med3x (qse_byte_t* a, qse_byte_t* b, qse_byte_t* c, qse_sort_comperx_t comper, void* ctx)
{
int n;
if (comper(a, b, ctx, &n) <= -1) return QSE_NULL;
if (n < 0)
{
if (comper(b, c, ctx, &n) <= -1) return QSE_NULL;
if (n < 0) return b;
if (comper(a, c, ctx, &n) <= -1) return QSE_NULL;
return (n < 0)? c: a;
}
else
{
if (comper(b, c, ctx, &n) <= -1) return QSE_NULL;
if (n > 0) return b;
if (comper(a, c, ctx, &n) <= -1) return QSE_NULL;
return (n > 0)? c: a;
}
}
void qse_qsort (void* base, qse_size_t nmemb, qse_size_t size, qse_sort_comper_t comper, void* ctx)
{
qse_byte_t*pa, *pb, *pc, *pd, *pl, *pm, *pn;
qse_byte_t* pa, * pb, * pc, * pd, * pl, * pm, * pn;
int swaptype, swap_cnt;
long r;
qse_size_t d;
register qse_byte_t*a = (qse_byte_t*)base;
register qse_byte_t* a = (qse_byte_t*)base;
loop:
SWAPINIT(a, size);
swaptype = get_swaptype(a, size);
swap_cnt = 0;
if (nmemb < 7)
{
for (pm = (qse_byte_t*)a + size;
pm < (qse_byte_t*) a + nmemb * size; pm += size)
qse_byte_t* end = (qse_byte_t*)a + (nmemb * size);
for (pm = (qse_byte_t*)a + size; pm < end; pm += size)
{
for (pl = pm; pl > (qse_byte_t*)a && comper(pl - size, pl, ctx) > 0; pl -= size)
{
swap(pl, pl - size);
swap(pl, pl - size, size);
}
}
return;
@ -149,7 +180,7 @@ loop:
}
pm = med3(pl, pm, pn, comper, ctx);
}
swap(a, pm);
swap(a, pm, size);
pa = pb = (qse_byte_t*)a + size;
pc = pd = (qse_byte_t*)a + (nmemb - 1) * size;
@ -160,7 +191,7 @@ loop:
if (r == 0)
{
swap_cnt = 1;
swap(pa, pb);
swap(pa, pb, size);
pa += size;
}
pb += size;
@ -170,13 +201,13 @@ loop:
if (r == 0)
{
swap_cnt = 1;
swap(pc, pd);
swap(pc, pd, size);
pd -= size;
}
pc -= size;
}
if (pb > pc) break;
swap (pb, pc);
swap (pb, pc, size);
swap_cnt = 1;
pb += size;
pc -= size;
@ -188,10 +219,9 @@ loop:
for (pm = (qse_byte_t*)a + size;
pm < (qse_byte_t*)a + nmemb * size; pm += size)
{
for (pl = pm; pl > (qse_byte_t*)a &&
comper(pl - size, pl, ctx) > 0; pl -= size)
for (pl = pm; pl > (qse_byte_t*)a && comper(pl - size, pl, ctx) > 0; pl -= size)
{
swap(pl, pl - size);
swap(pl, pl - size, size);
}
}
return;
@ -215,6 +245,134 @@ loop:
/* qsort(pn - r, r / size, size, comper);*/
}
int qse_qsortx (void* base, qse_size_t nmemb, qse_size_t size, qse_sort_comperx_t comper, void* ctx)
{
qse_byte_t* pa, * pb, * pc, * pd, * pl, * pm, * pn;
int swaptype, swap_cnt;
long r;
int n;
qse_size_t d;
register qse_byte_t* a = (qse_byte_t*)base;
loop:
swaptype = get_swaptype(a, size);
swap_cnt = 0;
if (nmemb < 7)
{
qse_byte_t* end = (qse_byte_t*)a + (nmemb * size);
for (pm = (qse_byte_t*)a + size; pm < end; pm += size)
{
pl = pm;
while (pl > (qse_byte_t*)a)
{
qse_byte_t* pl2 = pl - size;
if (comper(pl2, pl, ctx, &n) <= -1) return -1;
if (n <= 0) break;
swap (pl, pl2, size);
pl = pl2;
}
}
return 0;
}
pm = (qse_byte_t*)a + (nmemb / 2) * size;
if (nmemb > 7)
{
pl = (qse_byte_t*)a;
pn = (qse_byte_t*)a + (nmemb - 1) * size;
if (nmemb > 40)
{
d = (nmemb / 8) * size;
pl = med3x(pl, pl + d, pl + 2 * d, comper, ctx);
if (!pl) return -1;
pm = med3x(pm - d, pm, pm + d, comper, ctx);
if (!pm) return -1;
pn = med3x(pn - 2 * d, pn - d, pn, comper, ctx);
if (!pn) return -1;
}
pm = med3x(pl, pm, pn, comper, ctx);
if (!pm) return -1;
}
swap(a, pm, size);
pa = pb = (qse_byte_t*)a + size;
pc = pd = (qse_byte_t*)a + (nmemb - 1) * size;
for (;;)
{
while (pb <= pc)
{
if (comper(pb, a, ctx, &n) <= -1) return -1;
if (n > 0) break;
if (n == 0)
{
swap_cnt = 1;
swap(pa, pb, size);
pa += size;
}
pb += size;
}
while (pb <= pc)
{
if (comper(pc, a, ctx, &n) <= -1) return -1;
if (n < 0) break;
if (n == 0)
{
swap_cnt = 1;
swap(pc, pd, size);
pd -= size;
}
pc -= size;
}
if (pb > pc) break;
swap (pb, pc, size);
swap_cnt = 1;
pb += size;
pc -= size;
}
if (swap_cnt == 0)
{
/* switch to insertion sort */
qse_byte_t* end = (qse_byte_t*)a + (nmemb * size);
for (pm = (qse_byte_t*)a + size; pm < end; pm += size)
{
pl = pm;
while (pl > (qse_byte_t*)a)
{
if (comper(pl - size, pl, ctx, &n) <= -1) return -1;
if (n <= 0) break;
swap(pl, pl - size, size);
pl = pl - size;
}
}
return 0;
}
pn = (qse_byte_t*)a + nmemb * size;
r = qsort_min(pa - (qse_byte_t*)a, pb - pa);
vecswap (a, pb - r, r);
r = qsort_min (pd - pc, pn - pd - size);
vecswap (pb, pn - r, r);
if ((r = pb - pa) > size)
{
if (qse_qsortx(a, r / size, size, comper, ctx) <= -1) return -1;
}
if ((r = pd - pc) > size)
{
/* Iterate rather than recurse to save stack space */
a = pn - r;
nmemb = r / size;
goto loop;
}
/* qsortx(pn - r, r / size, size, comper);*/
return 0;
}
#if 0
/*