Do not define function g_thread_init_glib, if not G_THREADS_ENABLED. It's
[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 "glib.h"
36
37
38 #define MIN_ARRAY_SIZE  16
39
40 typedef struct _GRealArray  GRealArray;
41
42 struct _GRealArray
43 {
44   guint8 *data;
45   guint   len;
46   guint   alloc;
47   guint   elt_size;
48   guint   zero_terminated : 1;
49   guint   clear : 1;
50 };
51
52 #define g_array_elt_len(array,i) ((array)->elt_size * (i))
53 #define g_array_elt_pos(array,i) ((array)->data + g_array_elt_len((array),(i)))
54 #define g_array_elt_zero(array, pos, len)                               \
55   (memset (g_array_elt_pos ((array), pos), 0,  g_array_elt_len ((array), len)))
56 #define g_array_zero_terminate(array) G_STMT_START{                     \
57   if ((array)->zero_terminated)                                         \
58     g_array_elt_zero ((array), (array)->len, 1);                        \
59 }G_STMT_END
60
61 static gint g_nearest_pow        (gint        num) G_GNUC_CONST;
62 static void g_array_maybe_expand (GRealArray *array,
63                                   gint        len);
64
65 static GMemChunk *array_mem_chunk = NULL;
66 G_LOCK_DEFINE_STATIC (array_mem_chunk);
67
68 GArray*
69 g_array_new (gboolean zero_terminated,
70              gboolean clear,
71              guint    elt_size)
72 {
73   return (GArray*) g_array_sized_new (zero_terminated, clear, elt_size, 0);
74 }
75
76 GArray* g_array_sized_new (gboolean zero_terminated,
77                            gboolean clear,
78                            guint    elt_size,
79                            guint    reserved_size)
80 {
81   GRealArray *array;
82
83   G_LOCK (array_mem_chunk);
84   if (!array_mem_chunk)
85     array_mem_chunk = g_mem_chunk_new ("array mem chunk",
86                                        sizeof (GRealArray),
87                                        1024, G_ALLOC_AND_FREE);
88
89   array = g_chunk_new (GRealArray, array_mem_chunk);
90   G_UNLOCK (array_mem_chunk);
91
92   array->data            = NULL;
93   array->len             = 0;
94   array->alloc           = 0;
95   array->zero_terminated = (zero_terminated ? 1 : 0);
96   array->clear           = (clear ? 1 : 0);
97   array->elt_size        = elt_size;
98
99   if (array->zero_terminated || reserved_size != 0)
100     {
101       g_array_maybe_expand (array, reserved_size);
102       g_array_zero_terminate(array);
103     }
104
105   return (GArray*) array;
106 }
107
108 gchar*
109 g_array_free (GArray  *array,
110               gboolean free_segment)
111 {
112   gchar* segment;
113
114   g_return_val_if_fail (array, NULL);
115
116   if (free_segment)
117     {
118       g_free (array->data);
119       segment = NULL;
120     }
121   else
122     segment = array->data;
123
124   G_LOCK (array_mem_chunk);
125   g_mem_chunk_free (array_mem_chunk, array);
126   G_UNLOCK (array_mem_chunk);
127
128   return segment;
129 }
130
131 GArray*
132 g_array_append_vals (GArray       *farray,
133                      gconstpointer data,
134                      guint         len)
135 {
136   GRealArray *array = (GRealArray*) farray;
137
138   g_array_maybe_expand (array, len);
139
140   memcpy (g_array_elt_pos (array, array->len), data, 
141           g_array_elt_len (array, len));
142
143   array->len += len;
144
145   g_array_zero_terminate (array);
146
147   return farray;
148 }
149
150 GArray*
151 g_array_prepend_vals (GArray        *farray,
152                       gconstpointer  data,
153                       guint          len)
154 {
155   GRealArray *array = (GRealArray*) farray;
156
157   g_array_maybe_expand (array, len);
158
159   g_memmove (g_array_elt_pos (array, len), g_array_elt_pos (array, 0), 
160              g_array_elt_len (array, array->len));
161
162   memcpy (g_array_elt_pos (array, 0), data, g_array_elt_len (array, len));
163
164   array->len += len;
165
166   g_array_zero_terminate (array);
167
168   return farray;
169 }
170
171 GArray*
172 g_array_insert_vals (GArray        *farray,
173                      guint          index,
174                      gconstpointer  data,
175                      guint          len)
176 {
177   GRealArray *array = (GRealArray*) farray;
178
179   g_array_maybe_expand (array, len);
180
181   g_memmove (g_array_elt_pos (array, len + index), 
182              g_array_elt_pos (array, index), 
183              g_array_elt_len (array, array->len - index));
184
185   memcpy (g_array_elt_pos (array, index), data, g_array_elt_len (array, len));
186
187   array->len += len;
188
189   g_array_zero_terminate (array);
190
191   return farray;
192 }
193
194 GArray*
195 g_array_set_size (GArray *farray,
196                   guint   length)
197 {
198   GRealArray *array = (GRealArray*) farray;
199   if (length > array->len)
200     {
201       g_array_maybe_expand (array, length - array->len);
202       
203       if (array->clear)
204         g_array_elt_zero (array, array->len, length - array->len);
205     }
206 #ifdef ENABLE_GC_FRIENDLY  
207   else if (length < array->len)
208     g_array_elt_zero (array, length, array->len - length);
209 #endif /* ENABLE_GC_FRIENDLY */  
210   
211   array->len = length;
212   
213   g_array_zero_terminate (array);
214   
215   return farray;
216 }
217
218 GArray*
219 g_array_remove_index (GArray* farray,
220                       guint index)
221 {
222   GRealArray* array = (GRealArray*) farray;
223
224   g_return_val_if_fail (array, NULL);
225
226   g_return_val_if_fail (index < array->len, NULL);
227
228   if (index != array->len - 1)
229     g_memmove (g_array_elt_pos (array, index),
230                g_array_elt_pos (array, index + 1),
231                g_array_elt_len (array, array->len - index - 1));
232   
233   array->len -= 1;
234
235 #ifdef ENABLE_GC_FRIENDLY
236   g_array_elt_zero (array, array->len, 1);
237 #else /* !ENABLE_GC_FRIENDLY */
238   g_array_zero_terminate (array);
239 #endif /* ENABLE_GC_FRIENDLY */  
240
241   return farray;
242 }
243
244 GArray*
245 g_array_remove_index_fast (GArray* farray,
246                            guint   index)
247 {
248   GRealArray* array = (GRealArray*) farray;
249
250   g_return_val_if_fail (array, NULL);
251
252   g_return_val_if_fail (index < array->len, NULL);
253
254   if (index != array->len - 1)
255     memcpy (g_array_elt_pos (array, index), 
256             g_array_elt_pos (array, array->len - 1),
257             g_array_elt_len (array, 1));
258   
259   array->len -= 1;
260
261 #ifdef ENABLE_GC_FRIENDLY
262   g_array_elt_zero (array, array->len, 1);
263 #else /* !ENABLE_GC_FRIENDLY */
264   g_array_zero_terminate (array);
265 #endif /* ENABLE_GC_FRIENDLY */  
266
267   return farray;
268 }
269
270 void
271 g_array_sort (GArray       *farray,
272               GCompareFunc  compare_func)
273 {
274   GRealArray *array = (GRealArray*) farray;
275
276   g_return_if_fail (array != NULL);
277
278   qsort (array->data,
279          array->len,
280          array->elt_size,
281          compare_func);
282 }
283
284 void
285 g_array_sort_with_data (GArray           *farray,
286                         GCompareDataFunc  compare_func,
287                         gpointer          user_data)
288 {
289   GRealArray *array = (GRealArray*) farray;
290
291   g_return_if_fail (array != 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   guint 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   guint 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
570   qsort (array->pdata,
571          array->len,
572          sizeof (gpointer),
573          compare_func);
574 }
575
576 void
577 g_ptr_array_sort_with_data (GPtrArray        *array,
578                             GCompareDataFunc  compare_func,
579                             gpointer          user_data)
580 {
581   g_return_if_fail (array != NULL);
582
583   g_qsort_with_data (array->pdata,
584                      array->len,
585                      sizeof (gpointer),
586                      compare_func,
587                      user_data);
588 }
589
590 /* Byte arrays 
591  */
592
593 GByteArray* g_byte_array_new      (void)
594 {
595   return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, 0);
596 }
597
598 GByteArray* g_byte_array_sized_new (guint reserved_size)
599 {
600   return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, reserved_size);
601 }
602
603 guint8*     g_byte_array_free     (GByteArray *array,
604                                    gboolean    free_segment)
605 {
606   return (guint8*) g_array_free ((GArray*) array, free_segment);
607 }
608
609 GByteArray* g_byte_array_append   (GByteArray *array,
610                                    const guint8 *data,
611                                    guint       len)
612 {
613   g_array_append_vals ((GArray*) array, (guint8*)data, len);
614
615   return array;
616 }
617
618 GByteArray* g_byte_array_prepend  (GByteArray *array,
619                                    const guint8 *data,
620                                    guint       len)
621 {
622   g_array_prepend_vals ((GArray*) array, (guint8*)data, len);
623
624   return array;
625 }
626
627 GByteArray* g_byte_array_set_size (GByteArray *array,
628                                    guint       length)
629 {
630   g_array_set_size ((GArray*) array, length);
631
632   return array;
633 }
634
635 GByteArray* g_byte_array_remove_index (GByteArray *array,
636                                        guint index)
637 {
638   g_array_remove_index((GArray*) array, index);
639
640   return array;
641 }
642
643 GByteArray* g_byte_array_remove_index_fast (GByteArray *array,
644                                             guint index)
645 {
646   g_array_remove_index_fast((GArray*) array, index);
647
648   return array;
649 }
650
651 void
652 g_byte_array_sort (GByteArray   *array,
653                    GCompareFunc  compare_func)
654 {
655   g_array_sort ((GArray *) array, compare_func);
656 }
657
658 void
659 g_byte_array_sort_with_data (GByteArray       *array,
660                              GCompareDataFunc  compare_func,
661                              gpointer          user_data)
662 {
663   g_array_sort_with_data ((GArray *) array, compare_func, user_data);
664 }