1/* GObject - GLib Type, Object, Parameter and Signal Library
2 * Copyright (C) 2001 Red Hat, Inc.
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
15 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * MT safe
20 */
21
22#include "config.h"
23
24#include <string.h>
25#include <stdlib.h> /* qsort() */
26
27#include "gvaluearray.h"
28
29
30/**
31 * SECTION:value_arrays
32 * @short_description: A container structure to maintain an array of
33 * generic values
34 * @see_also: #GValue, #GParamSpecValueArray, g_param_spec_value_array()
35 * @title: Value arrays
36 *
37 * The prime purpose of a #GValueArray is for it to be used as an
38 * object property that holds an array of values. A #GValueArray wraps
39 * an array of #GValue elements in order for it to be used as a boxed
40 * type through %G_TYPE_VALUE_ARRAY.
41 *
42 * #GValueArray is deprecated in favour of #GArray since GLib 2.32. It
43 * is possible to create a #GArray that behaves like a #GValueArray by
44 * using the size of #GValue as the element size, and by setting
45 * g_value_unset() as the clear function using g_array_set_clear_func(),
46 * for instance, the following code:
47 *
48 * |[<!-- language="C" -->
49 * GValueArray *array = g_value_array_new (10);
50 * ]|
51 *
52 * can be replaced by:
53 *
54 * |[<!-- language="C" -->
55 * GArray *array = g_array_sized_new (FALSE, TRUE, sizeof (GValue), 10);
56 * g_array_set_clear_func (array, (GDestroyNotify) g_value_unset);
57 * ]|
58 *
59 * Deprecated: 2.32: Use #GArray instead, if possible for the given use case,
60 * as described above.
61 */
62
63#define GROUP_N_VALUES (8) /* power of 2 !! */
64
65
66/* --- functions --- */
67/**
68 * g_value_array_get_nth:
69 * @value_array: #GValueArray to get a value from
70 * @index_: index of the value of interest
71 *
72 * Return a pointer to the value at @index_ containd in @value_array.
73 *
74 * Returns: (transfer none): pointer to a value at @index_ in @value_array
75 *
76 * Deprecated: 2.32: Use g_array_index() instead.
77 */
78GValue*
79g_value_array_get_nth (GValueArray *value_array,
80 guint index)
81{
82 g_return_val_if_fail (value_array != NULL, NULL);
83 g_return_val_if_fail (index < value_array->n_values, NULL);
84
85 return value_array->values + index;
86}
87
88static inline void
89value_array_grow (GValueArray *value_array,
90 guint n_values,
91 gboolean zero_init)
92{
93 g_return_if_fail (n_values >= value_array->n_values);
94
95 value_array->n_values = n_values;
96 if (value_array->n_values > value_array->n_prealloced)
97 {
98 guint i = value_array->n_prealloced;
99
100 value_array->n_prealloced = (value_array->n_values + GROUP_N_VALUES - 1) & ~(GROUP_N_VALUES - 1);
101 value_array->values = g_renew (GValue, value_array->values, value_array->n_prealloced);
102 if (!zero_init)
103 i = value_array->n_values;
104 memset (s: value_array->values + i, c: 0,
105 n: (value_array->n_prealloced - i) * sizeof (value_array->values[0]));
106 }
107}
108
109/**
110 * g_value_array_new:
111 * @n_prealloced: number of values to preallocate space for
112 *
113 * Allocate and initialize a new #GValueArray, optionally preserve space
114 * for @n_prealloced elements. New arrays always contain 0 elements,
115 * regardless of the value of @n_prealloced.
116 *
117 * Returns: a newly allocated #GValueArray with 0 values
118 *
119 * Deprecated: 2.32: Use #GArray and g_array_sized_new() instead.
120 */
121GValueArray*
122g_value_array_new (guint n_prealloced)
123{
124 GValueArray *value_array = g_slice_new (GValueArray);
125
126 value_array->n_values = 0;
127 value_array->n_prealloced = 0;
128 value_array->values = NULL;
129 value_array_grow (value_array, n_values: n_prealloced, TRUE);
130 value_array->n_values = 0;
131
132 return value_array;
133}
134
135/**
136 * g_value_array_free: (skip)
137 * @value_array: #GValueArray to free
138 *
139 * Free a #GValueArray including its contents.
140 *
141 * Deprecated: 2.32: Use #GArray and g_array_unref() instead.
142 */
143void
144g_value_array_free (GValueArray *value_array)
145{
146 guint i;
147
148 g_return_if_fail (value_array != NULL);
149
150 for (i = 0; i < value_array->n_values; i++)
151 {
152 GValue *value = value_array->values + i;
153
154 if (G_VALUE_TYPE (value) != 0) /* we allow unset values in the array */
155 g_value_unset (value);
156 }
157 g_free (mem: value_array->values);
158 g_slice_free (GValueArray, value_array);
159}
160
161/**
162 * g_value_array_copy:
163 * @value_array: #GValueArray to copy
164 *
165 * Construct an exact copy of a #GValueArray by duplicating all its
166 * contents.
167 *
168 * Returns: (transfer full): Newly allocated copy of #GValueArray
169 *
170 * Deprecated: 2.32: Use #GArray and g_array_ref() instead.
171 */
172GValueArray*
173g_value_array_copy (const GValueArray *value_array)
174{
175 GValueArray *new_array;
176 guint i;
177
178 g_return_val_if_fail (value_array != NULL, NULL);
179
180 new_array = g_slice_new (GValueArray);
181 new_array->n_values = 0;
182 new_array->values = NULL;
183 new_array->n_prealloced = 0;
184 value_array_grow (value_array: new_array, n_values: value_array->n_values, TRUE);
185 for (i = 0; i < new_array->n_values; i++)
186 if (G_VALUE_TYPE (value_array->values + i) != 0)
187 {
188 GValue *value = new_array->values + i;
189
190 g_value_init (value, G_VALUE_TYPE (value_array->values + i));
191 g_value_copy (src_value: value_array->values + i, dest_value: value);
192 }
193 return new_array;
194}
195
196/**
197 * g_value_array_prepend:
198 * @value_array: #GValueArray to add an element to
199 * @value: (nullable): #GValue to copy into #GValueArray, or %NULL
200 *
201 * Insert a copy of @value as first element of @value_array. If @value is
202 * %NULL, an uninitialized value is prepended.
203 *
204 *
205 * Returns: (transfer none): the #GValueArray passed in as @value_array
206 *
207 * Deprecated: 2.32: Use #GArray and g_array_prepend_val() instead.
208 */
209GValueArray*
210g_value_array_prepend (GValueArray *value_array,
211 const GValue *value)
212{
213 g_return_val_if_fail (value_array != NULL, NULL);
214
215 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
216 return g_value_array_insert (value_array, index_: 0, value);
217 G_GNUC_END_IGNORE_DEPRECATIONS
218}
219
220/**
221 * g_value_array_append:
222 * @value_array: #GValueArray to add an element to
223 * @value: (nullable): #GValue to copy into #GValueArray, or %NULL
224 *
225 * Insert a copy of @value as last element of @value_array. If @value is
226 * %NULL, an uninitialized value is appended.
227 *
228 * Returns: (transfer none): the #GValueArray passed in as @value_array
229 *
230 * Deprecated: 2.32: Use #GArray and g_array_append_val() instead.
231 */
232GValueArray*
233g_value_array_append (GValueArray *value_array,
234 const GValue *value)
235{
236 g_return_val_if_fail (value_array != NULL, NULL);
237
238 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
239 return g_value_array_insert (value_array, index_: value_array->n_values, value);
240 G_GNUC_END_IGNORE_DEPRECATIONS
241}
242
243/**
244 * g_value_array_insert:
245 * @value_array: #GValueArray to add an element to
246 * @index_: insertion position, must be <= value_array->;n_values
247 * @value: (nullable): #GValue to copy into #GValueArray, or %NULL
248 *
249 * Insert a copy of @value at specified position into @value_array. If @value
250 * is %NULL, an uninitialized value is inserted.
251 *
252 * Returns: (transfer none): the #GValueArray passed in as @value_array
253 *
254 * Deprecated: 2.32: Use #GArray and g_array_insert_val() instead.
255 */
256GValueArray*
257g_value_array_insert (GValueArray *value_array,
258 guint index,
259 const GValue *value)
260{
261 guint i;
262
263 g_return_val_if_fail (value_array != NULL, NULL);
264 g_return_val_if_fail (index <= value_array->n_values, value_array);
265
266 i = value_array->n_values;
267 value_array_grow (value_array, n_values: value_array->n_values + 1, FALSE);
268 if (index + 1 < value_array->n_values)
269 memmove (dest: value_array->values + index + 1, src: value_array->values + index,
270 n: (i - index) * sizeof (value_array->values[0]));
271 memset (s: value_array->values + index, c: 0, n: sizeof (value_array->values[0]));
272 if (value)
273 {
274 g_value_init (value: value_array->values + index, G_VALUE_TYPE (value));
275 g_value_copy (src_value: value, dest_value: value_array->values + index);
276 }
277 return value_array;
278}
279
280/**
281 * g_value_array_remove:
282 * @value_array: #GValueArray to remove an element from
283 * @index_: position of value to remove, which must be less than
284 * @value_array->n_values
285 *
286 * Remove the value at position @index_ from @value_array.
287 *
288 * Returns: (transfer none): the #GValueArray passed in as @value_array
289 *
290 * Deprecated: 2.32: Use #GArray and g_array_remove_index() instead.
291 */
292GValueArray*
293g_value_array_remove (GValueArray *value_array,
294 guint index)
295{
296 g_return_val_if_fail (value_array != NULL, NULL);
297 g_return_val_if_fail (index < value_array->n_values, value_array);
298
299 if (G_VALUE_TYPE (value_array->values + index) != 0)
300 g_value_unset (value: value_array->values + index);
301 value_array->n_values--;
302 if (index < value_array->n_values)
303 memmove (dest: value_array->values + index, src: value_array->values + index + 1,
304 n: (value_array->n_values - index) * sizeof (value_array->values[0]));
305 if (value_array->n_prealloced > value_array->n_values)
306 memset (s: value_array->values + value_array->n_values, c: 0, n: sizeof (value_array->values[0]));
307
308 return value_array;
309}
310
311/**
312 * g_value_array_sort:
313 * @value_array: #GValueArray to sort
314 * @compare_func: (scope call): function to compare elements
315 *
316 * Sort @value_array using @compare_func to compare the elements according to
317 * the semantics of #GCompareFunc.
318 *
319 * The current implementation uses the same sorting algorithm as standard
320 * C qsort() function.
321 *
322 * Returns: (transfer none): the #GValueArray passed in as @value_array
323 *
324 * Deprecated: 2.32: Use #GArray and g_array_sort().
325 */
326GValueArray*
327g_value_array_sort (GValueArray *value_array,
328 GCompareFunc compare_func)
329{
330 g_return_val_if_fail (compare_func != NULL, NULL);
331
332 if (value_array->n_values)
333 qsort (base: value_array->values,
334 nmemb: value_array->n_values,
335 size: sizeof (value_array->values[0]),
336 compar: compare_func);
337 return value_array;
338}
339
340/**
341 * g_value_array_sort_with_data: (rename-to g_value_array_sort)
342 * @value_array: #GValueArray to sort
343 * @compare_func: (scope call): function to compare elements
344 * @user_data: (closure): extra data argument provided for @compare_func
345 *
346 * Sort @value_array using @compare_func to compare the elements according
347 * to the semantics of #GCompareDataFunc.
348 *
349 * The current implementation uses the same sorting algorithm as standard
350 * C qsort() function.
351 *
352 * Returns: (transfer none): the #GValueArray passed in as @value_array
353 *
354 * Deprecated: 2.32: Use #GArray and g_array_sort_with_data().
355 */
356GValueArray*
357g_value_array_sort_with_data (GValueArray *value_array,
358 GCompareDataFunc compare_func,
359 gpointer user_data)
360{
361 g_return_val_if_fail (value_array != NULL, NULL);
362 g_return_val_if_fail (compare_func != NULL, NULL);
363
364 if (value_array->n_values)
365 g_qsort_with_data (pbase: value_array->values,
366 total_elems: value_array->n_values,
367 size: sizeof (value_array->values[0]),
368 compare_func, user_data);
369 return value_array;
370}
371

source code of gtk/subprojects/glib/gobject/gvaluearray.c