enhanced asort() and asorti() to handle an array value.
added hawk_rtx_getarrvalfld() and hawk_rtx_setarrvalfld()
This commit is contained in:
		
							
								
								
									
										301
									
								
								hawk/lib/fnc.c
									
									
									
									
									
								
							
							
						
						
									
										301
									
								
								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); | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user