summaryrefslogtreecommitdiff
path: root/protocols/Sametime/src/glib/grel.c
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2014-03-22 13:34:19 +0000
committerGeorge Hazan <george.hazan@gmail.com>2014-03-22 13:34:19 +0000
commit79b554fe05162550656da3c4e459fb717dc4dadf (patch)
tree34b5856bb397b145e2a6e6b317742b73ff53ec9f /protocols/Sametime/src/glib/grel.c
parent739fd4137010dc56881cf8328770b3175a2f2696 (diff)
glib inlined into SameTime
git-svn-id: http://svn.miranda-ng.org/main/trunk@8685 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/Sametime/src/glib/grel.c')
-rw-r--r--protocols/Sametime/src/glib/grel.c675
1 files changed, 675 insertions, 0 deletions
diff --git a/protocols/Sametime/src/glib/grel.c b/protocols/Sametime/src/glib/grel.c
new file mode 100644
index 0000000000..59d5bbbfc4
--- /dev/null
+++ b/protocols/Sametime/src/glib/grel.c
@@ -0,0 +1,675 @@
+/* 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 Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "ghash.h"
+#include "gmessages.h"
+#include "gtestutils.h"
+#include "gstring.h"
+
+#undef G_DISABLE_DEPRECATED
+
+#include "grel.h"
+
+/**
+ * SECTION: relations
+ * @title: Relations and Tuples
+ * @short_description: tables of data which can be indexed on any
+ * number of fields
+ *
+ * A #GRelation is a table of data which can be indexed on any number
+ * of fields, rather like simple database tables. A #GRelation contains
+ * a number of records, called tuples. Each record contains a number of
+ * fields. Records are not ordered, so it is not possible to find the
+ * record at a particular index.
+ *
+ * Note that #GRelation tables are currently limited to 2 fields.
+ *
+ * To create a GRelation, use g_relation_new().
+ *
+ * To specify which fields should be indexed, use g_relation_index().
+ * Note that this must be called before any tuples are added to the
+ * #GRelation.
+ *
+ * To add records to a #GRelation use g_relation_insert().
+ *
+ * To determine if a given record appears in a #GRelation, use
+ * g_relation_exists(). Note that fields are compared directly, so
+ * pointers must point to the exact same position (i.e. different
+ * copies of the same string will not match.)
+ *
+ * To count the number of records which have a particular value in a
+ * given field, use g_relation_count().
+ *
+ * To get all the records which have a particular value in a given
+ * field, use g_relation_select(). To access fields of the resulting
+ * records, use g_tuples_index(). To free the resulting records use
+ * g_tuples_destroy().
+ *
+ * To delete all records which have a particular value in a given
+ * field, use g_relation_delete().
+ *
+ * To destroy the #GRelation, use g_relation_destroy().
+ *
+ * To help debug #GRelation objects, use g_relation_print().
+ *
+ * GRelation has been marked as deprecated, since this API has never
+ * been fully implemented, is not very actively maintained and rarely
+ * used.
+ **/
+
+typedef struct _GRealTuples GRealTuples;
+
+/**
+ * GRelation:
+ *
+ * The #GRelation struct is an opaque data structure to represent a
+ * <link linkend="glib-Relations-and-Tuples">Relation</link>. It should
+ * only be accessed via the following functions.
+ **/
+struct _GRelation
+{
+ gint fields;
+ gint current_field;
+
+ GHashTable *all_tuples;
+ GHashTable **hashed_tuple_tables;
+
+ gint count;
+};
+
+/**
+ * GTuples:
+ * @len: the number of records that matched.
+ *
+ * The #GTuples struct is used to return records (or tuples) from the
+ * #GRelation by g_relation_select(). It only contains one public
+ * member - the number of records that matched. To access the matched
+ * records, you must use g_tuples_index().
+ **/
+struct _GRealTuples
+{
+ gint len;
+ gint width;
+ gpointer *data;
+};
+
+static 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];
+}
+
+static guint
+tuple_hash_2 (gconstpointer v_a)
+{
+#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG
+ /* In practise this snippet has been written for 64-bit Windows
+ * where ints are 32 bits, pointers 64 bits. More exotic platforms
+ * need more tweaks.
+ */
+ guint* a = (guint*) v_a;
+
+ return (a[0] ^ a[1] ^ a[2] ^ a[3]);
+#else
+ gpointer* a = (gpointer*) v_a;
+
+ return (gulong)a[0] ^ (gulong)a[1];
+#endif
+}
+
+static GHashFunc
+tuple_hash (gint fields)
+{
+ switch (fields)
+ {
+ case 2:
+ return tuple_hash_2;
+ default:
+ g_error ("no tuple hash for %d", fields);
+ }
+
+ return NULL;
+}
+
+static GEqualFunc
+tuple_equal (gint fields)
+{
+ switch (fields)
+ {
+ case 2:
+ return tuple_equal_2;
+ default:
+ g_error ("no tuple equal for %d", fields);
+ }
+
+ return NULL;
+}
+
+/**
+ * g_relation_new:
+ * @fields: the number of fields.
+ * @Returns: a new #GRelation.
+ *
+ * Creates a new #GRelation with the given number of fields. Note that
+ * currently the number of fields must be 2.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+GRelation*
+g_relation_new (gint fields)
+{
+ GRelation* rel = g_new0 (GRelation, 1);
+
+ rel->fields = fields;
+ rel->all_tuples = g_hash_table_new (tuple_hash (fields), tuple_equal (fields));
+ rel->hashed_tuple_tables = g_new0 (GHashTable*, fields);
+
+ return rel;
+}
+
+static void
+relation_delete_value_tuple (gpointer tuple_key,
+ gpointer tuple_value,
+ gpointer user_data)
+{
+ GRelation *relation = user_data;
+ gpointer *tuple = tuple_value;
+ g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
+}
+
+static void
+g_relation_free_array (gpointer key, gpointer value, gpointer user_data)
+{
+ g_hash_table_destroy ((GHashTable*) value);
+}
+
+/**
+ * g_relation_destroy:
+ * @relation: a #GRelation.
+ *
+ * Destroys the #GRelation, freeing all memory allocated. However, it
+ * does not free memory allocated for the tuple data, so you should
+ * free that first if appropriate.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+void
+g_relation_destroy (GRelation *relation)
+{
+ gint i;
+
+ if (relation)
+ {
+ for (i = 0; i < relation->fields; i += 1)
+ {
+ if (relation->hashed_tuple_tables[i])
+ {
+ g_hash_table_foreach (relation->hashed_tuple_tables[i], g_relation_free_array, NULL);
+ g_hash_table_destroy (relation->hashed_tuple_tables[i]);
+ }
+ }
+
+ g_hash_table_foreach (relation->all_tuples, relation_delete_value_tuple, relation);
+ g_hash_table_destroy (relation->all_tuples);
+
+ g_free (relation->hashed_tuple_tables);
+ g_free (relation);
+ }
+}
+
+/**
+ * g_relation_index:
+ * @relation: a #GRelation.
+ * @field: the field to index, counting from 0.
+ * @hash_func: a function to produce a hash value from the field data.
+ * @key_equal_func: a function to compare two values of the given field.
+ *
+ * Creates an index on the given field. Note that this must be called
+ * before any records are added to the #GRelation.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+void
+g_relation_index (GRelation *relation,
+ gint field,
+ GHashFunc hash_func,
+ GEqualFunc key_equal_func)
+{
+ g_return_if_fail (relation != NULL);
+
+ g_return_if_fail (relation->count == 0 && relation->hashed_tuple_tables[field] == NULL);
+
+ relation->hashed_tuple_tables[field] = g_hash_table_new (hash_func, key_equal_func);
+}
+
+/**
+ * g_relation_insert:
+ * @relation: a #GRelation.
+ * @Varargs: the fields of the record to add. These must match the
+ * number of fields in the #GRelation, and of type #gpointer
+ * or #gconstpointer.
+ *
+ * Inserts a record into a #GRelation.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+void
+g_relation_insert (GRelation *relation,
+ ...)
+{
+ gpointer* tuple = g_slice_alloc (relation->fields * sizeof (gpointer));
+ va_list args;
+ gint i;
+
+ va_start (args, relation);
+
+ for (i = 0; i < relation->fields; i += 1)
+ tuple[i] = va_arg (args, gpointer);
+
+ va_end (args);
+
+ g_hash_table_insert (relation->all_tuples, tuple, tuple);
+
+ relation->count += 1;
+
+ for (i = 0; i < relation->fields; i += 1)
+ {
+ GHashTable *table;
+ gpointer key;
+ GHashTable *per_key_table;
+
+ table = relation->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 (relation->fields), tuple_equal (relation->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;
+ GRelation *relation = (GRelation *) user_data;
+ gint j;
+
+ g_assert (tuple_key == tuple_value);
+
+ for (j = 0; j < relation->fields; j += 1)
+ {
+ GHashTable *one_table = relation->hashed_tuple_tables[j];
+ gpointer one_key;
+ GHashTable *per_key_table;
+
+ if (one_table == NULL)
+ continue;
+
+ if (j == relation->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);
+ }
+
+ if (g_hash_table_remove (relation->all_tuples, tuple))
+ g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
+
+ relation->count -= 1;
+}
+
+/**
+ * g_relation_delete:
+ * @relation: a #GRelation.
+ * @key: the value to compare with.
+ * @field: the field of each record to match.
+ * @Returns: the number of records deleted.
+ *
+ * Deletes any records from a #GRelation that have the given key value
+ * in the given field.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+gint
+g_relation_delete (GRelation *relation,
+ gconstpointer key,
+ gint field)
+{
+ GHashTable *table;
+ GHashTable *key_table;
+ gint count;
+
+ g_return_val_if_fail (relation != NULL, 0);
+
+ table = relation->hashed_tuple_tables[field];
+ count = relation->count;
+
+ g_return_val_if_fail (table != NULL, 0);
+
+ key_table = g_hash_table_lookup (table, key);
+
+ if (!key_table)
+ return 0;
+
+ relation->current_field = field;
+
+ g_hash_table_foreach (key_table, g_relation_delete_tuple, relation);
+
+ g_hash_table_remove (table, key);
+
+ g_hash_table_destroy (key_table);
+
+ /* @@@ FIXME: Remove empty hash tables. */
+
+ return count - relation->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;
+}
+
+/**
+ * g_relation_select:
+ * @relation: a #GRelation.
+ * @key: the value to compare with.
+ * @field: the field of each record to match.
+ * @Returns: the records (tuples) that matched.
+ *
+ * Returns all of the tuples which have the given key in the given
+ * field. Use g_tuples_index() to access the returned records. The
+ * returned records should be freed with g_tuples_destroy().
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+GTuples*
+g_relation_select (GRelation *relation,
+ gconstpointer key,
+ gint field)
+{
+ GHashTable *table;
+ GHashTable *key_table;
+ GRealTuples *tuples;
+ gint count;
+
+ g_return_val_if_fail (relation != NULL, NULL);
+
+ table = relation->hashed_tuple_tables[field];
+
+ g_return_val_if_fail (table != NULL, NULL);
+
+ tuples = g_new0 (GRealTuples, 1);
+ 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) * relation->fields * count);
+ tuples->width = relation->fields;
+
+ g_hash_table_foreach (key_table, g_relation_select_tuple, tuples);
+
+ g_assert (count == tuples->len);
+
+ return (GTuples*)tuples;
+}
+
+/**
+ * g_relation_count:
+ * @relation: a #GRelation.
+ * @key: the value to compare with.
+ * @field: the field of each record to match.
+ * @Returns: the number of matches.
+ *
+ * Returns the number of tuples in a #GRelation that have the given
+ * value in the given field.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+gint
+g_relation_count (GRelation *relation,
+ gconstpointer key,
+ gint field)
+{
+ GHashTable *table;
+ GHashTable *key_table;
+
+ g_return_val_if_fail (relation != NULL, 0);
+
+ table = relation->hashed_tuple_tables[field];
+
+ g_return_val_if_fail (table != NULL, 0);
+
+ key_table = g_hash_table_lookup (table, key);
+
+ if (!key_table)
+ return 0;
+
+ return g_hash_table_size (key_table);
+}
+
+/**
+ * g_relation_exists:
+ * @relation: a #GRelation.
+ * @Varargs: the fields of the record to compare. The number must match
+ * the number of fields in the #GRelation.
+ * @Returns: %TRUE if a record matches.
+ *
+ * Returns %TRUE if a record with the given values exists in a
+ * #GRelation. Note that the values are compared directly, so that, for
+ * example, two copies of the same string will not match.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+gboolean
+g_relation_exists (GRelation *relation, ...)
+{
+ gpointer *tuple = g_slice_alloc (relation->fields * sizeof (gpointer));
+ va_list args;
+ gint i;
+ gboolean result;
+
+ va_start(args, relation);
+
+ for (i = 0; i < relation->fields; i += 1)
+ tuple[i] = va_arg(args, gpointer);
+
+ va_end(args);
+
+ result = g_hash_table_lookup (relation->all_tuples, tuple) != NULL;
+
+ g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
+
+ return result;
+}
+
+/**
+ * g_tuples_destroy:
+ * @tuples: the tuple data to free.
+ *
+ * Frees the records which were returned by g_relation_select(). This
+ * should always be called after g_relation_select() when you are
+ * finished with the records. The records are not removed from the
+ * #GRelation.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+void
+g_tuples_destroy (GTuples *tuples0)
+{
+ GRealTuples *tuples = (GRealTuples*) tuples0;
+
+ if (tuples)
+ {
+ g_free (tuples->data);
+ g_free (tuples);
+ }
+}
+
+/**
+ * g_tuples_index:
+ * @tuples: the tuple data, returned by g_relation_select().
+ * @index_: the index of the record.
+ * @field: the field to return.
+ * @Returns: the field of the record.
+ *
+ * Gets a field from the records returned by g_relation_select(). It
+ * returns the given field of the record at the given index. The
+ * returned value should not be changed.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+gpointer
+g_tuples_index (GTuples *tuples0,
+ gint index,
+ gint field)
+{
+ GRealTuples *tuples = (GRealTuples*) tuples0;
+
+ g_return_val_if_fail (tuples0 != NULL, NULL);
+ g_return_val_if_fail (field < tuples->width, NULL);
+
+ return tuples->data[index * tuples->width + field];
+}
+
+/* Print
+ */
+
+static void
+g_relation_print_one (gpointer tuple_key,
+ gpointer tuple_value,
+ gpointer user_data)
+{
+ gint i;
+ GString *gstring;
+ GRelation* rel = (GRelation*) user_data;
+ gpointer* tuples = (gpointer*) tuple_value;
+
+ gstring = g_string_new ("[");
+
+ for (i = 0; i < rel->fields; i += 1)
+ {
+ g_string_append_printf (gstring, "%p", tuples[i]);
+
+ if (i < (rel->fields - 1))
+ g_string_append (gstring, ",");
+ }
+
+ g_string_append (gstring, "]");
+ g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s", gstring->str);
+ g_string_free (gstring, TRUE);
+}
+
+static void
+g_relation_print_index (gpointer tuple_key,
+ gpointer tuple_value,
+ gpointer user_data)
+{
+ GRelation* rel = (GRelation*) user_data;
+ GHashTable* table = (GHashTable*) tuple_value;
+
+ g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** key %p", tuple_key);
+
+ g_hash_table_foreach (table,
+ g_relation_print_one,
+ rel);
+}
+
+/**
+ * g_relation_print:
+ * @relation: a #GRelation.
+ *
+ * Outputs information about all records in a #GRelation, as well as
+ * the indexes. It is for debugging.
+ *
+ * Deprecated: 2.26: Rarely used API
+ **/
+void
+g_relation_print (GRelation *relation)
+{
+ gint i;
+
+ g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** all tuples (%d)", relation->count);
+
+ g_hash_table_foreach (relation->all_tuples,
+ g_relation_print_one,
+ relation);
+
+ for (i = 0; i < relation->fields; i += 1)
+ {
+ if (relation->hashed_tuple_tables[i] == NULL)
+ continue;
+
+ g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** index %d", i);
+
+ g_hash_table_foreach (relation->hashed_tuple_tables[i],
+ g_relation_print_index,
+ relation);
+ }
+
+}