array.h - ltk - GUI toolkit for X11 (WIP)
HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
array.h (11836B)
---
1 /* FIXME: oops, I guess I left the old MIT license here - not sure if I should just
2 leave it as is or update it to ISC... */
3 /*
4 * Copyright (c) 2020-2026 lumidify <nobody@lumidify.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #ifndef LTK_ARRAY_H
26 #define LTK_ARRAY_H
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "util.h"
33 #include "memory.h"
34
35 /* FIXME: make this work on more compilers? */
36 #if (defined(__GNUC__) || defined(__clang__))
37 #define LTK_UNUSED_FUNC __attribute__((unused))
38 #else
39 #define LTK_UNUSED_FUNC
40 #endif
41
42 /* FIXME: add accesser macros; also add init function to not allocate array itself but initialize given pointer */
43 /* FIXME: separate struct definition and forward-declaration for header files */
44
45 #define LTK_ARRAY_INIT_STRUCT_DECL_BASE(name, type, storage) \
46 typedef struct { \
47 type *buf; \
48 size_t buf_size; \
49 size_t len; \
50 } ltk_array_##name;
51
52 #define LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type, storage) \
53 LTK_UNUSED_FUNC storage ltk_array_##name *ltk_array_create_##name(size_t initial_capacity); \
54 LTK_UNUSED_FUNC storage type ltk_array_pop_##name(ltk_array_##name *ar); \
55 LTK_UNUSED_FUNC storage size_t ltk_array_remove_if_##name( \
56 ltk_array_##name *ar, int (*callback)(type *, void *), void *data \
57 ); \
58 LTK_UNUSED_FUNC storage void ltk_array_prepare_gap_##name(ltk_array_##name *ar, size_t index, size_t len); \
59 LTK_UNUSED_FUNC storage void ltk_array_insert_##name(ltk_array_##name *ar, size_t index, type elem); \
60 LTK_UNUSED_FUNC storage void ltk_array_insert_multiple_##name(ltk_array_##name *ar, size_t index, type *elem, size_t len); \
61 LTK_UNUSED_FUNC storage void ltk_array_delete_##name(ltk_array_##name *ar, size_t index, size_t len); \
62 LTK_UNUSED_FUNC storage void ltk_array_resize_##name(ltk_array_##name *ar, size_t size, type default_val); \
63 LTK_UNUSED_FUNC storage void ltk_array_change_capacity_##name(ltk_array_##name *ar, size_t size); \
64 LTK_UNUSED_FUNC storage void ltk_array_len_to_capacity_##name(ltk_array_##name *ar, type default_val); \
65 LTK_UNUSED_FUNC storage void ltk_array_destroy_##name(ltk_array_##name *ar); \
66 LTK_UNUSED_FUNC storage void ltk_array_reset_##name(ltk_array_##name *ar); \
67 LTK_UNUSED_FUNC storage void ltk_array_append_##name(ltk_array_##name *ar, type elem); \
68 LTK_UNUSED_FUNC storage void ltk_array_destroy_deep_##name(ltk_array_##name *ar, void (*destroy_func)(type)); \
69 LTK_UNUSED_FUNC storage type ltk_array_get_safe_##name(ltk_array_##name *ar, size_t index); \
70 LTK_UNUSED_FUNC storage void ltk_array_set_safe_##name(ltk_array_##name *ar, size_t index, type e);
71
72 #define LTK_ARRAY_INIT_IMPL_BASE(name, type, storage) \
73 LTK_UNUSED_FUNC storage ltk_array_##name * \
74 ltk_array_create_##name(size_t initial_capacity) { \
75 if (initial_capacity == 0) \
76 ltk_fatal("Array capacity is zero\n"); \
77 ltk_array_##name *ar = ltk_malloc(sizeof(ltk_array_##name)); \
78 ar->buf = ltk_reallocarray(NULL, initial_capacity, sizeof(type)); \
79 ar->buf_size = initial_capacity; \
80 ar->len = 0; \
81 return ar; \
82 } \
83 \
84 LTK_UNUSED_FUNC storage type \
85 ltk_array_pop_##name(ltk_array_##name *ar) { \
86 if (ar->len == 0) \
87 ltk_fatal("Array empty; cannot pop.\n"); \
88 ar->len--; \
89 return ar->buf[ar->len]; \
90 } \
91 \
92 LTK_UNUSED_FUNC storage size_t \
93 ltk_array_remove_if_##name(ltk_array_##name *ar, int (*callback)(type *, void *), void *data) { \
94 size_t removed = 0; \
95 for (size_t i = 0; i < ar->len; i++) { \
96 if (callback(&ar->buf[i], data)) \
97 removed++; \
98 else \
99 ar->buf[i - removed] = ar->buf[i]; \
100 } \
101 /* FIXME: maybe release memory */ \
102 ar->len -= removed; \
103 return removed; \
104 } \
105 \
106 /* FIXME: having this function in the public interface is ugly */ \
107 LTK_UNUSED_FUNC storage void \
108 ltk_array_prepare_gap_##name(ltk_array_##name *ar, size_t index, size_t len) { \
109 if (index > ar->len) \
110 ltk_fatal("Array index out of bounds\n"); \
111 ltk_array_change_capacity_##name(ar, ar->len + len); \
112 ar->len += len; \
113 if (ar->len - len == index) \
114 return; \
115 memmove(ar->buf + index + len, ar->buf + index, \
116 (ar->len - len - index) * sizeof(type)); \
117 } \
118 \
119 LTK_UNUSED_FUNC storage void \
120 ltk_array_insert_##name(ltk_array_##name *ar, size_t index, type elem) { \
121 ltk_array_prepare_gap_##name(ar, index, 1); \
122 ar->buf[index] = elem; \
123 } \
124 \
125 LTK_UNUSED_FUNC storage void \
126 ltk_array_insert_multiple_##name(ltk_array_##name *ar, size_t index, type *elem, size_t len) { \
127 ltk_array_prepare_gap_##name(ar, index, len); \
128 for (size_t i = 0; i < len; i++) { \
129 ar->buf[index + i] = elem[i]; \
130 } \
131 } \
132 \
133 LTK_UNUSED_FUNC storage void \
134 ltk_array_delete_##name(ltk_array_##name *ar, size_t index, size_t len) { \
135 /* FIXME: integer overflow protection everywhere */ \
136 if (index + len > ar->len) \
137 ltk_fatal("Array index out of bounds\n"); \
138 /* FIXME: maybe release memory at some point? */ \
139 memmove(ar->buf + index, ar->buf + index + len, (ar->len - index - len) * sizeof(type)); \
140 ar->len -= len; \
141 } \
142 \
143 LTK_UNUSED_FUNC storage void \
144 ltk_array_append_##name(ltk_array_##name *ar, type elem) { \
145 if (ar->len == ar->buf_size) \
146 ltk_array_change_capacity_##name(ar, ar->len + 1); \
147 ar->buf[ar->len++] = elem; \
148 } \
149 \
150 LTK_UNUSED_FUNC storage void \
151 ltk_array_reset_##name(ltk_array_##name *ar) { \
152 ar->len = 0; \
153 ltk_array_change_capacity_##name(ar, 1); \
154 } \
155 \
156 LTK_UNUSED_FUNC storage void \
157 ltk_array_resize_##name(ltk_array_##name *ar, size_t len, type default_val) { \
158 ltk_array_change_capacity_##name(ar, len); \
159 for (size_t i = ar->len; i < len; i++) { \
160 ar->buf[i] = default_val; \
161 } \
162 ar->len = len; \
163 } \
164 \
165 LTK_UNUSED_FUNC storage void \
166 ltk_array_change_capacity_##name(ltk_array_##name *ar, size_t len) { \
167 size_t new_size = ideal_array_size(ar->buf_size, len); \
168 if (new_size != ar->buf_size) { \
169 ar->buf = ltk_reallocarray(ar->buf, new_size, sizeof(type)); \
170 ar->buf_size = new_size; \
171 ar->len = ar->len < new_size ? ar->len : new_size; \
172 } \
173 } \
174 \
175 LTK_UNUSED_FUNC storage void \
176 ltk_array_len_to_capacity_##name(ltk_array_##name *ar, type default_val) { \
177 for (size_t i = ar->len; i < ar->buf_size; i++) { \
178 ar->buf[i] = default_val; \
179 } \
180 ar->len = ar->buf_size; \
181 } \
182 \
183 LTK_UNUSED_FUNC storage void \
184 ltk_array_destroy_##name(ltk_array_##name *ar) { \
185 if (!ar) \
186 return; \
187 ltk_free(ar->buf); \
188 ltk_free(ar); \
189 } \
190 \
191 LTK_UNUSED_FUNC storage void \
192 ltk_array_destroy_deep_##name(ltk_array_##name *ar, void (*destroy_func)(type)) { \
193 if (!ar) \
194 return; \
195 for (size_t i = 0; i < ar->len; i++) { \
196 destroy_func(ar->buf[i]); \
197 } \
198 ltk_array_destroy_##name(ar); \
199 } \
200 \
201 LTK_UNUSED_FUNC storage type \
202 ltk_array_get_safe_##name(ltk_array_##name *ar, size_t index) { \
203 if (index >= ar->len) \
204 ltk_fatal("Index out of bounds.\n"); \
205 return ar->buf[index]; \
206 } \
207 \
208 LTK_UNUSED_FUNC storage void \
209 ltk_array_set_safe_##name(ltk_array_##name *ar, size_t index, type e) { \
210 if (index >= ar->len) \
211 ltk_fatal("Index out of bounds.\n"); \
212 ar->buf[index] = e; \
213 }
214
215 /* FIXME: resize and change_capacity should maybe also take destroy_func optionally if size/capacity is decreased */
216 #define ltk_array(name) ltk_array_##name
217 #define ltk_array_create(name, initial_capacity) ltk_array_create_##name(initial_capacity)
218 #define ltk_array_pop(name, ar) ltk_array_pop_##name(ar)
219 #define ltk_array_remove_if(name, ar, callback, data) ltk_array_remove_if_##name(ar, callback, data)
220 #define ltk_array_insert(name, ar, index, elem) ltk_array_insert_##name(ar, index, elem)
221 #define ltk_array_insert_multiple(name, ar, index, elem, len) ltk_array_insert_multiple_##name(ar, index, elem, len)
222 #define ltk_array_delete(name, ar, index, len) ltk_array_delete_##name(ar, index, len)
223 #define ltk_array_resize(name, ar, size, default_val) ltk_array_resize_##name(ar, size, default_val)
224 #define ltk_array_change_capacity(name, ar, size) ltk_array_change_capacity_##name(ar, size)
225 #define ltk_array_len_to_capacity(name, ar, default_val) ltk_array_len_to_capacity_##name(ar, default_val)
226 #define ltk_array_destroy(name, ar) ltk_array_destroy_##name(ar)
227 #define ltk_array_reset(name, ar) ltk_array_reset_##name(ar)
228 #define ltk_array_clear(ar) ((ar)->len = 0)
229 #define ltk_array_append(name, ar, elem) ltk_array_append_##name(ar, elem)
230 #define ltk_array_destroy_deep(name, ar, destroy_func) ltk_array_destroy_deep_##name(ar, destroy_func)
231 #define ltk_array_len(ar) ((ar)->len)
232 #define ltk_array_get_buf(ar) ((ar)->buf)
233 #define ltk_array_get(ar, index) ((ar)->buf[index])
234 #define ltk_array_get_safe(name, ar, index) ltk_array_get_safe_##name(ar, index)
235 #define ltk_array_set_safe(name, ar, index, e) ltk_array_set_safe_##name(ar, index, e)
236
237 #define LTK_ARRAY_INIT_DECL(name, type) \
238 LTK_ARRAY_INIT_STRUCT_DECL_BASE(name, type,) \
239 LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type,)
240
241 /* mainly for header files that shouldn't include all the function declarations */
242 #define LTK_ARRAY_INIT_STRUCT_DECL(name, type)LTK_ARRAY_INIT_STRUCT_DECL_BASE(name, type,)
243 #define LTK_ARRAY_INIT_FUNC_DECL(name, type)LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type,)
244 #define LTK_ARRAY_INIT_FUNC_DECL_STATIC(name, type)LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type, static)
245
246 #define LTK_ARRAY_INIT_DECL_STATIC(name, type) \
247 LTK_ARRAY_INIT_STRUCT_DECL_BASE(name, type, static) \
248 LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type, static)
249
250 #define LTK_ARRAY_INIT_IMPL(name, type) LTK_ARRAY_INIT_IMPL_BASE(name, type,)
251 #define LTK_ARRAY_INIT_IMPL_STATIC(name, type) LTK_ARRAY_INIT_IMPL_BASE(name, type, static)
252
253 #endif /* LTK_ARRAY_H */