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.
20 * Modified by the GLib Team and others 1997-1999. 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 typedef struct _GRealRelation GRealRelation
;
35 typedef struct _GRealTuples GRealTuples
;
42 GHashTable
*all_tuples
;
43 GHashTable
**hashed_tuple_tables
;
44 GMemChunk
*tuple_chunk
;
57 tuple_equal_2 (gconstpointer v_a
,
60 gpointer
* a
= (gpointer
*) v_a
;
61 gpointer
* b
= (gpointer
*) v_b
;
63 return a
[0] == b
[0] && a
[1] == b
[1];
67 tuple_hash_2 (gconstpointer v_a
)
69 gpointer
* a
= (gpointer
*) v_a
;
71 return (gulong
)a
[0] ^ (gulong
)a
[1];
75 tuple_hash (gint fields
)
82 g_error ("no tuple hash for %d", fields
);
89 tuple_equal (gint fields
)
96 g_error ("no tuple equal for %d", fields
);
103 g_relation_new (gint fields
)
105 GRealRelation
* rel
= g_new0 (GRealRelation
, 1);
107 rel
->fields
= fields
;
108 rel
->tuple_chunk
= g_mem_chunk_new ("Relation Chunk",
109 fields
* sizeof (gpointer
),
110 fields
* sizeof (gpointer
) * 128,
112 rel
->all_tuples
= g_hash_table_new (tuple_hash (fields
), tuple_equal (fields
));
113 rel
->hashed_tuple_tables
= g_new0 (GHashTable
*, fields
);
115 return (GRelation
*) rel
;
119 g_relation_free_array (gpointer key
, gpointer value
, gpointer user_data
)
121 g_hash_table_destroy ((GHashTable
*) value
);
125 g_relation_destroy (GRelation
*relation
)
127 GRealRelation
*rel
= (GRealRelation
*) relation
;
132 g_hash_table_destroy (rel
->all_tuples
);
133 g_mem_chunk_destroy (rel
->tuple_chunk
);
135 for (i
= 0; i
< rel
->fields
; i
+= 1)
137 if (rel
->hashed_tuple_tables
[i
])
139 g_hash_table_foreach (rel
->hashed_tuple_tables
[i
], g_relation_free_array
, NULL
);
140 g_hash_table_destroy (rel
->hashed_tuple_tables
[i
]);
144 g_free (rel
->hashed_tuple_tables
);
150 g_relation_index (GRelation
*relation
,
153 GCompareFunc key_compare_func
)
155 GRealRelation
*rel
= (GRealRelation
*) relation
;
157 g_return_if_fail (relation
!= NULL
);
159 g_return_if_fail (rel
->count
== 0 && rel
->hashed_tuple_tables
[field
] == NULL
);
161 rel
->hashed_tuple_tables
[field
] = g_hash_table_new (hash_func
, key_compare_func
);
165 g_relation_insert (GRelation
*relation
,
168 GRealRelation
*rel
= (GRealRelation
*) relation
;
169 gpointer
* tuple
= g_chunk_new (gpointer
, rel
->tuple_chunk
);
173 va_start(args
, relation
);
175 for (i
= 0; i
< rel
->fields
; i
+= 1)
176 tuple
[i
] = va_arg(args
, gpointer
);
180 g_hash_table_insert (rel
->all_tuples
, tuple
, tuple
);
184 for (i
= 0; i
< rel
->fields
; i
+= 1)
188 GHashTable
*per_key_table
;
190 table
= rel
->hashed_tuple_tables
[i
];
196 per_key_table
= g_hash_table_lookup (table
, key
);
198 if (per_key_table
== NULL
)
200 per_key_table
= g_hash_table_new (tuple_hash (rel
->fields
), tuple_equal (rel
->fields
));
201 g_hash_table_insert (table
, key
, per_key_table
);
204 g_hash_table_insert (per_key_table
, tuple
, tuple
);
209 g_relation_delete_tuple (gpointer tuple_key
,
210 gpointer tuple_value
,
213 gpointer
*tuple
= (gpointer
*) tuple_value
;
214 GRealRelation
*rel
= (GRealRelation
*) user_data
;
217 g_assert (tuple_key
== tuple_value
);
219 for (j
= 0; j
< rel
->fields
; j
+= 1)
221 GHashTable
*one_table
= rel
->hashed_tuple_tables
[j
];
223 GHashTable
*per_key_table
;
225 if (one_table
== NULL
)
228 if (j
== rel
->current_field
)
229 /* can't delete from the table we're foreaching in */
234 per_key_table
= g_hash_table_lookup (one_table
, one_key
);
236 g_hash_table_remove (per_key_table
, tuple
);
239 g_hash_table_remove (rel
->all_tuples
, tuple
);
245 g_relation_delete (GRelation
*relation
,
249 GRealRelation
*rel
= (GRealRelation
*) relation
;
250 GHashTable
*table
= rel
->hashed_tuple_tables
[field
];
251 GHashTable
*key_table
;
252 gint count
= rel
->count
;
254 g_return_val_if_fail (relation
!= NULL
, 0);
255 g_return_val_if_fail (table
!= NULL
, 0);
257 key_table
= g_hash_table_lookup (table
, key
);
262 rel
->current_field
= field
;
264 g_hash_table_foreach (key_table
, g_relation_delete_tuple
, rel
);
266 g_hash_table_remove (table
, key
);
268 g_hash_table_destroy (key_table
);
270 /* @@@ FIXME: Remove empty hash tables. */
272 return count
- rel
->count
;
276 g_relation_select_tuple (gpointer tuple_key
,
277 gpointer tuple_value
,
280 gpointer
*tuple
= (gpointer
*) tuple_value
;
281 GRealTuples
*tuples
= (GRealTuples
*) user_data
;
282 gint stride
= sizeof (gpointer
) * tuples
->width
;
284 g_assert (tuple_key
== tuple_value
);
286 memcpy (tuples
->data
+ (tuples
->len
* tuples
->width
),
294 g_relation_select (GRelation
*relation
,
298 GRealRelation
*rel
= (GRealRelation
*) relation
;
299 GHashTable
*table
= rel
->hashed_tuple_tables
[field
];
300 GHashTable
*key_table
;
301 GRealTuples
*tuples
= g_new0 (GRealTuples
, 1);
304 g_return_val_if_fail (relation
!= NULL
, NULL
);
305 g_return_val_if_fail (table
!= NULL
, NULL
);
307 key_table
= g_hash_table_lookup (table
, key
);
310 return (GTuples
*)tuples
;
312 count
= g_relation_count (relation
, key
, field
);
314 tuples
->data
= g_malloc (sizeof (gpointer
) * rel
->fields
* count
);
315 tuples
->width
= rel
->fields
;
317 g_hash_table_foreach (key_table
, g_relation_select_tuple
, tuples
);
319 g_assert (count
== tuples
->len
);
321 return (GTuples
*)tuples
;
325 g_relation_count (GRelation
*relation
,
329 GRealRelation
*rel
= (GRealRelation
*) relation
;
330 GHashTable
*table
= rel
->hashed_tuple_tables
[field
];
331 GHashTable
*key_table
;
333 g_return_val_if_fail (relation
!= NULL
, 0);
334 g_return_val_if_fail (table
!= NULL
, 0);
336 key_table
= g_hash_table_lookup (table
, key
);
341 return g_hash_table_size (key_table
);
345 g_relation_exists (GRelation
*relation
, ...)
347 GRealRelation
*rel
= (GRealRelation
*) relation
;
348 gpointer
* tuple
= g_chunk_new (gpointer
, rel
->tuple_chunk
);
353 va_start(args
, relation
);
355 for (i
= 0; i
< rel
->fields
; i
+= 1)
356 tuple
[i
] = va_arg(args
, gpointer
);
360 result
= g_hash_table_lookup (rel
->all_tuples
, tuple
) != NULL
;
362 g_mem_chunk_free (rel
->tuple_chunk
, tuple
);
368 g_tuples_destroy (GTuples
*tuples0
)
370 GRealTuples
*tuples
= (GRealTuples
*) tuples0
;
374 g_free (tuples
->data
);
380 g_tuples_index (GTuples
*tuples0
,
384 GRealTuples
*tuples
= (GRealTuples
*) tuples0
;
386 g_return_val_if_fail (tuples0
!= NULL
, NULL
);
387 g_return_val_if_fail (field
< tuples
->width
, NULL
);
389 return tuples
->data
[index
* tuples
->width
+ field
];
396 g_relation_print_one (gpointer tuple_key
,
397 gpointer tuple_value
,
402 GRealRelation
* rel
= (GRealRelation
*) user_data
;
403 gpointer
* tuples
= (gpointer
*) tuple_value
;
405 gstring
= g_string_new ("[");
407 for (i
= 0; i
< rel
->fields
; i
+= 1)
409 g_string_sprintfa (gstring
, "%p", tuples
[i
]);
411 if (i
< (rel
->fields
- 1))
412 g_string_append (gstring
, ",");
415 g_string_append (gstring
, "]");
416 g_log (g_log_domain_glib
, G_LOG_LEVEL_INFO
, gstring
->str
);
417 g_string_free (gstring
, TRUE
);
421 g_relation_print_index (gpointer tuple_key
,
422 gpointer tuple_value
,
425 GRealRelation
* rel
= (GRealRelation
*) user_data
;
426 GHashTable
* table
= (GHashTable
*) tuple_value
;
428 g_log (g_log_domain_glib
, G_LOG_LEVEL_INFO
, "*** key %p", tuple_key
);
430 g_hash_table_foreach (table
,
431 g_relation_print_one
,
436 g_relation_print (GRelation
*relation
)
439 GRealRelation
* rel
= (GRealRelation
*) relation
;
441 g_log (g_log_domain_glib
, G_LOG_LEVEL_INFO
, "*** all tuples (%d)", rel
->count
);
443 g_hash_table_foreach (rel
->all_tuples
,
444 g_relation_print_one
,
447 for (i
= 0; i
< rel
->fields
; i
+= 1)
449 if (rel
->hashed_tuple_tables
[i
] == NULL
)
452 g_log (g_log_domain_glib
, G_LOG_LEVEL_INFO
, "*** index %d", i
);
454 g_hash_table_foreach (rel
->hashed_tuple_tables
[i
],
455 g_relation_print_index
,