|
1 /* GObject - GLib Type, Object, Parameter and Signal Library |
|
2 * Copyright (C) 2001 Red Hat, Inc. |
|
3 * Portions copyright (c) 2006-2009 Nokia Corporation. All rights reserved. |
|
4 * |
|
5 * This library is free software; you can redistribute it and/or |
|
6 * modify it under the terms of the GNU Lesser General Public |
|
7 * License as published by the Free Software Foundation; either |
|
8 * version 2 of the License, or (at your option) any later version. |
|
9 * |
|
10 * This library is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 * Lesser General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU Lesser General |
|
16 * Public License along with this library; if not, write to the |
|
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
|
18 * Boston, MA 02111-1307, USA. |
|
19 */ |
|
20 |
|
21 /* |
|
22 * MT safe |
|
23 */ |
|
24 |
|
25 #include "config.h" |
|
26 |
|
27 #include <string.h> |
|
28 #include <stdlib.h> /* qsort() */ |
|
29 |
|
30 #include "gvaluearray.h" |
|
31 #include "gobjectalias.h" |
|
32 |
|
33 |
|
34 /** |
|
35 * SECTION:value_arrays |
|
36 * @short_description: A container structure to maintain an array of |
|
37 * generic values |
|
38 * @see_also: #GValue, #GParamSpecValueArray, g_param_spec_value_array() |
|
39 * @title: Value arrays |
|
40 * |
|
41 * The prime purpose of a #GValueArray is for it to be used as an |
|
42 * object property that holds an array of values. A #GValueArray wraps |
|
43 * an array of #GValue elements in order for it to be used as a boxed |
|
44 * type through %G_TYPE_VALUE_ARRAY. |
|
45 */ |
|
46 |
|
47 |
|
48 #ifdef DISABLE_MEM_POOLS |
|
49 # define GROUP_N_VALUES (1) /* power of 2 !! */ |
|
50 #else |
|
51 # define GROUP_N_VALUES (8) /* power of 2 !! */ |
|
52 #endif |
|
53 |
|
54 |
|
55 /* --- functions --- */ |
|
56 /** |
|
57 * g_value_array_get_nth: |
|
58 * @value_array: #GValueArray to get a value from |
|
59 * @index_: index of the value of interest |
|
60 * |
|
61 * Return a pointer to the value at @index_ containd in @value_array. |
|
62 * |
|
63 * Returns: pointer to a value at @index_ in @value_array |
|
64 */ |
|
65 EXPORT_C GValue* |
|
66 g_value_array_get_nth (GValueArray *value_array, |
|
67 guint index) |
|
68 { |
|
69 g_return_val_if_fail (value_array != NULL, NULL); |
|
70 g_return_val_if_fail (index < value_array->n_values, NULL); |
|
71 |
|
72 return value_array->values + index; |
|
73 } |
|
74 |
|
75 static inline void |
|
76 value_array_grow (GValueArray *value_array, |
|
77 guint n_values, |
|
78 gboolean zero_init) |
|
79 { |
|
80 g_return_if_fail (n_values >= value_array->n_values); |
|
81 |
|
82 value_array->n_values = n_values; |
|
83 if (value_array->n_values > value_array->n_prealloced) |
|
84 { |
|
85 guint i = value_array->n_prealloced; |
|
86 |
|
87 value_array->n_prealloced = (value_array->n_values + GROUP_N_VALUES - 1) & ~(GROUP_N_VALUES - 1); |
|
88 value_array->values = g_renew (GValue, value_array->values, value_array->n_prealloced); |
|
89 if (!zero_init) |
|
90 i = value_array->n_values; |
|
91 memset (value_array->values + i, 0, |
|
92 (value_array->n_prealloced - i) * sizeof (value_array->values[0])); |
|
93 } |
|
94 } |
|
95 |
|
96 static inline void |
|
97 value_array_shrink (GValueArray *value_array) |
|
98 { |
|
99 #ifdef DISABLE_MEM_POOLS |
|
100 if (value_array->n_prealloced >= value_array->n_values + GROUP_N_VALUES) |
|
101 { |
|
102 value_array->n_prealloced = (value_array->n_values + GROUP_N_VALUES - 1) & ~(GROUP_N_VALUES - 1); |
|
103 value_array->values = g_renew (GValue, value_array->values, value_array->n_prealloced); |
|
104 } |
|
105 #endif |
|
106 } |
|
107 |
|
108 /** |
|
109 * g_value_array_new: |
|
110 * @n_prealloced: number of values to preallocate space for |
|
111 * |
|
112 * Allocate and initialize a new #GValueArray, optionally preserve space |
|
113 * for @n_prealloced elements. New arrays always contain 0 elements, |
|
114 * regardless of the value of @n_prealloced. |
|
115 * |
|
116 * Returns: a newly allocated #GValueArray with 0 values |
|
117 */ |
|
118 EXPORT_C GValueArray* |
|
119 g_value_array_new (guint n_prealloced) |
|
120 { |
|
121 GValueArray *value_array = g_slice_new (GValueArray); |
|
122 |
|
123 value_array->n_values = 0; |
|
124 value_array->n_prealloced = 0; |
|
125 value_array->values = NULL; |
|
126 value_array_grow (value_array, n_prealloced, TRUE); |
|
127 value_array->n_values = 0; |
|
128 |
|
129 return value_array; |
|
130 } |
|
131 |
|
132 /** |
|
133 * g_value_array_free: |
|
134 * @value_array: #GValueArray to free |
|
135 * |
|
136 * Free a #GValueArray including its contents. |
|
137 */ |
|
138 EXPORT_C void |
|
139 g_value_array_free (GValueArray *value_array) |
|
140 { |
|
141 guint i; |
|
142 |
|
143 g_return_if_fail (value_array != NULL); |
|
144 |
|
145 for (i = 0; i < value_array->n_values; i++) |
|
146 { |
|
147 GValue *value = value_array->values + i; |
|
148 |
|
149 if (G_VALUE_TYPE (value) != 0) /* we allow unset values in the array */ |
|
150 g_value_unset (value); |
|
151 } |
|
152 g_free (value_array->values); |
|
153 g_slice_free (GValueArray, value_array); |
|
154 } |
|
155 |
|
156 /** |
|
157 * g_value_array_copy: |
|
158 * @value_array: #GValueArray to copy |
|
159 * |
|
160 * Construct an exact copy of a #GValueArray by duplicating all its |
|
161 * contents. |
|
162 * |
|
163 * Returns: Newly allocated copy of #GValueArray |
|
164 */ |
|
165 EXPORT_C GValueArray* |
|
166 g_value_array_copy (const GValueArray *value_array) |
|
167 { |
|
168 GValueArray *new_array; |
|
169 guint i; |
|
170 |
|
171 g_return_val_if_fail (value_array != NULL, NULL); |
|
172 |
|
173 new_array = g_slice_new (GValueArray); |
|
174 new_array->n_values = 0; |
|
175 new_array->values = NULL; |
|
176 new_array->n_prealloced = 0; |
|
177 value_array_grow (new_array, value_array->n_values, TRUE); |
|
178 for (i = 0; i < new_array->n_values; i++) |
|
179 if (G_VALUE_TYPE (value_array->values + i) != 0) |
|
180 { |
|
181 GValue *value = new_array->values + i; |
|
182 |
|
183 g_value_init (value, G_VALUE_TYPE (value_array->values + i)); |
|
184 g_value_copy (value_array->values + i, value); |
|
185 } |
|
186 return new_array; |
|
187 } |
|
188 |
|
189 /** |
|
190 * g_value_array_prepend: |
|
191 * @value_array: #GValueArray to add an element to |
|
192 * @value: #GValue to copy into #GValueArray |
|
193 * |
|
194 * Insert a copy of @value as first element of @value_array. |
|
195 * |
|
196 * Returns: the #GValueArray passed in as @value_array |
|
197 */ |
|
198 EXPORT_C GValueArray* |
|
199 g_value_array_prepend (GValueArray *value_array, |
|
200 const GValue *value) |
|
201 { |
|
202 g_return_val_if_fail (value_array != NULL, NULL); |
|
203 |
|
204 return g_value_array_insert (value_array, 0, value); |
|
205 } |
|
206 |
|
207 /** |
|
208 * g_value_array_append: |
|
209 * @value_array: #GValueArray to add an element to |
|
210 * @value: #GValue to copy into #GValueArray |
|
211 * |
|
212 * Insert a copy of @value as last element of @value_array. |
|
213 * |
|
214 * Returns: the #GValueArray passed in as @value_array |
|
215 */ |
|
216 EXPORT_C GValueArray* |
|
217 g_value_array_append (GValueArray *value_array, |
|
218 const GValue *value) |
|
219 { |
|
220 g_return_val_if_fail (value_array != NULL, NULL); |
|
221 |
|
222 return g_value_array_insert (value_array, value_array->n_values, value); |
|
223 } |
|
224 |
|
225 /** |
|
226 * g_value_array_insert: |
|
227 * @value_array: #GValueArray to add an element to |
|
228 * @index_: insertion position, must be <= value_array->n_values |
|
229 * @value: #GValue to copy into #GValueArray |
|
230 * |
|
231 * Insert a copy of @value at specified position into @value_array. |
|
232 * |
|
233 * Returns: the #GValueArray passed in as @value_array |
|
234 */ |
|
235 EXPORT_C GValueArray* |
|
236 g_value_array_insert (GValueArray *value_array, |
|
237 guint index, |
|
238 const GValue *value) |
|
239 { |
|
240 guint i; |
|
241 |
|
242 g_return_val_if_fail (value_array != NULL, NULL); |
|
243 g_return_val_if_fail (index <= value_array->n_values, value_array); |
|
244 |
|
245 /* we support NULL for "value" as a shortcut for an unset value */ |
|
246 |
|
247 i = value_array->n_values; |
|
248 value_array_grow (value_array, value_array->n_values + 1, FALSE); |
|
249 if (index + 1 < value_array->n_values) |
|
250 g_memmove (value_array->values + index + 1, value_array->values + index, |
|
251 (i - index) * sizeof (value_array->values[0])); |
|
252 memset (value_array->values + index, 0, sizeof (value_array->values[0])); |
|
253 if (value) |
|
254 { |
|
255 g_value_init (value_array->values + index, G_VALUE_TYPE (value)); |
|
256 g_value_copy (value, value_array->values + index); |
|
257 } |
|
258 return value_array; |
|
259 } |
|
260 |
|
261 /** |
|
262 * g_value_array_remove: |
|
263 * @value_array: #GValueArray to remove an element from |
|
264 * @index_: position of value to remove, must be < value_array->n_values |
|
265 * |
|
266 * Remove the value at position @index_ from @value_array. |
|
267 * |
|
268 * Returns: the #GValueArray passed in as @value_array |
|
269 */ |
|
270 EXPORT_C GValueArray* |
|
271 g_value_array_remove (GValueArray *value_array, |
|
272 guint index) |
|
273 { |
|
274 g_return_val_if_fail (value_array != NULL, NULL); |
|
275 g_return_val_if_fail (index < value_array->n_values, value_array); |
|
276 |
|
277 if (G_VALUE_TYPE (value_array->values + index) != 0) |
|
278 g_value_unset (value_array->values + index); |
|
279 value_array->n_values--; |
|
280 if (index < value_array->n_values) |
|
281 g_memmove (value_array->values + index, value_array->values + index + 1, |
|
282 (value_array->n_values - index) * sizeof (value_array->values[0])); |
|
283 value_array_shrink (value_array); |
|
284 if (value_array->n_prealloced > value_array->n_values) |
|
285 memset (value_array->values + value_array->n_values, 0, sizeof (value_array->values[0])); |
|
286 |
|
287 return value_array; |
|
288 } |
|
289 |
|
290 /** |
|
291 * g_value_array_sort: |
|
292 * @value_array: #GValueArray to sort |
|
293 * @compare_func: function to compare elements |
|
294 * |
|
295 * Sort @value_array using @compare_func to compare the elements accoring to |
|
296 * the semantics of #GCompareFunc. |
|
297 * |
|
298 * The current implementation uses Quick-Sort as sorting algorithm. |
|
299 * |
|
300 * Returns: the #GValueArray passed in as @value_array |
|
301 */ |
|
302 EXPORT_C GValueArray* |
|
303 g_value_array_sort (GValueArray *value_array, |
|
304 GCompareFunc compare_func) |
|
305 { |
|
306 g_return_val_if_fail (compare_func != NULL, NULL); |
|
307 |
|
308 if (value_array->n_values) |
|
309 qsort (value_array->values, |
|
310 value_array->n_values, |
|
311 sizeof (value_array->values[0]), |
|
312 compare_func); |
|
313 return value_array; |
|
314 } |
|
315 |
|
316 /** |
|
317 * g_value_array_sort_with_data: |
|
318 * @value_array: #GValueArray to sort |
|
319 * @compare_func: function to compare elements |
|
320 * @user_data: extra data argument provided for @compare_func |
|
321 * |
|
322 * Sort @value_array using @compare_func to compare the elements accoring |
|
323 * to the semantics of #GCompareDataFunc. |
|
324 * |
|
325 * The current implementation uses Quick-Sort as sorting algorithm. |
|
326 * |
|
327 * Returns: the #GValueArray passed in as @value_array |
|
328 */ |
|
329 EXPORT_C GValueArray* |
|
330 g_value_array_sort_with_data (GValueArray *value_array, |
|
331 GCompareDataFunc compare_func, |
|
332 gpointer user_data) |
|
333 { |
|
334 g_return_val_if_fail (value_array != NULL, NULL); |
|
335 g_return_val_if_fail (compare_func != NULL, NULL); |
|
336 |
|
337 if (value_array->n_values) |
|
338 g_qsort_with_data (value_array->values, |
|
339 value_array->n_values, |
|
340 sizeof (value_array->values[0]), |
|
341 compare_func, user_data); |
|
342 return value_array; |
|
343 } |
|
344 |
|
345 #define __G_VALUE_ARRAY_C__ |
|
346 #include "gobjectaliasdef.c" |