fix preallocation logic, support DISABLE_MEM_POOLS properly, group value
[platform/upstream/glib.git] / gobject / gvaluearray.c
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 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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * MT safe
22  */
23
24 #include        "gvaluearray.h"
25 #include        <string.h>
26 #include        <stdlib.h>      /* qsort() */
27
28 #ifdef  DISABLE_MEM_POOLS
29 #  define       GROUP_N_VALUES  (1)     /* power of 2 !! */
30 #else
31 #  define       GROUP_N_VALUES  (8)     /* power of 2 !! */
32 #endif
33
34
35 /* --- functions --- */
36 GValue*
37 g_value_array_get_nth (GValueArray *value_array,
38                        guint        index)
39 {
40   g_return_val_if_fail (value_array != NULL, NULL);
41   g_return_val_if_fail (index < value_array->n_values, NULL);
42
43   return value_array->values + index;
44 }
45
46 static inline void
47 value_array_grow (GValueArray *value_array,
48                   guint        n_values,
49                   gboolean     zero_init)
50 {
51   g_return_if_fail (n_values >= value_array->n_values);
52
53   value_array->n_values = n_values;
54   if (value_array->n_values > value_array->n_prealloced)
55     {
56       guint i = value_array->n_prealloced;
57
58       value_array->n_prealloced = (value_array->n_values + GROUP_N_VALUES - 1) & ~(GROUP_N_VALUES - 1);
59       value_array->values = g_renew (GValue, value_array->values, value_array->n_prealloced);
60       if (!zero_init)
61         i = value_array->n_values;
62       memset (value_array->values + i, 0,
63               (value_array->n_prealloced - i) * sizeof (value_array->values[0]));
64     }
65 }
66
67 static inline void
68 value_array_shrink (GValueArray *value_array)
69 {
70 #ifdef  DISABLE_MEM_POOLS
71   if (value_array->n_prealloced >= value_array->n_values + GROUP_N_VALUES)
72     {
73       value_array->n_prealloced = (value_array->n_values + GROUP_N_VALUES - 1) & ~(GROUP_N_VALUES - 1);
74       value_array->values = g_renew (GValue, value_array->values, value_array->n_prealloced);
75     }
76 #endif
77 }
78
79 GValueArray*
80 g_value_array_new (guint n_prealloced)
81 {
82   GValueArray *value_array = g_new (GValueArray, 1);
83
84   value_array->n_values = 0;
85   value_array->n_prealloced = 0;
86   value_array->values = NULL;
87   value_array_grow (value_array, n_prealloced, TRUE);
88   value_array->n_values = 0;
89
90   return value_array;
91 }
92
93 void
94 g_value_array_free (GValueArray *value_array)
95 {
96   guint i;
97
98   g_return_if_fail (value_array != NULL);
99
100   for (i = 0; i < value_array->n_values; i++)
101     {
102       GValue *value = value_array->values + i;
103
104       if (G_VALUE_TYPE (value) != 0) /* we allow unset values in the array */
105         g_value_unset (value);
106     }
107   g_free (value_array->values);
108   g_free (value_array);
109 }
110
111 GValueArray*
112 g_value_array_copy (const GValueArray *value_array)
113 {
114   GValueArray *new_array;
115   guint i;
116
117   g_return_val_if_fail (value_array != NULL, NULL);
118
119   new_array = g_new (GValueArray, 1);
120   new_array->n_values = 0;
121   new_array->values = NULL;
122   new_array->n_prealloced = 0;
123   value_array_grow (new_array, value_array->n_values, TRUE);
124   for (i = 0; i < new_array->n_values; i++)
125     if (G_VALUE_TYPE (value_array->values + i) != 0)
126       {
127         GValue *value = new_array->values + i;
128         
129         g_value_init (value, G_VALUE_TYPE (value_array->values + i));
130         g_value_copy (value_array->values + i, value);
131       }
132   return new_array;
133 }
134
135 GValueArray*
136 g_value_array_prepend (GValueArray  *value_array,
137                        const GValue *value)
138 {
139   g_return_val_if_fail (value_array != NULL, NULL);
140
141   return g_value_array_insert (value_array, 0, value);
142 }
143
144 GValueArray*
145 g_value_array_append (GValueArray  *value_array,
146                       const GValue *value)
147 {
148   g_return_val_if_fail (value_array != NULL, NULL);
149
150   return g_value_array_insert (value_array, value_array->n_values, value);
151 }
152
153 GValueArray*
154 g_value_array_insert (GValueArray  *value_array,
155                       guint         index,
156                       const GValue *value)
157 {
158   guint i;
159
160   g_return_val_if_fail (value_array != NULL, NULL);
161   g_return_val_if_fail (index <= value_array->n_values, value_array);
162
163   /* we support NULL for "value" as a shortcut for an unset value */
164
165   i = value_array->n_values;
166   value_array_grow (value_array, value_array->n_values + 1, FALSE);
167   if (index + 1 < value_array->n_values)
168     g_memmove (value_array->values + index + 1, value_array->values + index,
169                (i - index) * sizeof (value_array->values[0]));
170   memset (value_array->values + index, 0, sizeof (value_array->values[0]));
171   if (value)
172     {
173       g_value_init (value_array->values + index, G_VALUE_TYPE (value));
174       g_value_copy (value, value_array->values + index);
175     }
176   return value_array;
177 }
178
179 GValueArray*
180 g_value_array_remove (GValueArray *value_array,
181                       guint        index)
182 {
183   g_return_val_if_fail (value_array != NULL, NULL);
184   g_return_val_if_fail (index < value_array->n_values, value_array);
185
186   if (G_VALUE_TYPE (value_array->values + index) != 0)
187     g_value_unset (value_array->values + index);
188   value_array->n_values--;
189   if (index < value_array->n_values)
190     g_memmove (value_array->values + index, value_array->values + index + 1,
191                (value_array->n_values - index) * sizeof (value_array->values[0]));
192   value_array_shrink (value_array);
193   if (value_array->n_prealloced > value_array->n_values)
194     memset (value_array->values + value_array->n_values, 0, sizeof (value_array->values[0]));
195
196   return value_array;
197 }
198
199 GValueArray*
200 g_value_array_sort (GValueArray *value_array,
201                     GCompareFunc compare_func)
202 {
203   g_return_val_if_fail (compare_func != NULL, NULL);
204
205   if (value_array->n_values)
206     qsort (value_array->values,
207            value_array->n_values,
208            sizeof (value_array->values[0]),
209            compare_func);
210   return value_array;
211 }
212
213 GValueArray*
214 g_value_array_sort_with_data (GValueArray     *value_array,
215                               GCompareDataFunc compare_func,
216                               gpointer         user_data)
217 {
218   g_return_val_if_fail (value_array != NULL, NULL);
219   g_return_val_if_fail (compare_func != NULL, NULL);
220
221   if (value_array->n_values)
222     g_qsort_with_data (value_array->values,
223                        value_array->n_values,
224                        sizeof (value_array->values[0]),
225                        compare_func, user_data);
226   return value_array;
227 }