summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--ChangeLog.pre-2-022
-rw-r--r--ChangeLog.pre-2-1022
-rw-r--r--ChangeLog.pre-2-1222
-rw-r--r--ChangeLog.pre-2-222
-rw-r--r--ChangeLog.pre-2-422
-rw-r--r--ChangeLog.pre-2-622
-rw-r--r--ChangeLog.pre-2-822
-rw-r--r--Makefile.am1
-rw-r--r--garray.c177
-rw-r--r--ghash.c8
-rw-r--r--glib.h122
-rw-r--r--glib/Makefile.am1
-rw-r--r--glib/garray.c177
-rw-r--r--glib/ghash.c8
-rw-r--r--glib/glib.h122
-rw-r--r--glib/grel.c428
-rw-r--r--glib/gstring.c2
-rw-r--r--glib/gutils.c21
-rw-r--r--grel.c428
-rw-r--r--gstring.c2
-rw-r--r--gutils.c21
-rw-r--r--testglib.c109
-rw-r--r--tests/testglib.c109
24 files changed, 1904 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 8100e464b..6286236f2 100644
--- 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>
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index 8100e464b..6286236f2 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -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>
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 8100e464b..6286236f2 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -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>
diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12
index 8100e464b..6286236f2 100644
--- a/ChangeLog.pre-2-12
+++ b/ChangeLog.pre-2-12
@@ -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>
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index 8100e464b..6286236f2 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -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>
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 8100e464b..6286236f2 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -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>
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 8100e464b..6286236f2 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -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>
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 8100e464b..6286236f2 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -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>
diff --git a/Makefile.am b/Makefile.am
index 84f563524..d09d201b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,6 +23,7 @@ libglib_1_1_la_SOURCES = \
gslist.c \
gtimer.c \
gtree.c \
+ grel.c \
gstring.c \
gscanner.c \
gutils.c
diff --git a/garray.c b/garray.c
index 4d814a44a..16c1063a8 100644
--- 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 ceee09843..ee364c9c2 100644
--- 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 37d49e970..c3733d440 100644
--- 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;
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 84f563524..d09d201b7 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -23,6 +23,7 @@ libglib_1_1_la_SOURCES = \
gslist.c \
gtimer.c \
gtree.c \
+ grel.c \
gstring.c \
gscanner.c \
gutils.c
diff --git a/glib/garray.c b/glib/garray.c
index 4d814a44a..16c1063a8 100644
--- a/glib/garray.c
+++ b/glib/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/glib/ghash.c b/glib/ghash.c
index ceee09843..ee364c9c2 100644
--- a/glib/ghash.c
+++ b/glib/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/glib.h b/glib/glib.h
index 37d49e970..c3733d440 100644
--- a/glib/glib.h
+++ b/glib/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;
diff --git a/glib/grel.c b/glib/grel.c
new file mode 100644
index 000000000..91d2b68e2
--- /dev/null
+++ b/glib/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);
+ }
+
+}
diff --git a/glib/gstring.c b/glib/gstring.c
index 8350552d2..173a0b8c1 100644
--- a/glib/gstring.c
+++ b/glib/gstring.c
@@ -16,12 +16,12 @@
* 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;
diff --git a/glib/gutils.c b/glib/gutils.c
index 8528163f4..c33efc4bd 100644
--- a/glib/gutils.c
+++ b/glib/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;
+}
diff --git a/grel.c b/grel.c
new file mode 100644
index 000000000..91d2b68e2
--- /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);
+ }
+
+}
diff --git a/gstring.c b/gstring.c
index 8350552d2..173a0b8c1 100644
--- a/gstring.c
+++ b/gstring.c
@@ -16,12 +16,12 @@
* 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;
diff --git a/gutils.c b/gutils.c
index 8528163f4..c33efc4bd 100644
--- 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;
+}
diff --git a/testglib.c b/testglib.c
index e96dfb570..45d58dc99 100644
--- a/testglib.c
+++ b/testglib.c
@@ -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;
}
diff --git a/tests/testglib.c b/tests/testglib.c
index e96dfb570..45d58dc99 100644
--- a/tests/testglib.c
+++ b/tests/testglib.c
@@ -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;
}