/src/gstreamer/subprojects/glib-2.86.3/glib/deprecated/grel.c
Line | Count | Source |
1 | | /* GLIB - Library of useful routines for C programming |
2 | | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free |
18 | | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | | */ |
20 | | |
21 | | /* |
22 | | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
23 | | * file for a list of people on the GLib Team. See the ChangeLog |
24 | | * files for a list of changes. These files are distributed with |
25 | | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
26 | | */ |
27 | | |
28 | | /* |
29 | | * MT safe |
30 | | */ |
31 | | |
32 | | #include "config.h" |
33 | | |
34 | | /* we know we are deprecated here, no need for warnings */ |
35 | | #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS |
36 | | #define GLIB_DISABLE_DEPRECATION_WARNINGS |
37 | | #endif |
38 | | |
39 | | #include "grel.h" |
40 | | |
41 | | #include <glib/gmessages.h> |
42 | | #include <glib/gtestutils.h> |
43 | | #include <glib/gstring.h> |
44 | | #include <glib/gslice.h> |
45 | | #include <glib/ghash.h> |
46 | | |
47 | | #include <stdarg.h> |
48 | | #include <string.h> |
49 | | |
50 | | /** |
51 | | * GRelation: |
52 | | * |
53 | | * A `GRelation` is a table of data which can be indexed on any number |
54 | | * of fields, rather like simple database tables. A `GRelation` contains |
55 | | * a number of records, called tuples. Each record contains a number of |
56 | | * fields. Records are not ordered, so it is not possible to find the |
57 | | * record at a particular index. |
58 | | * |
59 | | * Note that `GRelation` tables are currently limited to 2 fields. |
60 | | * |
61 | | * To create a `GRelation`, use [func@GLib.Relation.new]. |
62 | | * |
63 | | * To specify which fields should be indexed, use [method@GLib.Relation.index]. |
64 | | * Note that this must be called before any tuples are added to the |
65 | | * `GRelation`. |
66 | | * |
67 | | * To add records to a `GRelation` use [method@GLib.Relation.insert]. |
68 | | * |
69 | | * To determine if a given record appears in a `GRelation`, use |
70 | | * [method@GLib.Relation.exists]. Note that fields are compared directly, so |
71 | | * pointers must point to the exact same position (i.e. different |
72 | | * copies of the same string will not match.) |
73 | | * |
74 | | * To count the number of records which have a particular value in a |
75 | | * given field, use [method@GLib.Relation.count]. |
76 | | * |
77 | | * To get all the records which have a particular value in a given |
78 | | * field, use [method@GLib.Relation.select]. To access fields of the resulting |
79 | | * records, use [method@GLib.Tuples.index]. To free the resulting records use |
80 | | * [method@GLib.Tuples.destroy]. |
81 | | * |
82 | | * To delete all records which have a particular value in a given |
83 | | * field, use [method@GLib.Relation.delete]. |
84 | | * |
85 | | * To destroy the `GRelation`, use [method@GLib.Relation.destroy]. |
86 | | * |
87 | | * To help debug `GRelation` objects, use [method@GLib.Relation.print]. |
88 | | * |
89 | | * `GRelation` has been marked as deprecated, since this API has never |
90 | | * been fully implemented, is not very actively maintained and rarely |
91 | | * used. |
92 | | * |
93 | | * Deprecated: 2.26: Rarely used API |
94 | | **/ |
95 | | |
96 | | typedef struct _GRealTuples GRealTuples; |
97 | | |
98 | | struct _GRelation |
99 | | { |
100 | | size_t fields; |
101 | | size_t current_field; |
102 | | |
103 | | GHashTable *all_tuples; |
104 | | GHashTable **hashed_tuple_tables; |
105 | | |
106 | | size_t count; |
107 | | }; |
108 | | |
109 | | static size_t relation_count_internal (GRelation *relation, |
110 | | gconstpointer key, |
111 | | size_t field); |
112 | | |
113 | | /** |
114 | | * GTuples: |
115 | | * @len: the number of records that matched. |
116 | | * |
117 | | * The #GTuples struct is used to return records (or tuples) from the |
118 | | * #GRelation by g_relation_select(). It only contains one public |
119 | | * member - the number of records that matched. To access the matched |
120 | | * records, you must use g_tuples_index(). |
121 | | * |
122 | | * Deprecated: 2.26: Rarely used API |
123 | | **/ |
124 | | struct _GRealTuples |
125 | | { |
126 | | guint len; |
127 | | size_t width; |
128 | | gpointer *data; |
129 | | }; |
130 | | |
131 | | static gboolean |
132 | | tuple_equal_2 (gconstpointer v_a, |
133 | | gconstpointer v_b) |
134 | 0 | { |
135 | 0 | gpointer* a = (gpointer*) v_a; |
136 | 0 | gpointer* b = (gpointer*) v_b; |
137 | | |
138 | 0 | return a[0] == b[0] && a[1] == b[1]; |
139 | 0 | } |
140 | | |
141 | | static guint |
142 | | tuple_hash_2 (gconstpointer v_a) |
143 | 0 | { |
144 | | #if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG |
145 | | /* In practise this snippet has been written for 64-bit Windows |
146 | | * where ints are 32 bits, pointers 64 bits. More exotic platforms |
147 | | * need more tweaks. |
148 | | */ |
149 | | guint* a = (guint*) v_a; |
150 | | |
151 | | return (a[0] ^ a[1] ^ a[2] ^ a[3]); |
152 | | #else |
153 | 0 | gpointer* a = (gpointer*) v_a; |
154 | | |
155 | 0 | return (gulong)a[0] ^ (gulong)a[1]; |
156 | 0 | #endif |
157 | 0 | } |
158 | | |
159 | | static GHashFunc |
160 | | tuple_hash (gint fields) |
161 | 0 | { |
162 | 0 | switch (fields) |
163 | 0 | { |
164 | 0 | case 2: |
165 | 0 | return tuple_hash_2; |
166 | 0 | default: |
167 | 0 | g_error ("no tuple hash for %d", fields); |
168 | 0 | } |
169 | | |
170 | 0 | return NULL; |
171 | 0 | } |
172 | | |
173 | | static GEqualFunc |
174 | | tuple_equal (gint fields) |
175 | 0 | { |
176 | 0 | switch (fields) |
177 | 0 | { |
178 | 0 | case 2: |
179 | 0 | return tuple_equal_2; |
180 | 0 | default: |
181 | 0 | g_error ("no tuple equal for %d", fields); |
182 | 0 | } |
183 | | |
184 | 0 | return NULL; |
185 | 0 | } |
186 | | |
187 | | /** |
188 | | * g_relation_new: |
189 | | * @fields: the number of fields. |
190 | | * |
191 | | * Creates a new #GRelation with the given number of fields. Note that |
192 | | * currently the number of fields must be 2. |
193 | | * |
194 | | * Returns: a new #GRelation. |
195 | | * |
196 | | * Deprecated: 2.26: Rarely used API |
197 | | **/ |
198 | | GRelation* |
199 | | g_relation_new (gint fields) |
200 | 0 | { |
201 | 0 | GRelation* rel = g_new0 (GRelation, 1); |
202 | 0 | size_t unsigned_fields; |
203 | | |
204 | 0 | g_return_val_if_fail (fields == 2, NULL); |
205 | | |
206 | 0 | unsigned_fields = (size_t) fields; |
207 | |
|
208 | 0 | rel->fields = unsigned_fields; |
209 | 0 | rel->all_tuples = g_hash_table_new (tuple_hash (unsigned_fields), tuple_equal (unsigned_fields)); |
210 | 0 | rel->hashed_tuple_tables = g_new0 (GHashTable*, unsigned_fields); |
211 | | |
212 | 0 | return rel; |
213 | 0 | } |
214 | | |
215 | | static void |
216 | | relation_delete_value_tuple (gpointer tuple_key, |
217 | | gpointer tuple_value, |
218 | | gpointer user_data) |
219 | 0 | { |
220 | 0 | GRelation *relation = user_data; |
221 | 0 | gpointer *tuple = tuple_value; |
222 | 0 | g_slice_free1 (relation->fields * sizeof (gpointer), tuple); |
223 | 0 | } |
224 | | |
225 | | static void |
226 | | g_relation_free_array (gpointer key, gpointer value, gpointer user_data) |
227 | 0 | { |
228 | 0 | g_hash_table_destroy ((GHashTable*) value); |
229 | 0 | } |
230 | | |
231 | | /** |
232 | | * g_relation_destroy: |
233 | | * @relation: a #GRelation. |
234 | | * |
235 | | * Destroys the #GRelation, freeing all memory allocated. However, it |
236 | | * does not free memory allocated for the tuple data, so you should |
237 | | * free that first if appropriate. |
238 | | * |
239 | | * Deprecated: 2.26: Rarely used API |
240 | | **/ |
241 | | void |
242 | | g_relation_destroy (GRelation *relation) |
243 | 0 | { |
244 | 0 | if (relation) |
245 | 0 | { |
246 | 0 | for (size_t i = 0; i < relation->fields; i += 1) |
247 | 0 | { |
248 | 0 | if (relation->hashed_tuple_tables[i]) |
249 | 0 | { |
250 | 0 | g_hash_table_foreach (relation->hashed_tuple_tables[i], g_relation_free_array, NULL); |
251 | 0 | g_hash_table_destroy (relation->hashed_tuple_tables[i]); |
252 | 0 | } |
253 | 0 | } |
254 | |
|
255 | 0 | g_hash_table_foreach (relation->all_tuples, relation_delete_value_tuple, relation); |
256 | 0 | g_hash_table_destroy (relation->all_tuples); |
257 | | |
258 | 0 | g_free (relation->hashed_tuple_tables); |
259 | 0 | g_free (relation); |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | | /** |
264 | | * g_relation_index: |
265 | | * @relation: a #GRelation. |
266 | | * @field: the field to index, counting from 0. |
267 | | * @hash_func: a function to produce a hash value from the field data. |
268 | | * @key_equal_func: a function to compare two values of the given field. |
269 | | * |
270 | | * Creates an index on the given field. Note that this must be called |
271 | | * before any records are added to the #GRelation. |
272 | | * |
273 | | * Deprecated: 2.26: Rarely used API |
274 | | **/ |
275 | | void |
276 | | g_relation_index (GRelation *relation, |
277 | | gint field, |
278 | | GHashFunc hash_func, |
279 | | GEqualFunc key_equal_func) |
280 | 0 | { |
281 | 0 | g_return_if_fail (relation != NULL); |
282 | | |
283 | 0 | g_return_if_fail (relation->count == 0 && relation->hashed_tuple_tables[field] == NULL); |
284 | | |
285 | 0 | relation->hashed_tuple_tables[field] = g_hash_table_new (hash_func, key_equal_func); |
286 | 0 | } |
287 | | |
288 | | /** |
289 | | * g_relation_insert: |
290 | | * @relation: a #GRelation. |
291 | | * @...: the fields of the record to add. These must match the |
292 | | * number of fields in the #GRelation, and of type #gpointer |
293 | | * or #gconstpointer. |
294 | | * |
295 | | * Inserts a record into a #GRelation. |
296 | | * |
297 | | * Deprecated: 2.26: Rarely used API |
298 | | **/ |
299 | | void |
300 | | g_relation_insert (GRelation *relation, |
301 | | ...) |
302 | 0 | { |
303 | 0 | gpointer* tuple = g_slice_alloc (relation->fields * sizeof (gpointer)); |
304 | 0 | va_list args; |
305 | | |
306 | 0 | va_start (args, relation); |
307 | | |
308 | 0 | for (size_t i = 0; i < relation->fields; i += 1) |
309 | 0 | tuple[i] = va_arg (args, gpointer); |
310 | | |
311 | 0 | va_end (args); |
312 | | |
313 | 0 | g_hash_table_insert (relation->all_tuples, tuple, tuple); |
314 | | |
315 | 0 | relation->count += 1; |
316 | | |
317 | 0 | for (size_t i = 0; i < relation->fields; i += 1) |
318 | 0 | { |
319 | 0 | GHashTable *table; |
320 | 0 | gpointer key; |
321 | 0 | GHashTable *per_key_table; |
322 | | |
323 | 0 | table = relation->hashed_tuple_tables[i]; |
324 | | |
325 | 0 | if (table == NULL) |
326 | 0 | continue; |
327 | | |
328 | 0 | key = tuple[i]; |
329 | 0 | per_key_table = g_hash_table_lookup (table, key); |
330 | | |
331 | 0 | if (per_key_table == NULL) |
332 | 0 | { |
333 | 0 | per_key_table = g_hash_table_new (tuple_hash (relation->fields), tuple_equal (relation->fields)); |
334 | 0 | g_hash_table_insert (table, key, per_key_table); |
335 | 0 | } |
336 | | |
337 | 0 | g_hash_table_insert (per_key_table, tuple, tuple); |
338 | 0 | } |
339 | 0 | } |
340 | | |
341 | | static void |
342 | | g_relation_delete_tuple (gpointer tuple_key, |
343 | | gpointer tuple_value, |
344 | | gpointer user_data) |
345 | 0 | { |
346 | 0 | gpointer *tuple = (gpointer*) tuple_value; |
347 | 0 | GRelation *relation = (GRelation *) user_data; |
348 | | |
349 | 0 | g_assert (tuple_key == tuple_value); |
350 | | |
351 | 0 | for (size_t j = 0; j < relation->fields; j += 1) |
352 | 0 | { |
353 | 0 | GHashTable *one_table = relation->hashed_tuple_tables[j]; |
354 | 0 | gpointer one_key; |
355 | 0 | GHashTable *per_key_table; |
356 | | |
357 | 0 | if (one_table == NULL) |
358 | 0 | continue; |
359 | | |
360 | 0 | if (j == relation->current_field) |
361 | | /* can't delete from the table we're foreaching in */ |
362 | 0 | continue; |
363 | | |
364 | 0 | one_key = tuple[j]; |
365 | | |
366 | 0 | per_key_table = g_hash_table_lookup (one_table, one_key); |
367 | | |
368 | 0 | g_hash_table_remove (per_key_table, tuple); |
369 | 0 | } |
370 | | |
371 | 0 | if (g_hash_table_remove (relation->all_tuples, tuple)) |
372 | 0 | g_slice_free1 (relation->fields * sizeof (gpointer), tuple); |
373 | | |
374 | 0 | relation->count -= 1; |
375 | 0 | } |
376 | | |
377 | | /** |
378 | | * g_relation_delete: |
379 | | * @relation: a #GRelation. |
380 | | * @key: the value to compare with. |
381 | | * @field: the field of each record to match. |
382 | | * |
383 | | * Deletes any records from a #GRelation that have the given key value |
384 | | * in the given field. |
385 | | * |
386 | | * Returns: the number of records deleted. |
387 | | * |
388 | | * Deprecated: 2.26: Rarely used API |
389 | | **/ |
390 | | gint |
391 | | g_relation_delete (GRelation *relation, |
392 | | gconstpointer key, |
393 | | gint field) |
394 | 0 | { |
395 | 0 | GHashTable *table; |
396 | 0 | GHashTable *key_table; |
397 | 0 | size_t count; |
398 | 0 | size_t unsigned_field; |
399 | | |
400 | 0 | g_return_val_if_fail (relation != NULL, 0); |
401 | 0 | g_return_val_if_fail (field >= 0 && (size_t) field < relation->fields, 0); |
402 | | |
403 | 0 | unsigned_field = (size_t) field; |
404 | 0 | table = relation->hashed_tuple_tables[unsigned_field]; |
405 | 0 | count = relation->count; |
406 | |
|
407 | 0 | g_return_val_if_fail (table != NULL, 0); |
408 | | |
409 | 0 | key_table = g_hash_table_lookup (table, key); |
410 | | |
411 | 0 | if (!key_table) |
412 | 0 | return 0; |
413 | | |
414 | 0 | relation->current_field = unsigned_field; |
415 | | |
416 | 0 | g_hash_table_foreach (key_table, g_relation_delete_tuple, relation); |
417 | | |
418 | 0 | g_hash_table_remove (table, key); |
419 | | |
420 | 0 | g_hash_table_destroy (key_table); |
421 | | |
422 | | /* @@@ FIXME: Remove empty hash tables. */ |
423 | | |
424 | 0 | return count - relation->count; |
425 | 0 | } |
426 | | |
427 | | static void |
428 | | g_relation_select_tuple (gpointer tuple_key, |
429 | | gpointer tuple_value, |
430 | | gpointer user_data) |
431 | 0 | { |
432 | 0 | gpointer *tuple = (gpointer*) tuple_value; |
433 | 0 | GRealTuples *tuples = (GRealTuples*) user_data; |
434 | 0 | size_t stride = sizeof (gpointer) * tuples->width; |
435 | | |
436 | 0 | g_assert (tuple_key == tuple_value); |
437 | | |
438 | 0 | memcpy (tuples->data + (tuples->len * tuples->width), |
439 | 0 | tuple, |
440 | 0 | stride); |
441 | | |
442 | 0 | tuples->len += 1; |
443 | 0 | } |
444 | | |
445 | | /** |
446 | | * g_relation_select: |
447 | | * @relation: a #GRelation. |
448 | | * @key: the value to compare with. |
449 | | * @field: the field of each record to match. |
450 | | * |
451 | | * Returns all of the tuples which have the given key in the given |
452 | | * field. Use g_tuples_index() to access the returned records. The |
453 | | * returned records should be freed with g_tuples_destroy(). |
454 | | * |
455 | | * Returns: the records (tuples) that matched. |
456 | | * |
457 | | * Deprecated: 2.26: Rarely used API |
458 | | **/ |
459 | | GTuples* |
460 | | g_relation_select (GRelation *relation, |
461 | | gconstpointer key, |
462 | | gint field) |
463 | 0 | { |
464 | 0 | GHashTable *table; |
465 | 0 | GHashTable *key_table; |
466 | 0 | GRealTuples *tuples; |
467 | 0 | size_t count; |
468 | 0 | size_t unsigned_field; |
469 | | |
470 | 0 | g_return_val_if_fail (relation != NULL, NULL); |
471 | 0 | g_return_val_if_fail (field >= 0 && (size_t) field < relation->fields, NULL); |
472 | | |
473 | 0 | unsigned_field = (size_t) field; |
474 | 0 | table = relation->hashed_tuple_tables[unsigned_field]; |
475 | |
|
476 | 0 | g_return_val_if_fail (table != NULL, NULL); |
477 | | |
478 | 0 | tuples = g_new0 (GRealTuples, 1); |
479 | 0 | key_table = g_hash_table_lookup (table, key); |
480 | | |
481 | 0 | if (!key_table) |
482 | 0 | return (GTuples*)tuples; |
483 | | |
484 | 0 | count = relation_count_internal (relation, key, unsigned_field); |
485 | | |
486 | 0 | tuples->data = g_malloc (sizeof (gpointer) * relation->fields * count); |
487 | 0 | tuples->width = relation->fields; |
488 | | |
489 | 0 | g_hash_table_foreach (key_table, g_relation_select_tuple, tuples); |
490 | | |
491 | 0 | g_assert (count == (size_t) tuples->len); |
492 | | |
493 | 0 | return (GTuples*)tuples; |
494 | 0 | } |
495 | | |
496 | | static size_t |
497 | | relation_count_internal (GRelation *relation, |
498 | | gconstpointer key, |
499 | | size_t field) |
500 | 0 | { |
501 | 0 | GHashTable *table; |
502 | 0 | GHashTable *key_table; |
503 | |
|
504 | 0 | g_return_val_if_fail (relation != NULL, 0); |
505 | 0 | g_return_val_if_fail (field < relation->fields, 0); |
506 | | |
507 | 0 | table = relation->hashed_tuple_tables[field]; |
508 | |
|
509 | 0 | g_return_val_if_fail (table != NULL, 0); |
510 | | |
511 | 0 | key_table = g_hash_table_lookup (table, key); |
512 | |
|
513 | 0 | if (!key_table) |
514 | 0 | return 0; |
515 | | |
516 | 0 | return g_hash_table_size (key_table); |
517 | 0 | } |
518 | | |
519 | | /** |
520 | | * g_relation_count: |
521 | | * @relation: a #GRelation. |
522 | | * @key: the value to compare with. |
523 | | * @field: the field of each record to match. |
524 | | * |
525 | | * Returns the number of tuples in a #GRelation that have the given |
526 | | * value in the given field. |
527 | | * |
528 | | * Returns: the number of matches. |
529 | | * |
530 | | * Deprecated: 2.26: Rarely used API |
531 | | **/ |
532 | | gint |
533 | | g_relation_count (GRelation *relation, |
534 | | gconstpointer key, |
535 | | gint field) |
536 | 0 | { |
537 | 0 | unsigned int n_matches; |
538 | |
|
539 | 0 | g_return_val_if_fail (field >= 0 && (size_t) field < relation->fields, 0); |
540 | | |
541 | | /* Do the best we can with the limited return type */ |
542 | 0 | n_matches = relation_count_internal (relation, key, (size_t) field); |
543 | 0 | g_return_val_if_fail (n_matches <= G_MAXINT, G_MAXINT); |
544 | 0 | return (gint) n_matches; |
545 | 0 | } |
546 | | |
547 | | /** |
548 | | * g_relation_exists: |
549 | | * @relation: a #GRelation. |
550 | | * @...: the fields of the record to compare. The number must match |
551 | | * the number of fields in the #GRelation. |
552 | | * |
553 | | * Returns %TRUE if a record with the given values exists in a |
554 | | * #GRelation. Note that the values are compared directly, so that, for |
555 | | * example, two copies of the same string will not match. |
556 | | * |
557 | | * Returns: %TRUE if a record matches. |
558 | | * |
559 | | * Deprecated: 2.26: Rarely used API |
560 | | **/ |
561 | | gboolean |
562 | | g_relation_exists (GRelation *relation, ...) |
563 | 0 | { |
564 | 0 | gpointer *tuple = g_slice_alloc (relation->fields * sizeof (gpointer)); |
565 | 0 | va_list args; |
566 | 0 | gboolean result; |
567 | | |
568 | 0 | va_start(args, relation); |
569 | | |
570 | 0 | for (size_t i = 0; i < relation->fields; i += 1) |
571 | 0 | tuple[i] = va_arg(args, gpointer); |
572 | | |
573 | 0 | va_end(args); |
574 | | |
575 | 0 | result = g_hash_table_lookup (relation->all_tuples, tuple) != NULL; |
576 | | |
577 | 0 | g_slice_free1 (relation->fields * sizeof (gpointer), tuple); |
578 | | |
579 | 0 | return result; |
580 | 0 | } |
581 | | |
582 | | /** |
583 | | * g_tuples_destroy: |
584 | | * @tuples: the tuple data to free. |
585 | | * |
586 | | * Frees the records which were returned by g_relation_select(). This |
587 | | * should always be called after g_relation_select() when you are |
588 | | * finished with the records. The records are not removed from the |
589 | | * #GRelation. |
590 | | * |
591 | | * Deprecated: 2.26: Rarely used API |
592 | | **/ |
593 | | void |
594 | | g_tuples_destroy (GTuples *tuples0) |
595 | 0 | { |
596 | 0 | GRealTuples *tuples = (GRealTuples*) tuples0; |
597 | | |
598 | 0 | if (tuples) |
599 | 0 | { |
600 | 0 | g_free (tuples->data); |
601 | 0 | g_free (tuples); |
602 | 0 | } |
603 | 0 | } |
604 | | |
605 | | /** |
606 | | * g_tuples_index: |
607 | | * @tuples: the tuple data, returned by g_relation_select(). |
608 | | * @index_: the index of the record. |
609 | | * @field: the field to return. |
610 | | * |
611 | | * Gets a field from the records returned by g_relation_select(). It |
612 | | * returns the given field of the record at the given index. The |
613 | | * returned value should not be changed. |
614 | | * |
615 | | * Returns: the field of the record. |
616 | | * |
617 | | * Deprecated: 2.26: Rarely used API |
618 | | **/ |
619 | | gpointer |
620 | | g_tuples_index (GTuples *tuples0, |
621 | | gint index, |
622 | | gint field) |
623 | 0 | { |
624 | 0 | GRealTuples *tuples = (GRealTuples*) tuples0; |
625 | 0 | size_t unsigned_index, unsigned_field; |
626 | |
|
627 | 0 | g_return_val_if_fail (tuples0 != NULL, NULL); |
628 | 0 | g_return_val_if_fail (index >= 0, NULL); |
629 | 0 | g_return_val_if_fail (field >= 0 && (size_t) field < tuples->width, NULL); |
630 | | |
631 | 0 | unsigned_index = (size_t) index; |
632 | 0 | unsigned_field = (size_t) field; |
633 | |
|
634 | 0 | return tuples->data[unsigned_index * tuples->width + unsigned_field]; |
635 | 0 | } |
636 | | |
637 | | /* Print |
638 | | */ |
639 | | |
640 | | static void |
641 | | g_relation_print_one (gpointer tuple_key, |
642 | | gpointer tuple_value, |
643 | | gpointer user_data) |
644 | 0 | { |
645 | 0 | GString *gstring; |
646 | 0 | GRelation* rel = (GRelation*) user_data; |
647 | 0 | gpointer* tuples = (gpointer*) tuple_value; |
648 | |
|
649 | 0 | gstring = g_string_new ("["); |
650 | | |
651 | 0 | for (size_t i = 0; i < rel->fields; i += 1) |
652 | 0 | { |
653 | 0 | g_string_append_printf (gstring, "%p", tuples[i]); |
654 | | |
655 | 0 | if (i < (rel->fields - 1)) |
656 | 0 | g_string_append (gstring, ","); |
657 | 0 | } |
658 | | |
659 | 0 | g_string_append (gstring, "]"); |
660 | 0 | g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s", gstring->str); |
661 | 0 | g_string_free (gstring, TRUE); |
662 | 0 | } |
663 | | |
664 | | static void |
665 | | g_relation_print_index (gpointer tuple_key, |
666 | | gpointer tuple_value, |
667 | | gpointer user_data) |
668 | 0 | { |
669 | 0 | GRelation* rel = (GRelation*) user_data; |
670 | 0 | GHashTable* table = (GHashTable*) tuple_value; |
671 | | |
672 | 0 | g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** key %p", tuple_key); |
673 | | |
674 | 0 | g_hash_table_foreach (table, |
675 | 0 | g_relation_print_one, |
676 | 0 | rel); |
677 | 0 | } |
678 | | |
679 | | /** |
680 | | * g_relation_print: |
681 | | * @relation: a #GRelation. |
682 | | * |
683 | | * Outputs information about all records in a #GRelation, as well as |
684 | | * the indexes. It is for debugging. |
685 | | * |
686 | | * Deprecated: 2.26: Rarely used API |
687 | | **/ |
688 | | void |
689 | | g_relation_print (GRelation *relation) |
690 | 0 | { |
691 | 0 | g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** all tuples (%" G_GSIZE_FORMAT ")", relation->count); |
692 | | |
693 | 0 | g_hash_table_foreach (relation->all_tuples, |
694 | 0 | g_relation_print_one, |
695 | 0 | relation); |
696 | | |
697 | 0 | for (size_t i = 0; i < relation->fields; i += 1) |
698 | 0 | { |
699 | 0 | if (relation->hashed_tuple_tables[i] == NULL) |
700 | 0 | continue; |
701 | | |
702 | 0 | g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "*** index %" G_GSIZE_FORMAT, i); |
703 | | |
704 | 0 | g_hash_table_foreach (relation->hashed_tuple_tables[i], |
705 | 0 | g_relation_print_index, |
706 | 0 | relation); |
707 | 0 | } |
708 | | |
709 | 0 | } |