Skip to content

Commit

Permalink
types: introduce ucv_array_sort_r() and ucv_object_sort_r()
Browse files Browse the repository at this point in the history
Introduce two new functions for ordering arrays and object keys which
utilize a different compare callback signature and allow passing a user
provided pointer to the comparison callback.

The main advantages of the `ucv_*_sort_r()` flavors are the ability to
pass custom context to comparisons via the user data pointer and the
invocation of the comparison callback with direct `uc_value_t *` pointers
instead of opaque `const void *` arguments pointing to `uc_value_t *` or
json-c internal `struct lh_entry *` pointers respectively.

Suggested-by: Isaac de Wolff <[email protected]>
[align naming and whitespace with the rest of the codebase, rename some
 variables for clarity, group sort related changes into two commits,
 drop constness from `uc_value_t *` compare function arguments]
Signed-off-by: Jo-Philipp Wich <[email protected]>

sort

Signed-off-by: Jo-Philipp Wich <[email protected]>
  • Loading branch information
jow- committed Dec 2, 2024
1 parent b0b5d93 commit 590c846
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 3 deletions.
2 changes: 2 additions & 0 deletions include/ucode/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand All @@ -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 *);

Expand Down
28 changes: 28 additions & 0 deletions include/ucode/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
66 changes: 63 additions & 3 deletions types.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *))
{
Expand Down Expand Up @@ -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;
Expand All @@ -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];
Expand All @@ -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)
{
Expand Down

0 comments on commit 590c846

Please sign in to comment.