Made GArray behave correct. Now zero_terminated really means, that the
[platform/upstream/glib.git] / glib / garray.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * 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  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GLib Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 /* 
28  * MT safe
29  */
30
31 #include <string.h>
32 #include "glib.h"
33
34
35 #define MIN_ARRAY_SIZE  16
36
37 typedef struct _GRealArray  GRealArray;
38
39 struct _GRealArray
40 {
41   guint8 *data;
42   guint   len;
43   guint   alloc;
44   guint   elt_size;
45   guint   zero_terminated : 1;
46   guint   clear : 1;
47 };
48
49 #define g_array_elt_len(array,i) ((array)->elt_size * (i))
50 #define g_array_elt_pos(array,i) ((array)->data + g_array_elt_len((array),(i)))
51 #define g_array_elt_zero(array, pos, len)                               \
52   (memset (g_array_elt_pos ((array), pos), 0,  g_array_elt_len ((array), len)))
53 #define g_array_zero_terminate(array) G_STMT_START{                     \
54   if ((array)->zero_terminated)                                         \
55     g_array_elt_zero ((array), (array)->len, 1);                        \
56 }G_STMT_END
57
58 static gint g_nearest_pow        (gint        num);
59 static void g_array_maybe_expand (GRealArray *array,
60                                   gint        len);
61
62 static GMemChunk *array_mem_chunk = NULL;
63 G_LOCK_DEFINE_STATIC (array_mem_chunk);
64
65 GArray*
66 g_array_new (gboolean zero_terminated,
67              gboolean clear,
68              guint    elt_size)
69 {
70   GRealArray *array;
71
72   G_LOCK (array_mem_chunk);
73   if (!array_mem_chunk)
74     array_mem_chunk = g_mem_chunk_new ("array mem chunk",
75                                        sizeof (GRealArray),
76                                        1024, G_ALLOC_AND_FREE);
77
78   array = g_chunk_new (GRealArray, array_mem_chunk);
79   G_UNLOCK (array_mem_chunk);
80
81   array->data            = NULL;
82   array->len             = 0;
83   array->alloc           = 0;
84   array->zero_terminated = (zero_terminated ? 1 : 0);
85   array->clear           = (clear ? 1 : 0);
86   array->elt_size        = elt_size;
87
88   if (array->zero_terminated)
89     {
90       g_array_maybe_expand (array, 0);
91       g_array_elt_zero (array, 0, 1);
92     }
93
94   return (GArray*) array;
95 }
96
97 void
98 g_array_free (GArray  *array,
99               gboolean free_segment)
100 {
101   if (free_segment)
102     g_free (array->data);
103
104   G_LOCK (array_mem_chunk);
105   g_mem_chunk_free (array_mem_chunk, array);
106   G_UNLOCK (array_mem_chunk);
107 }
108
109 GArray*
110 g_array_append_vals (GArray       *farray,
111                      gconstpointer data,
112                      guint         len)
113 {
114   GRealArray *array = (GRealArray*) farray;
115
116   g_array_maybe_expand (array, len);
117
118   memcpy (g_array_elt_pos (array, array->len), data, 
119           g_array_elt_len (array, len));
120
121   array->len += len;
122
123   g_array_zero_terminate (array);
124
125   return farray;
126 }
127
128 GArray*
129 g_array_prepend_vals (GArray        *farray,
130                       gconstpointer  data,
131                       guint          len)
132 {
133   GRealArray *array = (GRealArray*) farray;
134
135   g_array_maybe_expand (array, len);
136
137   g_memmove (g_array_elt_pos (array, len), g_array_elt_pos (array, 0), 
138              g_array_elt_len (array, array->len));
139
140   memcpy (g_array_elt_pos (array, 0), data, g_array_elt_len (array, len));
141
142   array->len += len;
143
144   g_array_zero_terminate (array);
145
146   return farray;
147 }
148
149 GArray*
150 g_array_insert_vals (GArray        *farray,
151                      guint          index,
152                      gconstpointer  data,
153                      guint          len)
154 {
155   GRealArray *array = (GRealArray*) farray;
156
157   g_array_maybe_expand (array, len);
158
159   g_memmove (g_array_elt_pos (array, len + index), 
160              g_array_elt_pos (array, index), 
161              g_array_elt_len (array, array->len - index));
162
163   memcpy (g_array_elt_pos (array, index), data, g_array_elt_len (array, len));
164
165   array->len += len;
166
167   g_array_zero_terminate (array);
168
169   return farray;
170 }
171
172 GArray*
173 g_array_set_size (GArray *farray,
174                   guint   length)
175 {
176   GRealArray *array = (GRealArray*) farray;
177
178   if (array->len < length)
179     {
180       g_array_maybe_expand (array, length - array->len);
181       
182       if (array->clear)
183         g_array_elt_zero (array, array->len, length - array->len);
184     }
185   
186   array->len = length;
187   
188   g_array_zero_terminate (array);
189   
190   return farray;
191 }
192
193 GArray*
194 g_array_remove_index (GArray* farray,
195                       guint index)
196 {
197   GRealArray* array = (GRealArray*) farray;
198
199   g_return_val_if_fail (array, NULL);
200
201   g_return_val_if_fail (index >= 0 && index < array->len, NULL);
202
203   if (index != array->len - 1)
204     g_memmove (g_array_elt_pos (array, index),
205                g_array_elt_pos (array, index + 1),
206                g_array_elt_len (array, array->len - index - 1));
207   
208   array->len -= 1;
209
210   g_array_zero_terminate (array);
211
212   return farray;
213 }
214
215 GArray*
216 g_array_remove_index_fast (GArray* farray,
217                            guint index)
218 {
219   GRealArray* array = (GRealArray*) farray;
220
221   g_return_val_if_fail (array, NULL);
222
223   g_return_val_if_fail (index >= 0 && index < array->len, NULL);
224
225   if (index != array->len - 1)
226     g_memmove (g_array_elt_pos (array, index), 
227                g_array_elt_pos (array, array->len - 1),
228                g_array_elt_len (array, 1));
229   
230   array->len -= 1;
231
232   g_array_zero_terminate (array);
233
234   return farray;
235 }
236
237 static gint
238 g_nearest_pow (gint num)
239 {
240   gint n = 1;
241
242   while (n < num)
243     n <<= 1;
244
245   return n;
246 }
247
248 static void
249 g_array_maybe_expand (GRealArray *array,
250                       gint        len)
251 {
252   guint want_alloc = g_array_elt_len (array, array->len + len + 
253                                       array->zero_terminated);
254
255   if (want_alloc > array->alloc)
256     {
257       array->alloc = g_nearest_pow (want_alloc);
258       array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
259
260       array->data = g_realloc (array->data, array->alloc);
261     }
262 }
263
264 /* Pointer Array
265  */
266
267 typedef struct _GRealPtrArray  GRealPtrArray;
268
269 struct _GRealPtrArray
270 {
271   gpointer *pdata;
272   guint     len;
273   guint     alloc;
274 };
275
276 static void g_ptr_array_maybe_expand (GRealPtrArray *array,
277                                       gint           len);
278
279 static GMemChunk *ptr_array_mem_chunk = NULL;
280 G_LOCK_DEFINE_STATIC (ptr_array_mem_chunk);
281
282
283 GPtrArray*
284 g_ptr_array_new (void)
285 {
286   GRealPtrArray *array;
287
288   G_LOCK (ptr_array_mem_chunk);
289   if (!ptr_array_mem_chunk)
290     ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk",
291                                            sizeof (GRealPtrArray),
292                                            1024, G_ALLOC_AND_FREE);
293
294   array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk);
295   G_UNLOCK (ptr_array_mem_chunk);
296
297   array->pdata = NULL;
298   array->len = 0;
299   array->alloc = 0;
300
301   return (GPtrArray*) array;
302 }
303
304 void
305 g_ptr_array_free (GPtrArray   *array,
306                   gboolean  free_segment)
307 {
308   g_return_if_fail (array);
309
310   if (free_segment)
311     g_free (array->pdata);
312
313   G_LOCK (ptr_array_mem_chunk);
314   g_mem_chunk_free (ptr_array_mem_chunk, array);
315   G_UNLOCK (ptr_array_mem_chunk);
316 }
317
318 static void
319 g_ptr_array_maybe_expand (GRealPtrArray *array,
320                           gint        len)
321 {
322   if ((array->len + len) > array->alloc)
323     {
324       array->alloc = g_nearest_pow (array->len + len);
325       array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
326       array->pdata = g_realloc (array->pdata, sizeof(gpointer) * array->alloc);
327     }
328 }
329
330 void
331 g_ptr_array_set_size  (GPtrArray   *farray,
332                        gint          length)
333 {
334   GRealPtrArray* array = (GRealPtrArray*) farray;
335
336   g_return_if_fail (array);
337
338   if (length > array->len)
339     {
340       int i;
341       g_ptr_array_maybe_expand (array, (length - array->len));
342       /* This is not 
343        *     memset (array->pdata + array->len, 0,
344        *            sizeof (gpointer) * (length - array->len));
345        * to make it really portable. Remember (void*)NULL needn't be
346        * bitwise zero. It of course is silly not to use memset (..,0,..).
347        */
348       for (i = array->len; i < length; i++)
349         array->pdata[i] = NULL;
350     }
351
352   array->len = length;
353 }
354
355 gpointer
356 g_ptr_array_remove_index (GPtrArray* farray,
357                           guint index)
358 {
359   GRealPtrArray* array = (GRealPtrArray*) farray;
360   gpointer result;
361
362   g_return_val_if_fail (array, NULL);
363
364   g_return_val_if_fail (index >= 0 && index < array->len, NULL);
365
366   result = array->pdata[index];
367   
368   if (index != array->len - 1)
369     g_memmove (array->pdata + index, array->pdata + index + 1, 
370                sizeof (gpointer) * (array->len - index - 1));
371   
372   array->len -= 1;
373
374   return result;
375 }
376
377 gpointer
378 g_ptr_array_remove_index_fast (GPtrArray* farray,
379                                guint index)
380 {
381   GRealPtrArray* array = (GRealPtrArray*) farray;
382   gpointer result;
383
384   g_return_val_if_fail (array, NULL);
385
386   g_return_val_if_fail (index >= 0 && index < array->len, NULL);
387
388   result = array->pdata[index];
389   
390   if (index != array->len - 1)
391     array->pdata[index] = array->pdata[array->len - 1];
392
393   array->len -= 1;
394
395   return result;
396 }
397
398 gboolean
399 g_ptr_array_remove (GPtrArray* farray,
400                     gpointer data)
401 {
402   GRealPtrArray* array = (GRealPtrArray*) farray;
403   int i;
404
405   g_return_val_if_fail (array, FALSE);
406
407   for (i = 0; i < array->len; i += 1)
408     {
409       if (array->pdata[i] == data)
410         {
411           g_ptr_array_remove_index (farray, i);
412           return TRUE;
413         }
414     }
415
416   return FALSE;
417 }
418
419 gboolean
420 g_ptr_array_remove_fast (GPtrArray* farray,
421                          gpointer data)
422 {
423   GRealPtrArray* array = (GRealPtrArray*) farray;
424   int i;
425
426   g_return_val_if_fail (array, FALSE);
427
428   for (i = 0; i < array->len; i += 1)
429     {
430       if (array->pdata[i] == data)
431         {
432           g_ptr_array_remove_index_fast (farray, i);
433           return TRUE;
434         }
435     }
436
437   return FALSE;
438 }
439
440 void
441 g_ptr_array_add (GPtrArray* farray,
442                  gpointer data)
443 {
444   GRealPtrArray* array = (GRealPtrArray*) farray;
445
446   g_return_if_fail (array);
447
448   g_ptr_array_maybe_expand (array, 1);
449
450   array->pdata[array->len++] = data;
451 }
452
453 /* Byte arrays 
454  */
455
456 GByteArray* g_byte_array_new      (void)
457 {
458   return (GByteArray*) g_array_new (FALSE, FALSE, 1);
459 }
460
461 void        g_byte_array_free     (GByteArray *array,
462                                    gboolean    free_segment)
463 {
464   g_array_free ((GArray*) array, free_segment);
465 }
466
467 GByteArray* g_byte_array_append   (GByteArray *array,
468                                    const guint8 *data,
469                                    guint       len)
470 {
471   g_array_append_vals ((GArray*) array, (guint8*)data, len);
472
473   return array;
474 }
475
476 GByteArray* g_byte_array_prepend  (GByteArray *array,
477                                    const guint8 *data,
478                                    guint       len)
479 {
480   g_array_prepend_vals ((GArray*) array, (guint8*)data, len);
481
482   return array;
483 }
484
485 GByteArray* g_byte_array_set_size (GByteArray *array,
486                                    guint       length)
487 {
488   g_array_set_size ((GArray*) array, length);
489
490   return array;
491 }
492
493 GByteArray* g_byte_array_remove_index (GByteArray *array,
494                                        guint index)
495 {
496   g_array_remove_index((GArray*) array, index);
497
498   return array;
499 }
500
501 GByteArray* g_byte_array_remove_index_fast (GByteArray *array,
502                                                    guint index)
503 {
504   g_array_remove_index_fast((GArray*) array, index);
505
506   return array;
507 }