Updates
[glib.git] / glib / grel.c
blobb6ee65110565bb86e32c9a84eefe1ad221002505
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/.
26 /*
27 * MT safe
30 #include "config.h"
32 #include <stdarg.h>
33 #include <string.h>
35 #include "glib.h"
36 #include "galias.h"
39 typedef struct _GRealTuples GRealTuples;
41 struct _GRelation
43 gint fields;
44 gint current_field;
46 GHashTable *all_tuples;
47 GHashTable **hashed_tuple_tables;
49 gint count;
52 struct _GRealTuples
54 gint len;
55 gint width;
56 gpointer *data;
59 static gboolean
60 tuple_equal_2 (gconstpointer v_a,
61 gconstpointer v_b)
63 gpointer* a = (gpointer*) v_a;
64 gpointer* b = (gpointer*) v_b;
66 return a[0] == b[0] && a[1] == b[1];
69 static guint
70 tuple_hash_2 (gconstpointer v_a)
72 #if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG
73 /* In practise this snippet has been written for 64-bit Windows
74 * where ints are 32 bits, pointers 64 bits. More exotic platforms
75 * need more tweaks.
77 guint* a = (guint*) v_a;
79 return (a[0] ^ a[1] ^ a[2] ^ a[3]);
80 #else
81 gpointer* a = (gpointer*) v_a;
83 return (gulong)a[0] ^ (gulong)a[1];
84 #endif
87 static GHashFunc
88 tuple_hash (gint fields)
90 switch (fields)
92 case 2:
93 return tuple_hash_2;
94 default:
95 g_error ("no tuple hash for %d", fields);
98 return NULL;
101 static GEqualFunc
102 tuple_equal (gint fields)
104 switch (fields)
106 case 2:
107 return tuple_equal_2;
108 default:
109 g_error ("no tuple equal for %d", fields);
112 return NULL;
115 GRelation*
116 g_relation_new (gint fields)
118 GRelation* rel = g_new0 (GRelation, 1);
120 rel->fields = fields;
121 rel->all_tuples = g_hash_table_new (tuple_hash (fields), tuple_equal (fields));
122 rel->hashed_tuple_tables = g_new0 (GHashTable*, fields);
124 return rel;
127 static void
128 relation_delete_value_tuple (gpointer tuple_key,
129 gpointer tuple_value,
130 gpointer user_data)
132 GRelation *relation = user_data;
133 gpointer *tuple = tuple_value;
134 g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
137 static void
138 g_relation_free_array (gpointer key, gpointer value, gpointer user_data)
140 g_hash_table_destroy ((GHashTable*) value);
143 void
144 g_relation_destroy (GRelation *relation)
146 gint i;
148 if (relation)
150 for (i = 0; i < relation->fields; i += 1)
152 if (relation->hashed_tuple_tables[i])
154 g_hash_table_foreach (relation->hashed_tuple_tables[i], g_relation_free_array, NULL);
155 g_hash_table_destroy (relation->hashed_tuple_tables[i]);
159 g_hash_table_foreach (relation->all_tuples, relation_delete_value_tuple, relation);
160 g_hash_table_destroy (relation->all_tuples);
162 g_free (relation->hashed_tuple_tables);
163 g_free (relation);
167 void
168 g_relation_index (GRelation *relation,
169 gint field,
170 GHashFunc hash_func,
171 GEqualFunc key_equal_func)
173 g_return_if_fail (relation != NULL);
175 g_return_if_fail (relation->count == 0 && relation->hashed_tuple_tables[field] == NULL);
177 relation->hashed_tuple_tables[field] = g_hash_table_new (hash_func, key_equal_func);
180 void
181 g_relation_insert (GRelation *relation,
182 ...)
184 gpointer* tuple = g_slice_alloc (relation->fields * sizeof (gpointer));
185 va_list args;
186 gint i;
188 va_start (args, relation);
190 for (i = 0; i < relation->fields; i += 1)
191 tuple[i] = va_arg (args, gpointer);
193 va_end (args);
195 g_hash_table_insert (relation->all_tuples, tuple, tuple);
197 relation->count += 1;
199 for (i = 0; i < relation->fields; i += 1)
201 GHashTable *table;
202 gpointer key;
203 GHashTable *per_key_table;
205 table = relation->hashed_tuple_tables[i];
207 if (table == NULL)
208 continue;
210 key = tuple[i];
211 per_key_table = g_hash_table_lookup (table, key);
213 if (per_key_table == NULL)
215 per_key_table = g_hash_table_new (tuple_hash (relation->fields), tuple_equal (relation->fields));
216 g_hash_table_insert (table, key, per_key_table);
219 g_hash_table_insert (per_key_table, tuple, tuple);
223 static void
224 g_relation_delete_tuple (gpointer tuple_key,
225 gpointer tuple_value,
226 gpointer user_data)
228 gpointer *tuple = (gpointer*) tuple_value;
229 GRelation *relation = (GRelation *) user_data;
230 gint j;
232 g_assert (tuple_key == tuple_value);
234 for (j = 0; j < relation->fields; j += 1)
236 GHashTable *one_table = relation->hashed_tuple_tables[j];
237 gpointer one_key;
238 GHashTable *per_key_table;
240 if (one_table == NULL)
241 continue;
243 if (j == relation->current_field)
244 /* can't delete from the table we're foreaching in */
245 continue;
247 one_key = tuple[j];
249 per_key_table = g_hash_table_lookup (one_table, one_key);
251 g_hash_table_remove (per_key_table, tuple);
254 if (g_hash_table_remove (relation->all_tuples, tuple))
255 g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
257 relation->count -= 1;
260 gint
261 g_relation_delete (GRelation *relation,
262 gconstpointer key,
263 gint field)
265 GHashTable *table;
266 GHashTable *key_table;
267 gint count;
269 g_return_val_if_fail (relation != NULL, 0);
271 table = relation->hashed_tuple_tables[field];
272 count = relation->count;
274 g_return_val_if_fail (table != NULL, 0);
276 key_table = g_hash_table_lookup (table, key);
278 if (!key_table)
279 return 0;
281 relation->current_field = field;
283 g_hash_table_foreach (key_table, g_relation_delete_tuple, relation);
285 g_hash_table_remove (table, key);
287 g_hash_table_destroy (key_table);
289 /* @@@ FIXME: Remove empty hash tables. */
291 return count - relation->count;
294 static void
295 g_relation_select_tuple (gpointer tuple_key,
296 gpointer tuple_value,
297 gpointer user_data)
299 gpointer *tuple = (gpointer*) tuple_value;
300 GRealTuples *tuples = (GRealTuples*) user_data;
301 gint stride = sizeof (gpointer) * tuples->width;
303 g_assert (tuple_key == tuple_value);
305 memcpy (tuples->data + (tuples->len * tuples->width),
306 tuple,
307 stride);
309 tuples->len += 1;
312 GTuples*
313 g_relation_select (GRelation *relation,
314 gconstpointer key,
315 gint field)
317 GHashTable *table;
318 GHashTable *key_table;
319 GRealTuples *tuples;
320 gint count;
322 g_return_val_if_fail (relation != NULL, NULL);
324 table = relation->hashed_tuple_tables[field];
326 g_return_val_if_fail (table != NULL, NULL);
328 tuples = g_new0 (GRealTuples, 1);
329 key_table = g_hash_table_lookup (table, key);
331 if (!key_table)
332 return (GTuples*)tuples;
334 count = g_relation_count (relation, key, field);
336 tuples->data = g_malloc (sizeof (gpointer) * relation->fields * count);
337 tuples->width = relation->fields;
339 g_hash_table_foreach (key_table, g_relation_select_tuple, tuples);
341 g_assert (count == tuples->len);
343 return (GTuples*)tuples;
346 gint
347 g_relation_count (GRelation *relation,
348 gconstpointer key,
349 gint field)
351 GHashTable *table;
352 GHashTable *key_table;
354 g_return_val_if_fail (relation != NULL, 0);
356 table = relation->hashed_tuple_tables[field];
358 g_return_val_if_fail (table != NULL, 0);
360 key_table = g_hash_table_lookup (table, key);
362 if (!key_table)
363 return 0;
365 return g_hash_table_size (key_table);
368 gboolean
369 g_relation_exists (GRelation *relation, ...)
371 gpointer *tuple = g_slice_alloc (relation->fields * sizeof (gpointer));
372 va_list args;
373 gint i;
374 gboolean result;
376 va_start(args, relation);
378 for (i = 0; i < relation->fields; i += 1)
379 tuple[i] = va_arg(args, gpointer);
381 va_end(args);
383 result = g_hash_table_lookup (relation->all_tuples, tuple) != NULL;
385 g_slice_free1 (relation->fields * sizeof (gpointer), tuple);
387 return result;
390 void
391 g_tuples_destroy (GTuples *tuples0)
393 GRealTuples *tuples = (GRealTuples*) tuples0;
395 if (tuples)
397 g_free (tuples->data);
398 g_free (tuples);
402 gpointer
403 g_tuples_index (GTuples *tuples0,
404 gint index,
405 gint field)
407 GRealTuples *tuples = (GRealTuples*) tuples0;
409 g_return_val_if_fail (tuples0 != NULL, NULL);
410 g_return_val_if_fail (field < tuples->width, NULL);
412 return tuples->data[index * tuples->width + field];
415 /* Print
418 static void
419 g_relation_print_one (gpointer tuple_key,
420 gpointer tuple_value,
421 gpointer user_data)
423 gint i;
424 GString *gstring;
425 GRelation* rel = (GRelation*) user_data;
426 gpointer* tuples = (gpointer*) tuple_value;
428 gstring = g_string_new ("[");
430 for (i = 0; i < rel->fields; i += 1)
432 g_string_append_printf (gstring, "%p", tuples[i]);
434 if (i < (rel->fields - 1))
435 g_string_append (gstring, ",");
438 g_string_append (gstring, "]");
439 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s", gstring->str);
440 g_string_free (gstring, TRUE);
443 static void
444 g_relation_print_index (gpointer tuple_key,
445 gpointer tuple_value,
446 gpointer user_data)
448 GRelation* rel = (GRelation*) user_data;
449 GHashTable* table = (GHashTable*) tuple_value;
451 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** key %p", tuple_key);
453 g_hash_table_foreach (table,
454 g_relation_print_one,
455 rel);
458 void
459 g_relation_print (GRelation *relation)
461 gint i;
463 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** all tuples (%d)", relation->count);
465 g_hash_table_foreach (relation->all_tuples,
466 g_relation_print_one,
467 relation);
469 for (i = 0; i < relation->fields; i += 1)
471 if (relation->hashed_tuple_tables[i] == NULL)
472 continue;
474 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** index %d", i);
476 g_hash_table_foreach (relation->hashed_tuple_tables[i],
477 g_relation_print_index,
478 relation);
483 #define __G_REL_C__
484 #include "galiasdef.c"