2.94
xs_list_tools.h
1/* copyright (c) 2022 - 2026 grunfink et al. / MIT license */
2
3#ifndef _XS_LIST_TOOLS_H
4
5#define _XS_LIST_TOOLS_H
6
7 xs_list *xs_list_insert_sorted(xs_list *list, const xs_val *nv);
8 xs_val **xs_list_to_array(const xs_list *l, int *len);
9 int xs_list_sort_cmp(const void *p1, const void *p2);
10 int xs_list_sort_inv_cmp(const void *p1, const void *p2);
11 int xs_list_sort_dict_cmp(const char *field, const void *p1, const void *p2);
12 xs_list *xs_list_sort(const xs_list *l, int (*cmp)(const void *, const void *));
13 xs_list *xs_list_shuffle(const xs_list *l);
14
15#ifdef XS_IMPLEMENTATION
16
17#include "xs_random.h"
18
19xs_list *xs_list_insert_sorted(xs_list *list, const xs_val *nv)
20/* inserts a string in the list in its ordered position */
21{
22 XS_ASSERT_TYPE(list, XSTYPE_LIST);
23
24 int offset = xs_size(list);
25
26 const xs_val *v;
27 xs_list_foreach(list, v) {
28 /* if this element is greater or equal, insert here */
29 if (xs_cmp(v, nv) >= 0) {
30 offset = v - list;
31 break;
32 }
33 }
34
35 return _xs_list_write_litem(list, offset - 1, nv, xs_size(nv));
36}
37
38
39xs_val **xs_list_to_array(const xs_list *l, int *len)
40/* converts a list to an array of values */
41/* must be freed after use */
42{
43 *len = xs_list_len(l);
44 xs_val **a = xs_realloc(NULL, *len * sizeof(xs_val *));
45 const xs_val *v;
46 int n = 0;
47
48 xs_list_foreach(l, v)
49 a[n++] = (xs_val *)v;
50
51 return a;
52}
53
54
55int xs_list_sort_cmp(const void *p1, const void *p2)
56/* default list sorting function */
57{
58 const xs_val *v1 = *(xs_val **)p1;
59 const xs_val *v2 = *(xs_val **)p2;
60
61 return xs_cmp(v1, v2);
62}
63
64
65int xs_list_sort_inv_cmp(const void *p1, const void *p2)
66/* default list inverse sorting function */
67{
68 const xs_val *v1 = *(xs_val **)p1;
69 const xs_val *v2 = *(xs_val **)p2;
70
71 return xs_cmp(v2, v1);
72}
73
74
75int xs_list_sort_dict_cmp(const char *field, const void *p1, const void *p2)
76/* compare sorting function for a field an array of dicts */
77{
78 const xs_dict *d1 = *(xs_val **)p1;
79 const xs_dict *d2 = *(xs_val **)p2;
80
81 if (xs_type(d1) != XSTYPE_DICT || xs_type(d2) != XSTYPE_DICT)
82 return 0;
83
84 return xs_cmp(xs_dict_get_def(d1, field, ""),
85 xs_dict_get_def(d2, field, ""));
86}
87
88
89xs_list *xs_list_sort(const xs_list *l, int (*cmp)(const void *, const void *))
90/* returns a sorted copy of l. cmp can be null for standard sorting */
91{
92 int sz;
93 xs_val **a = xs_list_to_array(l, &sz);
94 xs_list *nl = xs_dup(l);
95 char *p = nl + 1 + _XS_TYPE_SIZE;
96
97 /* sort the array */
98 qsort(a, sz, sizeof(xs_val *), cmp ? cmp : xs_list_sort_cmp);
99
100 /* transfer the sorted list over the copy */
101 for (int n = 0; n < sz; n++) {
102 /* get the litem */
103 const char *e = a[n] - 1;
104 int z = xs_size(e);
105
106 memcpy(p, e, z);
107 p += z;
108 }
109
110 xs_free(a);
111
112 return nl;
113}
114
115
116xs_list *xs_list_shuffle(const xs_list *l)
117/* returns a shuffled list */
118{
119 int sz;
120 xs_val **a = xs_list_to_array(l, &sz);
121 xs_list *nl = xs_list_new();
122 unsigned int seed = 0;
123
124 xs_rnd_buf(&seed, sizeof(seed));
125
126 /* shuffle */
127 for (int n = sz - 1; n > 0; n--) {
128 int m = xs_rnd_int32_d(&seed) % n;
129 void *p = a[n];
130 a[n] = a[m];
131 a[m] = p;
132 }
133
134 for (int n = 0; n < sz; n++)
135 nl = xs_list_append(nl, a[n]);
136
137 xs_free(a);
138
139 return nl;
140}
141
142
143#endif /* XS_IMPLEMENTATION */
144
145#endif /* XS_LIST_TOOLS_H */