[Changes from josh to sync with his glib stuff -Yosh]
authorJosh MacDonald <jmacd@icw.EECS.Berkeley.EDU>
Fri, 12 Jun 1998 09:38:32 +0000 (09:38 +0000)
committerManish Singh <yosh@src.gnome.org>
Fri, 12 Jun 1998 09:38:32 +0000 (09:38 +0000)
Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>

        * glib.h: add new hash and equal functions g_int_*.  complement
        g_direct_hash with g_direct_equal.

        * grel.c: new file, GRelations implement tuples of N-N mappings.
        A comment in glib.h briefly describes the interface.

        * ghash.c: new function, g_hash_table_size

        * glib.h: new typedefs, gsize, gssize, gtime.

        * garray.c: new functions implementing a simplified GArray.  This
        GPtrArray is an array of gpointers and has functions to add and
        remove elements, much like java.lang.Vector.

        * garray.c: new functions for the single-byte special case of
        GArray.  The functions g_byte_array* operate on arrays of bytes.
        Internally, a GArray is used.

        * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...

24 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
Makefile.am
garray.c
ghash.c
glib.h
glib/Makefile.am
glib/garray.c
glib/ghash.c
glib/glib.h
glib/grel.c [new file with mode: 0644]
glib/gstring.c
glib/gutils.c
grel.c [new file with mode: 0644]
gstring.c
gutils.c
testglib.c
tests/testglib.c

index 8100e46..6286236 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>
+
+       * glib.h: add new hash and equal functions g_int_*.  complement
+       g_direct_hash with g_direct_equal.
+
+       * grel.c: new file, GRelations implement tuples of N-N mappings.
+       A comment in glib.h briefly describes the interface.
+
+       * ghash.c: new function, g_hash_table_size
+
+       * glib.h: new typedefs, gsize, gssize, gtime.
+
+       * garray.c: new functions implementing a simplified GArray.  This
+       GPtrArray is an array of gpointers and has functions to add and
+       remove elements, much like java.lang.Vector.
+
+       * garray.c: new functions for the single-byte special case of
+       GArray.  The functions g_byte_array* operate on arrays of bytes.
+       Internally, a GArray is used.
+
+       * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...
+
 1998-06-11  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
        * gdataset.c: #include <string.h>
index 8100e46..6286236 100644 (file)
@@ -1,3 +1,25 @@
+Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>
+
+       * glib.h: add new hash and equal functions g_int_*.  complement
+       g_direct_hash with g_direct_equal.
+
+       * grel.c: new file, GRelations implement tuples of N-N mappings.
+       A comment in glib.h briefly describes the interface.
+
+       * ghash.c: new function, g_hash_table_size
+
+       * glib.h: new typedefs, gsize, gssize, gtime.
+
+       * garray.c: new functions implementing a simplified GArray.  This
+       GPtrArray is an array of gpointers and has functions to add and
+       remove elements, much like java.lang.Vector.
+
+       * garray.c: new functions for the single-byte special case of
+       GArray.  The functions g_byte_array* operate on arrays of bytes.
+       Internally, a GArray is used.
+
+       * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...
+
 1998-06-11  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
        * gdataset.c: #include <string.h>
index 8100e46..6286236 100644 (file)
@@ -1,3 +1,25 @@
+Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>
+
+       * glib.h: add new hash and equal functions g_int_*.  complement
+       g_direct_hash with g_direct_equal.
+
+       * grel.c: new file, GRelations implement tuples of N-N mappings.
+       A comment in glib.h briefly describes the interface.
+
+       * ghash.c: new function, g_hash_table_size
+
+       * glib.h: new typedefs, gsize, gssize, gtime.
+
+       * garray.c: new functions implementing a simplified GArray.  This
+       GPtrArray is an array of gpointers and has functions to add and
+       remove elements, much like java.lang.Vector.
+
+       * garray.c: new functions for the single-byte special case of
+       GArray.  The functions g_byte_array* operate on arrays of bytes.
+       Internally, a GArray is used.
+
+       * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...
+
 1998-06-11  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
        * gdataset.c: #include <string.h>
index 8100e46..6286236 100644 (file)
@@ -1,3 +1,25 @@
+Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>
+
+       * glib.h: add new hash and equal functions g_int_*.  complement
+       g_direct_hash with g_direct_equal.
+
+       * grel.c: new file, GRelations implement tuples of N-N mappings.
+       A comment in glib.h briefly describes the interface.
+
+       * ghash.c: new function, g_hash_table_size
+
+       * glib.h: new typedefs, gsize, gssize, gtime.
+
+       * garray.c: new functions implementing a simplified GArray.  This
+       GPtrArray is an array of gpointers and has functions to add and
+       remove elements, much like java.lang.Vector.
+
+       * garray.c: new functions for the single-byte special case of
+       GArray.  The functions g_byte_array* operate on arrays of bytes.
+       Internally, a GArray is used.
+
+       * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...
+
 1998-06-11  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
        * gdataset.c: #include <string.h>
index 8100e46..6286236 100644 (file)
@@ -1,3 +1,25 @@
+Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>
+
+       * glib.h: add new hash and equal functions g_int_*.  complement
+       g_direct_hash with g_direct_equal.
+
+       * grel.c: new file, GRelations implement tuples of N-N mappings.
+       A comment in glib.h briefly describes the interface.
+
+       * ghash.c: new function, g_hash_table_size
+
+       * glib.h: new typedefs, gsize, gssize, gtime.
+
+       * garray.c: new functions implementing a simplified GArray.  This
+       GPtrArray is an array of gpointers and has functions to add and
+       remove elements, much like java.lang.Vector.
+
+       * garray.c: new functions for the single-byte special case of
+       GArray.  The functions g_byte_array* operate on arrays of bytes.
+       Internally, a GArray is used.
+
+       * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...
+
 1998-06-11  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
        * gdataset.c: #include <string.h>
index 8100e46..6286236 100644 (file)
@@ -1,3 +1,25 @@
+Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>
+
+       * glib.h: add new hash and equal functions g_int_*.  complement
+       g_direct_hash with g_direct_equal.
+
+       * grel.c: new file, GRelations implement tuples of N-N mappings.
+       A comment in glib.h briefly describes the interface.
+
+       * ghash.c: new function, g_hash_table_size
+
+       * glib.h: new typedefs, gsize, gssize, gtime.
+
+       * garray.c: new functions implementing a simplified GArray.  This
+       GPtrArray is an array of gpointers and has functions to add and
+       remove elements, much like java.lang.Vector.
+
+       * garray.c: new functions for the single-byte special case of
+       GArray.  The functions g_byte_array* operate on arrays of bytes.
+       Internally, a GArray is used.
+
+       * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...
+
 1998-06-11  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
        * gdataset.c: #include <string.h>
index 8100e46..6286236 100644 (file)
@@ -1,3 +1,25 @@
+Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>
+
+       * glib.h: add new hash and equal functions g_int_*.  complement
+       g_direct_hash with g_direct_equal.
+
+       * grel.c: new file, GRelations implement tuples of N-N mappings.
+       A comment in glib.h briefly describes the interface.
+
+       * ghash.c: new function, g_hash_table_size
+
+       * glib.h: new typedefs, gsize, gssize, gtime.
+
+       * garray.c: new functions implementing a simplified GArray.  This
+       GPtrArray is an array of gpointers and has functions to add and
+       remove elements, much like java.lang.Vector.
+
+       * garray.c: new functions for the single-byte special case of
+       GArray.  The functions g_byte_array* operate on arrays of bytes.
+       Internally, a GArray is used.
+
+       * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...
+
 1998-06-11  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
        * gdataset.c: #include <string.h>
index 8100e46..6286236 100644 (file)
@@ -1,3 +1,25 @@
+Fri Jun 12 00:39:28 1998  Josh MacDonald  <jmacd@icw.EECS.Berkeley.EDU>
+
+       * glib.h: add new hash and equal functions g_int_*.  complement
+       g_direct_hash with g_direct_equal.
+
+       * grel.c: new file, GRelations implement tuples of N-N mappings.
+       A comment in glib.h briefly describes the interface.
+
+       * ghash.c: new function, g_hash_table_size
+
+       * glib.h: new typedefs, gsize, gssize, gtime.
+
+       * garray.c: new functions implementing a simplified GArray.  This
+       GPtrArray is an array of gpointers and has functions to add and
+       remove elements, much like java.lang.Vector.
+
+       * garray.c: new functions for the single-byte special case of
+       GArray.  The functions g_byte_array* operate on arrays of bytes.
+       Internally, a GArray is used.
+
+       * testglib.c: tests for g_ptr_array, g_byte_array, and g_relation...
+
 1998-06-11  Federico Mena Quintero  <federico@nuclecu.unam.mx>
 
        * gdataset.c: #include <string.h>
index 84f5635..d09d201 100644 (file)
@@ -23,6 +23,7 @@ libglib_1_1_la_SOURCES = \
                gslist.c        \
                gtimer.c        \
                gtree.c         \
+               grel.c          \
                gstring.c       \
                gscanner.c      \
                gutils.c
index 4d814a4..16c1063 100644 (file)
--- a/garray.c
+++ b/garray.c
@@ -141,3 +141,180 @@ g_array_maybe_expand (GRealArray *array,
       memset (array->data + old_alloc, 0, array->alloc - old_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;
+
+
+
+GPtrArray*
+g_ptr_array_new ()
+{
+  GRealPtrArray *array;
+
+  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);
+
+  array->pdata = NULL;
+  array->len = 0;
+  array->alloc = 0;
+
+  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_mem_chunk_free (ptr_array_mem_chunk, array);
+}
+
+static void
+g_ptr_array_maybe_expand (GRealPtrArray *array,
+                         gint        len)
+{
+  guint old_alloc;
+
+  if ((array->len + len) > array->alloc)
+    {
+      old_alloc = array->alloc;
+
+      array->alloc = g_nearest_pow (array->len + len);
+      array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
+      if (array->pdata)
+       array->pdata = g_realloc (array->pdata, sizeof(gpointer) * array->alloc);
+      else
+       array->pdata = g_new0 (gpointer, array->alloc);
+
+      memset (array->pdata + old_alloc, 0, array->alloc - old_alloc);
+    }
+}
+
+void
+g_ptr_array_set_size  (GPtrArray   *farray,
+                      gint          length)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+
+  g_return_if_fail (array);
+
+  if (length > array->len)
+    g_ptr_array_maybe_expand (array, (length - array->len));
+
+  array->len = length;
+}
+
+void
+g_ptr_array_remove_index (GPtrArray* farray,
+                         gint index)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+
+  g_return_if_fail (array);
+
+  g_return_if_fail (index >= array->len);
+
+  array->pdata[index] = array->pdata[array->len - 1];
+
+  array->pdata[array->len - 1] = NULL;
+
+  array->len -= 1;
+}
+
+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;
+}
+
+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_new (FALSE);
+}
+
+void       g_byte_array_free     (GByteArray *array,
+                                  gint        free_segment)
+{
+  g_array_free ((GArray*) array, free_segment);
+}
+
+GByteArray* g_byte_array_append   (GByteArray *array,
+                                  const guint8 *data,
+                                  guint       len)
+{
+  g_rarray_append ((GArray*) array, (guint8*)data, len);
+
+  return array;
+}
+
+GByteArray* g_byte_array_prepend  (GByteArray *array,
+                                  const guint8 *data,
+                                  guint       len)
+{
+  g_rarray_prepend ((GArray*) array, (guint8*)data, len);
+
+  return array;
+}
+
+GByteArray* g_byte_array_truncate (GByteArray *array,
+                                  gint        length)
+{
+  g_rarray_truncate ((GArray*) array, length, 1);
+
+  return array;
+}
diff --git a/ghash.c b/ghash.c
index ceee098..ee364c9 100644 (file)
--- a/ghash.c
+++ b/ghash.c
@@ -424,3 +424,11 @@ g_hash_nodes_destroy (GHashNode *hash_node)
       node_free_list = hash_node;
     }
 }
+
+/* Returns the number of elements contained in the hash table. */
+gint g_hash_table_size (GHashTable *hash_table)
+{
+  g_return_val_if_fail (hash_table, 0);
+
+  return ((GRealHashTable *) hash_table)->nnodes;
+}
diff --git a/glib.h b/glib.h
index 37d49e9..c3733d4 100644 (file)
--- a/glib.h
+++ b/glib.h
@@ -433,6 +433,10 @@ typedef unsigned long      guint32;
 /* This should never happen */
 #endif
 
+typedef gint32  gssize;
+typedef guint32 gsize;
+typedef gint32  gtime;
+
 
 typedef struct _GList          GList;
 typedef struct _GSList         GSList;
@@ -445,10 +449,14 @@ typedef struct _GListAllocator    GListAllocator;
 typedef struct _GStringChunk   GStringChunk;
 typedef struct _GString                GString;
 typedef struct _GArray         GArray;
+typedef struct _GPtrArray      GPtrArray;
+typedef struct _GByteArray     GByteArray;
 typedef struct _GDebugKey      GDebugKey;
 typedef struct _GScannerConfig GScannerConfig;
 typedef struct _GScanner       GScanner;
 typedef union  _GValue         GValue;
+typedef struct _GRelation      GRelation;
+typedef struct _GTuples        GTuples;
 
 
 typedef void           (*GFunc)                (gpointer  data,
@@ -501,6 +509,23 @@ struct _GArray
   guint len;
 };
 
+struct _GByteArray
+{
+  guint8 *data;
+  guint   len;
+};
+
+struct _GPtrArray
+{
+  gpointer *pdata;
+  guint     len;
+};
+
+struct _GTuples
+{
+  guint len;
+};
+
 struct _GDebugKey
 {
   gchar *key;
@@ -635,6 +660,7 @@ void            g_hash_table_thaw    (GHashTable     *hash_table);
 void       g_hash_table_foreach (GHashTable     *hash_table,
                                  GHFunc          func,
                                  gpointer        user_data);
+gint       g_hash_table_size    (GHashTable     *hash_table);
 
 
 /* Caches
@@ -891,17 +917,63 @@ GArray* g_rarray_truncate (GArray   *array,
                           gint      length,
                           gint      size);
 
+/* Resizable pointer array.  This interface is much less complicated
+ * than the above.  Add appends appends a pointer.  Remove fills any
+ * cleared spot and shortens the array.
+ */
+
+#define     g_ptr_array_index(array,index) (array->pdata)[index]
+
+GPtrArray*  g_ptr_array_new               (void);
+void               g_ptr_array_free               (GPtrArray   *array,
+                                           gboolean     free_seg);
+void        g_ptr_array_set_size           (GPtrArray   *array,
+                                           gint         length);
+void        g_ptr_array_remove_index       (GPtrArray   *array,
+                                           gint         index);
+gboolean    g_ptr_array_remove             (GPtrArray   *array,
+                                           gpointer     data);
+void        g_ptr_array_add                (GPtrArray   *array,
+                                           gpointer     data);
+
+/* Byte arrays, an array of guint8.  Implemented as a GArray,
+ * but type-safe.
+ */
+
+GByteArray* g_byte_array_new      (void);
+void       g_byte_array_free     (GByteArray *array,
+                                  gint        free_segment);
+
+GByteArray* g_byte_array_append   (GByteArray   *array,
+                                  const guint8 *data,
+                                  guint         len);
+
+GByteArray* g_byte_array_prepend  (GByteArray   *array,
+                                  const guint8 *data,
+                                  guint         len);
+
+GByteArray* g_byte_array_truncate (GByteArray *array,
+                                  gint        length);
+
+
 /* Hash Functions
  */
 gint  g_str_equal (gconstpointer   v,
                   gconstpointer   v2);
 guint g_str_hash  (gconstpointer v);
 
+gint  g_int_equal (gconstpointer v,
+                  gconstpointer v2);
+guint g_int_hash  (gconstpointer v);
+
 /* This "hash" function will just return the key's adress as an
  * unsigned integer. Useful for hashing on plain adresses or
  * simple integer values.
  */
-guint g_direct_hash (gconstpointer key);
+guint g_direct_hash  (gconstpointer v);
+gint  g_direct_equal (gconstpointer v,
+                     gconstpointer v2);
+
 
 
 /* Location Associated Data
@@ -1141,6 +1213,54 @@ GList*       g_completion_complete     (GCompletion* cmp,
                                         gchar** new_prefix);
 void         g_completion_free         (GCompletion* cmp);
 
+/* GRelation: Indexed Relations.  Imagine a really simple table in a
+ * database.  Relations are not ordered.  This data type is meant for
+ * maintaining a N-way mapping.
+ *
+ * g_relation_new() creates a relation with FIELDS fields
+ *
+ * g_relation_destroy() frees all resources
+ * g_tuples_destroy() frees the result of g_relation_select()
+ *
+ * g_relation_index() indexes relation FIELD with the provided
+ *   equality and hash functions.  this must be done before any
+ *   calls to insert are made.
+ *
+ * g_relation_insert() inserts a new tuple.  you are expected to
+ *   provide the right number of fields.
+ *
+ * g_relation_delete() deletes all relations with KEY in FIELD
+ * g_relation_select() returns ...
+ * g_relation_count() counts ...
+ */
+
+GRelation* g_relation_new     (gint         fields);
+void       g_relation_destroy (GRelation   *relation);
+void       g_relation_index   (GRelation   *relation,
+                              gint         field,
+                              GHashFunc    hash_func,
+                              GCompareFunc key_compare_func);
+void       g_relation_insert  (GRelation   *relation,
+                              ...);
+gint       g_relation_delete  (GRelation   *relation,
+                              gconstpointer  key,
+                              gint         field);
+GTuples*   g_relation_select  (GRelation   *relation,
+                              gconstpointer  key,
+                              gint         field);
+gint       g_relation_count   (GRelation   *relation,
+                              gconstpointer  key,
+                              gint         field);
+gboolean   g_relation_exists  (GRelation   *relation,
+                              ...);
+void       g_relation_print   (GRelation   *relation);
+
+void       g_tuples_destroy   (GTuples     *tuples);
+gpointer   g_tuples_index     (GTuples     *tuples,
+                              gint         index,
+                              gint         field);
+
+
 /* Glib version.
  */
 extern const guint glib_major_version;
index 84f5635..d09d201 100644 (file)
@@ -23,6 +23,7 @@ libglib_1_1_la_SOURCES = \
                gslist.c        \
                gtimer.c        \
                gtree.c         \
+               grel.c          \
                gstring.c       \
                gscanner.c      \
                gutils.c
index 4d814a4..16c1063 100644 (file)
@@ -141,3 +141,180 @@ g_array_maybe_expand (GRealArray *array,
       memset (array->data + old_alloc, 0, array->alloc - old_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;
+
+
+
+GPtrArray*
+g_ptr_array_new ()
+{
+  GRealPtrArray *array;
+
+  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);
+
+  array->pdata = NULL;
+  array->len = 0;
+  array->alloc = 0;
+
+  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_mem_chunk_free (ptr_array_mem_chunk, array);
+}
+
+static void
+g_ptr_array_maybe_expand (GRealPtrArray *array,
+                         gint        len)
+{
+  guint old_alloc;
+
+  if ((array->len + len) > array->alloc)
+    {
+      old_alloc = array->alloc;
+
+      array->alloc = g_nearest_pow (array->len + len);
+      array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
+      if (array->pdata)
+       array->pdata = g_realloc (array->pdata, sizeof(gpointer) * array->alloc);
+      else
+       array->pdata = g_new0 (gpointer, array->alloc);
+
+      memset (array->pdata + old_alloc, 0, array->alloc - old_alloc);
+    }
+}
+
+void
+g_ptr_array_set_size  (GPtrArray   *farray,
+                      gint          length)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+
+  g_return_if_fail (array);
+
+  if (length > array->len)
+    g_ptr_array_maybe_expand (array, (length - array->len));
+
+  array->len = length;
+}
+
+void
+g_ptr_array_remove_index (GPtrArray* farray,
+                         gint index)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+
+  g_return_if_fail (array);
+
+  g_return_if_fail (index >= array->len);
+
+  array->pdata[index] = array->pdata[array->len - 1];
+
+  array->pdata[array->len - 1] = NULL;
+
+  array->len -= 1;
+}
+
+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;
+}
+
+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_new (FALSE);
+}
+
+void       g_byte_array_free     (GByteArray *array,
+                                  gint        free_segment)
+{
+  g_array_free ((GArray*) array, free_segment);
+}
+
+GByteArray* g_byte_array_append   (GByteArray *array,
+                                  const guint8 *data,
+                                  guint       len)
+{
+  g_rarray_append ((GArray*) array, (guint8*)data, len);
+
+  return array;
+}
+
+GByteArray* g_byte_array_prepend  (GByteArray *array,
+                                  const guint8 *data,
+                                  guint       len)
+{
+  g_rarray_prepend ((GArray*) array, (guint8*)data, len);
+
+  return array;
+}
+
+GByteArray* g_byte_array_truncate (GByteArray *array,
+                                  gint        length)
+{
+  g_rarray_truncate ((GArray*) array, length, 1);
+
+  return array;
+}
index ceee098..ee364c9 100644 (file)
@@ -424,3 +424,11 @@ g_hash_nodes_destroy (GHashNode *hash_node)
       node_free_list = hash_node;
     }
 }
+
+/* Returns the number of elements contained in the hash table. */
+gint g_hash_table_size (GHashTable *hash_table)
+{
+  g_return_val_if_fail (hash_table, 0);
+
+  return ((GRealHashTable *) hash_table)->nnodes;
+}
index 37d49e9..c3733d4 100644 (file)
@@ -433,6 +433,10 @@ typedef unsigned long      guint32;
 /* This should never happen */
 #endif
 
+typedef gint32  gssize;
+typedef guint32 gsize;
+typedef gint32  gtime;
+
 
 typedef struct _GList          GList;
 typedef struct _GSList         GSList;
@@ -445,10 +449,14 @@ typedef struct _GListAllocator    GListAllocator;
 typedef struct _GStringChunk   GStringChunk;
 typedef struct _GString                GString;
 typedef struct _GArray         GArray;
+typedef struct _GPtrArray      GPtrArray;
+typedef struct _GByteArray     GByteArray;
 typedef struct _GDebugKey      GDebugKey;
 typedef struct _GScannerConfig GScannerConfig;
 typedef struct _GScanner       GScanner;
 typedef union  _GValue         GValue;
+typedef struct _GRelation      GRelation;
+typedef struct _GTuples        GTuples;
 
 
 typedef void           (*GFunc)                (gpointer  data,
@@ -501,6 +509,23 @@ struct _GArray
   guint len;
 };
 
+struct _GByteArray
+{
+  guint8 *data;
+  guint   len;
+};
+
+struct _GPtrArray
+{
+  gpointer *pdata;
+  guint     len;
+};
+
+struct _GTuples
+{
+  guint len;
+};
+
 struct _GDebugKey
 {
   gchar *key;
@@ -635,6 +660,7 @@ void            g_hash_table_thaw    (GHashTable     *hash_table);
 void       g_hash_table_foreach (GHashTable     *hash_table,
                                  GHFunc          func,
                                  gpointer        user_data);
+gint       g_hash_table_size    (GHashTable     *hash_table);
 
 
 /* Caches
@@ -891,17 +917,63 @@ GArray* g_rarray_truncate (GArray   *array,
                           gint      length,
                           gint      size);
 
+/* Resizable pointer array.  This interface is much less complicated
+ * than the above.  Add appends appends a pointer.  Remove fills any
+ * cleared spot and shortens the array.
+ */
+
+#define     g_ptr_array_index(array,index) (array->pdata)[index]
+
+GPtrArray*  g_ptr_array_new               (void);
+void               g_ptr_array_free               (GPtrArray   *array,
+                                           gboolean     free_seg);
+void        g_ptr_array_set_size           (GPtrArray   *array,
+                                           gint         length);
+void        g_ptr_array_remove_index       (GPtrArray   *array,
+                                           gint         index);
+gboolean    g_ptr_array_remove             (GPtrArray   *array,
+                                           gpointer     data);
+void        g_ptr_array_add                (GPtrArray   *array,
+                                           gpointer     data);
+
+/* Byte arrays, an array of guint8.  Implemented as a GArray,
+ * but type-safe.
+ */
+
+GByteArray* g_byte_array_new      (void);
+void       g_byte_array_free     (GByteArray *array,
+                                  gint        free_segment);
+
+GByteArray* g_byte_array_append   (GByteArray   *array,
+                                  const guint8 *data,
+                                  guint         len);
+
+GByteArray* g_byte_array_prepend  (GByteArray   *array,
+                                  const guint8 *data,
+                                  guint         len);
+
+GByteArray* g_byte_array_truncate (GByteArray *array,
+                                  gint        length);
+
+
 /* Hash Functions
  */
 gint  g_str_equal (gconstpointer   v,
                   gconstpointer   v2);
 guint g_str_hash  (gconstpointer v);
 
+gint  g_int_equal (gconstpointer v,
+                  gconstpointer v2);
+guint g_int_hash  (gconstpointer v);
+
 /* This "hash" function will just return the key's adress as an
  * unsigned integer. Useful for hashing on plain adresses or
  * simple integer values.
  */
-guint g_direct_hash (gconstpointer key);
+guint g_direct_hash  (gconstpointer v);
+gint  g_direct_equal (gconstpointer v,
+                     gconstpointer v2);
+
 
 
 /* Location Associated Data
@@ -1141,6 +1213,54 @@ GList*       g_completion_complete     (GCompletion* cmp,
                                         gchar** new_prefix);
 void         g_completion_free         (GCompletion* cmp);
 
+/* GRelation: Indexed Relations.  Imagine a really simple table in a
+ * database.  Relations are not ordered.  This data type is meant for
+ * maintaining a N-way mapping.
+ *
+ * g_relation_new() creates a relation with FIELDS fields
+ *
+ * g_relation_destroy() frees all resources
+ * g_tuples_destroy() frees the result of g_relation_select()
+ *
+ * g_relation_index() indexes relation FIELD with the provided
+ *   equality and hash functions.  this must be done before any
+ *   calls to insert are made.
+ *
+ * g_relation_insert() inserts a new tuple.  you are expected to
+ *   provide the right number of fields.
+ *
+ * g_relation_delete() deletes all relations with KEY in FIELD
+ * g_relation_select() returns ...
+ * g_relation_count() counts ...
+ */
+
+GRelation* g_relation_new     (gint         fields);
+void       g_relation_destroy (GRelation   *relation);
+void       g_relation_index   (GRelation   *relation,
+                              gint         field,
+                              GHashFunc    hash_func,
+                              GCompareFunc key_compare_func);
+void       g_relation_insert  (GRelation   *relation,
+                              ...);
+gint       g_relation_delete  (GRelation   *relation,
+                              gconstpointer  key,
+                              gint         field);
+GTuples*   g_relation_select  (GRelation   *relation,
+                              gconstpointer  key,
+                              gint         field);
+gint       g_relation_count   (GRelation   *relation,
+                              gconstpointer  key,
+                              gint         field);
+gboolean   g_relation_exists  (GRelation   *relation,
+                              ...);
+void       g_relation_print   (GRelation   *relation);
+
+void       g_tuples_destroy   (GTuples     *tuples);
+gpointer   g_tuples_index     (GTuples     *tuples,
+                              gint         index,
+                              gint         field);
+
+
 /* Glib version.
  */
 extern const guint glib_major_version;
diff --git a/glib/grel.c b/glib/grel.c
new file mode 100644 (file)
index 0000000..91d2b68
--- /dev/null
@@ -0,0 +1,428 @@
+/* GLIB - Library of useful routines for C programming
+ * 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
+ * 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.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "glib.h"
+#include <stdarg.h>
+
+typedef struct _GRealRelation      GRealRelation;
+typedef struct _GRealTuples        GRealTuples;
+
+struct _GRealRelation
+{
+  gint fields;
+  gint current_field;
+
+  GHashTable   *all_tuples;
+  GHashTable  **hashed_tuple_tables;
+  GMemChunk    *tuple_chunk;
+
+  gint count;
+};
+
+struct _GRealTuples
+{
+  gint      len;
+  gint      width;
+  gpointer *data;
+};
+
+gboolean
+tuple_equal_2 (gconstpointer v_a, gconstpointer v_b)
+{
+  gpointer* a = (gpointer*) v_a;
+  gpointer* b = (gpointer*) v_b;
+
+  return a[0] == b[0] && a[1] == b[1];
+}
+
+guint
+tuple_hash_2 (gconstpointer v_a)
+{
+  gpointer* a = (gpointer*) v_a;
+
+  return (gulong)a[0] ^ (gulong)a[1];
+}
+
+GHashFunc
+tuple_hash (gint fields)
+{
+  switch (fields)
+    {
+    case 2:
+      return tuple_hash_2;
+    default:
+      g_error ("no tuple hash for %d", fields);
+    }
+
+  return NULL;
+}
+
+GCompareFunc
+tuple_equal (gint fields)
+{
+  switch (fields)
+    {
+    case 2:
+      return tuple_equal_2;
+    default:
+      g_error ("no tuple equal for %d", fields);
+    }
+
+  return NULL;
+}
+
+GRelation*
+g_relation_new (gint fields)
+{
+  GRealRelation* rel = g_new0 (GRealRelation, 1);
+
+  rel->fields = fields;
+  rel->tuple_chunk = g_mem_chunk_new ("Relation Chunk",
+                                     fields * sizeof (gpointer),
+                                     fields * sizeof (gpointer) * 128,
+                                     G_ALLOC_AND_FREE);
+  rel->all_tuples = g_hash_table_new (tuple_hash (fields), tuple_equal (fields));
+  rel->hashed_tuple_tables = g_new0 (GHashTable*, fields);
+
+  return (GRelation*) rel;
+}
+
+static void
+g_relation_free_array (gpointer key, gpointer value, gpointer user_data)
+{
+  g_hash_table_destroy ((GHashTable*) value);
+}
+
+void
+g_relation_destroy (GRelation *relation)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  gint i;
+
+  if (rel)
+    {
+      g_hash_table_destroy (rel->all_tuples);
+      g_mem_chunk_destroy (rel->tuple_chunk);
+
+      for (i = 0; i < rel->fields; i += 1)
+       {
+         if (rel->hashed_tuple_tables[i])
+           {
+             g_hash_table_foreach (rel->hashed_tuple_tables[i], g_relation_free_array, NULL);
+             g_hash_table_destroy (rel->hashed_tuple_tables[i]);
+           }
+       }
+
+      g_free (rel->hashed_tuple_tables);
+      g_free (rel);
+    }
+}
+
+void
+g_relation_index (GRelation   *relation,
+                 gint         field,
+                 GHashFunc    hash_func,
+                 GCompareFunc key_compare_func)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+
+  g_assert (rel->count == 0 && rel->hashed_tuple_tables[field] == NULL);
+
+  rel->hashed_tuple_tables[field] = g_hash_table_new (hash_func, key_compare_func);
+}
+
+void
+g_relation_insert (GRelation   *relation,
+                  ...)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  gpointer* tuple = g_chunk_new (gpointer, rel->tuple_chunk);
+  va_list args;
+  gint i;
+
+  va_start(args, relation);
+
+  for (i = 0; i < rel->fields; i += 1)
+    tuple[i] = va_arg(args, gpointer);
+
+  va_end(args);
+
+  g_hash_table_insert (rel->all_tuples, tuple, tuple);
+
+  rel->count += 1;
+
+  for (i = 0; i < rel->fields; i += 1)
+    {
+      GHashTable *table;
+      gpointer    key;
+      GHashTable *per_key_table;
+
+      table = rel->hashed_tuple_tables[i];
+
+      if (table == NULL)
+       continue;
+
+      key = tuple[i];
+      per_key_table = g_hash_table_lookup (table, key);
+
+      if (per_key_table == NULL)
+       {
+         per_key_table = g_hash_table_new (tuple_hash (rel->fields), tuple_equal (rel->fields));
+         g_hash_table_insert (table, key, per_key_table);
+       }
+
+      g_hash_table_insert (per_key_table, tuple, tuple);
+    }
+}
+
+static void
+g_relation_delete_tuple (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
+{
+  gpointer      *tuple = (gpointer*) tuple_value;
+  GRealRelation *rel = (GRealRelation *) user_data;
+  gint           j;
+
+  g_assert (tuple_key == tuple_value);
+
+  for (j = 0; j < rel->fields; j += 1)
+    {
+      GHashTable *one_table = rel->hashed_tuple_tables[j];
+      gpointer    one_key;
+      GHashTable *per_key_table;
+
+      if (one_table == NULL)
+       continue;
+
+      if (j == rel->current_field)
+       /* can't delete from the table we're foreaching in */
+       continue;
+
+      one_key = tuple[j];
+
+      per_key_table = g_hash_table_lookup (one_table, one_key);
+
+      g_hash_table_remove (per_key_table, tuple);
+    }
+
+  g_hash_table_remove (rel->all_tuples, tuple);
+
+  rel->count -= 1;
+}
+
+gint
+g_relation_delete  (GRelation   *relation,
+                   gconstpointer  key,
+                   gint         field)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  GHashTable *table = rel->hashed_tuple_tables[field];
+  GHashTable *key_table;
+  gint        count = rel->count;
+
+  g_assert (table);
+
+  key_table = g_hash_table_lookup (table, key);
+
+  if (!key_table)
+    return 0;
+
+  rel->current_field = field;
+
+  g_hash_table_foreach (key_table, g_relation_delete_tuple, rel);
+
+  g_hash_table_remove (table, key);
+
+  g_hash_table_destroy (key_table);
+
+  /* @@@ Remove empty hash tables. */
+
+  return count - rel->count;
+}
+
+static void
+g_relation_select_tuple (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
+{
+  gpointer    *tuple = (gpointer*) tuple_value;
+  GRealTuples *tuples = (GRealTuples*) user_data;
+  gint stride = sizeof (gpointer) * tuples->width;
+
+  g_assert (tuple_key == tuple_value);
+
+  memcpy (tuples->data + (tuples->len * tuples->width),
+         tuple,
+         stride);
+
+  tuples->len += 1;
+}
+
+GTuples*
+g_relation_select (GRelation   *relation,
+                  gconstpointer  key,
+                  gint         field)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  GHashTable  *table = rel->hashed_tuple_tables[field];
+  GHashTable  *key_table;
+  GRealTuples *tuples = g_new0 (GRealTuples, 1);
+  gint count;
+
+  g_assert (table);
+
+  key_table = g_hash_table_lookup (table, key);
+
+  if (!key_table)
+    return (GTuples*)tuples;
+
+  count = g_relation_count (relation, key, field);
+
+  tuples->data = g_malloc (sizeof (gpointer) * rel->fields * count);
+  tuples->width = rel->fields;
+
+  g_hash_table_foreach (key_table, g_relation_select_tuple, tuples);
+
+  g_assert (count == tuples->len);
+
+  return (GTuples*)tuples;
+}
+
+gint
+g_relation_count (GRelation   *relation,
+                 gconstpointer  key,
+                 gint         field)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  GHashTable  *table = rel->hashed_tuple_tables[field];
+  GHashTable  *key_table;
+
+  g_assert (table);
+
+  key_table = g_hash_table_lookup (table, key);
+
+  if (!key_table)
+    return 0;
+
+  return g_hash_table_size (key_table);
+}
+
+gboolean
+g_relation_exists (GRelation   *relation, ...)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  gpointer* tuple = g_chunk_new (gpointer, rel->tuple_chunk);
+  va_list args;
+  gint i;
+  gboolean result;
+
+  va_start(args, relation);
+
+  for (i = 0; i < rel->fields; i += 1)
+    tuple[i] = va_arg(args, gpointer);
+
+  va_end(args);
+
+  result = g_hash_table_lookup (rel->all_tuples, tuple) != NULL;
+
+  g_mem_chunk_free (rel->tuple_chunk, tuple);
+
+  return result;
+}
+
+void
+g_tuples_destroy (GTuples *tuples0)
+{
+  GRealTuples *tuples = (GRealTuples*) tuples0;
+
+  if (tuples)
+    {
+      g_free (tuples->data);
+      g_free (tuples);
+    }
+}
+
+gpointer
+g_tuples_index (GTuples     *tuples0,
+               gint         index,
+               gint         field)
+{
+  GRealTuples *tuples = (GRealTuples*) tuples0;
+
+  g_assert (field < tuples->width);
+
+  return tuples->data[index * tuples->width + field];
+}
+
+/* Print
+ */
+
+void
+g_relation_print_one (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
+{
+  gint i;
+  GRealRelation* rel = (GRealRelation*) user_data;
+  gpointer* tuples = (gpointer*) tuple_value;
+
+  g_print ("[");
+
+  for (i = 0; i < rel->fields; i += 1)
+    {
+      g_print ("%p", tuples[i]);
+
+      if (i < (rel->fields - 1))
+       g_print (",");
+    }
+
+  g_print ("]\n");
+}
+
+void
+g_relation_print_index (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
+{
+  GRealRelation* rel = (GRealRelation*) user_data;
+  GHashTable* table = (GHashTable*) tuple_value;
+
+  g_print ("*** key %p\n", tuple_key);
+
+  g_hash_table_foreach (table,
+                       g_relation_print_one,
+                       rel);
+}
+
+void
+g_relation_print (GRelation *relation)
+{
+  gint i;
+  GRealRelation* rel = (GRealRelation*) relation;
+
+  g_print ("*** all tuples (%d)\n", rel->count);
+
+  g_hash_table_foreach (rel->all_tuples,
+                       g_relation_print_one,
+                       rel);
+
+  for (i = 0; i < rel->fields; i += 1)
+    {
+      if (rel->hashed_tuple_tables[i] == NULL)
+       continue;
+
+      g_print ("*** index %d\n", i);
+
+      g_hash_table_foreach (rel->hashed_tuple_tables[i],
+                           g_relation_print_index,
+                           rel);
+    }
+
+}
index 8350552..173a0b8 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
-#include <glib.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include "glib.h"
 
 
 typedef struct _GRealStringChunk GRealStringChunk;
index 8528163..c33efc4 100644 (file)
@@ -851,8 +851,25 @@ g_parse_debug_string  (const gchar *string,
 }
 
 guint
-g_direct_hash(gconstpointer key)
+g_direct_hash(gconstpointer v)
 {
-  return GPOINTER_TO_UINT (key);
+  return GPOINTER_TO_UINT (v);
 }
 
+gint
+g_direct_equal(gconstpointer v, gconstpointer v2)
+{
+  return GPOINTER_TO_UINT (v) == GPOINTER_TO_UINT (v2);
+}
+
+gint
+g_int_equal (gconstpointer v, gconstpointer v2)
+{
+  return *((const gint*) v) == *((const gint*) v2);
+}
+
+guint
+g_int_hash (gconstpointer v)
+{
+  return *(const gint*) v;
+}
diff --git a/grel.c b/grel.c
new file mode 100644 (file)
index 0000000..91d2b68
--- /dev/null
+++ b/grel.c
@@ -0,0 +1,428 @@
+/* GLIB - Library of useful routines for C programming
+ * 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
+ * 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.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "glib.h"
+#include <stdarg.h>
+
+typedef struct _GRealRelation      GRealRelation;
+typedef struct _GRealTuples        GRealTuples;
+
+struct _GRealRelation
+{
+  gint fields;
+  gint current_field;
+
+  GHashTable   *all_tuples;
+  GHashTable  **hashed_tuple_tables;
+  GMemChunk    *tuple_chunk;
+
+  gint count;
+};
+
+struct _GRealTuples
+{
+  gint      len;
+  gint      width;
+  gpointer *data;
+};
+
+gboolean
+tuple_equal_2 (gconstpointer v_a, gconstpointer v_b)
+{
+  gpointer* a = (gpointer*) v_a;
+  gpointer* b = (gpointer*) v_b;
+
+  return a[0] == b[0] && a[1] == b[1];
+}
+
+guint
+tuple_hash_2 (gconstpointer v_a)
+{
+  gpointer* a = (gpointer*) v_a;
+
+  return (gulong)a[0] ^ (gulong)a[1];
+}
+
+GHashFunc
+tuple_hash (gint fields)
+{
+  switch (fields)
+    {
+    case 2:
+      return tuple_hash_2;
+    default:
+      g_error ("no tuple hash for %d", fields);
+    }
+
+  return NULL;
+}
+
+GCompareFunc
+tuple_equal (gint fields)
+{
+  switch (fields)
+    {
+    case 2:
+      return tuple_equal_2;
+    default:
+      g_error ("no tuple equal for %d", fields);
+    }
+
+  return NULL;
+}
+
+GRelation*
+g_relation_new (gint fields)
+{
+  GRealRelation* rel = g_new0 (GRealRelation, 1);
+
+  rel->fields = fields;
+  rel->tuple_chunk = g_mem_chunk_new ("Relation Chunk",
+                                     fields * sizeof (gpointer),
+                                     fields * sizeof (gpointer) * 128,
+                                     G_ALLOC_AND_FREE);
+  rel->all_tuples = g_hash_table_new (tuple_hash (fields), tuple_equal (fields));
+  rel->hashed_tuple_tables = g_new0 (GHashTable*, fields);
+
+  return (GRelation*) rel;
+}
+
+static void
+g_relation_free_array (gpointer key, gpointer value, gpointer user_data)
+{
+  g_hash_table_destroy ((GHashTable*) value);
+}
+
+void
+g_relation_destroy (GRelation *relation)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  gint i;
+
+  if (rel)
+    {
+      g_hash_table_destroy (rel->all_tuples);
+      g_mem_chunk_destroy (rel->tuple_chunk);
+
+      for (i = 0; i < rel->fields; i += 1)
+       {
+         if (rel->hashed_tuple_tables[i])
+           {
+             g_hash_table_foreach (rel->hashed_tuple_tables[i], g_relation_free_array, NULL);
+             g_hash_table_destroy (rel->hashed_tuple_tables[i]);
+           }
+       }
+
+      g_free (rel->hashed_tuple_tables);
+      g_free (rel);
+    }
+}
+
+void
+g_relation_index (GRelation   *relation,
+                 gint         field,
+                 GHashFunc    hash_func,
+                 GCompareFunc key_compare_func)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+
+  g_assert (rel->count == 0 && rel->hashed_tuple_tables[field] == NULL);
+
+  rel->hashed_tuple_tables[field] = g_hash_table_new (hash_func, key_compare_func);
+}
+
+void
+g_relation_insert (GRelation   *relation,
+                  ...)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  gpointer* tuple = g_chunk_new (gpointer, rel->tuple_chunk);
+  va_list args;
+  gint i;
+
+  va_start(args, relation);
+
+  for (i = 0; i < rel->fields; i += 1)
+    tuple[i] = va_arg(args, gpointer);
+
+  va_end(args);
+
+  g_hash_table_insert (rel->all_tuples, tuple, tuple);
+
+  rel->count += 1;
+
+  for (i = 0; i < rel->fields; i += 1)
+    {
+      GHashTable *table;
+      gpointer    key;
+      GHashTable *per_key_table;
+
+      table = rel->hashed_tuple_tables[i];
+
+      if (table == NULL)
+       continue;
+
+      key = tuple[i];
+      per_key_table = g_hash_table_lookup (table, key);
+
+      if (per_key_table == NULL)
+       {
+         per_key_table = g_hash_table_new (tuple_hash (rel->fields), tuple_equal (rel->fields));
+         g_hash_table_insert (table, key, per_key_table);
+       }
+
+      g_hash_table_insert (per_key_table, tuple, tuple);
+    }
+}
+
+static void
+g_relation_delete_tuple (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
+{
+  gpointer      *tuple = (gpointer*) tuple_value;
+  GRealRelation *rel = (GRealRelation *) user_data;
+  gint           j;
+
+  g_assert (tuple_key == tuple_value);
+
+  for (j = 0; j < rel->fields; j += 1)
+    {
+      GHashTable *one_table = rel->hashed_tuple_tables[j];
+      gpointer    one_key;
+      GHashTable *per_key_table;
+
+      if (one_table == NULL)
+       continue;
+
+      if (j == rel->current_field)
+       /* can't delete from the table we're foreaching in */
+       continue;
+
+      one_key = tuple[j];
+
+      per_key_table = g_hash_table_lookup (one_table, one_key);
+
+      g_hash_table_remove (per_key_table, tuple);
+    }
+
+  g_hash_table_remove (rel->all_tuples, tuple);
+
+  rel->count -= 1;
+}
+
+gint
+g_relation_delete  (GRelation   *relation,
+                   gconstpointer  key,
+                   gint         field)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  GHashTable *table = rel->hashed_tuple_tables[field];
+  GHashTable *key_table;
+  gint        count = rel->count;
+
+  g_assert (table);
+
+  key_table = g_hash_table_lookup (table, key);
+
+  if (!key_table)
+    return 0;
+
+  rel->current_field = field;
+
+  g_hash_table_foreach (key_table, g_relation_delete_tuple, rel);
+
+  g_hash_table_remove (table, key);
+
+  g_hash_table_destroy (key_table);
+
+  /* @@@ Remove empty hash tables. */
+
+  return count - rel->count;
+}
+
+static void
+g_relation_select_tuple (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
+{
+  gpointer    *tuple = (gpointer*) tuple_value;
+  GRealTuples *tuples = (GRealTuples*) user_data;
+  gint stride = sizeof (gpointer) * tuples->width;
+
+  g_assert (tuple_key == tuple_value);
+
+  memcpy (tuples->data + (tuples->len * tuples->width),
+         tuple,
+         stride);
+
+  tuples->len += 1;
+}
+
+GTuples*
+g_relation_select (GRelation   *relation,
+                  gconstpointer  key,
+                  gint         field)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  GHashTable  *table = rel->hashed_tuple_tables[field];
+  GHashTable  *key_table;
+  GRealTuples *tuples = g_new0 (GRealTuples, 1);
+  gint count;
+
+  g_assert (table);
+
+  key_table = g_hash_table_lookup (table, key);
+
+  if (!key_table)
+    return (GTuples*)tuples;
+
+  count = g_relation_count (relation, key, field);
+
+  tuples->data = g_malloc (sizeof (gpointer) * rel->fields * count);
+  tuples->width = rel->fields;
+
+  g_hash_table_foreach (key_table, g_relation_select_tuple, tuples);
+
+  g_assert (count == tuples->len);
+
+  return (GTuples*)tuples;
+}
+
+gint
+g_relation_count (GRelation   *relation,
+                 gconstpointer  key,
+                 gint         field)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  GHashTable  *table = rel->hashed_tuple_tables[field];
+  GHashTable  *key_table;
+
+  g_assert (table);
+
+  key_table = g_hash_table_lookup (table, key);
+
+  if (!key_table)
+    return 0;
+
+  return g_hash_table_size (key_table);
+}
+
+gboolean
+g_relation_exists (GRelation   *relation, ...)
+{
+  GRealRelation *rel = (GRealRelation *) relation;
+  gpointer* tuple = g_chunk_new (gpointer, rel->tuple_chunk);
+  va_list args;
+  gint i;
+  gboolean result;
+
+  va_start(args, relation);
+
+  for (i = 0; i < rel->fields; i += 1)
+    tuple[i] = va_arg(args, gpointer);
+
+  va_end(args);
+
+  result = g_hash_table_lookup (rel->all_tuples, tuple) != NULL;
+
+  g_mem_chunk_free (rel->tuple_chunk, tuple);
+
+  return result;
+}
+
+void
+g_tuples_destroy (GTuples *tuples0)
+{
+  GRealTuples *tuples = (GRealTuples*) tuples0;
+
+  if (tuples)
+    {
+      g_free (tuples->data);
+      g_free (tuples);
+    }
+}
+
+gpointer
+g_tuples_index (GTuples     *tuples0,
+               gint         index,
+               gint         field)
+{
+  GRealTuples *tuples = (GRealTuples*) tuples0;
+
+  g_assert (field < tuples->width);
+
+  return tuples->data[index * tuples->width + field];
+}
+
+/* Print
+ */
+
+void
+g_relation_print_one (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
+{
+  gint i;
+  GRealRelation* rel = (GRealRelation*) user_data;
+  gpointer* tuples = (gpointer*) tuple_value;
+
+  g_print ("[");
+
+  for (i = 0; i < rel->fields; i += 1)
+    {
+      g_print ("%p", tuples[i]);
+
+      if (i < (rel->fields - 1))
+       g_print (",");
+    }
+
+  g_print ("]\n");
+}
+
+void
+g_relation_print_index (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
+{
+  GRealRelation* rel = (GRealRelation*) user_data;
+  GHashTable* table = (GHashTable*) tuple_value;
+
+  g_print ("*** key %p\n", tuple_key);
+
+  g_hash_table_foreach (table,
+                       g_relation_print_one,
+                       rel);
+}
+
+void
+g_relation_print (GRelation *relation)
+{
+  gint i;
+  GRealRelation* rel = (GRealRelation*) relation;
+
+  g_print ("*** all tuples (%d)\n", rel->count);
+
+  g_hash_table_foreach (rel->all_tuples,
+                       g_relation_print_one,
+                       rel);
+
+  for (i = 0; i < rel->fields; i += 1)
+    {
+      if (rel->hashed_tuple_tables[i] == NULL)
+       continue;
+
+      g_print ("*** index %d\n", i);
+
+      g_hash_table_foreach (rel->hashed_tuple_tables[i],
+                           g_relation_print_index,
+                           rel);
+    }
+
+}
index 8350552..173a0b8 100644 (file)
--- a/gstring.c
+++ b/gstring.c
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
-#include <glib.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include "glib.h"
 
 
 typedef struct _GRealStringChunk GRealStringChunk;
index 8528163..c33efc4 100644 (file)
--- a/gutils.c
+++ b/gutils.c
@@ -851,8 +851,25 @@ g_parse_debug_string  (const gchar *string,
 }
 
 guint
-g_direct_hash(gconstpointer key)
+g_direct_hash(gconstpointer v)
 {
-  return GPOINTER_TO_UINT (key);
+  return GPOINTER_TO_UINT (v);
 }
 
+gint
+g_direct_equal(gconstpointer v, gconstpointer v2)
+{
+  return GPOINTER_TO_UINT (v) == GPOINTER_TO_UINT (v2);
+}
+
+gint
+g_int_equal (gconstpointer v, gconstpointer v2)
+{
+  return *((const gint*) v) == *((const gint*) v2);
+}
+
+guint
+g_int_hash (gconstpointer v)
+{
+  return *(const gint*) v;
+}
index e96dfb5..45d58dc 100644 (file)
@@ -104,9 +104,14 @@ main (int   argc,
   gchar *mem[10000], *tmp_string, *tmp_string_2;
   gint i, j;
   GArray *garray;
+  GPtrArray *gparray;
+  GByteArray *gbarray;
   GString *string1, *string2;
   GTree *tree;
   char chars[62];
+  GRelation *relation;
+  GTuples *tuples;
+  gint data [1024];
 
   g_print ("checking size of gint8...%ld (should be 1)\n", (glong)sizeof (gint8));
   g_print ("checking size of gint16...%ld (should be 2)\n", (glong)sizeof (gint16));
@@ -396,6 +401,110 @@ main (int   argc,
 
   /* g_debug (argv[0]); */
 
+  /* Relation tests */
+
+  g_print ("checking relations...");
+
+  relation = g_relation_new (2);
+
+  g_relation_index (relation, 0, g_int_hash, g_int_equal);
+  g_relation_index (relation, 1, g_int_hash, g_int_equal);
+
+  for (i = 0; i < 1024; i += 1)
+    data[i] = i;
+
+  for (i = 1; i < 1023; i += 1)
+    {
+      g_relation_insert (relation, data + i, data + i + 1);
+      g_relation_insert (relation, data + i, data + i - 1);
+    }
+
+  for (i = 2; i < 1022; i += 1)
+    {
+      g_assert (! g_relation_exists (relation, data + i, data + i));
+      g_assert (! g_relation_exists (relation, data + i, data + i + 2));
+      g_assert (! g_relation_exists (relation, data + i, data + i - 2));
+    }
+
+  for (i = 1; i < 1023; i += 1)
+    {
+      g_assert (g_relation_exists (relation, data + i, data + i + 1));
+      g_assert (g_relation_exists (relation, data + i, data + i - 1));
+    }
+
+  for (i = 2; i < 1022; i += 1)
+    {
+      g_assert (g_relation_count (relation, data + i, 0) == 2);
+      g_assert (g_relation_count (relation, data + i, 1) == 2);
+    }
+
+  g_assert (g_relation_count (relation, data, 0) == 0);
+
+  g_assert (g_relation_count (relation, data + 42, 0) == 2);
+  g_assert (g_relation_count (relation, data + 43, 1) == 2);
+  g_assert (g_relation_count (relation, data + 41, 1) == 2);
+  g_relation_delete (relation, data + 42, 0);
+  g_assert (g_relation_count (relation, data + 42, 0) == 0);
+  g_assert (g_relation_count (relation, data + 43, 1) == 1);
+  g_assert (g_relation_count (relation, data + 41, 1) == 1);
+
+  tuples = g_relation_select (relation, data + 200, 0);
+
+  g_assert (tuples->len == 2);
+
+#if 0
+  for (i = 0; i < tuples->len; i += 1)
+    {
+      printf ("%d %d\n",
+             *(gint*) g_tuples_index (tuples, i, 0),
+             *(gint*) g_tuples_index (tuples, i, 1));
+    }
+#endif
+
+  g_assert (g_relation_exists (relation, data + 300, data + 301));
+  g_relation_delete (relation, data + 300, 0);
+  g_assert (!g_relation_exists (relation, data + 300, data + 301));
+
+  g_tuples_destroy (tuples);
+
+  g_relation_destroy (relation);
+
+  relation = NULL;
+
+  g_print ("ok\n");
+
+  g_print ("checking pointer arrays...");
+
+  gparray = g_ptr_array_new ();
+  for (i = 0; i < 10000; i++)
+    g_ptr_array_add (gparray, (void*)i);
+
+  for (i = 0; i < 10000; i++)
+    if (g_ptr_array_index (gparray, i) != (void*)i)
+      g_print ("array fails: %p ( %p )\n", g_ptr_array_index (gparray, i), (void*)i);
+
+  g_ptr_array_free (gparray, TRUE);
+
+  g_print ("ok\n");
+
+
+  g_print ("checking byte arrays...");
+
+  gbarray = g_byte_array_new ();
+  for (i = 0; i < 10000; i++)
+    g_byte_array_append (gbarray, "abcd", 4);
+
+  for (i = 0; i < 10000; i++)
+    {
+      g_assert (gbarray->data[4*i] == 'a');
+      g_assert (gbarray->data[4*i+1] == 'b');
+      g_assert (gbarray->data[4*i+2] == 'c');
+      g_assert (gbarray->data[4*i+3] == 'd');
+    }
+
+  g_byte_array_free (gbarray, TRUE);
+
+  g_print ("ok\n");
 
   return 0;
 }
index e96dfb5..45d58dc 100644 (file)
@@ -104,9 +104,14 @@ main (int   argc,
   gchar *mem[10000], *tmp_string, *tmp_string_2;
   gint i, j;
   GArray *garray;
+  GPtrArray *gparray;
+  GByteArray *gbarray;
   GString *string1, *string2;
   GTree *tree;
   char chars[62];
+  GRelation *relation;
+  GTuples *tuples;
+  gint data [1024];
 
   g_print ("checking size of gint8...%ld (should be 1)\n", (glong)sizeof (gint8));
   g_print ("checking size of gint16...%ld (should be 2)\n", (glong)sizeof (gint16));
@@ -396,6 +401,110 @@ main (int   argc,
 
   /* g_debug (argv[0]); */
 
+  /* Relation tests */
+
+  g_print ("checking relations...");
+
+  relation = g_relation_new (2);
+
+  g_relation_index (relation, 0, g_int_hash, g_int_equal);
+  g_relation_index (relation, 1, g_int_hash, g_int_equal);
+
+  for (i = 0; i < 1024; i += 1)
+    data[i] = i;
+
+  for (i = 1; i < 1023; i += 1)
+    {
+      g_relation_insert (relation, data + i, data + i + 1);
+      g_relation_insert (relation, data + i, data + i - 1);
+    }
+
+  for (i = 2; i < 1022; i += 1)
+    {
+      g_assert (! g_relation_exists (relation, data + i, data + i));
+      g_assert (! g_relation_exists (relation, data + i, data + i + 2));
+      g_assert (! g_relation_exists (relation, data + i, data + i - 2));
+    }
+
+  for (i = 1; i < 1023; i += 1)
+    {
+      g_assert (g_relation_exists (relation, data + i, data + i + 1));
+      g_assert (g_relation_exists (relation, data + i, data + i - 1));
+    }
+
+  for (i = 2; i < 1022; i += 1)
+    {
+      g_assert (g_relation_count (relation, data + i, 0) == 2);
+      g_assert (g_relation_count (relation, data + i, 1) == 2);
+    }
+
+  g_assert (g_relation_count (relation, data, 0) == 0);
+
+  g_assert (g_relation_count (relation, data + 42, 0) == 2);
+  g_assert (g_relation_count (relation, data + 43, 1) == 2);
+  g_assert (g_relation_count (relation, data + 41, 1) == 2);
+  g_relation_delete (relation, data + 42, 0);
+  g_assert (g_relation_count (relation, data + 42, 0) == 0);
+  g_assert (g_relation_count (relation, data + 43, 1) == 1);
+  g_assert (g_relation_count (relation, data + 41, 1) == 1);
+
+  tuples = g_relation_select (relation, data + 200, 0);
+
+  g_assert (tuples->len == 2);
+
+#if 0
+  for (i = 0; i < tuples->len; i += 1)
+    {
+      printf ("%d %d\n",
+             *(gint*) g_tuples_index (tuples, i, 0),
+             *(gint*) g_tuples_index (tuples, i, 1));
+    }
+#endif
+
+  g_assert (g_relation_exists (relation, data + 300, data + 301));
+  g_relation_delete (relation, data + 300, 0);
+  g_assert (!g_relation_exists (relation, data + 300, data + 301));
+
+  g_tuples_destroy (tuples);
+
+  g_relation_destroy (relation);
+
+  relation = NULL;
+
+  g_print ("ok\n");
+
+  g_print ("checking pointer arrays...");
+
+  gparray = g_ptr_array_new ();
+  for (i = 0; i < 10000; i++)
+    g_ptr_array_add (gparray, (void*)i);
+
+  for (i = 0; i < 10000; i++)
+    if (g_ptr_array_index (gparray, i) != (void*)i)
+      g_print ("array fails: %p ( %p )\n", g_ptr_array_index (gparray, i), (void*)i);
+
+  g_ptr_array_free (gparray, TRUE);
+
+  g_print ("ok\n");
+
+
+  g_print ("checking byte arrays...");
+
+  gbarray = g_byte_array_new ();
+  for (i = 0; i < 10000; i++)
+    g_byte_array_append (gbarray, "abcd", 4);
+
+  for (i = 0; i < 10000; i++)
+    {
+      g_assert (gbarray->data[4*i] == 'a');
+      g_assert (gbarray->data[4*i+1] == 'b');
+      g_assert (gbarray->data[4*i+2] == 'c');
+      g_assert (gbarray->data[4*i+3] == 'd');
+    }
+
+  g_byte_array_free (gbarray, TRUE);
+
+  g_print ("ok\n");
 
   return 0;
 }