applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[platform/upstream/glib.git] / garray.c
index 4d814a4..13dac56 100644 (file)
--- a/garray.c
+++ b/garray.c
@@ -2,27 +2,38 @@
  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/*
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+/* 
+ * MT safe
+ */
+
 #include <string.h>
 #include "glib.h"
 
 
 #define MIN_ARRAY_SIZE  16
 
-
 typedef struct _GRealArray  GRealArray;
 
 struct _GRealArray
@@ -30,88 +41,217 @@ struct _GRealArray
   guint8 *data;
   guint   len;
   guint   alloc;
-  guint   zero_terminated;
+  guint   elt_size;
+  guint   zero_terminated : 1;
+  guint   clear : 1;
 };
 
+#define g_array_elt_len(array,i) ((array)->elt_size * (i))
+#define g_array_elt_pos(array,i) ((array)->data + g_array_elt_len((array),(i)))
+#define g_array_elt_zero(array, pos, len)                              \
+  (memset (g_array_elt_pos ((array), pos), 0,  g_array_elt_len ((array), len)))
+#define g_array_zero_terminate(array) G_STMT_START{                    \
+  if ((array)->zero_terminated)                                                \
+    g_array_elt_zero ((array), (array)->len, 1);                       \
+}G_STMT_END
 
 static gint g_nearest_pow        (gint        num);
 static void g_array_maybe_expand (GRealArray *array,
                                  gint        len);
 
-
 static GMemChunk *array_mem_chunk = NULL;
-
+G_LOCK_DEFINE_STATIC (array_mem_chunk);
 
 GArray*
-g_array_new (gint zero_terminated)
+g_array_new (gboolean zero_terminated,
+            gboolean clear,
+            guint    elt_size)
+{
+  return (GArray*) g_array_sized_new (zero_terminated, clear, elt_size, 0);
+}
+
+GArray* g_array_sized_new (gboolean zero_terminated,
+                          gboolean clear,
+                          guint    elt_size,
+                          guint    reserved_size)
 {
   GRealArray *array;
 
+  G_LOCK (array_mem_chunk);
   if (!array_mem_chunk)
     array_mem_chunk = g_mem_chunk_new ("array mem chunk",
                                       sizeof (GRealArray),
                                       1024, G_ALLOC_AND_FREE);
 
   array = g_chunk_new (GRealArray, array_mem_chunk);
+  G_UNLOCK (array_mem_chunk);
 
-  array->data = NULL;
-  array->len = 0;
-  array->alloc = 0;
+  array->data            = NULL;
+  array->len             = 0;
+  array->alloc           = 0;
   array->zero_terminated = (zero_terminated ? 1 : 0);
+  array->clear           = (clear ? 1 : 0);
+  array->elt_size        = elt_size;
+
+  if (array->zero_terminated || reserved_size != 0)
+    {
+      g_array_maybe_expand (array, reserved_size);
+      g_array_zero_terminate(array);
+    }
 
   return (GArray*) array;
 }
 
 void
-g_array_free (GArray *array,
-             gint    free_segment)
+g_array_free (GArray  *array,
+             gboolean free_segment)
 {
   if (free_segment)
     g_free (array->data);
 
+  G_LOCK (array_mem_chunk);
   g_mem_chunk_free (array_mem_chunk, array);
+  G_UNLOCK (array_mem_chunk);
 }
 
 GArray*
-g_rarray_append (GArray   *array,
-                gpointer  data,
-                gint      size)
+g_array_append_vals (GArray       *farray,
+                    gconstpointer data,
+                    guint         len)
 {
-  g_array_maybe_expand ((GRealArray*) array, size);
+  GRealArray *array = (GRealArray*) farray;
 
-  memcpy (array->data + array->len, data, size);
+  g_array_maybe_expand (array, len);
 
-  array->len += size;
+  memcpy (g_array_elt_pos (array, array->len), data, 
+         g_array_elt_len (array, len));
 
-  return array;
+  array->len += len;
+
+  g_array_zero_terminate (array);
+
+  return farray;
 }
 
 GArray*
-g_rarray_prepend (GArray   *array,
-                 gpointer  data,
-                 gint      size)
+g_array_prepend_vals (GArray        *farray,
+                     gconstpointer  data,
+                     guint          len)
 {
-  g_array_maybe_expand ((GRealArray*) array, size);
+  GRealArray *array = (GRealArray*) farray;
 
-  g_memmove (array->data + size, array->data, array->len);
-  memcpy (array->data, data, size);
+  g_array_maybe_expand (array, len);
 
-  array->len += size;
+  g_memmove (g_array_elt_pos (array, len), g_array_elt_pos (array, 0), 
+            g_array_elt_len (array, array->len));
 
-  return array;
+  memcpy (g_array_elt_pos (array, 0), data, g_array_elt_len (array, len));
+
+  array->len += len;
+
+  g_array_zero_terminate (array);
+
+  return farray;
 }
 
 GArray*
-g_rarray_truncate (GArray *array,
-                  gint    length,
-                  gint    size)
+g_array_insert_vals (GArray        *farray,
+                    guint          index,
+                    gconstpointer  data,
+                    guint          len)
 {
-  if (array->data)
-    memset (array->data + length * size, 0, size);
-  array->len = length * size;
-  return array;
+  GRealArray *array = (GRealArray*) farray;
+
+  g_array_maybe_expand (array, len);
+
+  g_memmove (g_array_elt_pos (array, len + index), 
+            g_array_elt_pos (array, index), 
+            g_array_elt_len (array, array->len - index));
+
+  memcpy (g_array_elt_pos (array, index), data, g_array_elt_len (array, len));
+
+  array->len += len;
+
+  g_array_zero_terminate (array);
+
+  return farray;
+}
+
+GArray*
+g_array_set_size (GArray *farray,
+                 guint   length)
+{
+  GRealArray *array = (GRealArray*) farray;
+  if (length > array->len)
+    {
+      g_array_maybe_expand (array, length - array->len);
+      
+      if (array->clear)
+       g_array_elt_zero (array, array->len, length - array->len);
+    }
+#ifdef ENABLE_GC_FRIENDLY  
+  else if (length < array->len)
+    g_array_elt_zero (array, length, array->len - length);
+#endif /* ENABLE_GC_FRIENDLY */  
+  
+  array->len = length;
+  
+  g_array_zero_terminate (array);
+  
+  return farray;
 }
 
+GArray*
+g_array_remove_index (GArray* farray,
+                     guint index)
+{
+  GRealArray* array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_return_val_if_fail (index < array->len, NULL);
+
+  if (index != array->len - 1)
+    g_memmove (g_array_elt_pos (array, index),
+              g_array_elt_pos (array, index + 1),
+              g_array_elt_len (array, array->len - index - 1));
+  
+  array->len -= 1;
+
+#ifdef ENABLE_GC_FRIENDLY
+  g_array_elt_zero (array, array->len, 1);
+#else /* !ENABLE_GC_FRIENDLY */
+  g_array_zero_terminate (array);
+#endif /* ENABLE_GC_FRIENDLY */  
+
+  return farray;
+}
+
+GArray*
+g_array_remove_index_fast (GArray* farray,
+                          guint   index)
+{
+  GRealArray* array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_return_val_if_fail (index < array->len, NULL);
+
+  if (index != array->len - 1)
+    g_memmove (g_array_elt_pos (array, index), 
+              g_array_elt_pos (array, array->len - 1),
+              g_array_elt_len (array, 1));
+  
+  array->len -= 1;
+
+#ifdef ENABLE_GC_FRIENDLY
+  g_array_elt_zero (array, array->len, 1);
+#else /* !ENABLE_GC_FRIENDLY */
+  g_array_zero_terminate (array);
+#endif /* ENABLE_GC_FRIENDLY */  
+
+  return farray;
+}
 
 static gint
 g_nearest_pow (gint num)
@@ -128,16 +268,302 @@ static void
 g_array_maybe_expand (GRealArray *array,
                      gint        len)
 {
-  guint old_alloc;
+  guint want_alloc = g_array_elt_len (array, array->len + len + 
+                                     array->zero_terminated);
 
-  if ((array->len + len) > array->alloc)
+  if (want_alloc > array->alloc)
     {
-      old_alloc = array->alloc;
+      want_alloc = g_nearest_pow (want_alloc);
+      want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE);
+
+      array->data = g_realloc (array->data, want_alloc);
+
+#ifdef ENABLE_GC_FRIENDLY
+      memset (array->data + array->alloc, 0, want_alloc - array->alloc);
+#endif /* ENABLE_GC_FRIENDLY */
+
+      array->alloc = want_alloc;
+    }
+}
+
+/* Pointer Array
+ */
+
+typedef struct _GRealPtrArray  GRealPtrArray;
+
+struct _GRealPtrArray
+{
+  gpointer *pdata;
+  guint     len;
+  guint     alloc;
+};
+
+static void g_ptr_array_maybe_expand (GRealPtrArray *array,
+                                     gint           len);
+
+static GMemChunk *ptr_array_mem_chunk = NULL;
+G_LOCK_DEFINE_STATIC (ptr_array_mem_chunk);
 
-      array->alloc = g_nearest_pow (array->len + array->zero_terminated + len);
+
+GPtrArray*
+g_ptr_array_new (void)
+{
+  return g_ptr_array_sized_new (0);
+}
+
+GPtrArray*  
+g_ptr_array_sized_new (guint reserved_size)
+{
+  GRealPtrArray *array;
+
+  G_LOCK (ptr_array_mem_chunk);
+  if (!ptr_array_mem_chunk)
+    ptr_array_mem_chunk = g_mem_chunk_new ("array mem chunk",
+                                          sizeof (GRealPtrArray),
+                                          1024, G_ALLOC_AND_FREE);
+
+  array = g_chunk_new (GRealPtrArray, ptr_array_mem_chunk);
+  G_UNLOCK (ptr_array_mem_chunk);
+
+  array->pdata = NULL;
+  array->len = 0;
+  array->alloc = 0;
+
+  if (reserved_size != 0)
+    g_ptr_array_maybe_expand (array, reserved_size);
+
+  return (GPtrArray*) array;  
+}
+
+void
+g_ptr_array_free (GPtrArray   *array,
+                 gboolean  free_segment)
+{
+  g_return_if_fail (array);
+
+  if (free_segment)
+    g_free (array->pdata);
+
+  G_LOCK (ptr_array_mem_chunk);
+  g_mem_chunk_free (ptr_array_mem_chunk, array);
+  G_UNLOCK (ptr_array_mem_chunk);
+}
+
+static void
+g_ptr_array_maybe_expand (GRealPtrArray *array,
+                         gint        len)
+{
+  if ((array->len + len) > array->alloc)
+    {
+#ifdef ENABLE_GC_FRIENDLY
+      guint old_alloc = array->alloc;
+#endif /* ENABLE_GC_FRIENDLY */
+      array->alloc = g_nearest_pow (array->len + len);
       array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
-      array->data = g_realloc (array->data, array->alloc);
+      array->pdata = g_realloc (array->pdata, sizeof(gpointer) * array->alloc);
+#ifdef ENABLE_GC_FRIENDLY
+      for ( ; old_alloc < array->alloc; old_alloc++)
+       array->pdata [old_alloc] = NULL;
+#endif /* ENABLE_GC_FRIENDLY */
+    }
+}
+
+void
+g_ptr_array_set_size  (GPtrArray   *farray,
+                      gint          length)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+
+  g_return_if_fail (array);
 
-      memset (array->data + old_alloc, 0, array->alloc - old_alloc);
+  if (length > array->len)
+    {
+      int i;
+      g_ptr_array_maybe_expand (array, (length - array->len));
+      /* This is not 
+       *     memset (array->pdata + array->len, 0,
+       *            sizeof (gpointer) * (length - array->len));
+       * to make it really portable. Remember (void*)NULL needn't be
+       * bitwise zero. It of course is silly not to use memset (..,0,..).
+       */
+      for (i = array->len; i < length; i++)
+       array->pdata[i] = NULL;
+    }
+#ifdef ENABLE_GC_FRIENDLY  
+  else if (length < array->len)
+    {
+      int i;
+      for (i = length; i < array->len; i++)
+       array->pdata[i] = NULL;
+    }
+#endif /* ENABLE_GC_FRIENDLY */  
+
+  array->len = length;
+}
+
+gpointer
+g_ptr_array_remove_index (GPtrArray* farray,
+                         guint      index)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  gpointer result;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_return_val_if_fail (index < array->len, NULL);
+
+  result = array->pdata[index];
+  
+  if (index != array->len - 1)
+    g_memmove (array->pdata + index, array->pdata + index + 1, 
+              sizeof (gpointer) * (array->len - index - 1));
+  
+  array->len -= 1;
+
+#ifdef ENABLE_GC_FRIENDLY  
+  array->pdata[array->len] = NULL;
+#endif /* ENABLE_GC_FRIENDLY */  
+
+  return result;
+}
+
+gpointer
+g_ptr_array_remove_index_fast (GPtrArray* farray,
+                              guint      index)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  gpointer result;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_return_val_if_fail (index < array->len, NULL);
+
+  result = array->pdata[index];
+  
+  if (index != array->len - 1)
+    array->pdata[index] = array->pdata[array->len - 1];
+
+  array->len -= 1;
+
+#ifdef ENABLE_GC_FRIENDLY  
+  array->pdata[array->len] = NULL;
+#endif /* ENABLE_GC_FRIENDLY */  
+
+  return result;
+}
+
+gboolean
+g_ptr_array_remove (GPtrArray* farray,
+                   gpointer data)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  int i;
+
+  g_return_val_if_fail (array, FALSE);
+
+  for (i = 0; i < array->len; i += 1)
+    {
+      if (array->pdata[i] == data)
+       {
+         g_ptr_array_remove_index (farray, i);
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
+
+gboolean
+g_ptr_array_remove_fast (GPtrArray* farray,
+                        gpointer data)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  int i;
+
+  g_return_val_if_fail (array, FALSE);
+
+  for (i = 0; i < array->len; i += 1)
+    {
+      if (array->pdata[i] == data)
+       {
+         g_ptr_array_remove_index_fast (farray, i);
+         return TRUE;
+       }
     }
+
+  return FALSE;
+}
+
+void
+g_ptr_array_add (GPtrArray* farray,
+                gpointer data)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+
+  g_return_if_fail (array);
+
+  g_ptr_array_maybe_expand (array, 1);
+
+  array->pdata[array->len++] = data;
+}
+
+/* Byte arrays 
+ */
+
+GByteArray* g_byte_array_new      (void)
+{
+  return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, 0);
+}
+
+GByteArray* g_byte_array_sized_new (guint reserved_size)
+{
+  return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, reserved_size);
+}
+
+void       g_byte_array_free     (GByteArray *array,
+                                  gboolean    free_segment)
+{
+  g_array_free ((GArray*) array, free_segment);
+}
+
+GByteArray* g_byte_array_append   (GByteArray *array,
+                                  const guint8 *data,
+                                  guint       len)
+{
+  g_array_append_vals ((GArray*) array, (guint8*)data, len);
+
+  return array;
+}
+
+GByteArray* g_byte_array_prepend  (GByteArray *array,
+                                  const guint8 *data,
+                                  guint       len)
+{
+  g_array_prepend_vals ((GArray*) array, (guint8*)data, len);
+
+  return array;
+}
+
+GByteArray* g_byte_array_set_size (GByteArray *array,
+                                  guint       length)
+{
+  g_array_set_size ((GArray*) array, length);
+
+  return array;
+}
+
+GByteArray* g_byte_array_remove_index (GByteArray *array,
+                                      guint index)
+{
+  g_array_remove_index((GArray*) array, index);
+
+  return array;
+}
+
+GByteArray* g_byte_array_remove_index_fast (GByteArray *array,
+                                                  guint index)
+{
+  g_array_remove_index_fast((GArray*) array, index);
+
+  return array;
 }