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