tarray.h - ltk - Socket-based GUI 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)
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
tarray.h (7752B)
---
1 /*
2 * This file is part of the Lumidify ToolKit (LTK)
3 * Copyright (c) 2020, 2023 lumidify <nobody@lumidify.org>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #ifndef _LTK_ARRAY_H_
25 #define _LTK_ARRAY_H_
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "util.h"
31 #include "memory.h"
32
33 /* FIXME: make this work on more compilers? */
34 #if (defined(__GNUC__) || defined(__clang__))
35 #define LTK_UNUSED_FUNC __attribute__((unused))
36 #else
37 #define LTK_UNUSED_FUNC
38 #endif
39
40 #define LTK_ARRAY_INIT_DECL_BASE(name, type, storage) \
41 typedef struct { \
42 type *buf; \
43 size_t buf_size; \
44 size_t len; \
45 } ltk_array_##name; \
46 \
47 LTK_UNUSED_FUNC storage ltk_array_##name *ltk_array_create_##name(size_t initial_len); \
48 LTK_UNUSED_FUNC storage type ltk_array_pop_##name(ltk_array_##name *ar); \
49 LTK_UNUSED_FUNC storage void ltk_array_prepare_gap_##name(ltk_array_##name *ar, size_t index, size_t len); \
50 LTK_UNUSED_FUNC storage void ltk_array_insert_##name(ltk_array_##name *ar, size_t index, type *elem, size_t len); \
51 LTK_UNUSED_FUNC storage void ltk_array_resize_##name(ltk_array_##name *ar, size_t size); \
52 LTK_UNUSED_FUNC storage void ltk_array_destroy_##name(ltk_array_##name *ar); \
53 LTK_UNUSED_FUNC storage void ltk_array_clear_##name(ltk_array_##name *ar); \
54 LTK_UNUSED_FUNC storage void ltk_array_append_##name(ltk_array_##name *ar, type elem); \
55 LTK_UNUSED_FUNC storage void ltk_array_destroy_deep_##name(ltk_array_##name *ar, void (*destroy_func)(type)); \
56 LTK_UNUSED_FUNC storage type ltk_array_get_safe_##name(ltk_array_##name *ar, size_t index); \
57 LTK_UNUSED_FUNC storage void ltk_array_set_safe_##name(ltk_array_##name *ar, size_t index, type e);
58
59 #define LTK_ARRAY_INIT_IMPL_BASE(name, type, storage) \
60 LTK_UNUSED_FUNC storage ltk_array_##name * \
61 ltk_array_create_##name(size_t initial_len) { \
62 if (initial_len == 0) \
63 ltk_fatal("Array length is zero\n"); \
64 ltk_array_##name *ar = ltk_malloc(sizeof(ltk_array_##name)); \
65 ar->buf = ltk_reallocarray(NULL, initial_len, sizeof(type)); \
66 ar->buf_size = initial_len; \
67 ar->len = 0; \
68 return ar; \
69 } \
70 \
71 LTK_UNUSED_FUNC storage type \
72 ltk_array_pop_##name(ltk_array_##name *ar) { \
73 if (ar->len == 0) \
74 ltk_fatal("Array empty; cannot pop.\n"); \
75 ar->len--; \
76 return ar->buf[ar->len]; \
77 } \
78 \
79 /* FIXME: having this function in the public interface is ugly */ \
80 LTK_UNUSED_FUNC storage void \
81 ltk_array_prepare_gap_##name(ltk_array_##name *ar, size_t index, size_t len) { \
82 if (index > ar->len) \
83 ltk_fatal("Array index out of bounds\n"); \
84 ltk_array_resize_##name(ar, ar->len + len); \
85 ar->len += len; \
86 if (ar->len - len == index) \
87 return; \
88 memmove(ar->buf + index + len, ar->buf + index, \
89 (ar->len - len - index) * sizeof(type)); \
90 } \
91 \
92 LTK_UNUSED_FUNC storage void \
93 ltk_array_insert_##name(ltk_array_##name *ar, size_t index, type *elem, size_t len) { \
94 ltk_array_prepare_gap_##name(ar, index, len); \
95 for (size_t i = 0; i < len; i++) { \
96 ar->buf[index + i] = elem[i]; \
97 } \
98 } \
99 \
100 LTK_UNUSED_FUNC storage void \
101 ltk_array_append_##name(ltk_array_##name *ar, type elem) { \
102 if (ar->len == ar->buf_size) \
103 ltk_array_resize_##name(ar, ar->len + 1); \
104 ar->buf[ar->len++] = elem; \
105 } \
106 \
107 LTK_UNUSED_FUNC storage void \
108 ltk_array_clear_##name(ltk_array_##name *ar) { \
109 ar->len = 0; \
110 ltk_array_resize_##name(ar, 1); \
111 } \
112 \
113 LTK_UNUSED_FUNC storage void \
114 ltk_array_resize_##name(ltk_array_##name *ar, size_t len) { \
115 size_t new_size = ideal_array_size(ar->buf_size, len); \
116 if (new_size != ar->buf_size) { \
117 ar->buf = ltk_reallocarray(ar->buf, new_size, sizeof(type)); \
118 ar->buf_size = new_size; \
119 ar->len = ar->len < new_size ? ar->len : new_size; \
120 } \
121 } \
122 \
123 LTK_UNUSED_FUNC storage void \
124 ltk_array_destroy_##name(ltk_array_##name *ar) { \
125 if (!ar) \
126 return; \
127 ltk_free(ar->buf); \
128 ltk_free(ar); \
129 } \
130 \
131 LTK_UNUSED_FUNC storage void \
132 ltk_array_destroy_deep_##name(ltk_array_##name *ar, void (*destroy_func)(type)) { \
133 if (!ar) \
134 return; \
135 for (size_t i = 0; i < ar->len; i++) { \
136 destroy_func(ar->buf[i]); \
137 } \
138 ltk_array_destroy_##name(ar); \
139 } \
140 \
141 LTK_UNUSED_FUNC storage type \
142 ltk_array_get_safe_##name(ltk_array_##name *ar, size_t index) { \
143 if (index >= ar->len) \
144 ltk_fatal("Index out of bounds.\n"); \
145 return ar->buf[index]; \
146 } \
147 \
148 LTK_UNUSED_FUNC storage void \
149 ltk_array_set_safe_##name(ltk_array_##name *ar, size_t index, type e) { \
150 if (index >= ar->len) \
151 ltk_fatal("Index out of bounds.\n"); \
152 ar->buf[index] = e; \
153 }
154
155 #define ltk_array(name) ltk_array_##name
156 #define ltk_array_create(name, initial_len) ltk_array_create_##name(initial_len)
157 #define ltk_array_pop(name, ar) ltk_array_pop_##name(ar)
158 #define ltk_array_insert(name, ar, index, elem, len) ltk_array_insert_##name(ar, index, elem, len)
159 #define ltk_array_resize(name, ar, size) ltk_array_resize_##name(ar, size)
160 #define ltk_array_destroy(name, ar) ltk_array_destroy_##name(ar)
161 #define ltk_array_clear(name, ar) ltk_array_clear_##name(ar)
162 #define ltk_array_append(name, ar, elem) ltk_array_append_##name(ar, elem)
163 #define ltk_array_destroy_deep(name, ar, destroy_func) ltk_array_destroy_deep_##name(ar, destroy_func)
164 #define ltk_array_length(ar) ((ar)->len)
165 #define ltk_array_get(ar, index) ((ar)->buf[index])
166 #define ltk_array_get_safe(name, ar, index) ltk_array_get_safe_##name(ar, index)
167 #define ltk_array_set_safe(name, ar, index, e) ltk_array_set_safe_##name(ar, index, e)
168
169 #define LTK_ARRAY_INIT_DECL(name, type) LTK_ARRAY_INIT_DECL_BASE(name, type,)
170 #define LTK_ARRAY_INIT_IMPL(name, type) LTK_ARRAY_INIT_IMPL_BASE(name, type,)
171 #define LTK_ARRAY_INIT_DECL_STATIC(name, type) LTK_ARRAY_INIT_DECL_BASE(name, type, static)
172 #define LTK_ARRAY_INIT_IMPL_STATIC(name, type) LTK_ARRAY_INIT_IMPL_BASE(name, type, static)
173
174 #endif /* _LTK_ARRAY_H_ */