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