Ok, I'm a moron. When I originally implemented ENABLE_GC_FRIENDLY, I
[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 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 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-2000.  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 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include <string.h>
36 #include <stdlib.h>
37 #include "glib.h"
38
39
40 #define MIN_ARRAY_SIZE  16
41
42 typedef struct _GRealArray  GRealArray;
43
44 struct _GRealArray
45 {
46   guint8 *data;
47   guint   len;
48   guint   alloc;
49   guint   elt_size;
50   guint   zero_terminated : 1;
51   guint   clear : 1;
52 };
53
54 #define g_array_elt_len(array,i) ((array)->elt_size * (i))
55 #define g_array_elt_pos(array,i) ((array)->data + g_array_elt_len((array),(i)))
56 #define g_array_elt_zero(array, pos, len)                               \
57   (memset (g_array_elt_pos ((array), pos), 0,  g_array_elt_len ((array), len)))
58 #define g_array_zero_terminate(array) G_STMT_START{                     \
59   if ((array)->zero_terminated)                                         \
60     g_array_elt_zero ((array), (array)->len, 1);                        \
61 }G_STMT_END
62
63 static gint g_nearest_pow        (gint        num) G_GNUC_CONST;
64 static void g_array_maybe_expand (GRealArray *array,
65                                   gint        len);
66
67 static GMemChunk *array_mem_chunk = NULL;
68 G_LOCK_DEFINE_STATIC (array_mem_chunk);
69
70 GArray*
71 g_array_new (gboolean zero_terminated,
72              gboolean clear,
73              guint    elt_size)
74 {
75   return (GArray*) g_array_sized_new (zero_terminated, clear, elt_size, 0);
76 }
77
78 GArray* g_array_sized_new (gboolean zero_terminated,
79                            gboolean clear,
80                            guint    elt_size,
81                            guint    reserved_size)
82 {
83   GRealArray *array;
84
85   G_LOCK (array_mem_chunk);
86   if (!array_mem_chunk)
87     array_mem_chunk = g_mem_chunk_new ("array mem chunk",
88                                        sizeof (GRealArray),
89                                        1024, G_ALLOC_AND_FREE);
90
91   array = g_chunk_new (GRealArray, array_mem_chunk);
92   G_UNLOCK (array_mem_chunk);
93
94   array->data            = NULL;
95   array->len             = 0;
96   array->alloc           = 0;
97   array->zero_terminated = (zero_terminated ? 1 : 0);
98   array->clear           = (clear ? 1 : 0);
99   array->elt_size        = elt_size;
100
101   if (array->zero_terminated || reserved_size != 0)
102     {
103       g_array_maybe_expand (array, reserved_size);
104       g_array_zero_terminate(array);
105     }
106
107   return (GArray*) array;
108 }
109
110 gchar*
111 g_array_free (GArray  *array,
112               gboolean free_segment)
113 {
114   gchar* segment;
115
116   g_return_val_if_fail (array, NULL);
117
118   if (free_segment)
119     {
120       g_free (array->data);
121       segment = NULL;
122     }
123   else
124     segment = array->data;
125
126   G_LOCK (array_mem_chunk);
127   g_mem_chunk_free (array_mem_chunk, array);
128   G_UNLOCK (array_mem_chunk);
129
130   return segment;
131 }
132
133 GArray*
134 g_array_append_vals (GArray       *farray,
135                      gconstpointer data,
136                      guint         len)
137 {
138   GRealArray *array = (GRealArray*) farray;
139
140   g_array_maybe_expand (array, len);
141
142   memcpy (g_array_elt_pos (array, array->len), data, 
143           g_array_elt_len (array, len));
144
145   array->len += len;
146
147   g_array_zero_terminate (array);
148
149   return farray;
150 }
151
152 GArray*
153 g_array_prepend_vals (GArray        *farray,
154                       gconstpointer  data,
155                       guint          len)
156 {
157   GRealArray *array = (GRealArray*) farray;
158
159   g_array_maybe_expand (array, len);
160
161   g_memmove (g_array_elt_pos (array, len), g_array_elt_pos (array, 0), 
162              g_array_elt_len (array, array->len));
163
164   memcpy (g_array_elt_pos (array, 0), data, g_array_elt_len (array, len));
165
166   array->len += len;
167
168   g_array_zero_terminate (array);
169
170   return farray;
171 }
172
173 GArray*
174 g_array_insert_vals (GArray        *farray,
175                      guint          index,
176                      gconstpointer  data,
177                      guint          len)
178 {
179   GRealArray *array = (GRealArray*) farray;
180
181   g_array_maybe_expand (array, len);
182
183   g_memmove (g_array_elt_pos (array, len + index), 
184              g_array_elt_pos (array, index), 
185              g_array_elt_len (array, array->len - index));
186
187   memcpy (g_array_elt_pos (array, index), data, g_array_elt_len (array, len));
188
189   array->len += len;
190
191   g_array_zero_terminate (array);
192
193   return farray;
194 }
195
196 GArray*
197 g_array_set_size (GArray *farray,
198                   guint   length)
199 {
200   GRealArray *array = (GRealArray*) farray;
201   if (length > array->len)
202     {
203       g_array_maybe_expand (array, length - array->len);
204       
205       if (array->clear)
206         g_array_elt_zero (array, array->len, length - array->len);
207     }
208 #ifdef ENABLE_GC_FRIENDLY  
209   else if (length < array->len)
210     g_array_elt_zero (array, length, array->len - length);
211 #endif /* ENABLE_GC_FRIENDLY */  
212   
213   array->len = length;
214   
215   g_array_zero_terminate (array);
216   
217   return farray;
218 }
219
220 GArray*
221 g_array_remove_index (GArray* farray,
222                       guint index)
223 {
224   GRealArray* array = (GRealArray*) farray;
225
226   g_return_val_if_fail (array, NULL);
227
228   g_return_val_if_fail (index < array->len, NULL);
229
230   if (index != array->len - 1)
231     g_memmove (g_array_elt_pos (array, index),
232                g_array_elt_pos (array, index + 1),
233                g_array_elt_len (array, array->len - index - 1));
234   
235   array->len -= 1;
236
237 #ifdef ENABLE_GC_FRIENDLY
238   g_array_elt_zero (array, array->len, 1);
239 #else /* !ENABLE_GC_FRIENDLY */
240   g_array_zero_terminate (array);
241 #endif /* ENABLE_GC_FRIENDLY */  
242
243   return farray;
244 }
245
246 GArray*
247 g_array_remove_index_fast (GArray* farray,
248                            guint   index)
249 {
250   GRealArray* array = (GRealArray*) farray;
251
252   g_return_val_if_fail (array, NULL);
253
254   g_return_val_if_fail (index < array->len, NULL);
255
256   if (index != array->len - 1)
257     g_memmove (g_array_elt_pos (array, index), 
258                g_array_elt_pos (array, array->len - 1),
259                g_array_elt_len (array, 1));
260   
261   array->len -= 1;
262
263 #ifdef ENABLE_GC_FRIENDLY
264   g_array_elt_zero (array, array->len, 1);
265 #else /* !ENABLE_GC_FRIENDLY */
266   g_array_zero_terminate (array);
267 #endif /* ENABLE_GC_FRIENDLY */  
268
269   return farray;
270 }
271
272 void
273 g_array_sort (GArray       *farray,
274               GCompareFunc  compare_func)
275 {
276   GRealArray *array = (GRealArray*) farray;
277
278   g_return_if_fail (array != NULL);
279   g_return_if_fail (array->data != NULL);
280
281   qsort (array->data,
282          array->len,
283          array->elt_size,
284          compare_func);
285 }
286
287 void
288 g_array_sort_with_data (GArray           *farray,
289                         GCompareFuncData  compare_func,
290                         gpointer          user_data)
291 {
292   GRealArray *array = (GRealArray*) farray;
293
294   g_return_if_fail (array != NULL);
295   g_return_if_fail (array->data != NULL);
296
297   g_qsort_with_data (array->data,
298                      array->len,
299                      array->elt_size,
300                      compare_func,
301                      user_data);
302 }
303
304
305 static gint
306 g_nearest_pow (gint num)
307 {
308   gint n = 1;
309
310   while (n < num)
311     n <<= 1;
312
313   return n;
314 }
315
316 static void
317 g_array_maybe_expand (GRealArray *array,
318                       gint        len)
319 {
320   guint want_alloc = g_array_elt_len (array, array->len + len + 
321                                       array->zero_terminated);
322
323   if (want_alloc > array->alloc)
324     {
325       want_alloc = g_nearest_pow (want_alloc);
326       want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE);
327
328       array->data = g_realloc (array->data, want_alloc);
329
330 #ifdef ENABLE_GC_FRIENDLY
331       memset (array->data + array->alloc, 0, want_alloc - array->alloc);
332 #endif /* ENABLE_GC_FRIENDLY */
333
334       array->alloc = want_alloc;
335     }
336 }
337
338 /* Pointer Array
339  */
340
341 typedef struct _GRealPtrArray  GRealPtrArray;
342
343 struct _GRealPtrArray
344 {
345   gpointer *pdata;
346   guint     len;
347   guint     alloc;
348 };
349
350 static void g_ptr_array_maybe_expand (GRealPtrArray *array,
351                                       gint           len);
352
353 static GMemChunk *ptr_array_mem_chunk = NULL;
354 G_LOCK_DEFINE_STATIC (ptr_array_mem_chunk);
355
356
357 GPtrArray*
358 g_ptr_array_new (void)
359 {
360   return g_ptr_array_sized_new (0);
361 }
362
363 GPtrArray*  
364 g_ptr_array_sized_new (guint reserved_size)
365 {
366   GRealPtrArray *array;
367
368   G_LOCK (ptr_array_mem_chunk);
369   if (!ptr_array_mem_chunk)
370     ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk",
371                                            sizeof (GRealPtrArray),
372                                            1024, G_ALLOC_AND_FREE);
373
374   array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk);
375   G_UNLOCK (ptr_array_mem_chunk);
376
377   array->pdata = NULL;
378   array->len = 0;
379   array->alloc = 0;
380
381   if (reserved_size != 0)
382     g_ptr_array_maybe_expand (array, reserved_size);
383
384   return (GPtrArray*) array;  
385 }
386
387 gpointer*
388 g_ptr_array_free (GPtrArray   *array,
389                   gboolean  free_segment)
390 {
391   gpointer* segment;
392
393   g_return_val_if_fail (array, NULL);
394
395   if (free_segment)
396     {
397       g_free (array->pdata);
398       segment = NULL;
399     }
400   else
401     segment = array->pdata;
402
403   G_LOCK (ptr_array_mem_chunk);
404   g_mem_chunk_free (ptr_array_mem_chunk, array);
405   G_UNLOCK (ptr_array_mem_chunk);
406
407   return segment;
408 }
409
410 static void
411 g_ptr_array_maybe_expand (GRealPtrArray *array,
412                           gint        len)
413 {
414   if ((array->len + len) > array->alloc)
415     {
416 #ifdef ENABLE_GC_FRIENDLY
417       guint old_alloc = array->alloc;
418 #endif /* ENABLE_GC_FRIENDLY */
419       array->alloc = g_nearest_pow (array->len + len);
420       array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
421       array->pdata = g_realloc (array->pdata, sizeof(gpointer) * array->alloc);
422 #ifdef ENABLE_GC_FRIENDLY
423       for ( ; old_alloc < array->alloc; old_alloc++)
424         array->pdata [old_alloc] = NULL;
425 #endif /* ENABLE_GC_FRIENDLY */
426     }
427 }
428
429 void
430 g_ptr_array_set_size  (GPtrArray   *farray,
431                        gint          length)
432 {
433   GRealPtrArray* array = (GRealPtrArray*) farray;
434
435   g_return_if_fail (array);
436
437   if (length > array->len)
438     {
439       int i;
440       g_ptr_array_maybe_expand (array, (length - array->len));
441       /* This is not 
442        *     memset (array->pdata + array->len, 0,
443        *            sizeof (gpointer) * (length - array->len));
444        * to make it really portable. Remember (void*)NULL needn't be
445        * bitwise zero. It of course is silly not to use memset (..,0,..).
446        */
447       for (i = array->len; i < length; i++)
448         array->pdata[i] = NULL;
449     }
450 #ifdef ENABLE_GC_FRIENDLY  
451   else if (length < array->len)
452     {
453       int i;
454       for (i = length; i < array->len; i++)
455         array->pdata[i] = NULL;
456     }
457 #endif /* ENABLE_GC_FRIENDLY */  
458
459   array->len = length;
460 }
461
462 gpointer
463 g_ptr_array_remove_index (GPtrArray* farray,
464                           guint      index)
465 {
466   GRealPtrArray* array = (GRealPtrArray*) farray;
467   gpointer result;
468
469   g_return_val_if_fail (array, NULL);
470
471   g_return_val_if_fail (index < array->len, NULL);
472
473   result = array->pdata[index];
474   
475   if (index != array->len - 1)
476     g_memmove (array->pdata + index, array->pdata + index + 1, 
477                sizeof (gpointer) * (array->len - index - 1));
478   
479   array->len -= 1;
480
481 #ifdef ENABLE_GC_FRIENDLY  
482   array->pdata[array->len] = NULL;
483 #endif /* ENABLE_GC_FRIENDLY */  
484
485   return result;
486 }
487
488 gpointer
489 g_ptr_array_remove_index_fast (GPtrArray* farray,
490                                guint      index)
491 {
492   GRealPtrArray* array = (GRealPtrArray*) farray;
493   gpointer result;
494
495   g_return_val_if_fail (array, NULL);
496
497   g_return_val_if_fail (index < array->len, NULL);
498
499   result = array->pdata[index];
500   
501   if (index != array->len - 1)
502     array->pdata[index] = array->pdata[array->len - 1];
503
504   array->len -= 1;
505
506 #ifdef ENABLE_GC_FRIENDLY  
507   array->pdata[array->len] = NULL;
508 #endif /* ENABLE_GC_FRIENDLY */  
509
510   return result;
511 }
512
513 gboolean
514 g_ptr_array_remove (GPtrArray* farray,
515                     gpointer data)
516 {
517   GRealPtrArray* array = (GRealPtrArray*) farray;
518   int i;
519
520   g_return_val_if_fail (array, FALSE);
521
522   for (i = 0; i < array->len; i += 1)
523     {
524       if (array->pdata[i] == data)
525         {
526           g_ptr_array_remove_index (farray, i);
527           return TRUE;
528         }
529     }
530
531   return FALSE;
532 }
533
534 gboolean
535 g_ptr_array_remove_fast (GPtrArray* farray,
536                          gpointer data)
537 {
538   GRealPtrArray* array = (GRealPtrArray*) farray;
539   int i;
540
541   g_return_val_if_fail (array, FALSE);
542
543   for (i = 0; i < array->len; i += 1)
544     {
545       if (array->pdata[i] == data)
546         {
547           g_ptr_array_remove_index_fast (farray, i);
548           return TRUE;
549         }
550     }
551
552   return FALSE;
553 }
554
555 void
556 g_ptr_array_add (GPtrArray* farray,
557                  gpointer data)
558 {
559   GRealPtrArray* array = (GRealPtrArray*) farray;
560
561   g_return_if_fail (array);
562
563   g_ptr_array_maybe_expand (array, 1);
564
565   array->pdata[array->len++] = data;
566 }
567
568 void
569 g_ptr_array_sort (GPtrArray    *array,
570                   GCompareFunc  compare_func)
571 {
572   g_return_if_fail (array != NULL);
573   g_return_if_fail (array->pdata != NULL);
574
575   qsort (array->pdata,
576          array->len,
577          sizeof (gpointer),
578          compare_func);
579 }
580
581 void
582 g_ptr_array_sort_with_data (GPtrArray        *array,
583                             GCompareFuncData  compare_func,
584                             gpointer          user_data)
585 {
586   g_return_if_fail (array != NULL);
587   g_return_if_fail (array->pdata != NULL);
588
589   g_qsort_with_data (array->pdata,
590                      array->len,
591                      sizeof (gpointer),
592                      compare_func,
593                      user_data);
594 }
595
596 /* Byte arrays 
597  */
598
599 GByteArray* g_byte_array_new      (void)
600 {
601   return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, 0);
602 }
603
604 GByteArray* g_byte_array_sized_new (guint reserved_size)
605 {
606   return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, reserved_size);
607 }
608
609 guint8*     g_byte_array_free     (GByteArray *array,
610                                    gboolean    free_segment)
611 {
612   return (guint8*) g_array_free ((GArray*) array, free_segment);
613 }
614
615 GByteArray* g_byte_array_append   (GByteArray *array,
616                                    const guint8 *data,
617                                    guint       len)
618 {
619   g_array_append_vals ((GArray*) array, (guint8*)data, len);
620
621   return array;
622 }
623
624 GByteArray* g_byte_array_prepend  (GByteArray *array,
625                                    const guint8 *data,
626                                    guint       len)
627 {
628   g_array_prepend_vals ((GArray*) array, (guint8*)data, len);
629
630   return array;
631 }
632
633 GByteArray* g_byte_array_set_size (GByteArray *array,
634                                    guint       length)
635 {
636   g_array_set_size ((GArray*) array, length);
637
638   return array;
639 }
640
641 GByteArray* g_byte_array_remove_index (GByteArray *array,
642                                        guint index)
643 {
644   g_array_remove_index((GArray*) array, index);
645
646   return array;
647 }
648
649 GByteArray* g_byte_array_remove_index_fast (GByteArray *array,
650                                             guint index)
651 {
652   g_array_remove_index_fast((GArray*) array, index);
653
654   return array;
655 }
656
657 void
658 g_byte_array_sort (GByteArray   *array,
659                    GCompareFunc  compare_func)
660 {
661   g_array_sort ((GArray *) array, compare_func);
662 }
663
664 void
665 g_byte_array_sort_with_data (GByteArray       *array,
666                              GCompareFuncData  compare_func,
667                              gpointer          user_data)
668 {
669   g_array_sort_with_data ((GArray *) array, compare_func, user_data);
670 }