gap_buffer.h - ltkx - GUI toolkit for X11 (old)
HTML git clone git://lumidify.org/ltkx.git (fast, but not encrypted)
HTML git clone https://lumidify.org/ltkx.git (encrypted, but very slow)
HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltkx.git (over tor)
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
gap_buffer.h (7168B)
---
1 /*
2 * This file is part of the Lumidify ToolKit (LTK)
3 * Copyright (c) 2020 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_GAP_BUFFER_H_
25 #define _LTK_GAP_BUFFER_H_
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #define LTK_GAP_BUFFER_INIT_DECL(name, type) \
31 struct ltk_gap_buffer_##name { \
32 type *buf; \
33 size_t buf_size; \
34 size_t gap_left; \
35 size_t gap_size; \
36 size_t len; \
37 }; \
38 \
39 struct ltk_gap_buffer_##name * ltk_gap_buffer_create_##name(void); \
40 struct ltk_gap_buffer_##name * \
41 ltk_gap_buffer_create_from_data_##name(type *data, size_t len); \
42 type ltk_gap_buffer_get_##name(struct ltk_gap_buffer_##name *gb, size_t index); \
43 void ltk_gap_buffer_set_##name( \
44 struct ltk_gap_buffer_##name *gb, size_t index, type data); \
45 void ltk_gap_buffer_resize_gap_##name( \
46 struct ltk_gap_buffer_##name *gb, int len); \
47 void ltk_gap_buffer_insert_##name(struct ltk_gap_buffer_##name *gb, \
48 type *new, size_t start, size_t len); \
49 void ltk_gap_buffer_insert_single_##name( \
50 struct ltk_gap_buffer_##name *gb, type new); \
51 void ltk_gap_buffer_move_gap_##name( \
52 struct ltk_gap_buffer_##name *gb, size_t pos); \
53 void ltk_gap_buffer_clear_##name(struct ltk_gap_buffer_##name *gb); \
54 void ltk_gap_buffer_destroy_##name(struct ltk_gap_buffer_##name *gb);
55
56 #define LTK_GAP_BUFFER_INIT_IMPL(name, type) \
57 struct ltk_gap_buffer_##name * \
58 ltk_gap_buffer_create_##name(void) { \
59 struct ltk_gap_buffer_##name *gb = \
60 malloc(sizeof(struct ltk_gap_buffer_##name)); \
61 if (!gb) \
62 goto error; \
63 gb->buf = malloc(8 * sizeof(type)); \
64 if (!gb->buf) \
65 goto error; \
66 gb->buf_size = 8; \
67 gb->gap_left = 0; \
68 gb->gap_size = 8; \
69 gb->len = 0; \
70 return gb; \
71 error: \
72 (void)fprintf(stderr, "Out of memory while trying to" \
73 "allocate gap buffer\n"); \
74 exit(1); \
75 } \
76 \
77 struct ltk_gap_buffer_##name * \
78 ltk_gap_buffer_create_from_data_##name(type *data, size_t len) { \
79 struct ltk_gap_buffer_##name *gb = \
80 malloc(sizeof(struct ltk_gap_buffer_##name)); \
81 if (!gb) { \
82 (void)fprintf(stderr, "Out of memory while trying to" \
83 "allocate gap buffer\n"); \
84 exit(1); \
85 } \
86 gb->buf = data; \
87 gb->buf_size = len; \
88 gb->len = len; \
89 gb->gap_left = 0; \
90 gb->gap_size = 0; \
91 return gb; \
92 } \
93 \
94 type \
95 ltk_gap_buffer_get_##name(struct ltk_gap_buffer_##name *gb, size_t index) { \
96 if (index < gb->gap_left) \
97 return gb->buf[index]; \
98 else if (index + gb->gap_size < gb->len) \
99 return gb->buf[index + gb->gap_size]; \
100 (void)fprintf(stderr, "Gap buffer index out of bounds\n"); \
101 exit(1); \
102 } \
103 \
104 void \
105 ltk_gap_buffer_set_##name( \
106 struct ltk_gap_buffer_##name *gb, size_t index, type data) { \
107 if (index < gb->gap_left) \
108 gb->buf[index] = data; \
109 else if (index + gb->gap_size < gb->len) \
110 gb->buf[index + gb->gap_size] = data; \
111 (void)fprintf(stderr, "Gap buffer index out of bounds\n"); \
112 exit(1); \
113 } \
114 \
115 /* FIXME: \
116 a) use memmove() \
117 b) properly calculate the most efficient larger size \
118 */ \
119 void \
120 ltk_gap_buffer_resize_gap_##name( \
121 struct ltk_gap_buffer_##name *gb, int len) { \
122 /* FIXME: Should this use realloc? It's usually more efficient, but \
123 in this case, I would still need to copy the part after the gap \
124 manually, so it could potentially be copied twice, which really \
125 wouldn't be good. Maybe use realloc if only a small part is after \
126 the gap and just regular malloc otherwise? */ \
127 int new_size = gb->buf_size - gb->gap_size + len; \
128 type *new = malloc(new_size * sizeof(type)); \
129 if (!new) { \
130 (void)fprintf(stderr, "Out of memory while trying to" \
131 "resize gap buffer\n"); \
132 exit(1); \
133 } \
134 for (int i = 0; i < gb->gap_left; i++) { \
135 new[i] = gb->buf[i]; \
136 } \
137 for (int i = gb->gap_left + gb->gap_size; i < gb->buf_size; i++) { \
138 new[i - gb->gap_size + len] = gb->buf[i]; \
139 } \
140 free(gb->buf); \
141 gb->buf = new; \
142 } \
143 \
144 void \
145 ltk_gap_buffer_insert_##name(struct ltk_gap_buffer_##name *gb, \
146 type *new, size_t start, size_t len) { \
147 if (gb->gap_size < len) \
148 ltk_gap_buffer_resize_gap_##name(gb, len + 8); \
149 for (int i = 0; i < len; i++) { \
150 gb->buf[gb->gap_left + i] = new[start + i]; \
151 } \
152 gb->gap_left = gb->gap_left + len; \
153 gb->gap_size -= len; \
154 gb->len += len; \
155 } \
156 \
157 void \
158 ltk_gap_buffer_insert_single_##name( \
159 struct ltk_gap_buffer_##name *gb, type new) { \
160 ltk_gap_buffer_insert_##name(gb, &new, 0, 1); \
161 } \
162 \
163 void \
164 ltk_gap_buffer_move_gap_##name( \
165 struct ltk_gap_buffer_##name *gb, size_t pos) { \
166 if (pos == gb->gap_left) \
167 return; \
168 if (pos < 0 || pos > gb->buf_size - gb->gap_size) { \
169 (void)fprintf(stderr, "Index out of range while moving" \
170 "gap buffer gap\n"); \
171 return; \
172 } \
173 if (pos >= gb->gap_left) { \
174 for (int i = gb->gap_left; i < pos; i++) { \
175 gb->buf[i] = gb->buf[i + gb->gap_size]; \
176 } \
177 } else { \
178 for (int i = gb->gap_left - 1; i >= pos; i--) { \
179 gb->buf[i + gb->gap_size] = gb->buf[i]; \
180 } \
181 } \
182 gb->gap_left = pos; \
183 } \
184 \
185 void ltk_gap_buffer_clear_##name(struct ltk_gap_buffer_##name *gb) { \
186 gb->gap_left = 0; \
187 gb->len = 0; \
188 gb->gap_size = gb->buf_size; \
189 } \
190 \
191 void \
192 ltk_gap_buffer_destroy_##name(struct ltk_gap_buffer_##name *gb) { \
193 free(gb->buf); \
194 free(gb); \
195 }
196
197 #endif /* _LTK_GAP_BUFFER_H_ */