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/.
39 typedef struct _GRealTuples GRealTuples
;
46 GHashTable
*all_tuples
;
47 GHashTable
**hashed_tuple_tables
;
60 tuple_equal_2 (gconstpointer v_a
,
63 gpointer
* a
= (gpointer
*) v_a
;
64 gpointer
* b
= (gpointer
*) v_b
;
66 return a
[0] == b
[0] && a
[1] == b
[1];
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
77 guint
* a
= (guint
*) v_a
;
79 return (a
[0] ^ a
[1] ^ a
[2] ^ a
[3]);
81 gpointer
* a
= (gpointer
*) v_a
;
83 return (gulong
)a
[0] ^ (gulong
)a
[1];
88 tuple_hash (gint fields
)
95 g_error ("no tuple hash for %d", fields
);
102 tuple_equal (gint fields
)
107 return tuple_equal_2
;
109 g_error ("no tuple equal for %d", fields
);
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
);
128 relation_delete_value_tuple (gpointer tuple_key
,
129 gpointer tuple_value
,
132 GRelation
*relation
= user_data
;
133 gpointer
*tuple
= tuple_value
;
134 g_slice_free1 (relation
->fields
* sizeof (gpointer
), tuple
);
138 g_relation_free_array (gpointer key
, gpointer value
, gpointer user_data
)
140 g_hash_table_destroy ((GHashTable
*) value
);
144 g_relation_destroy (GRelation
*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
);
168 g_relation_index (GRelation
*relation
,
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
);
181 g_relation_insert (GRelation
*relation
,
184 gpointer
* tuple
= g_slice_alloc (relation
->fields
* sizeof (gpointer
));
188 va_start (args
, relation
);
190 for (i
= 0; i
< relation
->fields
; i
+= 1)
191 tuple
[i
] = va_arg (args
, gpointer
);
195 g_hash_table_insert (relation
->all_tuples
, tuple
, tuple
);
197 relation
->count
+= 1;
199 for (i
= 0; i
< relation
->fields
; i
+= 1)
203 GHashTable
*per_key_table
;
205 table
= relation
->hashed_tuple_tables
[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
);
224 g_relation_delete_tuple (gpointer tuple_key
,
225 gpointer tuple_value
,
228 gpointer
*tuple
= (gpointer
*) tuple_value
;
229 GRelation
*relation
= (GRelation
*) user_data
;
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
];
238 GHashTable
*per_key_table
;
240 if (one_table
== NULL
)
243 if (j
== relation
->current_field
)
244 /* can't delete from the table we're foreaching in */
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;
261 g_relation_delete (GRelation
*relation
,
266 GHashTable
*key_table
;
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
);
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
;
295 g_relation_select_tuple (gpointer tuple_key
,
296 gpointer tuple_value
,
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
),
313 g_relation_select (GRelation
*relation
,
318 GHashTable
*key_table
;
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
);
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
;
347 g_relation_count (GRelation
*relation
,
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
);
365 return g_hash_table_size (key_table
);
369 g_relation_exists (GRelation
*relation
, ...)
371 gpointer
*tuple
= g_slice_alloc (relation
->fields
* sizeof (gpointer
));
376 va_start(args
, relation
);
378 for (i
= 0; i
< relation
->fields
; i
+= 1)
379 tuple
[i
] = va_arg(args
, gpointer
);
383 result
= g_hash_table_lookup (relation
->all_tuples
, tuple
) != NULL
;
385 g_slice_free1 (relation
->fields
* sizeof (gpointer
), tuple
);
391 g_tuples_destroy (GTuples
*tuples0
)
393 GRealTuples
*tuples
= (GRealTuples
*) tuples0
;
397 g_free (tuples
->data
);
403 g_tuples_index (GTuples
*tuples0
,
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
];
419 g_relation_print_one (gpointer tuple_key
,
420 gpointer tuple_value
,
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
);
444 g_relation_print_index (gpointer tuple_key
,
445 gpointer tuple_value
,
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
,
459 g_relation_print (GRelation
*relation
)
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
,
469 for (i
= 0; i
< relation
->fields
; i
+= 1)
471 if (relation
->hashed_tuple_tables
[i
] == NULL
)
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
,
484 #include "galiasdef.c"