1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1999 The Free Software Foundation
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
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 #undef G_DISABLE_ASSERT
42 fill_hash_table_and_array (GHashTable
*hash_table
)
46 for (i
= 0; i
< 10000; i
++)
49 g_hash_table_insert (hash_table
, &array
[i
], &array
[i
]);
54 init_result_array (int result_array
[10000])
58 for (i
= 0; i
< 10000; i
++)
63 verify_result_array (int array
[10000])
67 for (i
= 0; i
< 10000; i
++)
68 g_assert (array
[i
] == i
);
72 handle_pair (gpointer key
, gpointer value
, int result_array
[10000])
76 g_assert (key
== value
);
80 g_assert (n
>= 0 && n
< 10000);
81 g_assert (result_array
[n
] == -1);
87 my_hash_callback_remove (gpointer key
,
100 my_hash_callback_remove_test (gpointer key
,
107 g_assert_not_reached ();
111 my_hash_callback (gpointer key
,
115 handle_pair (key
, value
, user_data
);
119 my_hash (gconstpointer key
)
121 return (guint
) *((const gint
*) key
);
125 my_hash_equal (gconstpointer a
,
128 return *((const gint
*) a
) == *((const gint
*) b
);
134 * This is a simplified version of the pathalias hashing function.
135 * Thanks to Steve Belovin and Peter Honeyman
137 * hash a string into a long int. 31 bit crc (from andrew appel).
138 * the crc table is computed at run time by crcinit() -- we could
139 * precompute, but it takes 1 clock tick on a 750.
141 * This fast table calculation works only if POLY is a prime polynomial
142 * in the field of integers modulo 2. Since the coefficients of a
143 * 32-bit polynomial won't fit in a 32-bit word, the high-order bit is
144 * implicit. IT MUST ALSO BE THE CASE that the coefficients of orders
145 * 31 down to 25 are zero. Happily, we have candidates, from
146 * E. J. Watson, "Primitive Polynomials (Mod 2)", Math. Comp. 16 (1962):
147 * x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + x^0
150 * We reverse the bits to get:
151 * 111101010000000000000000000000001 but drop the last 1
153 * 010010000000000000000000000000001 ditto, for 31-bit crc
157 #define POLY 0x48000000L /* 31-bit polynomial (avoids sign problems) */
159 static guint CrcTable
[128];
162 - crcinit - initialize tables for hash function
164 static void crcinit(void)
169 for (i
= 0; i
< 128; ++i
)
172 for (j
= 7 - 1; j
>= 0; --j
)
180 - hash - Honeyman's nice hashing function
183 honeyman_hash (gconstpointer key
)
185 const gchar
*name
= (const gchar
*) key
;
189 g_assert (name
!= NULL
);
190 g_assert (*name
!= 0);
192 size
= strlen (name
);
195 sum
= (sum
>> 7) ^ CrcTable
[(sum
^ (*name
++)) & 0x7f];
202 second_hash_cmp (gconstpointer a
, gconstpointer b
)
204 return strcmp (a
, b
) == 0;
210 one_hash (gconstpointer key
)
217 not_even_foreach (gpointer key
,
221 const char *_key
= (const char *) key
;
222 const char *_value
= (const char *) value
;
226 g_assert (_key
!= NULL
);
227 g_assert (*_key
!= 0);
228 g_assert (_value
!= NULL
);
229 g_assert (*_value
!= 0);
233 sprintf (val
, "%d value", i
);
234 g_assert (strcmp (_value
, val
) == 0);
236 g_assert ((i
% 2) != 0);
241 remove_even_foreach (gpointer key
,
245 const char *_key
= (const char *) key
;
246 const char *_value
= (const char *) value
;
250 g_assert (_key
!= NULL
);
251 g_assert (*_key
!= 0);
252 g_assert (_value
!= NULL
);
253 g_assert (*_value
!= 0);
257 sprintf (val
, "%d value", i
);
258 g_assert (strcmp (_value
, val
) == 0);
260 return ((i
% 2) == 0) ? TRUE
: FALSE
;
267 second_hash_test (gconstpointer d
)
269 gboolean simple_hash
= GPOINTER_TO_INT (d
);
272 char key
[20] = "", val
[20]="", *v
, *orig_key
, *orig_val
;
278 h
= g_hash_table_new_full (simple_hash
? one_hash
: honeyman_hash
,
281 g_assert (h
!= NULL
);
282 for (i
= 0; i
< 20; i
++)
284 sprintf (key
, "%d", i
);
285 g_assert (atoi (key
) == i
);
287 sprintf (val
, "%d value", i
);
288 g_assert (atoi (val
) == i
);
290 g_hash_table_insert (h
, g_strdup (key
), g_strdup (val
));
293 g_assert (g_hash_table_size (h
) == 20);
295 for (i
= 0; i
< 20; i
++)
297 sprintf (key
, "%d", i
);
298 g_assert (atoi(key
) == i
);
300 v
= (char *) g_hash_table_lookup (h
, key
);
302 g_assert (v
!= NULL
);
304 g_assert (atoi (v
) == i
);
307 sprintf (key
, "%d", 3);
308 g_hash_table_remove (h
, key
);
309 g_assert (g_hash_table_size (h
) == 19);
310 g_hash_table_foreach_remove (h
, remove_even_foreach
, NULL
);
311 g_assert (g_hash_table_size (h
) == 9);
312 g_hash_table_foreach (h
, not_even_foreach
, NULL
);
314 for (i
= 0; i
< 20; i
++)
316 sprintf (key
, "%d", i
);
317 g_assert (atoi(key
) == i
);
319 sprintf (val
, "%d value", i
);
320 g_assert (atoi (val
) == i
);
322 orig_key
= orig_val
= NULL
;
323 found
= g_hash_table_lookup_extended (h
, key
,
325 (gpointer
)&orig_val
);
326 if ((i
% 2) == 0 || i
== 3)
334 g_assert (orig_key
!= NULL
);
335 g_assert (strcmp (key
, orig_key
) == 0);
337 g_assert (orig_val
!= NULL
);
338 g_assert (strcmp (val
, orig_val
) == 0);
341 g_hash_table_destroy (h
);
345 find_first (gpointer key
,
350 gint
*test
= user_data
;
351 return (*v
== *test
);
355 direct_hash_test (void)
360 h
= g_hash_table_new (NULL
, NULL
);
361 g_assert (h
!= NULL
);
362 for (i
= 1; i
<= 20; i
++)
363 g_hash_table_insert (h
, GINT_TO_POINTER (i
),
364 GINT_TO_POINTER (i
+ 42));
366 g_assert (g_hash_table_size (h
) == 20);
368 for (i
= 1; i
<= 20; i
++)
370 rc
= GPOINTER_TO_INT (g_hash_table_lookup (h
, GINT_TO_POINTER (i
)));
373 g_assert ((rc
- 42) == i
);
376 g_hash_table_destroy (h
);
380 direct_hash_test2 (void)
385 h
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
386 g_assert (h
!= NULL
);
387 for (i
= 1; i
<= 20; i
++)
388 g_hash_table_insert (h
, GINT_TO_POINTER (i
),
389 GINT_TO_POINTER (i
+ 42));
391 g_assert (g_hash_table_size (h
) == 20);
393 for (i
= 1; i
<= 20; i
++)
395 rc
= GPOINTER_TO_INT (g_hash_table_lookup (h
, GINT_TO_POINTER (i
)));
398 g_assert ((rc
- 42) == i
);
401 g_hash_table_destroy (h
);
412 h
= g_hash_table_new (g_int_hash
, g_int_equal
);
413 g_assert (h
!= NULL
);
414 for (i
= 0; i
< 20; i
++)
417 g_hash_table_insert (h
, &values
[i
], GINT_TO_POINTER (i
+ 42));
420 g_assert (g_hash_table_size (h
) == 20);
422 for (i
= 0; i
< 20; i
++)
425 rc
= GPOINTER_TO_INT (g_hash_table_lookup (h
, &key
));
427 g_assert_cmpint (rc
, ==, i
+ 42);
430 g_hash_table_destroy (h
);
434 int64_hash_test (void)
441 h
= g_hash_table_new (g_int64_hash
, g_int64_equal
);
442 g_assert (h
!= NULL
);
443 for (i
= 0; i
< 20; i
++)
446 g_hash_table_insert (h
, &values
[i
], GINT_TO_POINTER (i
+ 42));
449 g_assert (g_hash_table_size (h
) == 20);
451 for (i
= 0; i
< 20; i
++)
454 rc
= GPOINTER_TO_INT (g_hash_table_lookup (h
, &key
));
456 g_assert_cmpint (rc
, ==, i
+ 42);
459 g_hash_table_destroy (h
);
463 double_hash_test (void)
470 h
= g_hash_table_new (g_double_hash
, g_double_equal
);
471 g_assert (h
!= NULL
);
472 for (i
= 0; i
< 20; i
++)
474 values
[i
] = i
+ 42.5;
475 g_hash_table_insert (h
, &values
[i
], GINT_TO_POINTER (i
+ 42));
478 g_assert (g_hash_table_size (h
) == 20);
480 for (i
= 0; i
< 20; i
++)
483 rc
= GPOINTER_TO_INT (g_hash_table_lookup (h
, &key
));
485 g_assert_cmpint (rc
, ==, i
+ 42);
488 g_hash_table_destroy (h
);
492 string_free (gpointer data
)
496 g_string_free (s
, TRUE
);
500 string_hash_test (void)
506 h
= g_hash_table_new_full ((GHashFunc
)g_string_hash
, (GEqualFunc
)g_string_equal
, string_free
, NULL
);
507 g_assert (h
!= NULL
);
508 for (i
= 0; i
< 20; i
++)
510 s
= g_string_new ("");
511 g_string_append_printf (s
, "%d", i
+ 42);
512 g_string_append_c (s
, '.');
513 g_string_prepend_unichar (s
, 0x2301);
514 g_hash_table_insert (h
, s
, GINT_TO_POINTER (i
+ 42));
517 g_assert (g_hash_table_size (h
) == 20);
519 s
= g_string_new ("");
520 for (i
= 0; i
< 20; i
++)
522 g_string_assign (s
, "");
523 g_string_append_printf (s
, "%d", i
+ 42);
524 g_string_append_c (s
, '.');
525 g_string_prepend_unichar (s
, 0x2301);
526 rc
= GPOINTER_TO_INT (g_hash_table_lookup (h
, s
));
528 g_assert_cmpint (rc
, ==, i
+ 42);
531 g_string_free (s
, TRUE
);
532 g_hash_table_destroy (h
);
536 set_check (gpointer key
,
542 g_assert_not_reached ();
544 g_assert_cmpint (atoi (key
) % 7, ==, 2);
552 GHashTable
*hash_table
=
553 g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
556 for (i
= 2; i
< 5000; i
+= 7)
558 char *s
= g_strdup_printf ("%d", i
);
559 g_assert (g_hash_table_add (hash_table
, s
));
562 g_assert (!g_hash_table_add (hash_table
, g_strdup_printf ("%d", 2)));
565 g_hash_table_foreach (hash_table
, set_check
, &i
);
566 g_assert_cmpint (i
, ==, g_hash_table_size (hash_table
));
568 g_assert (g_hash_table_contains (hash_table
, "2"));
569 g_assert (g_hash_table_contains (hash_table
, "9"));
570 g_assert (!g_hash_table_contains (hash_table
, "a"));
572 /* this will cause the hash table to loose set nature */
573 g_assert (g_hash_table_insert (hash_table
, g_strdup ("a"), "b"));
574 g_assert (!g_hash_table_insert (hash_table
, g_strdup ("a"), "b"));
576 g_assert (g_hash_table_replace (hash_table
, g_strdup ("c"), "d"));
577 g_assert (!g_hash_table_replace (hash_table
, g_strdup ("c"), "d"));
579 g_assert_cmpstr (g_hash_table_lookup (hash_table
, "2"), ==, "2");
580 g_assert_cmpstr (g_hash_table_lookup (hash_table
, "a"), ==, "b");
582 g_hash_table_destroy (hash_table
);
587 test_hash_misc (void)
589 GHashTable
*hash_table
;
593 GList
*keys
, *values
;
594 gint keys_len
, values_len
;
596 gpointer ikey
, ivalue
;
597 int result_array
[10000];
600 hash_table
= g_hash_table_new (my_hash
, my_hash_equal
);
601 fill_hash_table_and_array (hash_table
);
602 pvalue
= g_hash_table_find (hash_table
, find_first
, &value
);
603 if (!pvalue
|| *pvalue
!= value
)
604 g_assert_not_reached();
606 keys
= g_hash_table_get_keys (hash_table
);
608 g_assert_not_reached ();
610 values
= g_hash_table_get_values (hash_table
);
612 g_assert_not_reached ();
614 keys_len
= g_list_length (keys
);
615 values_len
= g_list_length (values
);
616 if (values_len
!= keys_len
&& keys_len
!= g_hash_table_size (hash_table
))
617 g_assert_not_reached ();
620 g_list_free (values
);
622 init_result_array (result_array
);
623 g_hash_table_iter_init (&iter
, hash_table
);
624 for (i
= 0; i
< 10000; i
++)
626 g_assert (g_hash_table_iter_next (&iter
, &ikey
, &ivalue
));
628 handle_pair (ikey
, ivalue
, result_array
);
631 g_hash_table_iter_remove (&iter
);
633 g_assert (! g_hash_table_iter_next (&iter
, &ikey
, &ivalue
));
634 g_assert (g_hash_table_size (hash_table
) == 5000);
635 verify_result_array (result_array
);
637 fill_hash_table_and_array (hash_table
);
639 init_result_array (result_array
);
640 g_hash_table_foreach (hash_table
, my_hash_callback
, result_array
);
641 verify_result_array (result_array
);
643 for (i
= 0; i
< 10000; i
++)
644 g_hash_table_remove (hash_table
, &array
[i
]);
646 fill_hash_table_and_array (hash_table
);
648 if (g_hash_table_foreach_remove (hash_table
, my_hash_callback_remove
, NULL
) != 5000 ||
649 g_hash_table_size (hash_table
) != 5000)
650 g_assert_not_reached();
652 g_hash_table_foreach (hash_table
, my_hash_callback_remove_test
, NULL
);
653 g_hash_table_destroy (hash_table
);
655 hash_table
= g_hash_table_new (my_hash
, my_hash_equal
);
656 fill_hash_table_and_array (hash_table
);
660 g_hash_table_iter_init (&iter
, hash_table
);
661 for (i
= 0; i
< 10000; i
++)
663 g_assert (g_hash_table_iter_next (&iter
, &ikey
, &ivalue
));
664 g_hash_table_iter_replace (&iter
, &n_array
[0]);
667 g_hash_table_iter_init (&iter
, hash_table
);
668 for (i
= 0; i
< 10000; i
++)
670 g_assert (g_hash_table_iter_next (&iter
, &ikey
, &ivalue
));
672 g_assert (ivalue
== &n_array
[0]);
675 g_hash_table_destroy (hash_table
);
678 static gint destroy_counter
;
681 value_destroy (gpointer value
)
692 gboolean abc_seen
= FALSE
;
693 gboolean cde_seen
= FALSE
;
694 gboolean xyz_seen
= FALSE
;
696 h
= g_hash_table_new_full (g_str_hash
, g_str_equal
, NULL
, value_destroy
);
697 g_hash_table_insert (h
, "abc", "ABC");
698 g_hash_table_insert (h
, "cde", "CDE");
699 g_hash_table_insert (h
, "xyz", "XYZ");
701 g_assert_cmpint (g_hash_table_size (h
), == , 3);
703 g_hash_table_iter_init (&iter
, h
);
705 while (g_hash_table_iter_next (&iter
, (gpointer
*)&key
, (gpointer
*)&value
))
707 if (strcmp (key
, "abc") == 0)
709 g_assert_cmpstr (value
, ==, "ABC");
711 g_hash_table_iter_steal (&iter
);
713 else if (strcmp (key
, "cde") == 0)
715 g_assert_cmpstr (value
, ==, "CDE");
718 else if (strcmp (key
, "xyz") == 0)
720 g_assert_cmpstr (value
, ==, "XYZ");
724 g_assert_cmpint (destroy_counter
, ==, 0);
726 g_assert (g_hash_table_iter_get_hash_table (&iter
) == h
);
727 g_assert (abc_seen
&& cde_seen
&& xyz_seen
);
728 g_assert_cmpint (g_hash_table_size (h
), == , 2);
730 g_hash_table_ref (h
);
731 g_hash_table_destroy (h
);
732 g_assert_cmpint (g_hash_table_size (h
), == , 0);
733 g_assert_cmpint (destroy_counter
, ==, 2);
734 g_hash_table_insert (h
, "uvw", "UVW");
735 g_hash_table_unref (h
);
736 g_assert_cmpint (destroy_counter
, ==, 3);
740 null_safe_str_hash (gconstpointer key
)
745 return g_str_hash (key
);
749 null_safe_str_equal (gconstpointer a
, gconstpointer b
)
751 return g_strcmp0 (a
, b
) == 0;
755 test_lookup_null_key (void)
762 g_test_bug ("642944");
764 h
= g_hash_table_new (null_safe_str_hash
, null_safe_str_equal
);
765 g_hash_table_insert (h
, "abc", "ABC");
767 res
= g_hash_table_lookup_extended (h
, NULL
, &key
, &value
);
770 g_hash_table_insert (h
, NULL
, "NULL");
772 res
= g_hash_table_lookup_extended (h
, NULL
, &key
, &value
);
774 g_assert_cmpstr (value
, ==, "NULL");
776 g_hash_table_unref (h
);
779 static gint destroy_key_counter
;
782 key_destroy (gpointer key
)
784 destroy_key_counter
++;
788 test_remove_all (void)
793 h
= g_hash_table_new_full (g_str_hash
, g_str_equal
, key_destroy
, value_destroy
);
795 g_hash_table_insert (h
, "abc", "cde");
796 g_hash_table_insert (h
, "cde", "xyz");
797 g_hash_table_insert (h
, "xyz", "abc");
800 destroy_key_counter
= 0;
802 g_hash_table_steal_all (h
);
803 g_assert_cmpint (destroy_counter
, ==, 0);
804 g_assert_cmpint (destroy_key_counter
, ==, 0);
806 g_hash_table_insert (h
, "abc", "ABC");
807 g_hash_table_insert (h
, "cde", "CDE");
808 g_hash_table_insert (h
, "xyz", "XYZ");
810 res
= g_hash_table_steal (h
, "nosuchkey");
812 g_assert_cmpint (destroy_counter
, ==, 0);
813 g_assert_cmpint (destroy_key_counter
, ==, 0);
815 res
= g_hash_table_steal (h
, "xyz");
817 g_assert_cmpint (destroy_counter
, ==, 0);
818 g_assert_cmpint (destroy_key_counter
, ==, 0);
820 g_hash_table_remove_all (h
);
821 g_assert_cmpint (destroy_counter
, ==, 2);
822 g_assert_cmpint (destroy_key_counter
, ==, 2);
824 g_hash_table_remove_all (h
);
825 g_assert_cmpint (destroy_counter
, ==, 2);
826 g_assert_cmpint (destroy_key_counter
, ==, 2);
828 g_hash_table_unref (h
);
831 GHashTable
*recursive_destruction_table
= NULL
;
833 recursive_value_destroy (gpointer value
)
837 if (recursive_destruction_table
)
838 g_hash_table_remove (recursive_destruction_table
, value
);
842 test_recursive_remove_all_subprocess (void)
846 h
= g_hash_table_new_full (g_str_hash
, g_str_equal
, key_destroy
, recursive_value_destroy
);
847 recursive_destruction_table
= h
;
849 /* Add more items compared to test_remove_all, as it would not fail otherwise. */
850 g_hash_table_insert (h
, "abc", "cde");
851 g_hash_table_insert (h
, "cde", "fgh");
852 g_hash_table_insert (h
, "fgh", "ijk");
853 g_hash_table_insert (h
, "ijk", "lmn");
854 g_hash_table_insert (h
, "lmn", "opq");
855 g_hash_table_insert (h
, "opq", "rst");
856 g_hash_table_insert (h
, "rst", "uvw");
857 g_hash_table_insert (h
, "uvw", "xyz");
858 g_hash_table_insert (h
, "xyz", "abc");
861 destroy_key_counter
= 0;
863 g_hash_table_remove_all (h
);
864 g_assert_cmpint (destroy_counter
, ==, 9);
865 g_assert_cmpint (destroy_key_counter
, ==, 9);
867 g_hash_table_unref (h
);
871 test_recursive_remove_all (void)
873 g_test_trap_subprocess ("/hash/recursive-remove-all/subprocess", 1000000, 0);
874 g_test_trap_assert_passed ();
883 hash_func (gconstpointer key
)
885 const RefCountedKey
*rkey
= key
;
887 return g_str_hash (rkey
->key
);
891 eq_func (gconstpointer a
, gconstpointer b
)
893 const RefCountedKey
*aa
= a
;
894 const RefCountedKey
*bb
= b
;
896 return g_strcmp0 (aa
->key
, bb
->key
) == 0;
900 key_unref (gpointer data
)
902 RefCountedKey
*key
= data
;
904 g_assert (key
->ref_count
> 0);
908 if (key
->ref_count
== 0)
912 static RefCountedKey
*
913 key_ref (RefCountedKey
*key
)
920 static RefCountedKey
*
921 key_new (const gchar
*key
)
925 rkey
= g_new (RefCountedKey
, 1);
934 set_ref_hash_test (void)
940 h
= g_hash_table_new_full (hash_func
, eq_func
, key_unref
, key_unref
);
942 key1
= key_new ("a");
943 key2
= key_new ("a");
945 g_assert_cmpint (key1
->ref_count
, ==, 1);
946 g_assert_cmpint (key2
->ref_count
, ==, 1);
948 g_hash_table_insert (h
, key_ref (key1
), key_ref (key1
));
950 g_assert_cmpint (key1
->ref_count
, ==, 3);
951 g_assert_cmpint (key2
->ref_count
, ==, 1);
953 g_hash_table_replace (h
, key_ref (key2
), key_ref (key2
));
955 g_assert_cmpint (key1
->ref_count
, ==, 1);
956 g_assert_cmpint (key2
->ref_count
, ==, 3);
958 g_hash_table_remove (h
, key1
);
960 g_assert_cmpint (key1
->ref_count
, ==, 1);
961 g_assert_cmpint (key2
->ref_count
, ==, 1);
963 g_hash_table_unref (h
);
976 GPtrArray
*fake_free_data
;
979 fake_free (gpointer dead
)
983 for (i
= 0; i
< fake_free_data
->len
; i
++)
985 FakeFreeData
*ffd
= g_ptr_array_index (fake_free_data
, i
);
987 if (ffd
->string
== (gchar
*) dead
)
989 g_assert (!ffd
->freed
);
995 g_assert_not_reached ();
999 value_destroy_insert (gpointer value
)
1001 g_hash_table_remove_all (h
);
1005 test_destroy_modify (void)
1010 g_test_bug ("650459");
1012 fake_free_data
= g_ptr_array_new ();
1014 h
= g_hash_table_new_full (g_str_hash
, g_str_equal
, fake_free
, value_destroy_insert
);
1016 ffd
= g_new0 (FakeFreeData
, 1);
1017 ffd
->string
= g_strdup ("a");
1018 g_ptr_array_add (fake_free_data
, ffd
);
1019 g_hash_table_insert (h
, ffd
->string
, "b");
1021 ffd
= g_new0 (FakeFreeData
, 1);
1022 ffd
->string
= g_strdup ("c");
1023 g_ptr_array_add (fake_free_data
, ffd
);
1024 g_hash_table_insert (h
, ffd
->string
, "d");
1026 ffd
= g_new0 (FakeFreeData
, 1);
1027 ffd
->string
= g_strdup ("e");
1028 g_ptr_array_add (fake_free_data
, ffd
);
1029 g_hash_table_insert (h
, ffd
->string
, "f");
1031 ffd
= g_new0 (FakeFreeData
, 1);
1032 ffd
->string
= g_strdup ("g");
1033 g_ptr_array_add (fake_free_data
, ffd
);
1034 g_hash_table_insert (h
, ffd
->string
, "h");
1036 ffd
= g_new0 (FakeFreeData
, 1);
1037 ffd
->string
= g_strdup ("h");
1038 g_ptr_array_add (fake_free_data
, ffd
);
1039 g_hash_table_insert (h
, ffd
->string
, "k");
1041 ffd
= g_new0 (FakeFreeData
, 1);
1042 ffd
->string
= g_strdup ("a");
1043 g_ptr_array_add (fake_free_data
, ffd
);
1044 g_hash_table_insert (h
, ffd
->string
, "c");
1046 g_hash_table_remove (h
, "c");
1048 /* that removed everything... */
1049 for (i
= 0; i
< fake_free_data
->len
; i
++)
1051 FakeFreeData
*ffd
= g_ptr_array_index (fake_free_data
, i
);
1053 g_assert (ffd
->freed
);
1054 g_free (ffd
->string
);
1058 g_ptr_array_unref (fake_free_data
);
1060 /* ... so this is a no-op */
1061 g_hash_table_remove (h
, "e");
1063 g_hash_table_unref (h
);
1067 find_str (gpointer key
, gpointer value
, gpointer data
)
1069 return g_str_equal (key
, data
);
1078 hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
1080 g_hash_table_insert (hash
, "a", "A");
1081 g_hash_table_insert (hash
, "b", "B");
1082 g_hash_table_insert (hash
, "c", "C");
1083 g_hash_table_insert (hash
, "d", "D");
1084 g_hash_table_insert (hash
, "e", "E");
1085 g_hash_table_insert (hash
, "f", "F");
1087 value
= g_hash_table_find (hash
, find_str
, "a");
1088 g_assert_cmpstr (value
, ==, "A");
1090 value
= g_hash_table_find (hash
, find_str
, "b");
1091 g_assert_cmpstr (value
, ==, "B");
1093 value
= g_hash_table_find (hash
, find_str
, "c");
1094 g_assert_cmpstr (value
, ==, "C");
1096 value
= g_hash_table_find (hash
, find_str
, "d");
1097 g_assert_cmpstr (value
, ==, "D");
1099 value
= g_hash_table_find (hash
, find_str
, "e");
1100 g_assert_cmpstr (value
, ==, "E");
1102 value
= g_hash_table_find (hash
, find_str
, "f");
1103 g_assert_cmpstr (value
, ==, "F");
1105 value
= g_hash_table_find (hash
, find_str
, "0");
1106 g_assert (value
== NULL
);
1108 g_hash_table_unref (hash
);
1111 gboolean seen_key
[6];
1114 foreach_func (gpointer key
, gpointer value
, gpointer data
)
1116 seen_key
[((char*)key
)[0] - 'a'] = TRUE
;
1125 hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
1127 g_hash_table_insert (hash
, "a", "A");
1128 g_hash_table_insert (hash
, "b", "B");
1129 g_hash_table_insert (hash
, "c", "C");
1130 g_hash_table_insert (hash
, "d", "D");
1131 g_hash_table_insert (hash
, "e", "E");
1132 g_hash_table_insert (hash
, "f", "F");
1134 for (i
= 0; i
< 6; i
++)
1135 seen_key
[i
] = FALSE
;
1137 g_hash_table_foreach (hash
, foreach_func
, NULL
);
1139 for (i
= 0; i
< 6; i
++)
1140 g_assert (seen_key
[i
]);
1142 g_hash_table_unref (hash
);
1146 foreach_steal_func (gpointer key
, gpointer value
, gpointer data
)
1148 GHashTable
*hash2
= data
;
1150 if (strstr ("ace", (gchar
*)key
))
1152 g_hash_table_insert (hash2
, key
, value
);
1161 test_foreach_steal (void)
1166 hash
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_free
);
1167 hash2
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_free
);
1169 g_hash_table_insert (hash
, g_strdup ("a"), g_strdup ("A"));
1170 g_hash_table_insert (hash
, g_strdup ("b"), g_strdup ("B"));
1171 g_hash_table_insert (hash
, g_strdup ("c"), g_strdup ("C"));
1172 g_hash_table_insert (hash
, g_strdup ("d"), g_strdup ("D"));
1173 g_hash_table_insert (hash
, g_strdup ("e"), g_strdup ("E"));
1174 g_hash_table_insert (hash
, g_strdup ("f"), g_strdup ("F"));
1176 g_hash_table_foreach_steal (hash
, foreach_steal_func
, hash2
);
1178 g_assert_cmpint (g_hash_table_size (hash
), ==, 3);
1179 g_assert_cmpint (g_hash_table_size (hash2
), ==, 3);
1181 g_assert_cmpstr (g_hash_table_lookup (hash2
, "a"), ==, "A");
1182 g_assert_cmpstr (g_hash_table_lookup (hash
, "b"), ==, "B");
1183 g_assert_cmpstr (g_hash_table_lookup (hash2
, "c"), ==, "C");
1184 g_assert_cmpstr (g_hash_table_lookup (hash
, "d"), ==, "D");
1185 g_assert_cmpstr (g_hash_table_lookup (hash2
, "e"), ==, "E");
1186 g_assert_cmpstr (g_hash_table_lookup (hash
, "f"), ==, "F");
1188 g_hash_table_unref (hash
);
1189 g_hash_table_unref (hash2
);
1192 /* Test g_hash_table_steal_extended() works properly with existing and
1193 * non-existing keys. */
1195 test_steal_extended (void)
1198 gchar
*stolen_key
= NULL
, *stolen_value
= NULL
;
1200 hash
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_free
);
1202 g_hash_table_insert (hash
, g_strdup ("a"), g_strdup ("A"));
1203 g_hash_table_insert (hash
, g_strdup ("b"), g_strdup ("B"));
1204 g_hash_table_insert (hash
, g_strdup ("c"), g_strdup ("C"));
1205 g_hash_table_insert (hash
, g_strdup ("d"), g_strdup ("D"));
1206 g_hash_table_insert (hash
, g_strdup ("e"), g_strdup ("E"));
1207 g_hash_table_insert (hash
, g_strdup ("f"), g_strdup ("F"));
1209 g_assert_true (g_hash_table_steal_extended (hash
, "a",
1210 (gpointer
*) &stolen_key
,
1211 (gpointer
*) &stolen_value
));
1212 g_assert_cmpstr (stolen_key
, ==, "a");
1213 g_assert_cmpstr (stolen_value
, ==, "A");
1214 g_clear_pointer (&stolen_key
, g_free
);
1215 g_clear_pointer (&stolen_value
, g_free
);
1217 g_assert_cmpuint (g_hash_table_size (hash
), ==, 5);
1219 g_assert_false (g_hash_table_steal_extended (hash
, "a",
1220 (gpointer
*) &stolen_key
,
1221 (gpointer
*) &stolen_value
));
1222 g_assert_null (stolen_key
);
1223 g_assert_null (stolen_value
);
1225 g_assert_false (g_hash_table_steal_extended (hash
, "never a key",
1226 (gpointer
*) &stolen_key
,
1227 (gpointer
*) &stolen_value
));
1228 g_assert_null (stolen_key
);
1229 g_assert_null (stolen_value
);
1231 g_assert_cmpuint (g_hash_table_size (hash
), ==, 5);
1233 g_hash_table_unref (hash
);
1242 gint noccupied
; /* nnodes + tombstones */
1248 GHashFunc hash_func
;
1249 GEqualFunc key_equal_func
;
1250 volatile gint ref_count
;
1252 #ifndef G_DISABLE_ASSERT
1255 GDestroyNotify key_destroy_func
;
1256 GDestroyNotify value_destroy_func
;
1260 count_keys (GHashTable
*h
, gint
*unused
, gint
*occupied
, gint
*tombstones
)
1267 for (i
= 0; i
< h
->size
; i
++)
1269 if (h
->hashes
[i
] == 0)
1271 else if (h
->hashes
[i
] == 1)
1279 check_data (GHashTable
*h
)
1283 for (i
= 0; i
< h
->size
; i
++)
1285 if (h
->hashes
[i
] < 2)
1287 g_assert (h
->keys
[i
] == NULL
);
1288 g_assert (h
->values
[i
] == NULL
);
1292 g_assert_cmpint (h
->hashes
[i
], ==, h
->hash_func (h
->keys
[i
]));
1298 check_consistency (GHashTable
*h
)
1304 count_keys (h
, &unused
, &occupied
, &tombstones
);
1306 g_assert_cmpint (occupied
, ==, h
->nnodes
);
1307 g_assert_cmpint (occupied
+ tombstones
, ==, h
->noccupied
);
1308 g_assert_cmpint (occupied
+ tombstones
+ unused
, ==, h
->size
);
1314 check_counts (GHashTable
*h
, gint occupied
, gint tombstones
)
1316 g_assert_cmpint (occupied
, ==, h
->nnodes
);
1317 g_assert_cmpint (occupied
+ tombstones
, ==, h
->noccupied
);
1321 trivial_key_destroy (gpointer key
)
1326 test_internal_consistency (void)
1330 h
= g_hash_table_new_full (g_str_hash
, g_str_equal
, trivial_key_destroy
, NULL
);
1332 check_counts (h
, 0, 0);
1333 check_consistency (h
);
1335 g_hash_table_insert (h
, "a", "A");
1336 g_hash_table_insert (h
, "b", "B");
1337 g_hash_table_insert (h
, "c", "C");
1338 g_hash_table_insert (h
, "d", "D");
1339 g_hash_table_insert (h
, "e", "E");
1340 g_hash_table_insert (h
, "f", "F");
1342 check_counts (h
, 6, 0);
1343 check_consistency (h
);
1345 g_hash_table_remove (h
, "a");
1346 check_counts (h
, 5, 1);
1347 check_consistency (h
);
1349 g_hash_table_remove (h
, "b");
1350 check_counts (h
, 4, 2);
1351 check_consistency (h
);
1353 g_hash_table_insert (h
, "c", "c");
1354 check_counts (h
, 4, 2);
1355 check_consistency (h
);
1357 g_hash_table_insert (h
, "a", "A");
1358 check_counts (h
, 5, 1);
1359 check_consistency (h
);
1361 g_hash_table_remove_all (h
);
1362 check_counts (h
, 0, 0);
1363 check_consistency (h
);
1365 g_hash_table_unref (h
);
1369 my_key_free (gpointer v
)
1372 g_assert (s
[0] != 'x');
1378 my_value_free (gpointer v
)
1381 g_assert (s
[0] != 'y');
1387 test_iter_replace (void)
1390 GHashTableIter iter
;
1394 g_test_bug ("662544");
1396 h
= g_hash_table_new_full (g_str_hash
, g_str_equal
, my_key_free
, my_value_free
);
1398 g_hash_table_insert (h
, g_strdup ("A"), g_strdup ("a"));
1399 g_hash_table_insert (h
, g_strdup ("B"), g_strdup ("b"));
1400 g_hash_table_insert (h
, g_strdup ("C"), g_strdup ("c"));
1402 g_hash_table_iter_init (&iter
, h
);
1404 while (g_hash_table_iter_next (&iter
, &k
, &v
))
1407 g_assert (g_ascii_islower (s
[0]));
1408 g_hash_table_iter_replace (&iter
, g_strdup (k
));
1411 g_hash_table_unref (h
);
1415 replace_first_character (gchar
*string
)
1421 test_set_insert_corruption (void)
1423 GHashTable
*hash_table
=
1424 g_hash_table_new_full (g_str_hash
, g_str_equal
,
1425 (GDestroyNotify
) replace_first_character
, NULL
);
1426 GHashTableIter iter
;
1429 gpointer key
, value
;
1431 g_test_bug ("692815");
1433 g_hash_table_insert (hash_table
, a
, a
);
1434 g_assert (g_hash_table_contains (hash_table
, "foo"));
1436 g_hash_table_insert (hash_table
, b
, b
);
1438 g_assert_cmpuint (g_hash_table_size (hash_table
), ==, 1);
1439 g_hash_table_iter_init (&iter
, hash_table
);
1440 if (!g_hash_table_iter_next (&iter
, &key
, &value
))
1441 g_assert_not_reached();
1443 /* per the documentation to g_hash_table_insert(), 'b' has now been freed,
1444 * and the sole key in 'hash_table' should be 'a'.
1446 g_assert (key
!= b
);
1447 g_assert (key
== a
);
1449 g_assert_cmpstr (b
, ==, "boo");
1451 /* g_hash_table_insert() also says that the value should now be 'b',
1452 * which is probably not what the caller intended but is precisely what they
1455 g_assert (value
== b
);
1457 /* even though the hash has now been de-set-ified: */
1458 g_assert (g_hash_table_contains (hash_table
, "foo"));
1460 g_hash_table_unref (hash_table
);
1464 test_set_to_strv (void)
1470 set
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
1471 g_hash_table_add (set
, g_strdup ("xyz"));
1472 g_hash_table_add (set
, g_strdup ("xyz"));
1473 g_hash_table_add (set
, g_strdup ("abc"));
1474 strv
= (gchar
**) g_hash_table_get_keys_as_array (set
, &n
);
1475 g_hash_table_steal_all (set
);
1476 g_hash_table_unref (set
);
1477 g_assert_cmpint (n
, ==, 2);
1478 n
= g_strv_length (strv
);
1479 g_assert_cmpint (n
, ==, 2);
1480 if (g_str_equal (strv
[0], "abc"))
1481 g_assert_cmpstr (strv
[1], ==, "xyz");
1484 g_assert_cmpstr (strv
[0], ==, "xyz");
1485 g_assert_cmpstr (strv
[1], ==, "abc");
1515 gdouble r
, min
, max
;
1522 q
= g_spaced_primes_closest (p
);
1523 g_assert (is_prime (q
));
1524 if (p
== 1) continue;
1526 r
= q
/ (gdouble
) p
;
1531 g_assert_cmpfloat (1.3, <, min
);
1532 g_assert_cmpfloat (max
, <, 2.0);
1536 main (int argc
, char *argv
[])
1538 g_test_init (&argc
, &argv
, NULL
);
1540 g_test_bug_base ("http://bugzilla.gnome.org/");
1542 g_test_add_func ("/hash/misc", test_hash_misc
);
1543 g_test_add_data_func ("/hash/one", GINT_TO_POINTER (TRUE
), second_hash_test
);
1544 g_test_add_data_func ("/hash/honeyman", GINT_TO_POINTER (FALSE
), second_hash_test
);
1545 g_test_add_func ("/hash/direct", direct_hash_test
);
1546 g_test_add_func ("/hash/direct2", direct_hash_test2
);
1547 g_test_add_func ("/hash/int", int_hash_test
);
1548 g_test_add_func ("/hash/int64", int64_hash_test
);
1549 g_test_add_func ("/hash/double", double_hash_test
);
1550 g_test_add_func ("/hash/string", string_hash_test
);
1551 g_test_add_func ("/hash/set", set_hash_test
);
1552 g_test_add_func ("/hash/set-ref", set_ref_hash_test
);
1553 g_test_add_func ("/hash/ref", test_hash_ref
);
1554 g_test_add_func ("/hash/remove-all", test_remove_all
);
1555 g_test_add_func ("/hash/recursive-remove-all", test_recursive_remove_all
);
1556 g_test_add_func ("/hash/recursive-remove-all/subprocess", test_recursive_remove_all_subprocess
);
1557 g_test_add_func ("/hash/find", test_find
);
1558 g_test_add_func ("/hash/foreach", test_foreach
);
1559 g_test_add_func ("/hash/foreach-steal", test_foreach_steal
);
1560 g_test_add_func ("/hash/steal-extended", test_steal_extended
);
1562 /* tests for individual bugs */
1563 g_test_add_func ("/hash/lookup-null-key", test_lookup_null_key
);
1564 g_test_add_func ("/hash/destroy-modify", test_destroy_modify
);
1565 g_test_add_func ("/hash/consistency", test_internal_consistency
);
1566 g_test_add_func ("/hash/iter-replace", test_iter_replace
);
1567 g_test_add_func ("/hash/set-insert-corruption", test_set_insert_corruption
);
1568 g_test_add_func ("/hash/set-to-strv", test_set_to_strv
);
1569 g_test_add_func ("/hash/primes", test_primes
);
1571 return g_test_run ();