1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
21 * file for a list of people on the GLib Team. See the ChangeLog
22 * files for a list of changes. These files are distributed with
23 * GLib at ftp://ftp.gtk.org/pub/gtk/.
34 #include <glib/gmessages.h>
35 #include <glib/gtestutils.h>
36 #include <glib/gstring.h>
37 #include <glib/gslice.h>
38 #include <glib/ghash.h>
45 * @title: Relations and Tuples
46 * @short_description: tables of data which can be indexed on any
49 * A #GRelation is a table of data which can be indexed on any number
50 * of fields, rather like simple database tables. A #GRelation contains
51 * a number of records, called tuples. Each record contains a number of
52 * fields. Records are not ordered, so it is not possible to find the
53 * record at a particular index.
55 * Note that #GRelation tables are currently limited to 2 fields.
57 * To create a GRelation, use g_relation_new().
59 * To specify which fields should be indexed, use g_relation_index().
60 * Note that this must be called before any tuples are added to the
63 * To add records to a #GRelation use g_relation_insert().
65 * To determine if a given record appears in a #GRelation, use
66 * g_relation_exists(). Note that fields are compared directly, so
67 * pointers must point to the exact same position (i.e. different
68 * copies of the same string will not match.)
70 * To count the number of records which have a particular value in a
71 * given field, use g_relation_count().
73 * To get all the records which have a particular value in a given
74 * field, use g_relation_select(). To access fields of the resulting
75 * records, use g_tuples_index(). To free the resulting records use
78 * To delete all records which have a particular value in a given
79 * field, use g_relation_delete().
81 * To destroy the #GRelation, use g_relation_destroy().
83 * To help debug #GRelation objects, use g_relation_print().
85 * GRelation has been marked as deprecated, since this API has never
86 * been fully implemented, is not very actively maintained and rarely
90 typedef struct _GRealTuples GRealTuples;
95 * The #GRelation struct is an opaque data structure to represent a
96 * <link linkend="glib-Relations-and-Tuples">Relation</link>. It should
97 * only be accessed via the following functions.
104 GHashTable *all_tuples;
105 GHashTable **hashed_tuple_tables;
112 * @len: the number of records that matched.
114 * The #GTuples struct is used to return records (or tuples) from the
115 * #GRelation by g_relation_select(). It only contains one public
116 * member - the number of records that matched. To access the matched
117 * records, you must use g_tuples_index().
127 tuple_equal_2 (gconstpointer v_a,
130 gpointer* a = (gpointer*) v_a;
131 gpointer* b = (gpointer*) v_b;
133 return a[0] == b[0] && a[1] == b[1];
137 tuple_hash_2 (gconstpointer v_a)
139 #if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG
140 /* In practise this snippet has been written for 64-bit Windows
141 * where ints are 32 bits, pointers 64 bits. More exotic platforms
144 guint* a = (guint*) v_a;
146 return (a[0] ^ a[1] ^ a[2] ^ a[3]);
148 gpointer* a = (gpointer*) v_a;
150 return (gulong)a[0] ^ (gulong)a[1];
155 tuple_hash (gint fields)
162 g_error ("no tuple hash for %d", fields);
169 tuple_equal (gint fields)
174 return tuple_equal_2;
176 g_error ("no tuple equal for %d", fields);
184 * @fields: the number of fields.
185 * @Returns: a new #GRelation.
187 * Creates a new #GRelation with the given number of fields. Note that
188 * currently the number of fields must be 2.
190 * Deprecated: 2.26: Rarely used API
193 g_relation_new (gint fields)
195 GRelation* rel = g_new0 (GRelation, 1);
197 rel->fields = fields;
198 rel->all_tuples = g_hash_table_new (tuple_hash (fields), tuple_equal (fields));
199 rel->hashed_tuple_tables = g_new0 (GHashTable*, fields);
205 relation_delete_value_tuple (gpointer tuple_key,
206 gpointer tuple_value,
209 GRelation *relation = user_data;
210 gpointer *tuple = tuple_value;
211 g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
215 g_relation_free_array (gpointer key, gpointer value, gpointer user_data)
217 g_hash_table_destroy ((GHashTable*) value);
221 * g_relation_destroy:
222 * @relation: a #GRelation.
224 * Destroys the #GRelation, freeing all memory allocated. However, it
225 * does not free memory allocated for the tuple data, so you should
226 * free that first if appropriate.
228 * Deprecated: 2.26: Rarely used API
231 g_relation_destroy (GRelation *relation)
237 for (i = 0; i < relation->fields; i += 1)
239 if (relation->hashed_tuple_tables[i])
241 g_hash_table_foreach (relation->hashed_tuple_tables[i], g_relation_free_array, NULL);
242 g_hash_table_destroy (relation->hashed_tuple_tables[i]);
246 g_hash_table_foreach (relation->all_tuples, relation_delete_value_tuple, relation);
247 g_hash_table_destroy (relation->all_tuples);
249 g_free (relation->hashed_tuple_tables);
256 * @relation: a #GRelation.
257 * @field: the field to index, counting from 0.
258 * @hash_func: a function to produce a hash value from the field data.
259 * @key_equal_func: a function to compare two values of the given field.
261 * Creates an index on the given field. Note that this must be called
262 * before any records are added to the #GRelation.
264 * Deprecated: 2.26: Rarely used API
267 g_relation_index (GRelation *relation,
270 GEqualFunc key_equal_func)
272 g_return_if_fail (relation != NULL);
274 g_return_if_fail (relation->count == 0 && relation->hashed_tuple_tables[field] == NULL);
276 relation->hashed_tuple_tables[field] = g_hash_table_new (hash_func, key_equal_func);
281 * @relation: a #GRelation.
282 * @...: the fields of the record to add. These must match the
283 * number of fields in the #GRelation, and of type #gpointer
286 * Inserts a record into a #GRelation.
288 * Deprecated: 2.26: Rarely used API
291 g_relation_insert (GRelation *relation,
294 gpointer* tuple = g_slice_alloc (relation->fields * sizeof (gpointer));
298 va_start (args, relation);
300 for (i = 0; i < relation->fields; i += 1)
301 tuple[i] = va_arg (args, gpointer);
305 g_hash_table_insert (relation->all_tuples, tuple, tuple);
307 relation->count += 1;
309 for (i = 0; i < relation->fields; i += 1)
313 GHashTable *per_key_table;
315 table = relation->hashed_tuple_tables[i];
321 per_key_table = g_hash_table_lookup (table, key);
323 if (per_key_table == NULL)
325 per_key_table = g_hash_table_new (tuple_hash (relation->fields), tuple_equal (relation->fields));
326 g_hash_table_insert (table, key, per_key_table);
329 g_hash_table_insert (per_key_table, tuple, tuple);
334 g_relation_delete_tuple (gpointer tuple_key,
335 gpointer tuple_value,
338 gpointer *tuple = (gpointer*) tuple_value;
339 GRelation *relation = (GRelation *) user_data;
342 g_assert (tuple_key == tuple_value);
344 for (j = 0; j < relation->fields; j += 1)
346 GHashTable *one_table = relation->hashed_tuple_tables[j];
348 GHashTable *per_key_table;
350 if (one_table == NULL)
353 if (j == relation->current_field)
354 /* can't delete from the table we're foreaching in */
359 per_key_table = g_hash_table_lookup (one_table, one_key);
361 g_hash_table_remove (per_key_table, tuple);
364 if (g_hash_table_remove (relation->all_tuples, tuple))
365 g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
367 relation->count -= 1;
372 * @relation: a #GRelation.
373 * @key: the value to compare with.
374 * @field: the field of each record to match.
375 * @Returns: the number of records deleted.
377 * Deletes any records from a #GRelation that have the given key value
378 * in the given field.
380 * Deprecated: 2.26: Rarely used API
383 g_relation_delete (GRelation *relation,
388 GHashTable *key_table;
391 g_return_val_if_fail (relation != NULL, 0);
393 table = relation->hashed_tuple_tables[field];
394 count = relation->count;
396 g_return_val_if_fail (table != NULL, 0);
398 key_table = g_hash_table_lookup (table, key);
403 relation->current_field = field;
405 g_hash_table_foreach (key_table, g_relation_delete_tuple, relation);
407 g_hash_table_remove (table, key);
409 g_hash_table_destroy (key_table);
411 /* @@@ FIXME: Remove empty hash tables. */
413 return count - relation->count;
417 g_relation_select_tuple (gpointer tuple_key,
418 gpointer tuple_value,
421 gpointer *tuple = (gpointer*) tuple_value;
422 GRealTuples *tuples = (GRealTuples*) user_data;
423 gint stride = sizeof (gpointer) * tuples->width;
425 g_assert (tuple_key == tuple_value);
427 memcpy (tuples->data + (tuples->len * tuples->width),
436 * @relation: a #GRelation.
437 * @key: the value to compare with.
438 * @field: the field of each record to match.
439 * @Returns: the records (tuples) that matched.
441 * Returns all of the tuples which have the given key in the given
442 * field. Use g_tuples_index() to access the returned records. The
443 * returned records should be freed with g_tuples_destroy().
445 * Deprecated: 2.26: Rarely used API
448 g_relation_select (GRelation *relation,
453 GHashTable *key_table;
457 g_return_val_if_fail (relation != NULL, NULL);
459 table = relation->hashed_tuple_tables[field];
461 g_return_val_if_fail (table != NULL, NULL);
463 tuples = g_new0 (GRealTuples, 1);
464 key_table = g_hash_table_lookup (table, key);
467 return (GTuples*)tuples;
469 count = g_relation_count (relation, key, field);
471 tuples->data = g_malloc (sizeof (gpointer) * relation->fields * count);
472 tuples->width = relation->fields;
474 g_hash_table_foreach (key_table, g_relation_select_tuple, tuples);
476 g_assert (count == tuples->len);
478 return (GTuples*)tuples;
483 * @relation: a #GRelation.
484 * @key: the value to compare with.
485 * @field: the field of each record to match.
486 * @Returns: the number of matches.
488 * Returns the number of tuples in a #GRelation that have the given
489 * value in the given field.
491 * Deprecated: 2.26: Rarely used API
494 g_relation_count (GRelation *relation,
499 GHashTable *key_table;
501 g_return_val_if_fail (relation != NULL, 0);
503 table = relation->hashed_tuple_tables[field];
505 g_return_val_if_fail (table != NULL, 0);
507 key_table = g_hash_table_lookup (table, key);
512 return g_hash_table_size (key_table);
517 * @relation: a #GRelation.
518 * @...: the fields of the record to compare. The number must match
519 * the number of fields in the #GRelation.
520 * @Returns: %TRUE if a record matches.
522 * Returns %TRUE if a record with the given values exists in a
523 * #GRelation. Note that the values are compared directly, so that, for
524 * example, two copies of the same string will not match.
526 * Deprecated: 2.26: Rarely used API
529 g_relation_exists (GRelation *relation, ...)
531 gpointer *tuple = g_slice_alloc (relation->fields * sizeof (gpointer));
536 va_start(args, relation);
538 for (i = 0; i < relation->fields; i += 1)
539 tuple[i] = va_arg(args, gpointer);
543 result = g_hash_table_lookup (relation->all_tuples, tuple) != NULL;
545 g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
552 * @tuples: the tuple data to free.
554 * Frees the records which were returned by g_relation_select(). This
555 * should always be called after g_relation_select() when you are
556 * finished with the records. The records are not removed from the
559 * Deprecated: 2.26: Rarely used API
562 g_tuples_destroy (GTuples *tuples0)
564 GRealTuples *tuples = (GRealTuples*) tuples0;
568 g_free (tuples->data);
575 * @tuples: the tuple data, returned by g_relation_select().
576 * @index_: the index of the record.
577 * @field: the field to return.
578 * @Returns: the field of the record.
580 * Gets a field from the records returned by g_relation_select(). It
581 * returns the given field of the record at the given index. The
582 * returned value should not be changed.
584 * Deprecated: 2.26: Rarely used API
587 g_tuples_index (GTuples *tuples0,
591 GRealTuples *tuples = (GRealTuples*) tuples0;
593 g_return_val_if_fail (tuples0 != NULL, NULL);
594 g_return_val_if_fail (field < tuples->width, NULL);
596 return tuples->data[index * tuples->width + field];
603 g_relation_print_one (gpointer tuple_key,
604 gpointer tuple_value,
609 GRelation* rel = (GRelation*) user_data;
610 gpointer* tuples = (gpointer*) tuple_value;
612 gstring = g_string_new ("[");
614 for (i = 0; i < rel->fields; i += 1)
616 g_string_append_printf (gstring, "%p", tuples[i]);
618 if (i < (rel->fields - 1))
619 g_string_append (gstring, ",");
622 g_string_append (gstring, "]");
623 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s", gstring->str);
624 g_string_free (gstring, TRUE);
628 g_relation_print_index (gpointer tuple_key,
629 gpointer tuple_value,
632 GRelation* rel = (GRelation*) user_data;
633 GHashTable* table = (GHashTable*) tuple_value;
635 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** key %p", tuple_key);
637 g_hash_table_foreach (table,
638 g_relation_print_one,
644 * @relation: a #GRelation.
646 * Outputs information about all records in a #GRelation, as well as
647 * the indexes. It is for debugging.
649 * Deprecated: 2.26: Rarely used API
652 g_relation_print (GRelation *relation)
656 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** all tuples (%d)", relation->count);
658 g_hash_table_foreach (relation->all_tuples,
659 g_relation_print_one,
662 for (i = 0; i < relation->fields; i += 1)
664 if (relation->hashed_tuple_tables[i] == NULL)
667 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** index %d", i);
669 g_hash_table_foreach (relation->hashed_tuple_tables[i],
670 g_relation_print_index,