diff --git a/include/ucode/types.h b/include/ucode/types.h index bf8b9f25..9cd7cfc5 100644 --- a/include/ucode/types.h +++ b/include/ucode/types.h @@ -388,6 +388,7 @@ uc_value_t *ucv_array_push(uc_value_t *, uc_value_t *); uc_value_t *ucv_array_shift(uc_value_t *); uc_value_t *ucv_array_unshift(uc_value_t *, uc_value_t *); void ucv_array_sort(uc_value_t *, int (*)(const void *, const void *)); +void ucv_array_sort_r(uc_value_t *, int (*)(uc_value_t *, uc_value_t *, void *), void *); bool ucv_array_delete(uc_value_t *, size_t, size_t); bool ucv_array_set(uc_value_t *, size_t, uc_value_t *); size_t ucv_array_length(uc_value_t *); @@ -396,6 +397,7 @@ uc_value_t *ucv_object_new(uc_vm_t *); uc_value_t *ucv_object_get(uc_value_t *, const char *, bool *); bool ucv_object_add(uc_value_t *, const char *, uc_value_t *); void ucv_object_sort(uc_value_t *, int (*)(const void *, const void *)); +void ucv_object_sort_r(uc_value_t *, int (*)(const char *, uc_value_t *, const char *, uc_value_t *, void *), void *); bool ucv_object_delete(uc_value_t *, const char *); size_t ucv_object_length(uc_value_t *); diff --git a/include/ucode/util.h b/include/ucode/util.h index cc92e339..1360d286 100644 --- a/include/ucode/util.h +++ b/include/ucode/util.h @@ -267,4 +267,32 @@ uc_vector_extend_(char **base, size_t itemsize, size_t count, size_t add) iter != NULL && iter >= (vec)->entries; \ iter--) +#ifdef __APPLE__ + +# define uc_vector_sort_cb(fn_, optype_, udtype_, ...) \ + int fn_(void *ud, const void *k1, const void *k2) { \ + optype_ v1 = *(optype_ *)k1; \ + optype_ v2 = *(optype_ *)k2; \ + udtype_ ctx = (udtype_)ud; \ + __VA_ARGS__ \ + } + +# define uc_vector_sort(v_, cmp_, ud_) \ + qsort_r((v_)->entries, (v_)->count, sizeof((v_)->entries[0]), ud_, cmp_) + +#else + +# define uc_vector_sort_cb(fn_, optype_, udtype_, ...) \ + int fn_(const void *k1, const void *k2, void *ud) { \ + optype_ v1 = *(optype_ *)k1; \ + optype_ v2 = *(optype_ *)k2; \ + udtype_ ctx = (udtype_)ud; \ + __VA_ARGS__ \ + } + +# define uc_vector_sort(v_, cmp_, ud_) \ + qsort_r((v_)->entries, (v_)->count, sizeof((v_)->entries[0]), cmp_, ud_) + +#endif + #endif /* UCODE_UTIL_H */ diff --git a/types.c b/types.c index 26f588e8..5c8a8e75 100644 --- a/types.c +++ b/types.c @@ -785,6 +785,28 @@ ucv_array_unshift(uc_value_t *uv, uc_value_t *item) return item; } +typedef struct { + int (*cmp)(uc_value_t *, uc_value_t *, void *); + void *ud; +} array_sort_ctx_t; + +static uc_vector_sort_cb(ucv_array_sort_r_cb, uc_value_t *, array_sort_ctx_t *, { + return ctx->cmp(v1, v2, ctx->ud); +}); + +void +ucv_array_sort_r(uc_value_t *uv, + int (*cmp)(uc_value_t *, uc_value_t *, void *), void *ud) +{ + array_sort_ctx_t ctx = { .cmp = cmp, .ud = ud }; + uc_array_t *array = (uc_array_t *)uv; + + if (ucv_type(uv) != UC_ARRAY || array->count <= 1) + return; + + uc_vector_sort(array, ucv_array_sort_r_cb, &ctx); +} + void ucv_array_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) { @@ -985,8 +1007,26 @@ ucv_object_add(uc_value_t *uv, const char *key, uc_value_t *val) return true; } -void -ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) + +typedef struct { + int (*cmp)(const void *, const void *); + int (*cmpr)(const char *, uc_value_t *, const char *, uc_value_t *, void *); + void *ud; +} object_sort_ctx_t; + +static uc_vector_sort_cb(ucv_object_sort_cb, const void *, object_sort_ctx_t *, { + return ctx->cmp(v1, v2); +}); + +static uc_vector_sort_cb(ucv_object_sort_r_cb, const struct lh_entry *, object_sort_ctx_t *, { + return ctx->cmpr( + v1 ? lh_entry_k(v1) : NULL, v1 ? lh_entry_v(v1) : NULL, + v2 ? lh_entry_k(v2) : NULL, v2 ? lh_entry_v(v2) : NULL, + ctx->ud); +}); + +static void +ucv_object_sort_common(uc_value_t *uv, object_sort_ctx_t *ctx) { uc_object_t *object = (uc_object_t *)uv; struct lh_table *t; @@ -1007,7 +1047,8 @@ ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) if (!keys.entries) return; - qsort(keys.entries, keys.count, sizeof(keys.entries[0]), cmp); + uc_vector_sort(&keys, + ctx->cmpr ? ucv_object_sort_r_cb : ucv_object_sort_cb, ctx); for (i = 0; i < keys.count; i++) { e = keys.entries[i]; @@ -1027,6 +1068,25 @@ ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) uc_vector_clear(&keys); } +void +ucv_object_sort_r(uc_value_t *uv, + int (*cmp)(const char *, uc_value_t *, + const char *, uc_value_t *, void *), + void *ud) +{ + object_sort_ctx_t ctx = { .cmp = NULL, .cmpr = cmp, .ud = ud }; + + ucv_object_sort_common(uv, &ctx); +} + +void +ucv_object_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) +{ + object_sort_ctx_t ctx = { .cmp = cmp, .cmpr = NULL, .ud = NULL }; + + ucv_object_sort_common(uv, &ctx); +} + bool ucv_object_delete(uc_value_t *uv, const char *key) {