commit fdd2217

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