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