From 2ac2ad8200d8abeffa34eb58ea49f8a73c19144e Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Tue, 7 May 2019 07:22:55 +0000 Subject: [PATCH] added qse_awk_rtx_getrefvaltype()/qse_awk_rtx_getrefval() finished asort() in awk added qse_sortx() --- qse/include/qse/awk/awk.h | 15 +++ qse/include/qse/cmn/alg.h | 21 ++++ qse/lib/awk/fnc.c | 198 +++++++++++++++++++-------------- qse/lib/awk/run.c | 6 +- qse/lib/awk/val.c | 65 ++++++++++- qse/lib/cmn/alg-sort.c | 228 ++++++++++++++++++++++++++++++++------ 6 files changed, 412 insertions(+), 121 deletions(-) diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index 149fd608..edaae3a4 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -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. diff --git a/qse/include/qse/cmn/alg.h b/qse/include/qse/cmn/alg.h index 2e486aba..9c70cd97 100644 --- a/qse/include/qse/cmn/alg.h +++ b/qse/include/qse/cmn/alg.h @@ -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 diff --git a/qse/lib/awk/fnc.c b/qse/lib/awk/fnc.c index 6614c06b..2bde88cc 100644 --- a/qse/lib/awk/fnc.c +++ b/qse/lib/awk/fnc.c @@ -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,30 +67,30 @@ 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}, - { {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("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("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("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("toupper"), 7}, 0, { {1, 1, QSE_NULL}, qse_awk_fnc_toupper, 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("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("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("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("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}, /* math functions */ - { {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("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("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("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("sqrt"), 4}, 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("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("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("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("sqrt"), 4}, 0, { {A_MAX, 0, QSE_T("math") }, QSE_NULL, 0 }, QSE_NULL}, /* time functions */ { {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; 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); @@ -821,7 +816,7 @@ int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) { /* no field at all*/ break; - } + } QSE_ASSERT ((tok.ptr != QSE_NULL && tok.len > 0) || tok.len == 0); @@ -848,13 +843,13 @@ 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) { if (rtx->gbl.ignorecase) qse_awk_freerex (rtx->awk, QSE_NULL, fs_rex_free); - else + else qse_awk_freerex (rtx->awk, fs_rex_free, QSE_NULL); } @@ -870,13 +865,13 @@ 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) { if (rtx->gbl.ignorecase) qse_awk_freerex (rtx->awk, QSE_NULL, fs_rex_free); - else + else qse_awk_freerex (rtx->awk, fs_rex_free, QSE_NULL); } return -1; @@ -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); - - if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) != QSE_AWK_VAL_MAP) + a0_type = QSE_AWK_RTX_GETVALTYPE(rtx, a0); + QSE_ASSERT (a0_type == QSE_AWK_VAL_REF); + + 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,30 +1587,43 @@ 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) { - a2 = qse_awk_rtx_getarg(rtx, 2); - if (QSE_AWK_RTX_GETVALTYPE(rtx, a2) != QSE_AWK_VAL_FUN) + a1 = qse_awk_rtx_getarg(rtx, 1); /* destination map */ + + if (nargs >= 3) { - qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINVAL, QSE_NULL); - return -1; - } + a2 = qse_awk_rtx_getarg(rtx, 2); + 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 (fun->nargs < 2) - { - /* the comparison accepts less than 2 arguments */ - 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); - 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); diff --git a/qse/lib/awk/run.c b/qse/lib/awk/run.c index faf39f4c..5f961582 100644 --- a/qse/lib/awk/run.c +++ b/qse/lib/awk/run.c @@ -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) { diff --git a/qse/lib/awk/val.c b/qse/lib/awk/val.c index b76ed422..e04c4e4c 100644 --- a/qse/lib/awk/val.c +++ b/qse/lib/awk/val.c @@ -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 */ diff --git a/qse/lib/cmn/alg-sort.c b/qse/lib/cmn/alg-sort.c index de3193d1..bd5b884d 100644 --- a/qse/lib/cmn/alg-sort.c +++ b/qse/lib/cmn/alg-sort.c @@ -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) { \ - long t = *(long*)(a); \ - *(long*)(a) = *(long*)(b); \ - *(long*)(b) = t; \ - } else swapfunc(a, b, size, swaptype) - -#define vecswap(a,b,n) if ((n) > 0) swapfunc(a, b, n, swaptype) +#define swap(a, b, elemsize) do { \ + switch (swaptype) \ + { \ + case 0: \ + { \ + 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) 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 /*