source: trunk/third/glib2/glib/garray.c @ 20721

Revision 20721, 16.5 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20720, which included commits to RCS files with non-trunk default branches.
Line 
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
40typedef struct _GRealArray  GRealArray;
41
42struct _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
61static gint g_nearest_pow        (gint        num) G_GNUC_CONST;
62static void g_array_maybe_expand (GRealArray *array,
63                                  gint        len);
64
65static GMemChunk *array_mem_chunk = NULL;
66G_LOCK_DEFINE_STATIC (array_mem_chunk);
67
68GArray*
69g_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
76GArray* 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
108gchar*
109g_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
131GArray*
132g_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
150GArray*
151g_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
171GArray*
172g_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
194GArray*
195g_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
218GArray*
219g_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
244GArray*
245g_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
270GArray*
271g_array_remove_range (GArray       *farray,
272                      guint         index_,
273                      guint         length)
274{
275  GRealArray *array = (GRealArray*) farray;
276
277  g_return_val_if_fail (array, NULL);
278  g_return_val_if_fail (index_ < array->len, NULL);
279  g_return_val_if_fail (index_ + length <= array->len, NULL);
280
281  if (index_ + length != array->len)
282    g_memmove (g_array_elt_pos (array, index_),
283               g_array_elt_pos (array, index_ + length),
284               (array->len - (index_ + length)) * array->elt_size);
285
286  array->len -= length;
287#ifdef ENABLE_GC_FRIENDLY
288  g_array_elt_zero (array, array->len, length);
289#else /* !ENABLE_GC_FRIENDLY */
290  g_array_zero_terminate (array);
291#endif /* ENABLE_GC_FRIENDLY */
292
293  return farray;
294}
295
296void
297g_array_sort (GArray       *farray,
298              GCompareFunc  compare_func)
299{
300  GRealArray *array = (GRealArray*) farray;
301
302  g_return_if_fail (array != NULL);
303
304  qsort (array->data,
305         array->len,
306         array->elt_size,
307         compare_func);
308}
309
310void
311g_array_sort_with_data (GArray           *farray,
312                        GCompareDataFunc  compare_func,
313                        gpointer          user_data)
314{
315  GRealArray *array = (GRealArray*) farray;
316
317  g_return_if_fail (array != NULL);
318
319  g_qsort_with_data (array->data,
320                     array->len,
321                     array->elt_size,
322                     compare_func,
323                     user_data);
324}
325
326
327static gint
328g_nearest_pow (gint num)
329{
330  gint n = 1;
331
332  while (n < num)
333    n <<= 1;
334
335  return n;
336}
337
338static void
339g_array_maybe_expand (GRealArray *array,
340                      gint        len)
341{
342  guint want_alloc = g_array_elt_len (array, array->len + len +
343                                      array->zero_terminated);
344
345  if (want_alloc > array->alloc)
346    {
347      want_alloc = g_nearest_pow (want_alloc);
348      want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE);
349
350      array->data = g_realloc (array->data, want_alloc);
351
352#ifdef ENABLE_GC_FRIENDLY
353      memset (array->data + array->alloc, 0, want_alloc - array->alloc);
354#endif /* ENABLE_GC_FRIENDLY */
355
356      array->alloc = want_alloc;
357    }
358}
359
360/* Pointer Array
361 */
362
363typedef struct _GRealPtrArray  GRealPtrArray;
364
365struct _GRealPtrArray
366{
367  gpointer *pdata;
368  guint     len;
369  guint     alloc;
370};
371
372static void g_ptr_array_maybe_expand (GRealPtrArray *array,
373                                      gint           len);
374
375static GMemChunk *ptr_array_mem_chunk = NULL;
376G_LOCK_DEFINE_STATIC (ptr_array_mem_chunk);
377
378
379GPtrArray*
380g_ptr_array_new (void)
381{
382  return g_ptr_array_sized_new (0);
383}
384
385GPtrArray* 
386g_ptr_array_sized_new (guint reserved_size)
387{
388  GRealPtrArray *array;
389
390  G_LOCK (ptr_array_mem_chunk);
391  if (!ptr_array_mem_chunk)
392    ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk",
393                                           sizeof (GRealPtrArray),
394                                           1024, G_ALLOC_AND_FREE);
395
396  array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk);
397  G_UNLOCK (ptr_array_mem_chunk);
398
399  array->pdata = NULL;
400  array->len = 0;
401  array->alloc = 0;
402
403  if (reserved_size != 0)
404    g_ptr_array_maybe_expand (array, reserved_size);
405
406  return (GPtrArray*) array; 
407}
408
409gpointer*
410g_ptr_array_free (GPtrArray   *array,
411                  gboolean  free_segment)
412{
413  gpointer* segment;
414
415  g_return_val_if_fail (array, NULL);
416
417  if (free_segment)
418    {
419      g_free (array->pdata);
420      segment = NULL;
421    }
422  else
423    segment = array->pdata;
424
425  G_LOCK (ptr_array_mem_chunk);
426  g_mem_chunk_free (ptr_array_mem_chunk, array);
427  G_UNLOCK (ptr_array_mem_chunk);
428
429  return segment;
430}
431
432static void
433g_ptr_array_maybe_expand (GRealPtrArray *array,
434                          gint        len)
435{
436  if ((array->len + len) > array->alloc)
437    {
438#ifdef ENABLE_GC_FRIENDLY
439      guint old_alloc = array->alloc;
440#endif /* ENABLE_GC_FRIENDLY */
441      array->alloc = g_nearest_pow (array->len + len);
442      array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
443      array->pdata = g_realloc (array->pdata, sizeof (gpointer) * array->alloc);
444#ifdef ENABLE_GC_FRIENDLY
445      for ( ; old_alloc < array->alloc; old_alloc++)
446        array->pdata [old_alloc] = NULL;
447#endif /* ENABLE_GC_FRIENDLY */
448    }
449}
450
451void
452g_ptr_array_set_size  (GPtrArray   *farray,
453                       gint          length)
454{
455  GRealPtrArray* array = (GRealPtrArray*) farray;
456
457  g_return_if_fail (array);
458
459  if (length > array->len)
460    {
461      int i;
462      g_ptr_array_maybe_expand (array, (length - array->len));
463      /* This is not
464       *     memset (array->pdata + array->len, 0,
465       *            sizeof (gpointer) * (length - array->len));
466       * to make it really portable. Remember (void*)NULL needn't be
467       * bitwise zero. It of course is silly not to use memset (..,0,..).
468       */
469      for (i = array->len; i < length; i++)
470        array->pdata[i] = NULL;
471    }
472#ifdef ENABLE_GC_FRIENDLY 
473  else if (length < array->len)
474    {
475      int i;
476      for (i = length; i < array->len; i++)
477        array->pdata[i] = NULL;
478    }
479#endif /* ENABLE_GC_FRIENDLY */ 
480
481  array->len = length;
482}
483
484gpointer
485g_ptr_array_remove_index (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    g_memmove (array->pdata + index, array->pdata + index + 1,
499               sizeof (gpointer) * (array->len - index - 1));
500 
501  array->len -= 1;
502
503#ifdef ENABLE_GC_FRIENDLY 
504  array->pdata[array->len] = NULL;
505#endif /* ENABLE_GC_FRIENDLY */ 
506
507  return result;
508}
509
510gpointer
511g_ptr_array_remove_index_fast (GPtrArray* farray,
512                               guint      index)
513{
514  GRealPtrArray* array = (GRealPtrArray*) farray;
515  gpointer result;
516
517  g_return_val_if_fail (array, NULL);
518
519  g_return_val_if_fail (index < array->len, NULL);
520
521  result = array->pdata[index];
522 
523  if (index != array->len - 1)
524    array->pdata[index] = array->pdata[array->len - 1];
525
526  array->len -= 1;
527
528#ifdef ENABLE_GC_FRIENDLY 
529  array->pdata[array->len] = NULL;
530#endif /* ENABLE_GC_FRIENDLY */ 
531
532  return result;
533}
534
535void
536g_ptr_array_remove_range (GPtrArray* farray,
537                          guint      index_,
538                          guint      length)
539{
540  GRealPtrArray* array = (GRealPtrArray*) farray;
541
542  g_return_if_fail (array);
543  g_return_if_fail (index_ < array->len);
544  g_return_if_fail (index_ + length <= array->len);
545
546  if (index_ + length != array->len)
547    g_memmove (&array->pdata[index_],
548               &array->pdata[index_ + length],
549               (array->len - (index_ + length)) * sizeof (gpointer));
550
551  array->len -= length;
552#ifdef ENABLE_GC_FRIENDLY
553  {
554    guint i;
555    for (i = 0; i < length; i++)
556      array->pdata[array->len + i] = NULL;
557  }
558#endif /* ENABLE_GC_FRIENDLY */
559}
560
561gboolean
562g_ptr_array_remove (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 (farray, i);
575          return TRUE;
576        }
577    }
578
579  return FALSE;
580}
581
582gboolean
583g_ptr_array_remove_fast (GPtrArray* farray,
584                         gpointer data)
585{
586  GRealPtrArray* array = (GRealPtrArray*) farray;
587  guint i;
588
589  g_return_val_if_fail (array, FALSE);
590
591  for (i = 0; i < array->len; i += 1)
592    {
593      if (array->pdata[i] == data)
594        {
595          g_ptr_array_remove_index_fast (farray, i);
596          return TRUE;
597        }
598    }
599
600  return FALSE;
601}
602
603void
604g_ptr_array_add (GPtrArray* farray,
605                 gpointer data)
606{
607  GRealPtrArray* array = (GRealPtrArray*) farray;
608
609  g_return_if_fail (array);
610
611  g_ptr_array_maybe_expand (array, 1);
612
613  array->pdata[array->len++] = data;
614}
615
616void
617g_ptr_array_sort (GPtrArray    *array,
618                  GCompareFunc  compare_func)
619{
620  g_return_if_fail (array != NULL);
621
622  qsort (array->pdata,
623         array->len,
624         sizeof (gpointer),
625         compare_func);
626}
627
628void
629g_ptr_array_sort_with_data (GPtrArray        *array,
630                            GCompareDataFunc  compare_func,
631                            gpointer          user_data)
632{
633  g_return_if_fail (array != NULL);
634
635  g_qsort_with_data (array->pdata,
636                     array->len,
637                     sizeof (gpointer),
638                     compare_func,
639                     user_data);
640}
641
642/**
643 * g_ptr_array_foreach:
644 * @array: a #GPtrArray
645 * @func: the function to call for each array element
646 * @user_data: user data to pass to the function
647 *
648 * Calls a function for each element of a #GPtrArray.
649 *
650 * Since: 2.4
651 **/
652void
653g_ptr_array_foreach (GPtrArray *array,
654                     GFunc      func,
655                     gpointer   user_data)
656{
657  guint i;
658
659  g_return_if_fail (array);
660
661  for (i = 0; i < array->len; i++)
662    (*func) (array->pdata[i], user_data);
663}
664
665/* Byte arrays
666 */
667
668GByteArray* g_byte_array_new      (void)
669{
670  return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, 0);
671}
672
673GByteArray* g_byte_array_sized_new (guint reserved_size)
674{
675  return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, reserved_size);
676}
677
678guint8*     g_byte_array_free     (GByteArray *array,
679                                   gboolean    free_segment)
680{
681  return (guint8*) g_array_free ((GArray*) array, free_segment);
682}
683
684GByteArray* g_byte_array_append   (GByteArray *array,
685                                   const guint8 *data,
686                                   guint       len)
687{
688  g_array_append_vals ((GArray*) array, (guint8*)data, len);
689
690  return array;
691}
692
693GByteArray* g_byte_array_prepend  (GByteArray *array,
694                                   const guint8 *data,
695                                   guint       len)
696{
697  g_array_prepend_vals ((GArray*) array, (guint8*)data, len);
698
699  return array;
700}
701
702GByteArray* g_byte_array_set_size (GByteArray *array,
703                                   guint       length)
704{
705  g_array_set_size ((GArray*) array, length);
706
707  return array;
708}
709
710GByteArray* g_byte_array_remove_index (GByteArray *array,
711                                       guint index)
712{
713  g_array_remove_index((GArray*) array, index);
714
715  return array;
716}
717
718GByteArray* g_byte_array_remove_index_fast (GByteArray *array,
719                                            guint index)
720{
721  g_array_remove_index_fast((GArray*) array, index);
722
723  return array;
724}
725
726GByteArray*
727g_byte_array_remove_range (GByteArray *array,
728                           guint index_,
729                           guint length)
730{
731  g_return_val_if_fail (array, NULL);
732  g_return_val_if_fail (index_ < array->len, NULL);
733  g_return_val_if_fail (index_ + length <= array->len, NULL);
734
735  return (GByteArray *)g_array_remove_range ((GArray*) array, index_, length);
736}
737
738void
739g_byte_array_sort (GByteArray   *array,
740                   GCompareFunc  compare_func)
741{
742  g_array_sort ((GArray *) array, compare_func);
743}
744
745void
746g_byte_array_sort_with_data (GByteArray       *array,
747                             GCompareDataFunc  compare_func,
748                             gpointer          user_data)
749{
750  g_array_sort_with_data ((GArray *) array, compare_func, user_data);
751}
Note: See TracBrowser for help on using the repository browser.