diff --git a/hawk/lib/fnc.c b/hawk/lib/fnc.c index d9ebdb3c..3dd8caec 100644 --- a/hawk/lib/fnc.c +++ b/hawk/lib/fnc.c @@ -1774,13 +1774,9 @@ static HAWK_INLINE int __fnc_asort (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi, hawk_oow_t nargs; hawk_val_t* a0, * a0_val; hawk_val_type_t a0_type, v_type; - hawk_val_t* r, * rmap = HAWK_NULL; + hawk_val_t* r, * rrv = HAWK_NULL; hawk_int_t rv = 0; /* as if no element in the map */ - hawk_val_map_itr_t itr; hawk_fun_t* fun = HAWK_NULL; - hawk_oow_t msz, i; - hawk_val_t** va; - int x; nargs = hawk_rtx_getnargs(rtx); @@ -1788,23 +1784,6 @@ static HAWK_INLINE int __fnc_asort (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi, a0_type = HAWK_RTX_GETVALTYPE(rtx, a0); HAWK_ASSERT (a0_type == HAWK_VAL_REF); -/* TODO: handle HAWK_VAL_ARR as input */ - v_type = hawk_rtx_getrefvaltype(rtx, (hawk_val_ref_t*)a0); - if (v_type != HAWK_VAL_MAP) - { - if (v_type == HAWK_VAL_NIL) - { - /* treat it as an empty value */ - goto done; - } - - hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_ENOTMAP, HAWK_T("source not a map")); - return -1; - } - - a0_val = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)a0); - HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, a0_val) == HAWK_VAL_MAP); - if (nargs >= 3) { fun = hawk_rtx_valtofun(rtx, hawk_rtx_getarg(rtx, 2)); @@ -1823,111 +1802,215 @@ static HAWK_INLINE int __fnc_asort (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi, } } - if (!hawk_rtx_getfirstmapvalitr(rtx, a0_val, &itr)) goto done; /* map empty */ - - msz = hawk_map_getsize(((hawk_val_map_t*)a0_val)->map); - HAWK_ASSERT (msz > 0); - - va = (hawk_val_t**)hawk_rtx_allocmem(rtx, msz * HAWK_SIZEOF(*va)); - if (HAWK_UNLIKELY(!va)) return -1; - i = 0; - if (sort_keys) + v_type = hawk_rtx_getrefvaltype(rtx, (hawk_val_ref_t*)a0); + switch (v_type) { - do + case HAWK_VAL_NIL: + goto done; /* treat it as an empty value */ + + case HAWK_VAL_MAP: + goto val_map; + + case HAWK_VAL_ARR: + goto val_arr; + + default: + hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_ENOTIDXACC); + return -1; + } + +val_map: + { + hawk_val_map_itr_t itr; + hawk_oow_t i, msz; + hawk_val_t** va; + int x; + + a0_val = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)a0); + HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, a0_val) == HAWK_VAL_MAP); + + if (!hawk_rtx_getfirstmapvalitr(rtx, a0_val, &itr)) goto done; /* map empty */ + + msz = hawk_map_getsize(((hawk_val_map_t*)a0_val)->map); + HAWK_ASSERT (msz > 0); + + va = (hawk_val_t**)hawk_rtx_allocmem(rtx, msz * HAWK_SIZEOF(*va)); + if (HAWK_UNLIKELY(!va)) return -1; + i = 0; + if (sort_keys) { - const hawk_oocs_t* key = HAWK_VAL_MAP_ITR_KEY(&itr); - va[i] = hawk_rtx_makestrvalwithoocs(rtx, key); - if (HAWK_UNLIKELY(!va[i])) - { - while (i > 0) - { - --i; - hawk_rtx_refdownval (rtx, va[i]); - } - hawk_rtx_freemem (rtx, va); - return -1; - } - hawk_rtx_refupval (rtx, va[i]); - i++; - } - while (hawk_rtx_getnextmapvalitr(rtx, a0_val, &itr)); - } - else - { - do - { - va[i] = (hawk_val_t*)HAWK_VAL_MAP_ITR_VAL(&itr); - hawk_rtx_refupval (rtx, va[i]); - i++; - } - while (hawk_rtx_getnextmapvalitr(rtx, a0_val, &itr)); - } - - if (fun) - { - struct cud_t cud; - cud.rtx = rtx; - cud.fun = fun; - x = hawk_qsortx(va, msz, HAWK_SIZEOF(*va), asort_compare_ud, &cud); - } - else - { - x = hawk_qsortx(va, msz, HAWK_SIZEOF(*va), asort_compare, rtx); - } - - if (x <= -1 || !(rmap = hawk_rtx_makemapval(rtx))) - { - for (i = 0; i < msz; i++) hawk_rtx_refdownval (rtx, va[i]); - hawk_rtx_freemem (rtx, va); - return -1; - } - - for (i = 0; i < msz; i++) - { - hawk_ooch_t ridx[128]; /* TODO: make it dynamic? can overflow? */ - hawk_oow_t ridx_len; - - ridx_len = hawk_fmt_uintmax_to_oocstr( - ridx, - HAWK_COUNTOF(ridx), - i, - 10 | HAWK_FMT_UINTMAX_NOTRUNC | HAWK_FMT_UINTMAX_NONULL, - -1, - HAWK_T('\0'), - HAWK_NULL - ); - - if (hawk_rtx_setmapvalfld(rtx, rmap, ridx, ridx_len, va[i]) == HAWK_NULL) - { - /* decrement the reference count of the values not added to the map */ do { - hawk_rtx_refdownval (rtx, va[i]); + const hawk_oocs_t* key = HAWK_VAL_MAP_ITR_KEY(&itr); + va[i] = hawk_rtx_makestrvalwithoocs(rtx, key); + if (HAWK_UNLIKELY(!va[i])) + { + while (i > 0) + { + --i; + hawk_rtx_refdownval (rtx, va[i]); + } + hawk_rtx_freemem (rtx, va); + return -1; + } + hawk_rtx_refupval (rtx, va[i]); i++; } - while (i < msz); - hawk_rtx_freeval (rtx, rmap, 0); /* this derefs the elements added. */ + while (hawk_rtx_getnextmapvalitr(rtx, a0_val, &itr)); + } + else + { + do + { + va[i] = (hawk_val_t*)HAWK_VAL_MAP_ITR_VAL(&itr); + hawk_rtx_refupval (rtx, va[i]); + i++; + } + while (hawk_rtx_getnextmapvalitr(rtx, a0_val, &itr)); + } + + if (fun) + { + struct cud_t cud; + cud.rtx = rtx; + cud.fun = fun; + x = hawk_qsortx(va, msz, HAWK_SIZEOF(*va), asort_compare_ud, &cud); + } + else + { + x = hawk_qsortx(va, msz, HAWK_SIZEOF(*va), asort_compare, rtx); + } + + if (x <= -1 || !(rrv = hawk_rtx_makemapval(rtx))) + { + for (i = 0; i < msz; i++) hawk_rtx_refdownval (rtx, va[i]); hawk_rtx_freemem (rtx, va); return -1; } - hawk_rtx_refdownval (rtx, va[i]); /* deref it as it has been added to the map */ + for (i = 0; i < msz; i++) + { + hawk_ooch_t ridx[128]; /* TODO: make it dynamic? can overflow? */ + hawk_oow_t ridx_len; + + ridx_len = hawk_fmt_uintmax_to_oocstr( + ridx, + HAWK_COUNTOF(ridx), + i + 1, /* basically 1-based */ + 10 | HAWK_FMT_UINTMAX_NOTRUNC | HAWK_FMT_UINTMAX_NONULL, + -1, + HAWK_T('\0'), + HAWK_NULL + ); + + if (hawk_rtx_setmapvalfld(rtx, rrv, ridx, ridx_len, va[i]) == HAWK_NULL) + { + /* decrement the reference count of the values not added to the map */ + do + { + hawk_rtx_refdownval (rtx, va[i]); + i++; + } + while (i < msz); + hawk_rtx_freeval (rtx, rrv, 0); /* this derefs the elements added. */ + hawk_rtx_freemem (rtx, va); + return -1; + } + + hawk_rtx_refdownval (rtx, va[i]); /* deref it as it has been added to the map */ + } + + rv = msz; + hawk_rtx_freemem (rtx, va); + goto done; } - rv = msz; - hawk_rtx_freemem (rtx, va); + +val_arr: + { + hawk_arr_t* arr; + hawk_oow_t i, j, msz, ssz; + hawk_val_t** va; + int x; + + a0_val = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)a0); + HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, a0_val) == HAWK_VAL_ARR); + arr = ((hawk_val_arr_t*)a0_val)->arr; + msz = HAWK_ARR_TALLY(arr); + if (msz == 0) goto done; /* array empty */ + + ssz = HAWK_ARR_SIZE(arr); + HAWK_ASSERT (msz <= ssz); + HAWK_ASSERT (msz <= HAWK_QUICKINT_MAX); + HAWK_ASSERT (ssz <= HAWK_QUICKINT_MAX); + + va = (hawk_val_t**)hawk_rtx_allocmem(rtx, msz * HAWK_SIZEOF(*va)); + if (HAWK_UNLIKELY(!va)) return -1; + for (i = 0, j = 0; j < ssz; j++) + { + if (HAWK_ARR_SLOT(arr, j)) + { + va[i] = sort_keys? hawk_rtx_makeintval(rtx, j): HAWK_ARR_DPTR(arr, j); + hawk_rtx_refupval (rtx, va[i]); + i++; + } + } + + if (fun) + { + struct cud_t cud; + cud.rtx = rtx; + cud.fun = fun; + x = hawk_qsortx(va, msz, HAWK_SIZEOF(*va), asort_compare_ud, &cud); + } + else + { + x = hawk_qsortx(va, msz, HAWK_SIZEOF(*va), asort_compare, rtx); + } + + if (x <= -1 || !(rrv = hawk_rtx_makearrval(rtx, -1))) + { + for (i = 0; i < msz; i++) hawk_rtx_refdownval (rtx, va[i]); + hawk_rtx_freemem (rtx, va); + return -1; + } + + for (i = 0; i < msz; i++) + { + if (hawk_rtx_setarrvalfld(rtx, rrv, i + 1, va[i]) == HAWK_NULL) /* i + 1 for 1-based indexing*/ + { + /* decrement the reference count of the values not added to the map */ + do + { + hawk_rtx_refdownval (rtx, va[i]); + i++; + } + while (i < msz); + hawk_rtx_freeval (rtx, rrv, 0); /* this derefs the elements added. */ + hawk_rtx_freemem (rtx, va); + return -1; + } + + hawk_rtx_refdownval (rtx, va[i]); /* deref it as it has been added to the map */ + } + + rv = msz; + hawk_rtx_freemem (rtx, va); + goto done; + } done: r = hawk_rtx_makeintval(rtx, rv); - if (!r) return -1; + if (HAWK_UNLIKELY(!r)) return -1; - if (rmap) + if (rrv) { - /* rmap can be NULL when a jump has been made for an empty source + int x; + /* rrv can be NULL when a jump has been made for an empty source * at the beginning of this fucntion */ - hawk_rtx_refupval (rtx, rmap); - x = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, (nargs >= 2)), rmap); - hawk_rtx_refdownval (rtx, rmap); + hawk_rtx_refupval (rtx, rrv); + x = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, (nargs >= 2)), rrv); + hawk_rtx_refdownval (rtx, rrv); if (x <= -1) { hawk_rtx_freeval (rtx, r, 0); diff --git a/hawk/lib/hawk.h b/hawk/lib/hawk.h index 3f9a7d6c..69065a69 100644 --- a/hawk/lib/hawk.h +++ b/hawk/lib/hawk.h @@ -2962,6 +2962,20 @@ HAWK_EXPORT hawk_val_map_itr_t* hawk_rtx_getnextmapvalitr ( hawk_val_map_itr_t* itr ); + +HAWK_EXPORT hawk_val_t* hawk_rtx_setarrvalfld ( + hawk_rtx_t* rtx, + hawk_val_t* arr, + hawk_ooi_t index, + hawk_val_t* v +); + +HAWK_EXPORT hawk_val_t* hawk_rtx_getarrvalfld ( + hawk_rtx_t* rtx, + hawk_val_t* arr, + hawk_ooi_t index +); + /** * The hawk_rtx_makerefval() function creates a reference value. * \return value on success, #HAWK_NULL on failure diff --git a/hawk/lib/val.c b/hawk/lib/val.c index a91a9934..9d0395b2 100644 --- a/hawk/lib/val.c +++ b/hawk/lib/val.c @@ -1287,6 +1287,30 @@ hawk_val_map_itr_t* hawk_rtx_getnextmapvalitr (hawk_rtx_t* rtx, hawk_val_t* map, return itr->pair? itr: HAWK_NULL; } +hawk_val_t* hawk_rtx_setarrvalfld (hawk_rtx_t* rtx, hawk_val_t* arr, hawk_ooi_t index, hawk_val_t* v) +{ + HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, arr) == HAWK_VAL_ARR); + + if (hawk_arr_upsert(((hawk_val_arr_t*)arr)->arr, index, v, 0) == HAWK_ARR_NIL) return HAWK_NULL; + + /* the value is passed in by an external party. we can't refup() + * and refdown() the value if htb_upsert() fails. that way, the value + * can be destroyed if it was passed with the reference count of 0. + * so we increment the reference count when htb_upsert() is complete */ + hawk_rtx_refupval (rtx, v); + + return v; +} + +hawk_val_t* hawk_rtx_getarrvalfld (hawk_rtx_t* rtx, hawk_val_t* arr, hawk_ooi_t index) +{ + hawk_arr_t* _arr; + HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, arr) == HAWK_VAL_ARR); + _arr = ((hawk_val_arr_t*)arr)->arr; + if (index < 0 || index >= HAWK_ARR_SIZE(_arr) || !HAWK_ARR_SLOT(_arr, index)) return HAWK_NULL; + return HAWK_ARR_DPTR(_arr, index); +} + hawk_val_t* hawk_rtx_makerefval (hawk_rtx_t* rtx, int id, hawk_val_t** adr) { hawk_val_ref_t* val;