1/*
2 * Copyright © 2020 Benjamin Otte
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20#include <glib.h>
21
22G_BEGIN_DECLS
23
24#ifndef GDK_ARRAY_TYPE_NAME
25#define GDK_ARRAY_TYPE_NAME GdkArray
26#endif
27
28#ifndef GDK_ARRAY_NAME
29#define GDK_ARRAY_NAME gdk_array
30#endif
31
32#ifndef GDK_ARRAY_ELEMENT_TYPE
33#define GDK_ARRAY_ELEMENT_TYPE gpointer
34#endif
35
36#ifdef GDK_ARRAY_PREALLOC
37#if GDK_ARRAY_PREALLOC == 0
38#undef GDK_ARRAY_PREALLOC
39#endif
40#endif
41
42#ifdef GDK_ARRAY_NULL_TERMINATED
43#define GDK_ARRAY_REAL_SIZE(_size) ((_size) + 1)
44#else
45#define GDK_ARRAY_REAL_SIZE(_size) (_size)
46#endif
47
48/* make this readable */
49#define _T_ GDK_ARRAY_ELEMENT_TYPE
50#define GdkArray GDK_ARRAY_TYPE_NAME
51#define gdk_array_paste_more(GDK_ARRAY_NAME, func_name) GDK_ARRAY_NAME ## _ ## func_name
52#define gdk_array_paste(GDK_ARRAY_NAME, func_name) gdk_array_paste_more (GDK_ARRAY_NAME, func_name)
53#define gdk_array(func_name) gdk_array_paste (GDK_ARRAY_NAME, func_name)
54
55typedef struct GdkArray GdkArray;
56
57struct GdkArray
58{
59 _T_ *start;
60 _T_ *end;
61 _T_ *end_allocation;
62#ifdef GDK_ARRAY_PREALLOC
63 _T_ preallocated[GDK_ARRAY_REAL_SIZE(GDK_ARRAY_PREALLOC)];
64#endif
65};
66
67/* no G_GNUC_UNUSED here, if you don't use an array type, remove it. */
68static inline void
69gdk_array(init) (GdkArray *self)
70{
71#ifdef GDK_ARRAY_PREALLOC
72 self->start = self->preallocated;
73 self->end = self->start;
74 self->end_allocation = self->start + GDK_ARRAY_PREALLOC;
75#ifdef GDK_ARRAY_NULL_TERMINATED
76 *self->start = *(_T_[1]) { 0 };
77#endif
78#else
79 self->start = NULL;
80 self->end = NULL;
81 self->end_allocation = NULL;
82#endif
83}
84
85static inline void
86gdk_array(free_elements) (_T_ *start,
87 _T_ *end)
88{
89#ifdef GDK_ARRAY_FREE_FUNC
90 _T_ *e;
91 for (e = start; e < end; e++)
92#ifdef GDK_ARRAY_BY_VALUE
93 GDK_ARRAY_FREE_FUNC (accel: e);
94#else
95 GDK_ARRAY_FREE_FUNC (*e);
96#endif
97#endif
98}
99
100/* no G_GNUC_UNUSED here */
101static inline void
102gdk_array(clear) (GdkArray *self)
103{
104 gdk_array(free_elements) (start: self->start, end: self->end);
105
106#ifdef GDK_ARRAY_PREALLOC
107 if (self->start != self->preallocated)
108#endif
109 g_free (mem: self->start);
110 gdk_array(init) (self);
111}
112
113G_GNUC_UNUSED static inline _T_ *
114gdk_array(get_data) (const GdkArray *self)
115{
116 return self->start;
117}
118
119G_GNUC_UNUSED static inline _T_ *
120gdk_array(index) (const GdkArray *self,
121 gsize pos)
122{
123 return self->start + pos;
124}
125
126G_GNUC_UNUSED static inline gsize
127gdk_array(get_capacity) (const GdkArray *self)
128{
129 return self->end_allocation - self->start;
130}
131
132G_GNUC_UNUSED static inline gsize
133gdk_array(get_size) (const GdkArray *self)
134{
135 return self->end - self->start;
136}
137
138G_GNUC_UNUSED static inline gboolean
139gdk_array(is_empty) (const GdkArray *self)
140{
141 return self->end == self->start;
142}
143
144G_GNUC_UNUSED static inline void
145gdk_array(reserve) (GdkArray *self,
146 gsize n)
147{
148 gsize new_size, size;
149
150 if (n <= gdk_array(get_capacity) (self))
151 return;
152
153 size = gdk_array(get_size) (self);
154 new_size = 1 << g_bit_storage (MAX (GDK_ARRAY_REAL_SIZE (n), 16) - 1);
155
156#ifdef GDK_ARRAY_PREALLOC
157 if (self->start == self->preallocated)
158 {
159 self->start = g_new (_T_, new_size);
160 memcpy (dest: self->start, src: self->preallocated, n: sizeof (_T_) * GDK_ARRAY_REAL_SIZE (size));
161 }
162 else
163#endif
164#ifdef GDK_ARRAY_NULL_TERMINATED
165 if (self->start == NULL)
166 {
167 self->start = g_new (_T_, new_size);
168 *self->start = *(_T_[1]) { 0 };
169 }
170 else
171#endif
172 self->start = g_renew (_T_, self->start, new_size);
173
174 self->end = self->start + size;
175 self->end_allocation = self->start + new_size;
176#ifdef GDK_ARRAY_NULL_TERMINATED
177 self->end_allocation--;
178#endif
179}
180
181G_GNUC_UNUSED static inline void
182gdk_array(splice) (GdkArray *self,
183 gsize pos,
184 gsize removed,
185 gboolean stolen,
186 _T_ *additions,
187 gsize added)
188{
189 gsize size;
190 gsize remaining;
191
192 size = gdk_array(get_size) (self);
193 g_assert (pos + removed <= size);
194 remaining = size - pos - removed;
195
196 if (!stolen)
197 gdk_array(free_elements) (gdk_array(index) (self, pos),
198 gdk_array(index) (self, pos: pos + removed));
199
200 gdk_array(reserve) (self, n: size - removed + added);
201
202 if (GDK_ARRAY_REAL_SIZE (remaining) && removed != added)
203 memmove (gdk_array(index) (self, pos: pos + added),
204 gdk_array(index) (self, pos: pos + removed),
205 GDK_ARRAY_REAL_SIZE (remaining) * sizeof (_T_));
206
207 if (added)
208 {
209 if (additions)
210 memcpy (gdk_array(index) (self, pos),
211 src: additions,
212 n: added * sizeof (_T_));
213#ifndef GDK_ARRAY_NO_MEMSET
214 else
215 memset (gdk_array(index) (self, pos), c: 0, n: added * sizeof (_T_));
216#endif
217 }
218
219
220 /* might overflow, but does the right thing */
221 self->end += added - removed;
222}
223
224G_GNUC_UNUSED static void
225gdk_array(set_size) (GdkArray *self,
226 gsize new_size)
227{
228 gsize old_size = gdk_array(get_size) (self);
229 if (new_size > old_size)
230 gdk_array(splice) (self, pos: old_size, removed: 0, FALSE, NULL, added: new_size - old_size);
231 else
232 gdk_array(splice) (self, pos: new_size, removed: old_size - new_size, FALSE, NULL, added: 0);
233}
234
235G_GNUC_UNUSED static void
236gdk_array(append) (GdkArray *self,
237#ifdef GDK_ARRAY_BY_VALUE
238 _T_ *value)
239#else
240 _T_ value)
241#endif
242{
243 gdk_array(splice) (self,
244 gdk_array(get_size) (self),
245 removed: 0,
246 FALSE,
247#ifdef GDK_ARRAY_BY_VALUE
248 additions: value,
249#else
250 &value,
251#endif
252 added: 1);
253}
254
255#ifdef GDK_ARRAY_BY_VALUE
256G_GNUC_UNUSED static _T_ *
257gdk_array(get) (const GdkArray *self,
258 gsize pos)
259{
260 return gdk_array(index) (self, pos);
261}
262#else
263G_GNUC_UNUSED static _T_
264gdk_array(get) (const GdkArray *self,
265 gsize pos)
266 {
267 return *gdk_array(index) (self, pos);
268 }
269#endif
270
271#ifndef GDK_ARRAY_NO_UNDEF
272
273#undef _T_
274#undef GdkArray
275#undef gdk_array_paste_more
276#undef gdk_array_paste
277#undef gdk_array
278#undef GDK_ARRAY_REAL_SIZE
279
280#undef GDK_ARRAY_BY_VALUE
281#undef GDK_ARRAY_ELEMENT_TYPE
282#undef GDK_ARRAY_FREE_FUNC
283#undef GDK_ARRAY_NAME
284#undef GDK_ARRAY_NULL_TERMINATED
285#undef GDK_ARRAY_PREALLOC
286#undef GDK_ARRAY_TYPE_NAME
287#undef GDK_ARRAY_NO_MEMSET
288#endif
289

source code of gtk/gdk/gdkarrayimpl.c