diff options
Diffstat (limited to 'protocols/Sametime/src/glib/grel.c')
| -rw-r--r-- | protocols/Sametime/src/glib/grel.c | 675 | 
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); +    } +   +}  | 
