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