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 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 * The qse_awk_rtx_setrefval() function changes the value
* of a variable referenced in \a ref. * of a variable referenced in \a ref.

View File

@ -55,10 +55,23 @@ typedef int (*qse_search_comper_t) (
void* ctx 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. * The qse_sort_comper_t type defines a sort callback function.
*/ */
typedef qse_search_comper_t qse_sort_comper_t; typedef qse_search_comper_t qse_sort_comper_t;
typedef qse_search_comperx_t qse_sort_comperx_t;
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { extern "C" {
@ -134,6 +147,14 @@ QSE_EXPORT void qse_qsort (
void* ctx 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 * 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. * - v: value. pass it after normal evaluation.
* - r: pass a variable by reference * - 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 * If the first character of the specifer is 'R', all
* parameters are passed by reference regarless of the remaining * parameters are passed by reference regarless of the remaining
@ -67,30 +67,30 @@ static qse_awk_fnc_t sysfnctab[] =
{ {QSE_T("typename"), 8}, 0, { {1, 1, QSE_NULL}, fnc_typename, 0 }, QSE_NULL}, { {QSE_T("typename"), 8}, 0, { {1, 1, QSE_NULL}, fnc_typename, 0 }, QSE_NULL},
/* array sort */ /* 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 */ /* string functions */
{ {QSE_T("gsub"), 4}, 0, { {2, 3, QSE_T("xvr")}, qse_awk_fnc_gsub, 0 }, QSE_NULL}, { {QSE_T("gsub"), 4}, 0, { {2, 3, QSE_T("xvr")}, qse_awk_fnc_gsub, 0 }, QSE_NULL},
{ {QSE_T("index"), 5}, 0, { {2, 3, QSE_NULL}, qse_awk_fnc_index, 0 }, QSE_NULL}, { {QSE_T("index"), 5}, 0, { {2, 3, QSE_NULL}, qse_awk_fnc_index, 0 }, QSE_NULL},
{ {QSE_T("length"), 6}, 1, { {0, 1, QSE_NULL}, qse_awk_fnc_length, 0 }, QSE_NULL}, { {QSE_T("length"), 6}, 1, { {0, 1, QSE_NULL}, qse_awk_fnc_length, 0 }, QSE_NULL},
{ {QSE_T("match"), 5}, 0, { {2, 4, QSE_T("vxvr")}, qse_awk_fnc_match, 0 }, QSE_NULL}, { {QSE_T("match"), 5}, 0, { {2, 4, QSE_T("vxvr")}, qse_awk_fnc_match, 0 }, QSE_NULL},
{ {QSE_T("split"), 5}, 0, { {2, 3, QSE_T("vrx")}, qse_awk_fnc_split, 0 }, QSE_NULL}, { {QSE_T("split"), 5}, 0, { {2, 3, QSE_T("vrx")}, qse_awk_fnc_split, 0 }, QSE_NULL},
{ {QSE_T("sprintf"), 7}, 0, { {1, A_MAX, QSE_NULL}, qse_awk_fnc_sprintf, 0 }, QSE_NULL}, { {QSE_T("sprintf"), 7}, 0, { {1, A_MAX, QSE_NULL}, qse_awk_fnc_sprintf, 0 }, QSE_NULL},
{ {QSE_T("sub"), 3}, 0, { {2, 3, QSE_T("xvr")}, qse_awk_fnc_sub, 0 }, QSE_NULL}, { {QSE_T("sub"), 3}, 0, { {2, 3, QSE_T("xvr")}, qse_awk_fnc_sub, 0 }, QSE_NULL},
{ {QSE_T("substr"), 6}, 0, { {2, 3, QSE_NULL}, qse_awk_fnc_substr, 0 }, QSE_NULL}, { {QSE_T("substr"), 6}, 0, { {2, 3, QSE_NULL}, qse_awk_fnc_substr, 0 }, QSE_NULL},
{ {QSE_T("tolower"), 7}, 0, { {1, 1, QSE_NULL}, qse_awk_fnc_tolower, 0 }, QSE_NULL}, { {QSE_T("tolower"), 7}, 0, { {1, 1, QSE_NULL}, qse_awk_fnc_tolower, 0 }, QSE_NULL},
{ {QSE_T("toupper"), 7}, 0, { {1, 1, QSE_NULL}, qse_awk_fnc_toupper, 0 }, QSE_NULL}, { {QSE_T("toupper"), 7}, 0, { {1, 1, QSE_NULL}, qse_awk_fnc_toupper, 0 }, QSE_NULL},
/* math functions */ /* math functions */
{ {QSE_T("sin"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("sin"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
{ {QSE_T("cos"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("cos"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
{ {QSE_T("tan"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("tan"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
{ {QSE_T("atan"), 4}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("atan"), 4}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
{ {QSE_T("atan2"), 5}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("atan2"), 5}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
{ {QSE_T("log"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("log"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
{ {QSE_T("log10"), 5}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("log10"), 5}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
{ {QSE_T("exp"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("exp"), 3}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
{ {QSE_T("sqrt"), 4}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("sqrt"), 4}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL},
/* time functions */ /* time functions */
{ {QSE_T("mktime"), 6}, 0, { {A_MAX, 0, QSE_T("sys") }, QSE_NULL, 0 }, QSE_NULL}, { {QSE_T("mktime"), 6}, 0, { {A_MAX, 0, QSE_T("sys") }, QSE_NULL, 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; a2 = (nargs >= 3)? qse_awk_rtx_getarg (rtx, 2): QSE_NULL;
a1_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, a1); a1_vtype = QSE_AWK_RTX_GETVALTYPE (rtx, a1);
QSE_ASSERT (a1_vtype == QSE_AWK_VAL_REF); QSE_ASSERT (a1_vtype == QSE_AWK_VAL_REF);
str.ptr = qse_awk_rtx_getvalstr(rtx, a0, &str.len); 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 */ /* get the value from FS */
t1 = qse_awk_rtx_getgbl(rtx, QSE_AWK_GBL_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) if (t1_vtype == QSE_AWK_VAL_NIL)
{ {
fs.ptr = QSE_T(" "); 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 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; if (fs.ptr == QSE_NULL) goto oops;
fs_free = (qse_char_t*)fs.ptr; 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) if (fs.len <= 1)
{ {
p = qse_awk_rtx_strxntok (rtx, p = qse_awk_rtx_strxntok(rtx, p, str.len, fs.ptr, fs.len, &tok);
p, str.len, fs.ptr, fs.len, &tok);
} }
else else
{ {
p = qse_awk_rtx_strxntokbyrex ( p = qse_awk_rtx_strxntokbyrex(rtx, str.ptr, org_len, p, str.len, fs_rex, &tok, &errnum);
rtx, str.ptr, org_len, p, str.len,
fs_rex, &tok, &errnum
);
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR) if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
{ {
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL); 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);*/ /*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/
qse_awk_rtx_freevalstr (rtx, a0, 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) if (fs_rex_free)
{ {
@ -870,7 +865,7 @@ oops:
/*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/ /*if (str_free) QSE_AWK_FREE (rtx->awk, str_free);*/
if (str.ptr) qse_awk_rtx_freevalstr (rtx, a0, str.ptr); 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) 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; 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; 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; 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; *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) static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{ {
qse_size_t nargs; 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_val_t* r, * rmap;
qse_awk_int_t rv = 0; /* as if no element in the map */ qse_awk_int_t rv = 0; /* as if no element in the map */
qse_awk_val_map_itr_t itr; 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_size_t msz, i;
qse_awk_val_t** va; qse_awk_val_t** va;
int x;
nargs = qse_awk_rtx_getnargs(rtx); nargs = qse_awk_rtx_getnargs(rtx);
a0 = qse_awk_rtx_getarg(rtx, 0); 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 */ /* treat it as an empty value */
goto done; goto done;
@ -1565,30 +1587,43 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
return -1; 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) if (nargs >= 2)
{ {
a2 = qse_awk_rtx_getarg(rtx, 2); a1 = qse_awk_rtx_getarg(rtx, 1); /* destination map */
if (QSE_AWK_RTX_GETVALTYPE(rtx, a2) != QSE_AWK_VAL_FUN)
{
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL);
return -1;
}
fun = ((qse_awk_val_fun_t*)a2)->fun; if (nargs >= 3)
if (fun->nargs < 2)
{ {
/* the comparison accepts less than 2 arguments */ a2 = qse_awk_rtx_getarg(rtx, 2);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL); if (QSE_AWK_RTX_GETVALTYPE(rtx, a2) != QSE_AWK_VAL_FUN)
return -1; {
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL);
return -1;
}
fun = ((qse_awk_val_fun_t*)a2)->fun;
if (fun->nargs < 2)
{
/* the comparison accepts less than 2 arguments */
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL);
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); 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; if (!va) return -1;
i = 0; 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); 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); rmap = qse_awk_rtx_makemapval(rtx);
if (!rmap) if (!rmap)
@ -1622,7 +1673,7 @@ static int fnc_asort (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
QSE_NULL 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_freeval (rtx, rmap, 0);
qse_awk_rtx_freemem (rtx, va); 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; rv = msz;
qse_awk_rtx_freemem (rtx, va); qse_awk_rtx_freemem (rtx, va);
/* TODO: set the resulting map back to a0.
* or to a1 if a1 is given */ qse_awk_rtx_refupval (rtx, rmap);
qse_awk_rtx_setretval (rtx, rmap); x = qse_awk_rtx_setrefval (rtx, (qse_awk_val_ref_t*)a1, rmap);
return 0; qse_awk_rtx_refdownval (rtx, rmap);
if (x <= -1) return -1;
done: done:
r = qse_awk_rtx_makeintval(rtx, rv); r = qse_awk_rtx_makeintval(rtx, rv);

View File

@ -1650,7 +1650,7 @@ qse_awk_val_t* qse_awk_rtx_callfun (
} }
else 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(). * is reference-counted up in capture_retval_on_exit().
* let's do the same thing for the return value normally * let's do the same thing for the return value normally
* returned. */ * returned. */
@ -5996,7 +5996,7 @@ static qse_awk_val_t* __eval_call (
} }
/* push all arguments onto the stack */ /* push all arguments onto the stack */
nargs = argpusher (run, call, apdata); nargs = argpusher(run, call, apdata);
if (nargs == (qse_size_t)-1) if (nargs == (qse_size_t)-1)
{ {
UNWIND_RTX_STACK_BASE (run); UNWIND_RTX_STACK_BASE (run);
@ -6049,7 +6049,7 @@ static qse_awk_val_t* __eval_call (
{ {
run->errinf.num = QSE_AWK_ENOERR; 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) 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)); 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) 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); 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; qse_awk_val_type_t rref_vtype;
rref = (qse_awk_val_t**)ref->adr; /* old value pointer */ 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) if (vtype == QSE_AWK_VAL_MAP)
{ {
/* new value: map, old value: nil or map => ok */ /* 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". * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/ */
#define swapcode(TYPE,parmi,parmj,n) { \ #define swapcode(TYPE,parmi,parmj,n) do { \
qse_size_t i = (n) / sizeof (TYPE); \ qse_size_t i = (n) / QSE_SIZEOF (TYPE); \
register TYPE *pi = (TYPE*)(parmi); \ register TYPE *pi = (TYPE*)(parmi); \
register TYPE *pj = (TYPE*)(parmj); \ register TYPE *pj = (TYPE*)(parmj); \
do { \ do { \
@ -73,29 +73,38 @@
*pi++ = *pj; \ *pi++ = *pj; \
*pj++ = t; \ *pj++ = t; \
} while (--i > 0); \ } 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 ( #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)
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 swap(a, b) \ #define swap(a, b, elemsize) do { \
if (swaptype == 0) { \ switch (swaptype) \
long t = *(long*)(a); \ { \
*(long*)(a) = *(long*)(b); \ case 0: \
*(long*)(b) = t; \ { \
} else swapfunc(a, b, size, swaptype) long t = *(long*)(a); \
*(long*)(a) = *(long*)(b); \
*(long*)(b) = t; \
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) 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) 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; int swaptype, swap_cnt;
long r; long r;
qse_size_t d; qse_size_t d;
register qse_byte_t*a = (qse_byte_t*)base; register qse_byte_t* a = (qse_byte_t*)base;
loop: loop:
SWAPINIT(a, size); swaptype = get_swaptype(a, size);
swap_cnt = 0; swap_cnt = 0;
if (nmemb < 7) if (nmemb < 7)
{ {
for (pm = (qse_byte_t*)a + size; qse_byte_t* end = (qse_byte_t*)a + (nmemb * size);
pm < (qse_byte_t*) a + nmemb * size; pm += 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) 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; return;
@ -149,7 +180,7 @@ loop:
} }
pm = med3(pl, pm, pn, comper, ctx); pm = med3(pl, pm, pn, comper, ctx);
} }
swap(a, pm); swap(a, pm, size);
pa = pb = (qse_byte_t*)a + size; pa = pb = (qse_byte_t*)a + size;
pc = pd = (qse_byte_t*)a + (nmemb - 1) * size; pc = pd = (qse_byte_t*)a + (nmemb - 1) * size;
@ -160,7 +191,7 @@ loop:
if (r == 0) if (r == 0)
{ {
swap_cnt = 1; swap_cnt = 1;
swap(pa, pb); swap(pa, pb, size);
pa += size; pa += size;
} }
pb += size; pb += size;
@ -170,13 +201,13 @@ loop:
if (r == 0) if (r == 0)
{ {
swap_cnt = 1; swap_cnt = 1;
swap(pc, pd); swap(pc, pd, size);
pd -= size; pd -= size;
} }
pc -= size; pc -= size;
} }
if (pb > pc) break; if (pb > pc) break;
swap (pb, pc); swap (pb, pc, size);
swap_cnt = 1; swap_cnt = 1;
pb += size; pb += size;
pc -= size; pc -= size;
@ -188,10 +219,9 @@ loop:
for (pm = (qse_byte_t*)a + size; for (pm = (qse_byte_t*)a + size;
pm < (qse_byte_t*)a + nmemb * size; pm += size) pm < (qse_byte_t*)a + nmemb * size; pm += size)
{ {
for (pl = pm; pl > (qse_byte_t*)a && for (pl = pm; pl > (qse_byte_t*)a && comper(pl - size, pl, ctx) > 0; pl -= size)
comper(pl - size, pl, ctx) > 0; pl -= size)
{ {
swap(pl, pl - size); swap(pl, pl - size, size);
} }
} }
return; return;
@ -215,6 +245,134 @@ loop:
/* qsort(pn - r, r / size, size, comper);*/ /* 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 #if 0
/* /*