main
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#include "xs.h"
8
9 xs_list *xs_list_insert_sorted(xs_list *list, const xs_val *nv);
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
21xs_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
41xs_val **xs_list_to_array(const xs_list *l, int *len)
42/* converts a list to an array of values */
43/* must be freed after use */
44{
45 *len = xs_list_len(l);
46 xs_val **a = xs_realloc(NULL, *len * sizeof(xs_val *));
47 const xs_val *v;
48 int n = 0;
49
50 xs_list_foreach(l, v)
51 a[n++] = (xs_val *)v;
52
53 return a;
54}
55
56
57int xs_list_sort_cmp(const void *p1, const void *p2)
58/* default list sorting function */
59{
60 const xs_val *v1 = *(xs_val **)p1;
61 const xs_val *v2 = *(xs_val **)p2;
62
63 return xs_cmp(v1, v2);
64}
65
66
67int xs_list_sort_inv_cmp(const void *p1, const void *p2)
68/* default list inverse sorting function */
69{
70 const xs_val *v1 = *(xs_val **)p1;
71 const xs_val *v2 = *(xs_val **)p2;
72
73 return xs_cmp(v2, v1);
74}
75
76
77int xs_list_sort_dict_cmp(const char *field, const void *p1, const void *p2)
78/* compare sorting function for a field an array of dicts */
79{
80 const xs_dict *d1 = *(xs_val **)p1;
81 const xs_dict *d2 = *(xs_val **)p2;
82
83 if (xs_type(d1) != XSTYPE_DICT || xs_type(d2) != XSTYPE_DICT)
84 return 0;
85
86 return xs_cmp(xs_dict_get_def(d1, field, ""),
87 xs_dict_get_def(d2, field, ""));
88}
89
90
91xs_list *xs_list_sort(const xs_list *l, int (*cmp)(const void *, const void *))
92/* returns a sorted copy of l. cmp can be null for standard sorting */
93{
94 int sz;
95 xs_val **a = xs_list_to_array(l, &sz);
96 xs_list *nl = xs_dup(l);
97 char *p = nl + 1 + _XS_TYPE_SIZE;
98
99 /* sort the array */
100 qsort(a, sz, sizeof(xs_val *), cmp ? cmp : xs_list_sort_cmp);
101
102 /* transfer the sorted list over the copy */
103 for (int n = 0; n < sz; n++) {
104 /* get the litem */
105 const char *e = a[n] - 1;
106 int z = xs_size(e);
107
108 memcpy(p, e, z);
109 p += z;
110 }
111
112 xs_free(a);
113
114 return nl;
115}
116
117
118xs_list *xs_list_shuffle(const xs_list *l)
119/* returns a shuffled list */
120{
121 int sz;
122 xs_val **a = xs_list_to_array(l, &sz);
123 xs_list *nl = xs_list_new();
124 unsigned int seed = 0;
125
126 xs_rnd_buf(&seed, sizeof(seed));
127
128 /* shuffle */
129 for (int n = sz - 1; n > 0; n--) {
130 int m = xs_rnd_int32_d(&seed) % n;
131 void *p = a[n];
132 a[n] = a[m];
133 a[m] = p;
134 }
135
136 for (int n = 0; n < sz; n++)
137 nl = xs_list_append(nl, a[n]);
138
139 xs_free(a);
140
141 return nl;
142}
143
144
145#endif /* XS_IMPLEMENTATION */
146
147#endif /* XS_LIST_TOOLS_H */