code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(206 lines)
1 // Functions that operate on lists
3 #pragma once
5 #include <stdbool.h>
7 #include "datatypes.h"
8 #include "integers.h"
9 #include "types.h"
10 #include "util.h"
12 extern char _EMPTY_LIST_SENTINEL;
13 #define EMPTY_LIST ((List_t){.data = &_EMPTY_LIST_SENTINEL})
14 #define EMPTY_ATOMIC_LIST ((List_t){.data = &_EMPTY_LIST_SENTINEL, .atomic = 1})
16 // Convert negative indices to back-indexed without branching: index0 = index + (index < 0)*(len+1)) - 1
17 #define List_get_checked(list_expr, index_expr, item_type, start, end) \
18 ({ \
19 const List_t list = list_expr; \
20 int64_t index = index_expr; \
21 int64_t off = index + (index < 0) * (list.length + 1) - 1; \
22 if (unlikely(off < 0 || off >= list.length)) \
23 fail_source(__SOURCE_FILE__, start, end, \
24 Text$concat(Text("Invalid list index: "), convert_to_text(index), Text(" (list has length "), \
25 convert_to_text((int64_t)list.length), Text(")\n"))); \
26 *(item_type *)(list.data + list.stride * off); \
27 })
28 #define List_get(list_expr, index_expr, item_type, var, optional_expr, none_expr) \
29 ({ \
30 const List_t list = list_expr; \
31 int64_t index = index_expr; \
32 int64_t offset = index + (index < 0) * (list.length + 1) - 1; \
33 unlikely(offset < 0 || offset >= list.length) ? none_expr : ({ \
34 item_type var = *(item_type *)(list.data + list.stride * offset); \
35 optional_expr; \
36 }); \
37 })
38 #define List_lvalue(item_type, list_expr, index_expr, start, end) \
39 *({ \
40 List_t *list = list_expr; \
41 int64_t index = index_expr; \
42 int64_t off = index + (index < 0) * (list->length + 1) - 1; \
43 if (unlikely(off < 0 || off >= list->length)) \
44 fail_source(__SOURCE_FILE__, start, end, \
45 Text$concat(Text("Invalid list index: "), convert_to_text(index), Text(" (list has length "), \
46 convert_to_text((int64_t)list->length), Text(")\n"))); \
47 if (list->data_refcount > 0) List$compact(list, sizeof(item_type)); \
48 (item_type *)(list->data + list->stride * off); \
49 })
50 #define List_set(item_type, list, index, value, start, end) List_lvalue(item_type, list_expr, index, start, end) = value
51 #define is_atomic(x) \
52 _Generic(x, \
53 bool: true, \
54 int8_t: true, \
55 int16_t: true, \
56 int32_t: true, \
57 int64_t: true, \
58 float: true, \
59 double: true, \
60 default: false)
61 #define TypedList(t, ...) \
62 ({ \
63 t items[] = {__VA_ARGS__}; \
64 (List_t){.length = sizeof(items) / sizeof(items[0]), \
65 .stride = (int64_t)&items[1] - (int64_t)&items[0], \
66 .data = sizeof(items) == 0 ? &_EMPTY_LIST_SENTINEL \
67 : memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \
68 .atomic = 0, \
69 .data_refcount = 0}; \
70 })
71 #define TypedListN(t, N, ...) \
72 ({ \
73 t items[N] = {__VA_ARGS__}; \
74 (List_t){.length = N, \
75 .stride = (int64_t)&items[1] - (int64_t)&items[0], \
76 .data = N == 0 ? &_EMPTY_LIST_SENTINEL : memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \
77 .atomic = 0, \
78 .data_refcount = 0}; \
79 })
80 #define List(x, ...) \
81 ({ \
82 __typeof(x) items[] = {x, __VA_ARGS__}; \
83 (List_t){.length = sizeof(items) / sizeof(items[0]), \
84 .stride = (int64_t)&items[1] - (int64_t)&items[0], \
85 .data = memcpy(is_atomic(x) ? GC_MALLOC_ATOMIC(sizeof(items)) : GC_MALLOC(sizeof(items)), items, \
86 sizeof(items)), \
87 .atomic = is_atomic(x), \
88 .data_refcount = 0}; \
89 })
90 // List refcounts use a saturating add, where once it's at the max value, it stays there.
91 #define LIST_INCREF(list) (list).data_refcount += ((list).data_refcount < LIST_MAX_DATA_REFCOUNT)
92 #define LIST_DECREF(list) (list).data_refcount -= ((list).data_refcount < LIST_MAX_DATA_REFCOUNT)
93 #define LIST_COPY(list) \
94 ({ \
95 LIST_INCREF(list); \
96 list; \
97 })
99 #define List$insert_value(list, item_expr, index, padded_item_size) \
100 List$insert(list, (__typeof(item_expr)[1]){item_expr}, index, padded_item_size)
101 void List$insert(List_t *list, const void *item, Int_t index, int64_t padded_item_size);
102 void List$insert_all(List_t *list, List_t to_insert, Int_t index, int64_t padded_item_size);
103 void List$remove_at(List_t *list, Int_t index, Int_t count, int64_t padded_item_size);
104 void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeInfo_t *type);
105 #define List$remove_item_value(list, item_expr, max, type) \
106 List$remove_item(list, (__typeof(item_expr)[1]){item_expr}, max, type)
108 #define List$pop(list_expr, index_expr, item_type, nonnone_var, nonnone_expr, none_expr) \
109 ({ \
110 List_t *list = list_expr; \
111 Int_t index = index_expr; \
112 int64_t index64 = Int64$from_int(index, false); \
113 int64_t off = index64 + (index64 < 0) * (list->length + 1) - 1; \
114 (off >= 0 && off < list->length) ? ({ \
115 item_type nonnone_var = *(item_type *)(list->data + off * list->stride); \
116 List$remove_at(list, index, I_small(1), sizeof(item_type)); \
117 nonnone_expr; \
118 }) \
119 : none_expr; \
122 OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type);
123 #define List$find_value(list, item_expr, type) \
124 ({ \
125 __typeof(item_expr) item = item_expr; \
126 List$find(list, &item, type); \
128 OptionalInt_t List$first(List_t list, Closure_t predicate);
129 void List$sort(List_t *list, Closure_t comparison, int64_t padded_item_size);
130 List_t List$sorted(List_t list, Closure_t comparison, int64_t padded_item_size);
131 void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_item_size);
132 List_t List$shuffled(List_t list, OptionalClosure_t random_int64, int64_t padded_item_size);
133 void *List$random(List_t list, OptionalClosure_t random_int64);
134 #define List$random_value(list, random_fn, t, nonnone_var, nonnone_expr, none_expr) \
135 ({ \
136 List_t _list_expr = list; \
137 (_list_expr.length == 0) ? none_expr : ({ \
138 t nonnone_var = *(t *)List$random(_list_expr, random_fn); \
139 nonnone_expr; \
140 }); \
142 List_t List$sample(List_t list, Int_t n, List_t weights, Closure_t random_num, int64_t padded_item_size);
143 Table_t List$counts(List_t list, const TypeInfo_t *type);
144 void List$clear(List_t *list);
145 void List$compact(List_t *list, int64_t padded_item_size);
146 PUREFUNC bool List$has(List_t list, void *item, const TypeInfo_t *type);
147 #define List$has_value(list, item_expr, type) \
148 ({ \
149 __typeof(item_expr) item = item_expr; \
150 List$has(list, &item, type); \
152 PUREFUNC List_t List$from(List_t list, Int_t first);
153 PUREFUNC List_t List$to(List_t list, Int_t last);
154 PUREFUNC List_t List$by(List_t list, Int_t stride, int64_t padded_item_size);
155 PUREFUNC List_t List$slice(List_t list, Int_t int_first, Int_t int_last);
156 PUREFUNC List_t List$reversed(List_t list, int64_t padded_item_size);
157 List_t List$concat(List_t x, List_t y, int64_t padded_item_size);
158 PUREFUNC uint64_t List$hash(const void *list, const TypeInfo_t *type);
159 PUREFUNC int32_t List$compare(const void *x, const void *y, const TypeInfo_t *type);
160 PUREFUNC bool List$equal(const void *x, const void *y, const TypeInfo_t *type);
161 PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t *);
162 Text_t List$as_text(const void *list, bool colorize, const TypeInfo_t *type);
163 void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size);
164 void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size);
165 #define List$heap_push_value(heap, _value, comparison, padded_item_size) \
166 ({ \
167 __typeof(_value) value = _value; \
168 List$heap_push(heap, &value, comparison, padded_item_size); \
170 void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_item_size);
171 #define List$heap_pop_value(heap, comparison, type, nonnone_var, nonnone_expr, none_expr) \
172 ({ \
173 List_t *_heap = heap; \
174 (_heap->length > 0) ? ({ \
175 type nonnone_var = *(type *)_heap->data; \
176 List$heap_pop(_heap, comparison, sizeof(type)); \
177 nonnone_expr; \
178 }) \
179 : none_expr; \
181 Int_t List$binary_search(List_t list, void *target, Closure_t comparison);
182 #define List$binary_search_value(list, target, comparison) \
183 ({ \
184 __typeof(target) _target = target; \
185 List$binary_search(list, &_target, comparison); \
187 void List$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type);
188 void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type);
190 #define List$metamethods \
191 { \
192 .as_text = List$as_text, \
193 .compare = List$compare, \
194 .equal = List$equal, \
195 .hash = List$hash, \
196 .is_none = List$is_none, \
197 .serialize = List$serialize, \
198 .deserialize = List$deserialize, \
201 #define List$info(item_info) \
202 &((TypeInfo_t){.size = sizeof(List_t), \
203 .align = __alignof__(List_t), \
204 .tag = ListInfo, \
205 .ListInfo.item = item_info, \
206 .metamethods = List$metamethods})