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 Library 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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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.
22 typedef struct _GRealRelation GRealRelation;
23 typedef struct _GRealTuples GRealTuples;
30 GHashTable *all_tuples;
31 GHashTable **hashed_tuple_tables;
32 GMemChunk *tuple_chunk;
45 tuple_equal_2 (gconstpointer v_a, gconstpointer v_b)
47 gpointer* a = (gpointer*) v_a;
48 gpointer* b = (gpointer*) v_b;
50 return a[0] == b[0] && a[1] == b[1];
54 tuple_hash_2 (gconstpointer v_a)
56 gpointer* a = (gpointer*) v_a;
58 return (gulong)a[0] ^ (gulong)a[1];
62 tuple_hash (gint fields)
69 g_error ("no tuple hash for %d", fields);
76 tuple_equal (gint fields)
83 g_error ("no tuple equal for %d", fields);
90 g_relation_new (gint fields)
92 GRealRelation* rel = g_new0 (GRealRelation, 1);
95 rel->tuple_chunk = g_mem_chunk_new ("Relation Chunk",
96 fields * sizeof (gpointer),
97 fields * sizeof (gpointer) * 128,
99 rel->all_tuples = g_hash_table_new (tuple_hash (fields), tuple_equal (fields));
100 rel->hashed_tuple_tables = g_new0 (GHashTable*, fields);
102 return (GRelation*) rel;
106 g_relation_free_array (gpointer key, gpointer value, gpointer user_data)
108 g_hash_table_destroy ((GHashTable*) value);
112 g_relation_destroy (GRelation *relation)
114 GRealRelation *rel = (GRealRelation *) relation;
119 g_hash_table_destroy (rel->all_tuples);
120 g_mem_chunk_destroy (rel->tuple_chunk);
122 for (i = 0; i < rel->fields; i += 1)
124 if (rel->hashed_tuple_tables[i])
126 g_hash_table_foreach (rel->hashed_tuple_tables[i], g_relation_free_array, NULL);
127 g_hash_table_destroy (rel->hashed_tuple_tables[i]);
131 g_free (rel->hashed_tuple_tables);
137 g_relation_index (GRelation *relation,
140 GCompareFunc key_compare_func)
142 GRealRelation *rel = (GRealRelation *) relation;
144 g_assert (rel->count == 0 && rel->hashed_tuple_tables[field] == NULL);
146 rel->hashed_tuple_tables[field] = g_hash_table_new (hash_func, key_compare_func);
150 g_relation_insert (GRelation *relation,
153 GRealRelation *rel = (GRealRelation *) relation;
154 gpointer* tuple = g_chunk_new (gpointer, rel->tuple_chunk);
158 va_start(args, relation);
160 for (i = 0; i < rel->fields; i += 1)
161 tuple[i] = va_arg(args, gpointer);
165 g_hash_table_insert (rel->all_tuples, tuple, tuple);
169 for (i = 0; i < rel->fields; i += 1)
173 GHashTable *per_key_table;
175 table = rel->hashed_tuple_tables[i];
181 per_key_table = g_hash_table_lookup (table, key);
183 if (per_key_table == NULL)
185 per_key_table = g_hash_table_new (tuple_hash (rel->fields), tuple_equal (rel->fields));
186 g_hash_table_insert (table, key, per_key_table);
189 g_hash_table_insert (per_key_table, tuple, tuple);
194 g_relation_delete_tuple (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
196 gpointer *tuple = (gpointer*) tuple_value;
197 GRealRelation *rel = (GRealRelation *) user_data;
200 g_assert (tuple_key == tuple_value);
202 for (j = 0; j < rel->fields; j += 1)
204 GHashTable *one_table = rel->hashed_tuple_tables[j];
206 GHashTable *per_key_table;
208 if (one_table == NULL)
211 if (j == rel->current_field)
212 /* can't delete from the table we're foreaching in */
217 per_key_table = g_hash_table_lookup (one_table, one_key);
219 g_hash_table_remove (per_key_table, tuple);
222 g_hash_table_remove (rel->all_tuples, tuple);
228 g_relation_delete (GRelation *relation,
232 GRealRelation *rel = (GRealRelation *) relation;
233 GHashTable *table = rel->hashed_tuple_tables[field];
234 GHashTable *key_table;
235 gint count = rel->count;
239 key_table = g_hash_table_lookup (table, key);
244 rel->current_field = field;
246 g_hash_table_foreach (key_table, g_relation_delete_tuple, rel);
248 g_hash_table_remove (table, key);
250 g_hash_table_destroy (key_table);
252 /* @@@ Remove empty hash tables. */
254 return count - rel->count;
258 g_relation_select_tuple (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
260 gpointer *tuple = (gpointer*) tuple_value;
261 GRealTuples *tuples = (GRealTuples*) user_data;
262 gint stride = sizeof (gpointer) * tuples->width;
264 g_assert (tuple_key == tuple_value);
266 memcpy (tuples->data + (tuples->len * tuples->width),
274 g_relation_select (GRelation *relation,
278 GRealRelation *rel = (GRealRelation *) relation;
279 GHashTable *table = rel->hashed_tuple_tables[field];
280 GHashTable *key_table;
281 GRealTuples *tuples = g_new0 (GRealTuples, 1);
286 key_table = g_hash_table_lookup (table, key);
289 return (GTuples*)tuples;
291 count = g_relation_count (relation, key, field);
293 tuples->data = g_malloc (sizeof (gpointer) * rel->fields * count);
294 tuples->width = rel->fields;
296 g_hash_table_foreach (key_table, g_relation_select_tuple, tuples);
298 g_assert (count == tuples->len);
300 return (GTuples*)tuples;
304 g_relation_count (GRelation *relation,
308 GRealRelation *rel = (GRealRelation *) relation;
309 GHashTable *table = rel->hashed_tuple_tables[field];
310 GHashTable *key_table;
314 key_table = g_hash_table_lookup (table, key);
319 return g_hash_table_size (key_table);
323 g_relation_exists (GRelation *relation, ...)
325 GRealRelation *rel = (GRealRelation *) relation;
326 gpointer* tuple = g_chunk_new (gpointer, rel->tuple_chunk);
331 va_start(args, relation);
333 for (i = 0; i < rel->fields; i += 1)
334 tuple[i] = va_arg(args, gpointer);
338 result = g_hash_table_lookup (rel->all_tuples, tuple) != NULL;
340 g_mem_chunk_free (rel->tuple_chunk, tuple);
346 g_tuples_destroy (GTuples *tuples0)
348 GRealTuples *tuples = (GRealTuples*) tuples0;
352 g_free (tuples->data);
358 g_tuples_index (GTuples *tuples0,
362 GRealTuples *tuples = (GRealTuples*) tuples0;
364 g_assert (field < tuples->width);
366 return tuples->data[index * tuples->width + field];
373 g_relation_print_one (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
376 GRealRelation* rel = (GRealRelation*) user_data;
377 gpointer* tuples = (gpointer*) tuple_value;
381 for (i = 0; i < rel->fields; i += 1)
383 g_print ("%p", tuples[i]);
385 if (i < (rel->fields - 1))
393 g_relation_print_index (gpointer tuple_key, gpointer tuple_value, gpointer user_data)
395 GRealRelation* rel = (GRealRelation*) user_data;
396 GHashTable* table = (GHashTable*) tuple_value;
398 g_print ("*** key %p\n", tuple_key);
400 g_hash_table_foreach (table,
401 g_relation_print_one,
406 g_relation_print (GRelation *relation)
409 GRealRelation* rel = (GRealRelation*) relation;
411 g_print ("*** all tuples (%d)\n", rel->count);
413 g_hash_table_foreach (rel->all_tuples,
414 g_relation_print_one,
417 for (i = 0; i < rel->fields; i += 1)
419 if (rel->hashed_tuple_tables[i] == NULL)
422 g_print ("*** index %d\n", i);
424 g_hash_table_foreach (rel->hashed_tuple_tables[i],
425 g_relation_print_index,