1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705
|
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
/*
* MT safe
*/
#include "config.h"
#include <string.h> /* memset */
#include "ghash.h"
#include "gmacros.h"
#include "glib-private.h"
#include "gstrfuncs.h"
#include "gatomic.h"
#include "gtestutils.h"
#include "gslice.h"
#include "grefcount.h"
#include "gvalgrind.h"
/* The following #pragma is here so we can do this...
*
* #ifndef USE_SMALL_ARRAYS
* is_big = TRUE;
* #endif
* return is_big ? *(((gpointer *) a) + index) : GUINT_TO_POINTER (*(((guint *) a) + index));
*
* ...instead of this...
*
* #ifndef USE_SMALL_ARRAYS
* return *(((gpointer *) a) + index);
* #else
* return is_big ? *(((gpointer *) a) + index) : GUINT_TO_POINTER (*(((guint *) a) + index));
* #endif
*
* ...and still compile successfully when -Werror=duplicated-branches is passed. */
#if defined(__GNUC__) && __GNUC__ > 6
#pragma GCC diagnostic ignored "-Wduplicated-branches"
#endif
/**
* GHashTable:
*
* The #GHashTable struct is an opaque data structure to represent a
* [Hash Table](data-structures.html#hash-tables). It should only be accessed via the
* following functions.
*/
/**
* GHashFunc:
* @key: a key
*
* Specifies the type of the hash function which is passed to
* g_hash_table_new() when a #GHashTable is created.
*
* The function is passed a key and should return a #guint hash value.
* The functions g_direct_hash(), g_int_hash() and g_str_hash() provide
* hash functions which can be used when the key is a #gpointer, #gint*,
* and #gchar* respectively.
*
* g_direct_hash() is also the appropriate hash function for keys
* of the form `GINT_TO_POINTER (n)` (or similar macros).
*
* A good hash functions should produce
* hash values that are evenly distributed over a fairly large range.
* The modulus is taken with the hash table size (a prime number) to
* find the 'bucket' to place each key into. The function should also
* be very fast, since it is called for each key lookup.
*
* Note that the hash functions provided by GLib have these qualities,
* but are not particularly robust against manufactured keys that
* cause hash collisions. Therefore, you should consider choosing
* a more secure hash function when using a GHashTable with keys
* that originate in untrusted data (such as HTTP requests).
* Using g_str_hash() in that situation might make your application
* vulnerable to
* [Algorithmic Complexity Attacks](https://lwn.net/Articles/474912/).
*
* The key to choosing a good hash is unpredictability. Even
* cryptographic hashes are very easy to find collisions for when the
* remainder is taken modulo a somewhat predictable prime number. There
* must be an element of randomness that an attacker is unable to guess.
*
* Returns: the hash value corresponding to the key
*/
/**
* GHFunc:
* @key: a key
* @value: the value corresponding to the key
* @user_data: user data passed to g_hash_table_foreach()
*
* Specifies the type of the function passed to g_hash_table_foreach().
* It is called with each key/value pair, together with the @user_data
* parameter which is passed to g_hash_table_foreach().
*/
/**
* GHRFunc:
* @key: a key
* @value: the value associated with the key
* @user_data: user data passed to the calling function
*
* Specifies the type of the function passed to
* [func@GLib.HashTable.find], [func@GLib.HashTable.foreach_remove], and
* [func@GLib.HashTable.foreach_steal].
*
* The function is called with each key/value pair, together with
* the @user_data parameter passed to the calling function.
*
* The function should return true if the key/value pair should be
* selected, meaning it has been found or it should be removed from the
* [struct@GLib.HashTable], depending on the calling function.
*
* Returns: true if the key/value pair should be selected, and
* false otherwise
*/
/**
* GEqualFunc:
* @a: a value
* @b: a value to compare with
*
* Specifies the type of a function used to test two values for
* equality. The function should return %TRUE if both values are equal
* and %FALSE otherwise.
*
* Returns: %TRUE if @a = @b; %FALSE otherwise
*/
/**
* GHashTableIter:
*
* A GHashTableIter structure represents an iterator that can be used
* to iterate over the elements of a #GHashTable. GHashTableIter
* structures are typically allocated on the stack and then initialized
* with g_hash_table_iter_init().
*
* The iteration order of a #GHashTableIter over the keys/values in a hash
* table is not defined.
*/
/**
* g_hash_table_freeze:
* @hash_table: a #GHashTable
*
* This function is deprecated and will be removed in the next major
* release of GLib. It does nothing.
*/
/**
* g_hash_table_thaw:
* @hash_table: a #GHashTable
*
* This function is deprecated and will be removed in the next major
* release of GLib. It does nothing.
*/
#define HASH_TABLE_MIN_SHIFT 3 /* 1 << 3 == 8 buckets */
#define UNUSED_HASH_VALUE 0
#define TOMBSTONE_HASH_VALUE 1
#define HASH_IS_UNUSED(h_) ((h_) == UNUSED_HASH_VALUE)
#define HASH_IS_TOMBSTONE(h_) ((h_) == TOMBSTONE_HASH_VALUE)
#define HASH_IS_REAL(h_) ((h_) >= 2)
/* The hash table can never have this as a valid position, as
* hash tables are allocated as a power of two, and the allocation
* required for this position would overflow. So we’re safe to use
* it to represent an invalid iter position. */
#define ITER_POSITION_INVALID G_MAXUINT
/* If int is smaller than void * on our arch, we start out with
* int-sized keys and values and resize to pointer-sized entries as
* needed. This saves a good amount of memory when the HT is being
* used with e.g. GUINT_TO_POINTER(). */
#define BIG_ENTRY_SIZE (SIZEOF_VOID_P)
#define SMALL_ENTRY_SIZE (SIZEOF_INT)
/* NB: The USE_SMALL_ARRAYS code assumes pointers are at most 8 bytes. */
#if SMALL_ENTRY_SIZE < BIG_ENTRY_SIZE && BIG_ENTRY_SIZE <= 8
# define USE_SMALL_ARRAYS
#endif
struct _GHashTable
{
gsize size;
gint mod;
guint mask;
guint nnodes;
guint noccupied; /* nnodes + tombstones */
guint have_big_keys : 1;
guint have_big_values : 1;
gpointer keys;
guint *hashes;
gpointer values;
GHashFunc hash_func;
GEqualFunc key_equal_func;
gatomicrefcount ref_count;
#ifndef G_DISABLE_ASSERT
/*
* Tracks the structure of the hash table, not its contents: is only
* incremented when a node is added or removed (is not incremented
* when the key or data of a node is modified).
*/
int version;
#endif
GDestroyNotify key_destroy_func;
GDestroyNotify value_destroy_func;
};
typedef struct
{
GHashTable *hash_table;
gpointer dummy1;
gpointer dummy2;
guint position;
gboolean dummy3;
gintptr version;
} RealIter;
G_STATIC_ASSERT (sizeof (GHashTableIter) == sizeof (RealIter));
G_STATIC_ASSERT (G_ALIGNOF (GHashTableIter) >= G_ALIGNOF (RealIter));
/* Each table size has an associated prime modulo (the first prime
* lower than the table size) used to find the initial bucket. Probing
* then works modulo 2^n. The prime modulo is necessary to get a
* good distribution with poor hash functions.
*/
static const gint prime_mod [] =
{
1, /* For 1 << 0 */
2,
3,
7,
13,
31,
61,
127,
251,
509,
1021,
2039,
4093,
8191,
16381,
32749,
65521, /* For 1 << 16 */
131071,
262139,
524287,
1048573,
2097143,
4194301,
8388593,
16777213,
33554393,
67108859,
134217689,
268435399,
536870909,
1073741789,
2147483647 /* For 1 << 31 */
};
static void
g_hash_table_set_shift (GHashTable *hash_table, gint shift)
{
if (shift > 31)
g_error ("adding more entries to hash table would overflow");
hash_table->size = 1u << shift;
hash_table->mod = prime_mod [shift];
/* hash_table->size is always a power of two, so we can calculate the mask
* by simply subtracting 1 from it. The leading assertion ensures that
* we're really dealing with a power of two. */
g_assert ((hash_table->size & (hash_table->size - 1)) == 0);
hash_table->mask = hash_table->size - 1;
}
static gint
g_hash_table_find_closest_shift (gint n)
{
gint i;
for (i = 0; n; i++)
n >>= 1;
return i;
}
static void
g_hash_table_set_shift_from_size (GHashTable *hash_table, gint size)
{
gint shift;
shift = g_hash_table_find_closest_shift (size);
shift = MAX (shift, HASH_TABLE_MIN_SHIFT);
g_hash_table_set_shift (hash_table, shift);
}
static inline gpointer
g_hash_table_realloc_key_or_value_array (gpointer a, size_t size, G_GNUC_UNUSED gboolean is_big)
{
#ifdef USE_SMALL_ARRAYS
return g_realloc (a, size * (is_big ? BIG_ENTRY_SIZE : SMALL_ENTRY_SIZE));
#else
return g_renew (gpointer, a, size);
#endif
}
static inline gpointer
g_hash_table_fetch_key_or_value (gpointer a, guint index, gboolean is_big)
{
#ifndef USE_SMALL_ARRAYS
is_big = TRUE;
#endif
return is_big ? *(((gpointer *) a) + index) : GUINT_TO_POINTER (*(((guint *) a) + index));
}
static inline void
g_hash_table_assign_key_or_value (gpointer a, guint index, gboolean is_big, gpointer v)
{
#ifndef USE_SMALL_ARRAYS
is_big = TRUE;
#endif
if (is_big)
*(((gpointer *) a) + index) = v;
else
*(((guint *) a) + index) = GPOINTER_TO_UINT (v);
}
static inline gpointer
g_hash_table_evict_key_or_value (gpointer a, guint index, gboolean is_big, gpointer v)
{
#ifndef USE_SMALL_ARRAYS
is_big = TRUE;
#endif
if (is_big)
{
gpointer r = *(((gpointer *) a) + index);
*(((gpointer *) a) + index) = v;
return r;
}
else
{
gpointer r = GUINT_TO_POINTER (*(((guint *) a) + index));
*(((guint *) a) + index) = GPOINTER_TO_UINT (v);
return r;
}
}
static inline guint
g_hash_table_hash_to_index (GHashTable *hash_table, guint hash)
{
/* Multiply the hash by a small prime before applying the modulo. This
* prevents the table from becoming densely packed, even with a poor hash
* function. A densely packed table would have poor performance on
* workloads with many failed lookups or a high degree of churn. */
return (hash * 11) % hash_table->mod;
}
/*
* g_hash_table_lookup_node:
* @hash_table: our #GHashTable
* @key: the key to look up against
* @hash_return: key hash return location
*
* Performs a lookup in the hash table, preserving extra information
* usually needed for insertion.
*
* This function first computes the hash value of the key using the
* user's hash function.
*
* If an entry in the table matching @key is found then this function
* returns the index of that entry in the table, and if not, the
* index of an unused node (empty or tombstone) where the key can be
* inserted.
*
* The computed hash value is returned in the variable pointed to
* by @hash_return. This is to save insertions from having to compute
* the hash record again for the new record.
*
* Returns: index of the described node
*/
static inline guint
g_hash_table_lookup_node (GHashTable *hash_table,
gconstpointer key,
guint *hash_return)
{
guint node_index;
guint node_hash;
guint hash_value;
guint first_tombstone = 0;
gboolean have_tombstone = FALSE;
guint step = 0;
hash_value = hash_table->hash_func (key);
if (G_UNLIKELY (!HASH_IS_REAL (hash_value)))
hash_value = 2;
*hash_return = hash_value;
node_index = g_hash_table_hash_to_index (hash_table, hash_value);
node_hash = hash_table->hashes[node_index];
while (!HASH_IS_UNUSED (node_hash))
{
/* We first check if our full hash values
* are equal so we can avoid calling the full-blown
* key equality function in most cases.
*/
if (node_hash == hash_value)
{
gpointer node_key = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
if (hash_table->key_equal_func)
{
if (hash_table->key_equal_func (node_key, key))
return node_index;
}
else if (node_key == key)
{
return node_index;
}
}
else if (HASH_IS_TOMBSTONE (node_hash) && !have_tombstone)
{
first_tombstone = node_index;
have_tombstone = TRUE;
}
step++;
node_index += step;
node_index &= hash_table->mask;
node_hash = hash_table->hashes[node_index];
}
if (have_tombstone)
return first_tombstone;
return node_index;
}
/*
* g_hash_table_remove_node:
* @hash_table: our #GHashTable
* @node: pointer to node to remove
* @notify: %TRUE if the destroy notify handlers are to be called
*
* Removes a node from the hash table and updates the node count.
* The node is replaced by a tombstone. No table resize is performed.
*
* If @notify is %TRUE then the destroy notify functions are called
* for the key and value of the hash node.
*/
static void
g_hash_table_remove_node (GHashTable *hash_table,
gint i,
gboolean notify)
{
gpointer key;
gpointer value;
key = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
value = g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values);
/* Erect tombstone */
hash_table->hashes[i] = TOMBSTONE_HASH_VALUE;
/* Be GC friendly */
g_hash_table_assign_key_or_value (hash_table->keys, i, hash_table->have_big_keys, NULL);
g_hash_table_assign_key_or_value (hash_table->values, i, hash_table->have_big_values, NULL);
g_assert (hash_table->nnodes > 0);
hash_table->nnodes--;
if (notify && hash_table->key_destroy_func)
hash_table->key_destroy_func (key);
if (notify && hash_table->value_destroy_func)
hash_table->value_destroy_func (value);
}
/*
* g_hash_table_setup_storage:
* @hash_table: our #GHashTable
*
* Initialise the hash table size, mask, mod, and arrays.
*/
static void
g_hash_table_setup_storage (GHashTable *hash_table)
{
gboolean small = FALSE;
/* We want to use small arrays only if:
* - we are running on a system where that makes sense (64 bit); and
* - we are not running under valgrind.
*/
#ifdef USE_SMALL_ARRAYS
small = TRUE;
# ifdef ENABLE_VALGRIND
if (RUNNING_ON_VALGRIND)
small = FALSE;
# endif
#endif
g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
hash_table->have_big_keys = !small;
hash_table->have_big_values = !small;
hash_table->keys = g_hash_table_realloc_key_or_value_array (NULL, hash_table->size, hash_table->have_big_keys);
hash_table->values = hash_table->keys;
hash_table->hashes = g_new0 (guint, hash_table->size);
}
/*
* g_hash_table_remove_all_nodes:
* @hash_table: our #GHashTable
* @notify: %TRUE if the destroy notify handlers are to be called
*
* Removes all nodes from the table.
*
* If @notify is %TRUE then the destroy notify functions are called
* for the key and value of the hash node.
*
* Since this may be a precursor to freeing the table entirely, we'd
* ideally perform no resize, and we can indeed avoid that in some
* cases. However: in the case that we'll be making callbacks to user
* code (via destroy notifies) we need to consider that the user code
* might call back into the table again. In this case, we setup a new
* set of arrays so that any callers will see an empty (but valid)
* table.
*/
static void
g_hash_table_remove_all_nodes (GHashTable *hash_table,
gboolean notify,
gboolean destruction)
{
int i;
gpointer key;
gpointer value;
gint old_size;
gpointer *old_keys;
gpointer *old_values;
guint *old_hashes;
gboolean old_have_big_keys;
gboolean old_have_big_values;
/* If the hash table is already empty, there is nothing to be done. */
if (hash_table->nnodes == 0)
return;
hash_table->nnodes = 0;
hash_table->noccupied = 0;
/* Easy case: no callbacks, so we just zero out the arrays */
if (!notify ||
(hash_table->key_destroy_func == NULL &&
hash_table->value_destroy_func == NULL))
{
if (!destruction)
{
memset (hash_table->hashes, 0, hash_table->size * sizeof (guint));
#ifdef USE_SMALL_ARRAYS
memset (hash_table->keys, 0, hash_table->size * (hash_table->have_big_keys ? BIG_ENTRY_SIZE : SMALL_ENTRY_SIZE));
memset (hash_table->values, 0, hash_table->size * (hash_table->have_big_values ? BIG_ENTRY_SIZE : SMALL_ENTRY_SIZE));
#else
memset (hash_table->keys, 0, hash_table->size * sizeof (gpointer));
memset (hash_table->values, 0, hash_table->size * sizeof (gpointer));
#endif
}
return;
}
/* Hard case: we need to do user callbacks. There are two
* possibilities here:
*
* 1) there are no outstanding references on the table and therefore
* nobody should be calling into it again (destroying == true)
*
* 2) there are outstanding references, and there may be future
* calls into the table, either after we return, or from the destroy
* notifies that we're about to do (destroying == false)
*
* We handle both cases by taking the current state of the table into
* local variables and replacing it with something else: in the "no
* outstanding references" cases we replace it with a bunch of
* null/zero values so that any access to the table will fail. In the
* "may receive future calls" case, we reinitialise the struct to
* appear like a newly-created empty table.
*
* In both cases, we take over the references for the current state,
* freeing them below.
*/
old_size = hash_table->size;
old_have_big_keys = hash_table->have_big_keys;
old_have_big_values = hash_table->have_big_values;
old_keys = g_steal_pointer (&hash_table->keys);
old_values = g_steal_pointer (&hash_table->values);
old_hashes = g_steal_pointer (&hash_table->hashes);
if (!destruction)
/* Any accesses will see an empty table */
g_hash_table_setup_storage (hash_table);
else
/* Will cause a quick crash on any attempted access */
hash_table->size = hash_table->mod = hash_table->mask = 0;
/* Now do the actual destroy notifies */
for (i = 0; i < old_size; i++)
{
if (HASH_IS_REAL (old_hashes[i]))
{
key = g_hash_table_fetch_key_or_value (old_keys, i, old_have_big_keys);
value = g_hash_table_fetch_key_or_value (old_values, i, old_have_big_values);
old_hashes[i] = UNUSED_HASH_VALUE;
g_hash_table_assign_key_or_value (old_keys, i, old_have_big_keys, NULL);
g_hash_table_assign_key_or_value (old_values, i, old_have_big_values, NULL);
if (hash_table->key_destroy_func != NULL)
hash_table->key_destroy_func (key);
if (hash_table->value_destroy_func != NULL)
hash_table->value_destroy_func (value);
}
}
/* Destroy old storage space. */
if (old_keys != old_values)
g_free (old_values);
g_free (old_keys);
g_free (old_hashes);
}
static void
realloc_arrays (GHashTable *hash_table, gboolean is_a_set)
{
hash_table->hashes = g_renew (guint, hash_table->hashes, hash_table->size);
hash_table->keys = g_hash_table_realloc_key_or_value_array (hash_table->keys, hash_table->size, hash_table->have_big_keys);
if (is_a_set)
hash_table->values = hash_table->keys;
else
hash_table->values = g_hash_table_realloc_key_or_value_array (hash_table->values, hash_table->size, hash_table->have_big_values);
}
/* When resizing the table in place, we use a temporary bit array to keep
* track of which entries have been assigned a proper location in the new
* table layout.
*
* Each bit corresponds to a bucket. A bit is set if an entry was assigned
* its corresponding location during the resize and thus should not be
* evicted. The array starts out cleared to zero. */
static inline gboolean
get_status_bit (const guint32 *bitmap, guint index)
{
return (bitmap[index / 32] >> (index % 32)) & 1;
}
static inline void
set_status_bit (guint32 *bitmap, guint index)
{
bitmap[index / 32] |= 1U << (index % 32);
}
/* By calling dedicated resize functions for sets and maps, we avoid 2x
* test-and-branch per key in the inner loop. This yields a small
* performance improvement at the cost of a bit of macro gunk. */
#define DEFINE_RESIZE_FUNC(fname) \
static void fname (GHashTable *hash_table, guint old_size, guint32 *reallocated_buckets_bitmap) \
{ \
guint i; \
\
for (i = 0; i < old_size; i++) \
{ \
guint node_hash = hash_table->hashes[i]; \
gpointer key, value G_GNUC_UNUSED; \
\
if (!HASH_IS_REAL (node_hash)) \
{ \
/* Clear tombstones */ \
hash_table->hashes[i] = UNUSED_HASH_VALUE; \
continue; \
} \
\
/* Skip entries relocated through eviction */ \
if (get_status_bit (reallocated_buckets_bitmap, i)) \
continue; \
\
hash_table->hashes[i] = UNUSED_HASH_VALUE; \
EVICT_KEYVAL (hash_table, i, NULL, NULL, key, value); \
\
for (;;) \
{ \
guint hash_val; \
guint replaced_hash; \
guint step = 0; \
\
hash_val = g_hash_table_hash_to_index (hash_table, node_hash); \
\
while (get_status_bit (reallocated_buckets_bitmap, hash_val)) \
{ \
step++; \
hash_val += step; \
hash_val &= hash_table->mask; \
} \
\
set_status_bit (reallocated_buckets_bitmap, hash_val); \
\
replaced_hash = hash_table->hashes[hash_val]; \
hash_table->hashes[hash_val] = node_hash; \
if (!HASH_IS_REAL (replaced_hash)) \
{ \
ASSIGN_KEYVAL (hash_table, hash_val, key, value); \
break; \
} \
\
node_hash = replaced_hash; \
EVICT_KEYVAL (hash_table, hash_val, key, value, key, value); \
} \
} \
}
#define ASSIGN_KEYVAL(ht, index, key, value) G_STMT_START{ \
g_hash_table_assign_key_or_value ((ht)->keys, (index), (ht)->have_big_keys, (key)); \
g_hash_table_assign_key_or_value ((ht)->values, (index), (ht)->have_big_values, (value)); \
}G_STMT_END
#define EVICT_KEYVAL(ht, index, key, value, outkey, outvalue) G_STMT_START{ \
(outkey) = g_hash_table_evict_key_or_value ((ht)->keys, (index), (ht)->have_big_keys, (key)); \
(outvalue) = g_hash_table_evict_key_or_value ((ht)->values, (index), (ht)->have_big_values, (value)); \
}G_STMT_END
DEFINE_RESIZE_FUNC (resize_map)
#undef ASSIGN_KEYVAL
#undef EVICT_KEYVAL
#define ASSIGN_KEYVAL(ht, index, key, value) G_STMT_START{ \
g_hash_table_assign_key_or_value ((ht)->keys, (index), (ht)->have_big_keys, (key)); \
}G_STMT_END
#define EVICT_KEYVAL(ht, index, key, value, outkey, outvalue) G_STMT_START{ \
(outkey) = g_hash_table_evict_key_or_value ((ht)->keys, (index), (ht)->have_big_keys, (key)); \
}G_STMT_END
DEFINE_RESIZE_FUNC (resize_set)
#undef ASSIGN_KEYVAL
#undef EVICT_KEYVAL
/*
* g_hash_table_resize:
* @hash_table: our #GHashTable
*
* Resizes the hash table to the optimal size based on the number of
* nodes currently held. If you call this function then a resize will
* occur, even if one does not need to occur.
* Use g_hash_table_maybe_resize() instead.
*
* This function may "resize" the hash table to its current size, with
* the side effect of cleaning up tombstones and otherwise optimizing
* the probe sequences.
*/
static void
g_hash_table_resize (GHashTable *hash_table)
{
guint32 *reallocated_buckets_bitmap;
gsize old_size;
gboolean is_a_set;
old_size = hash_table->size;
is_a_set = hash_table->keys == hash_table->values;
/* The outer checks in g_hash_table_maybe_resize() will only consider
* cleanup/resize when the load factor goes below .25 (1/4, ignoring
* tombstones) or above .9375 (15/16, including tombstones).
*
* Once this happens, tombstones will always be cleaned out. If our
* load sans tombstones is greater than .75 (1/1.333, see below), we'll
* take this opportunity to grow the table too.
*
* Immediately after growing, the load factor will be in the range
* .375 .. .469. After shrinking, it will be exactly .5. */
g_hash_table_set_shift_from_size (hash_table, (gint) (hash_table->nnodes * 1.333));
if (hash_table->size > old_size)
{
realloc_arrays (hash_table, is_a_set);
memset (&hash_table->hashes[old_size], 0, (hash_table->size - old_size) * sizeof (guint));
reallocated_buckets_bitmap = g_new0 (guint32, (hash_table->size + 31) / 32);
}
else
{
reallocated_buckets_bitmap = g_new0 (guint32, (old_size + 31) / 32);
}
if (is_a_set)
resize_set (hash_table, old_size, reallocated_buckets_bitmap);
else
resize_map (hash_table, old_size, reallocated_buckets_bitmap);
g_free (reallocated_buckets_bitmap);
if (hash_table->size < old_size)
realloc_arrays (hash_table, is_a_set);
hash_table->noccupied = hash_table->nnodes;
}
/*
* g_hash_table_maybe_resize:
* @hash_table: our #GHashTable
*
* Resizes the hash table, if needed.
*
* Essentially, calls g_hash_table_resize() if the table has strayed
* too far from its ideal size for its number of nodes.
*/
static inline void
g_hash_table_maybe_resize (GHashTable *hash_table)
{
gsize noccupied = hash_table->noccupied;
gsize size = hash_table->size;
if ((size > hash_table->nnodes * 4 && size > 1 << HASH_TABLE_MIN_SHIFT) ||
(size <= noccupied + (noccupied / 16)))
g_hash_table_resize (hash_table);
}
#ifdef USE_SMALL_ARRAYS
static inline gboolean
entry_is_big (gpointer v)
{
return (((guintptr) v) >> (SMALL_ENTRY_SIZE * 8)) != 0;
}
static inline gboolean
g_hash_table_maybe_make_big_keys_or_values (gpointer *a_p, gpointer v, gint ht_size)
{
if (entry_is_big (v))
{
guint *a = (guint *) *a_p;
gpointer *a_new;
gint i;
a_new = g_new (gpointer, ht_size);
for (i = 0; i < ht_size; i++)
{
a_new[i] = GUINT_TO_POINTER (a[i]);
}
g_free (a);
*a_p = a_new;
return TRUE;
}
return FALSE;
}
#endif
static inline void
g_hash_table_ensure_keyval_fits (GHashTable *hash_table, gpointer key, gpointer value)
{
gboolean is_a_set = (hash_table->keys == hash_table->values);
#ifdef USE_SMALL_ARRAYS
/* Convert from set to map? */
if (is_a_set)
{
if (hash_table->have_big_keys)
{
if (key != value)
hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size);
/* Keys and values are both big now, so no need for further checks */
return;
}
else
{
if (key != value)
{
hash_table->values = g_memdup2 (hash_table->keys, sizeof (guint) * hash_table->size);
is_a_set = FALSE;
}
}
}
/* Make keys big? */
if (!hash_table->have_big_keys)
{
hash_table->have_big_keys = g_hash_table_maybe_make_big_keys_or_values (&hash_table->keys, key, hash_table->size);
if (is_a_set)
{
hash_table->values = hash_table->keys;
hash_table->have_big_values = hash_table->have_big_keys;
}
}
/* Make values big? */
if (!is_a_set && !hash_table->have_big_values)
{
hash_table->have_big_values = g_hash_table_maybe_make_big_keys_or_values (&hash_table->values, value, hash_table->size);
}
#else
/* Just split if necessary */
if (is_a_set && key != value)
hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size);
#endif
}
/**
* g_hash_table_new:
* @hash_func: a function to create a hash value from a key
* @key_equal_func: a function to check two keys for equality
*
* Creates a new #GHashTable with a reference count of 1.
*
* Hash values returned by @hash_func are used to determine where keys
* are stored within the #GHashTable data structure. The g_direct_hash(),
* g_int_hash(), g_int64_hash(), g_double_hash() and g_str_hash()
* functions are provided for some common types of keys.
* If @hash_func is %NULL, g_direct_hash() is used.
*
* @key_equal_func is used when looking up keys in the #GHashTable.
* The g_direct_equal(), g_int_equal(), g_int64_equal(), g_double_equal()
* and g_str_equal() functions are provided for the most common types
* of keys. If @key_equal_func is %NULL, keys are compared directly in
* a similar fashion to g_direct_equal(), but without the overhead of
* a function call. @key_equal_func is called with the key from the hash table
* as its first parameter, and the user-provided key to check against as
* its second.
*
* Returns: (transfer full): a new #GHashTable
*/
GHashTable *
g_hash_table_new (GHashFunc hash_func,
GEqualFunc key_equal_func)
{
return g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL);
}
/**
* g_hash_table_new_full:
* @hash_func: a function to create a hash value from a key
* @key_equal_func: a function to check two keys for equality
* @key_destroy_func: (nullable): a function to free the memory allocated for the key
* used when removing the entry from the #GHashTable, or %NULL
* if you don't want to supply such a function.
* @value_destroy_func: (nullable): a function to free the memory allocated for the
* value used when removing the entry from the #GHashTable, or %NULL
* if you don't want to supply such a function.
*
* Creates a new #GHashTable like g_hash_table_new() with a reference
* count of 1 and allows to specify functions to free the memory
* allocated for the key and value that get called when removing the
* entry from the #GHashTable.
*
* Since version 2.42 it is permissible for destroy notify functions to
* recursively remove further items from the hash table. This is only
* permissible if the application still holds a reference to the hash table.
* This means that you may need to ensure that the hash table is empty by
* calling g_hash_table_remove_all() before releasing the last reference using
* g_hash_table_unref().
*
* Returns: (transfer full): a new #GHashTable
*/
GHashTable *
g_hash_table_new_full (GHashFunc hash_func,
GEqualFunc key_equal_func,
GDestroyNotify key_destroy_func,
GDestroyNotify value_destroy_func)
{
GHashTable *hash_table;
hash_table = g_slice_new (GHashTable);
g_atomic_ref_count_init (&hash_table->ref_count);
hash_table->nnodes = 0;
hash_table->noccupied = 0;
hash_table->hash_func = hash_func ? hash_func : g_direct_hash;
hash_table->key_equal_func = key_equal_func;
#ifndef G_DISABLE_ASSERT
hash_table->version = 0;
#endif
hash_table->key_destroy_func = key_destroy_func;
hash_table->value_destroy_func = value_destroy_func;
g_hash_table_setup_storage (hash_table);
return hash_table;
}
/**
* g_hash_table_new_similar:
* @other_hash_table: (not nullable) (transfer none): Another #GHashTable
*
* Creates a new #GHashTable like g_hash_table_new_full() with a reference
* count of 1.
*
* It inherits the hash function, the key equal function, the key destroy function,
* as well as the value destroy function, from @other_hash_table.
*
* The returned hash table will be empty; it will not contain the keys
* or values from @other_hash_table.
*
* Returns: (transfer full) (not nullable): a new #GHashTable
* Since: 2.72
*/
GHashTable *
g_hash_table_new_similar (GHashTable *other_hash_table)
{
g_return_val_if_fail (other_hash_table, NULL);
return g_hash_table_new_full (other_hash_table->hash_func,
other_hash_table->key_equal_func,
other_hash_table->key_destroy_func,
other_hash_table->value_destroy_func);
}
/**
* g_hash_table_iter_init:
* @iter: an uninitialized #GHashTableIter
* @hash_table: a #GHashTable
*
* Initializes a key/value pair iterator and associates it with
* @hash_table. Modifying the hash table after calling this function
* invalidates the returned iterator.
*
* The iteration order of a #GHashTableIter over the keys/values in a hash
* table is not defined.
*
* |[<!-- language="C" -->
* GHashTableIter iter;
* gpointer key, value;
*
* g_hash_table_iter_init (&iter, hash_table);
* while (g_hash_table_iter_next (&iter, &key, &value))
* {
* // do something with key and value
* }
* ]|
*
* Since: 2.16
*/
void
g_hash_table_iter_init (GHashTableIter *iter,
GHashTable *hash_table)
{
RealIter *ri = (RealIter *) iter;
g_return_if_fail (iter != NULL);
g_return_if_fail (hash_table != NULL);
ri->hash_table = hash_table;
ri->position = ITER_POSITION_INVALID;
#ifndef G_DISABLE_ASSERT
ri->version = hash_table->version;
#endif
}
/**
* g_hash_table_iter_next:
* @iter: an initialized #GHashTableIter
* @key: (out) (optional) (nullable): a location to store the key
* @value: (out) (optional) (nullable): a location to store the value
*
* Advances @iter and retrieves the key and/or value that are now
* pointed to as a result of this advancement. If %FALSE is returned,
* @key and @value are not set, and the iterator becomes invalid.
*
* Returns: %FALSE if the end of the #GHashTable has been reached.
*
* Since: 2.16
*/
gboolean
g_hash_table_iter_next (GHashTableIter *iter,
gpointer *key,
gpointer *value)
{
RealIter *ri = (RealIter *) iter;
guint position;
g_return_val_if_fail (iter != NULL, FALSE);
#ifndef G_DISABLE_ASSERT
g_return_val_if_fail (ri->version == ri->hash_table->version, FALSE);
#endif
g_return_val_if_fail (ri->position < ri->hash_table->size || ri->position == ITER_POSITION_INVALID, FALSE);
position = ri->position;
do
{
position++;
if (position >= ri->hash_table->size)
{
ri->position = position;
return FALSE;
}
}
while (!HASH_IS_REAL (ri->hash_table->hashes[position]));
if (key != NULL)
*key = g_hash_table_fetch_key_or_value (ri->hash_table->keys, position, ri->hash_table->have_big_keys);
if (value != NULL)
*value = g_hash_table_fetch_key_or_value (ri->hash_table->values, position, ri->hash_table->have_big_values);
ri->position = position;
return TRUE;
}
/**
* g_hash_table_iter_get_hash_table:
* @iter: an initialized #GHashTableIter
*
* Returns the #GHashTable associated with @iter.
*
* Returns: (transfer none): the #GHashTable associated with @iter.
*
* Since: 2.16
*/
GHashTable *
g_hash_table_iter_get_hash_table (GHashTableIter *iter)
{
g_return_val_if_fail (iter != NULL, NULL);
return ((RealIter *) iter)->hash_table;
}
static void
iter_remove_or_steal (RealIter *ri, gboolean notify)
{
g_return_if_fail (ri != NULL);
#ifndef G_DISABLE_ASSERT
g_return_if_fail (ri->version == ri->hash_table->version);
#endif
g_return_if_fail (ri->position != ITER_POSITION_INVALID);
g_return_if_fail ((gsize) ri->position < ri->hash_table->size);
g_hash_table_remove_node (ri->hash_table, ri->position, notify);
#ifndef G_DISABLE_ASSERT
ri->version++;
ri->hash_table->version++;
#endif
}
/**
* g_hash_table_iter_remove:
* @iter: an initialized #GHashTableIter
*
* Removes the key/value pair currently pointed to by the iterator
* from its associated #GHashTable. Can only be called after
* g_hash_table_iter_next() returned %TRUE, and cannot be called
* more than once for the same key/value pair.
*
* If the #GHashTable was created using g_hash_table_new_full(),
* the key and value are freed using the supplied destroy functions,
* otherwise you have to make sure that any dynamically allocated
* values are freed yourself.
*
* It is safe to continue iterating the #GHashTable afterward:
* |[<!-- language="C" -->
* while (g_hash_table_iter_next (&iter, &key, &value))
* {
* if (condition)
* g_hash_table_iter_remove (&iter);
* }
* ]|
*
* Since: 2.16
*/
void
g_hash_table_iter_remove (GHashTableIter *iter)
{
iter_remove_or_steal ((RealIter *) iter, TRUE);
}
/*
* g_hash_table_insert_node:
* @hash_table: our #GHashTable
* @node_index: pointer to node to insert/replace
* @key_hash: key hash
* @key: (nullable): key to replace with, or %NULL
* @value: value to replace with
* @keep_new_key: whether to replace the key in the node with @key
* @reusing_key: whether @key was taken out of the existing node
*
* Inserts a value at @node_index in the hash table and updates it.
*
* If @key has been taken out of the existing node (ie it is not
* passed in via a g_hash_table_insert/replace) call, then @reusing_key
* should be %TRUE.
*
* Returns: %TRUE if the key did not exist yet
*/
static gboolean
g_hash_table_insert_node (GHashTable *hash_table,
guint node_index,
guint key_hash,
gpointer new_key,
gpointer new_value,
gboolean keep_new_key,
gboolean reusing_key)
{
gboolean already_exists;
guint old_hash;
gpointer key_to_free = NULL;
gpointer key_to_keep = NULL;
gpointer value_to_free = NULL;
old_hash = hash_table->hashes[node_index];
already_exists = HASH_IS_REAL (old_hash);
/* Proceed in three steps. First, deal with the key because it is the
* most complicated. Then consider if we need to split the table in
* two (because writing the value will result in the set invariant
* becoming broken). Then deal with the value.
*
* There are three cases for the key:
*
* - entry already exists in table, reusing key:
* free the just-passed-in new_key and use the existing value
*
* - entry already exists in table, not reusing key:
* free the entry in the table, use the new key
*
* - entry not already in table:
* use the new key, free nothing
*
* We update the hash at the same time...
*/
if (already_exists)
{
/* Note: we must record the old value before writing the new key
* because we might change the value in the event that the two
* arrays are shared.
*/
value_to_free = g_hash_table_fetch_key_or_value (hash_table->values, node_index, hash_table->have_big_values);
if (keep_new_key)
{
key_to_free = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
key_to_keep = new_key;
}
else
{
key_to_free = new_key;
key_to_keep = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
}
}
else
{
hash_table->hashes[node_index] = key_hash;
key_to_keep = new_key;
}
/* Resize key/value arrays and split table as necessary */
g_hash_table_ensure_keyval_fits (hash_table, key_to_keep, new_value);
g_hash_table_assign_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys, key_to_keep);
/* Step 3: Actually do the write */
g_hash_table_assign_key_or_value (hash_table->values, node_index, hash_table->have_big_values, new_value);
/* Now, the bookkeeping... */
if (!already_exists)
{
hash_table->nnodes++;
if (HASH_IS_UNUSED (old_hash))
{
/* We replaced an empty node, and not a tombstone */
hash_table->noccupied++;
g_hash_table_maybe_resize (hash_table);
}
#ifndef G_DISABLE_ASSERT
hash_table->version++;
#endif
}
if (already_exists)
{
if (hash_table->key_destroy_func && !reusing_key)
(* hash_table->key_destroy_func) (key_to_free);
if (hash_table->value_destroy_func)
(* hash_table->value_destroy_func) (value_to_free);
}
return !already_exists;
}
/**
* g_hash_table_iter_replace:
* @iter: an initialized #GHashTableIter
* @value: the value to replace with
*
* Replaces the value currently pointed to by the iterator
* from its associated #GHashTable. Can only be called after
* g_hash_table_iter_next() returned %TRUE.
*
* If you supplied a @value_destroy_func when creating the
* #GHashTable, the old value is freed using that function.
*
* Since: 2.30
*/
void
g_hash_table_iter_replace (GHashTableIter *iter,
gpointer value)
{
RealIter *ri;
guint node_hash;
gpointer key;
ri = (RealIter *) iter;
g_return_if_fail (ri != NULL);
#ifndef G_DISABLE_ASSERT
g_return_if_fail (ri->version == ri->hash_table->version);
#endif
g_return_if_fail (ri->position != ITER_POSITION_INVALID);
g_return_if_fail ((gsize) ri->position < ri->hash_table->size);
node_hash = ri->hash_table->hashes[ri->position];
key = g_hash_table_fetch_key_or_value (ri->hash_table->keys, ri->position, ri->hash_table->have_big_keys);
g_hash_table_insert_node (ri->hash_table, ri->position, node_hash, key, value, TRUE, TRUE);
#ifndef G_DISABLE_ASSERT
ri->version++;
ri->hash_table->version++;
#endif
}
/**
* g_hash_table_iter_steal:
* @iter: an initialized #GHashTableIter
*
* Removes the key/value pair currently pointed to by the
* iterator from its associated #GHashTable, without calling
* the key and value destroy functions. Can only be called
* after g_hash_table_iter_next() returned %TRUE, and cannot
* be called more than once for the same key/value pair.
*
* Since: 2.16
*/
void
g_hash_table_iter_steal (GHashTableIter *iter)
{
iter_remove_or_steal ((RealIter *) iter, FALSE);
}
/**
* g_hash_table_ref:
* @hash_table: a valid #GHashTable
*
* Atomically increments the reference count of @hash_table by one.
* This function is MT-safe and may be called from any thread.
*
* Returns: (transfer full): the passed in #GHashTable
*
* Since: 2.10
*/
GHashTable *
g_hash_table_ref (GHashTable *hash_table)
{
g_return_val_if_fail (hash_table != NULL, NULL);
g_atomic_ref_count_inc (&hash_table->ref_count);
return hash_table;
}
/**
* g_hash_table_unref:
* @hash_table: (transfer full): a valid #GHashTable
*
* Atomically decrements the reference count of @hash_table by one.
* If the reference count drops to 0, all keys and values will be
* destroyed, and all memory allocated by the hash table is released.
* This function is MT-safe and may be called from any thread.
*
* Since: 2.10
*/
void
g_hash_table_unref (GHashTable *hash_table)
{
g_return_if_fail (hash_table != NULL);
if (g_atomic_ref_count_dec (&hash_table->ref_count))
{
g_hash_table_remove_all_nodes (hash_table, TRUE, TRUE);
if (hash_table->keys != hash_table->values)
g_free (hash_table->values);
g_free (hash_table->keys);
g_free (hash_table->hashes);
g_slice_free (GHashTable, hash_table);
}
}
/**
* g_hash_table_destroy:
* @hash_table: a #GHashTable
*
* Destroys all keys and values in the #GHashTable and decrements its
* reference count by 1. If keys and/or values are dynamically allocated,
* you should either free them first or create the #GHashTable with destroy
* notifiers using g_hash_table_new_full(). In the latter case the destroy
* functions you supplied will be called on all keys and values during the
* destruction phase.
*/
void
g_hash_table_destroy (GHashTable *hash_table)
{
g_return_if_fail (hash_table != NULL);
g_hash_table_remove_all (hash_table);
g_hash_table_unref (hash_table);
}
/**
* g_hash_table_lookup:
* @hash_table: a #GHashTable
* @key: the key to look up
*
* Looks up a key in a #GHashTable. Note that this function cannot
* distinguish between a key that is not present and one which is present
* and has the value %NULL. If you need this distinction, use
* g_hash_table_lookup_extended().
*
* Returns: (nullable): the associated value, or %NULL if the key is not found
*/
gpointer
g_hash_table_lookup (GHashTable *hash_table,
gconstpointer key)
{
guint node_index;
guint node_hash;
g_return_val_if_fail (hash_table != NULL, NULL);
node_index = g_hash_table_lookup_node (hash_table, key, &node_hash);
return HASH_IS_REAL (hash_table->hashes[node_index])
? g_hash_table_fetch_key_or_value (hash_table->values, node_index, hash_table->have_big_values)
: NULL;
}
/**
* g_hash_table_lookup_extended:
* @hash_table: a #GHashTable
* @lookup_key: the key to look up
* @orig_key: (out) (optional): return location for the original key
* @value: (out) (optional) (nullable): return location for the value associated
* with the key
*
* Looks up a key in the #GHashTable, returning the original key and the
* associated value and a #gboolean which is %TRUE if the key was found. This
* is useful if you need to free the memory allocated for the original key,
* for example before calling g_hash_table_remove().
*
* You can actually pass %NULL for @lookup_key to test
* whether the %NULL key exists, provided the hash and equal functions
* of @hash_table are %NULL-safe.
*
* Returns: %TRUE if the key was found in the #GHashTable
*/
gboolean
g_hash_table_lookup_extended (GHashTable *hash_table,
gconstpointer lookup_key,
gpointer *orig_key,
gpointer *value)
{
guint node_index;
guint node_hash;
g_return_val_if_fail (hash_table != NULL, FALSE);
node_index = g_hash_table_lookup_node (hash_table, lookup_key, &node_hash);
if (!HASH_IS_REAL (hash_table->hashes[node_index]))
{
if (orig_key != NULL)
*orig_key = NULL;
if (value != NULL)
*value = NULL;
return FALSE;
}
if (orig_key)
*orig_key = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
if (value)
*value = g_hash_table_fetch_key_or_value (hash_table->values, node_index, hash_table->have_big_values);
return TRUE;
}
/*
* g_hash_table_insert_internal:
* @hash_table: our #GHashTable
* @key: the key to insert
* @value: the value to insert
* @keep_new_key: if %TRUE and this key already exists in the table
* then call the destroy notify function on the old key. If %FALSE
* then call the destroy notify function on the new key.
*
* Implements the common logic for the g_hash_table_insert() and
* g_hash_table_replace() functions.
*
* Do a lookup of @key. If it is found, replace it with the new
* @value (and perhaps the new @key). If it is not found, create
* a new node.
*
* Returns: %TRUE if the key did not exist yet
*/
static gboolean
g_hash_table_insert_internal (GHashTable *hash_table,
gpointer key,
gpointer value,
gboolean keep_new_key)
{
guint key_hash;
guint node_index;
g_return_val_if_fail (hash_table != NULL, FALSE);
node_index = g_hash_table_lookup_node (hash_table, key, &key_hash);
return g_hash_table_insert_node (hash_table, node_index, key_hash, key, value, keep_new_key, FALSE);
}
/**
* g_hash_table_insert:
* @hash_table: a #GHashTable
* @key: a key to insert
* @value: the value to associate with the key
*
* Inserts a new key and value into a #GHashTable.
*
* If the key already exists in the #GHashTable its current
* value is replaced with the new value. If you supplied a
* @value_destroy_func when creating the #GHashTable, the old
* value is freed using that function. If you supplied a
* @key_destroy_func when creating the #GHashTable, the passed
* key is freed using that function.
*
* Starting from GLib 2.40, this function returns a boolean value to
* indicate whether the newly added value was already in the hash table
* or not.
*
* Returns: %TRUE if the key did not exist yet
*/
gboolean
g_hash_table_insert (GHashTable *hash_table,
gpointer key,
gpointer value)
{
return g_hash_table_insert_internal (hash_table, key, value, FALSE);
}
/**
* g_hash_table_replace:
* @hash_table: a #GHashTable
* @key: a key to insert
* @value: the value to associate with the key
*
* Inserts a new key and value into a #GHashTable similar to
* g_hash_table_insert(). The difference is that if the key
* already exists in the #GHashTable, it gets replaced by the
* new key. If you supplied a @value_destroy_func when creating
* the #GHashTable, the old value is freed using that function.
* If you supplied a @key_destroy_func when creating the
* #GHashTable, the old key is freed using that function.
*
* Starting from GLib 2.40, this function returns a boolean value to
* indicate whether the newly added value was already in the hash table
* or not.
*
* Returns: %TRUE if the key did not exist yet
*/
gboolean
g_hash_table_replace (GHashTable *hash_table,
gpointer key,
gpointer value)
{
return g_hash_table_insert_internal (hash_table, key, value, TRUE);
}
/**
* g_hash_table_add:
* @hash_table: a #GHashTable
* @key: (transfer full): a key to insert
*
* This is a convenience function for using a #GHashTable as a set. It
* is equivalent to calling g_hash_table_replace() with @key as both the
* key and the value.
*
* In particular, this means that if @key already exists in the hash table, then
* the old copy of @key in the hash table is freed and @key replaces it in the
* table.
*
* When a hash table only ever contains keys that have themselves as the
* corresponding value it is able to be stored more efficiently. See
* the discussion in the section description.
*
* Starting from GLib 2.40, this function returns a boolean value to
* indicate whether the newly added value was already in the hash table
* or not.
*
* Returns: %TRUE if the key did not exist yet
*
* Since: 2.32
*/
gboolean
g_hash_table_add (GHashTable *hash_table,
gpointer key)
{
return g_hash_table_insert_internal (hash_table, key, key, TRUE);
}
/**
* g_hash_table_contains:
* @hash_table: a #GHashTable
* @key: a key to check
*
* Checks if @key is in @hash_table.
*
* Returns: %TRUE if @key is in @hash_table, %FALSE otherwise.
*
* Since: 2.32
**/
gboolean
g_hash_table_contains (GHashTable *hash_table,
gconstpointer key)
{
guint node_index;
guint node_hash;
g_return_val_if_fail (hash_table != NULL, FALSE);
node_index = g_hash_table_lookup_node (hash_table, key, &node_hash);
return HASH_IS_REAL (hash_table->hashes[node_index]);
}
/*
* g_hash_table_remove_internal:
* @hash_table: our #GHashTable
* @key: the key to remove
* @notify: %TRUE if the destroy notify handlers are to be called
* Returns: %TRUE if a node was found and removed, else %FALSE
*
* Implements the common logic for the g_hash_table_remove() and
* g_hash_table_steal() functions.
*
* Do a lookup of @key and remove it if it is found, calling the
* destroy notify handlers only if @notify is %TRUE.
*/
static gboolean
g_hash_table_remove_internal (GHashTable *hash_table,
gconstpointer key,
gboolean notify)
{
guint node_index;
guint node_hash;
g_return_val_if_fail (hash_table != NULL, FALSE);
node_index = g_hash_table_lookup_node (hash_table, key, &node_hash);
if (!HASH_IS_REAL (hash_table->hashes[node_index]))
return FALSE;
g_hash_table_remove_node (hash_table, node_index, notify);
g_hash_table_maybe_resize (hash_table);
#ifndef G_DISABLE_ASSERT
hash_table->version++;
#endif
return TRUE;
}
/**
* g_hash_table_remove:
* @hash_table: a #GHashTable
* @key: the key to remove
*
* Removes a key and its associated value from a #GHashTable.
*
* If the #GHashTable was created using g_hash_table_new_full(), the
* key and value are freed using the supplied destroy functions, otherwise
* you have to make sure that any dynamically allocated values are freed
* yourself.
*
* Returns: %TRUE if the key was found and removed from the #GHashTable
*/
gboolean
g_hash_table_remove (GHashTable *hash_table,
gconstpointer key)
{
return g_hash_table_remove_internal (hash_table, key, TRUE);
}
/**
* g_hash_table_steal:
* @hash_table: a #GHashTable
* @key: the key to remove
*
* Removes a key and its associated value from a #GHashTable without
* calling the key and value destroy functions.
*
* Returns: %TRUE if the key was found and removed from the #GHashTable
*/
gboolean
g_hash_table_steal (GHashTable *hash_table,
gconstpointer key)
{
return g_hash_table_remove_internal (hash_table, key, FALSE);
}
/**
* g_hash_table_steal_extended:
* @hash_table: a #GHashTable
* @lookup_key: the key to look up
* @stolen_key: (out) (optional) (transfer full): return location for the
* original key
* @stolen_value: (out) (optional) (nullable) (transfer full): return location
* for the value associated with the key
*
* Looks up a key in the #GHashTable, stealing the original key and the
* associated value and returning %TRUE if the key was found. If the key was
* not found, %FALSE is returned.
*
* If found, the stolen key and value are removed from the hash table without
* calling the key and value destroy functions, and ownership is transferred to
* the caller of this method, as with g_hash_table_steal(). That is the case
* regardless whether @stolen_key or @stolen_value output parameters are
* requested.
*
* You can pass %NULL for @lookup_key, provided the hash and equal functions
* of @hash_table are %NULL-safe.
*
* The dictionary implementation optimizes for having all values identical to
* their keys, for example by using g_hash_table_add(). Before 2.82, when
* stealing both the key and the value from such a dictionary, the value was
* %NULL. Since 2.82, the returned value and key will be the same.
*
* Returns: %TRUE if the key was found in the #GHashTable
* Since: 2.58
*/
gboolean
g_hash_table_steal_extended (GHashTable *hash_table,
gconstpointer lookup_key,
gpointer *stolen_key,
gpointer *stolen_value)
{
guint node_index;
guint node_hash;
g_return_val_if_fail (hash_table != NULL, FALSE);
node_index = g_hash_table_lookup_node (hash_table, lookup_key, &node_hash);
if (!HASH_IS_REAL (hash_table->hashes[node_index]))
{
if (stolen_key != NULL)
*stolen_key = NULL;
if (stolen_value != NULL)
*stolen_value = NULL;
return FALSE;
}
if (stolen_key != NULL)
{
*stolen_key = g_hash_table_fetch_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys);
g_hash_table_assign_key_or_value (hash_table->keys, node_index, hash_table->have_big_keys, NULL);
}
if (stolen_value != NULL)
{
if (stolen_key && hash_table->keys == hash_table->values)
*stolen_value = *stolen_key;
else
{
*stolen_value = g_hash_table_fetch_key_or_value (hash_table->values, node_index, hash_table->have_big_values);
g_hash_table_assign_key_or_value (hash_table->values, node_index, hash_table->have_big_values, NULL);
}
}
g_hash_table_remove_node (hash_table, node_index, FALSE);
g_hash_table_maybe_resize (hash_table);
#ifndef G_DISABLE_ASSERT
hash_table->version++;
#endif
return TRUE;
}
/**
* g_hash_table_remove_all:
* @hash_table: a #GHashTable
*
* Removes all keys and their associated values from a #GHashTable.
*
* If the #GHashTable was created using g_hash_table_new_full(),
* the keys and values are freed using the supplied destroy functions,
* otherwise you have to make sure that any dynamically allocated
* values are freed yourself.
*
* Since: 2.12
*/
void
g_hash_table_remove_all (GHashTable *hash_table)
{
g_return_if_fail (hash_table != NULL);
#ifndef G_DISABLE_ASSERT
if (hash_table->nnodes != 0)
hash_table->version++;
#endif
g_hash_table_remove_all_nodes (hash_table, TRUE, FALSE);
g_hash_table_maybe_resize (hash_table);
}
/**
* g_hash_table_steal_all:
* @hash_table: a #GHashTable
*
* Removes all keys and their associated values from a #GHashTable
* without calling the key and value destroy functions.
*
* Since: 2.12
*/
void
g_hash_table_steal_all (GHashTable *hash_table)
{
g_return_if_fail (hash_table != NULL);
#ifndef G_DISABLE_ASSERT
if (hash_table->nnodes != 0)
hash_table->version++;
#endif
g_hash_table_remove_all_nodes (hash_table, FALSE, FALSE);
g_hash_table_maybe_resize (hash_table);
}
/**
* g_hash_table_steal_all_keys: (skip)
* @hash_table: a #GHashTable
*
* Removes all keys and their associated values from a #GHashTable
* without calling the key destroy functions, returning the keys
* as a #GPtrArray with the free func set to the @hash_table key
* destroy function.
*
* Returns: (transfer container): a #GPtrArray containing each key of
* the table. Unref with g_ptr_array_unref() when done.
*
* Since: 2.76
*/
GPtrArray *
g_hash_table_steal_all_keys (GHashTable *hash_table)
{
GPtrArray *array;
GDestroyNotify key_destroy_func;
g_return_val_if_fail (hash_table != NULL, NULL);
array = g_hash_table_get_keys_as_ptr_array (hash_table);
/* Ignore the key destroy notify calls during removal, and use it for the
* array elements instead, but restore it after the hash table has been
* cleared, so that newly added keys will continue using it.
*/
key_destroy_func = g_steal_pointer (&hash_table->key_destroy_func);
g_ptr_array_set_free_func (array, key_destroy_func);
g_hash_table_remove_all (hash_table);
hash_table->key_destroy_func = g_steal_pointer (&key_destroy_func);
return array;
}
/**
* g_hash_table_steal_all_values: (skip)
* @hash_table: a #GHashTable
*
* Removes all keys and their associated values from a #GHashTable
* without calling the value destroy functions, returning the values
* as a #GPtrArray with the free func set to the @hash_table value
* destroy function.
*
* Returns: (transfer container): a #GPtrArray containing each value of
* the table. Unref with g_ptr_array_unref() when done.
*
* Since: 2.76
*/
GPtrArray *
g_hash_table_steal_all_values (GHashTable *hash_table)
{
GPtrArray *array;
GDestroyNotify value_destroy_func;
g_return_val_if_fail (hash_table != NULL, NULL);
array = g_hash_table_get_values_as_ptr_array (hash_table);
/* Ignore the value destroy notify calls during removal, and use it for the
* array elements instead, but restore it after the hash table has been
* cleared, so that newly added values will continue using it.
*/
value_destroy_func = g_steal_pointer (&hash_table->value_destroy_func);
g_ptr_array_set_free_func (array, value_destroy_func);
g_hash_table_remove_all (hash_table);
hash_table->value_destroy_func = g_steal_pointer (&value_destroy_func);
return array;
}
/*
* g_hash_table_foreach_remove_or_steal:
* @hash_table: a #GHashTable
* @func: the user's callback function
* @user_data: data for @func
* @notify: %TRUE if the destroy notify handlers are to be called
*
* Implements the common logic for g_hash_table_foreach_remove()
* and g_hash_table_foreach_steal().
*
* Iterates over every node in the table, calling @func with the key
* and value of the node (and @user_data). If @func returns %TRUE the
* node is removed from the table.
*
* If @notify is true then the destroy notify handlers will be called
* for each removed node.
*/
static guint
g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
GHRFunc func,
gpointer user_data,
gboolean notify)
{
guint deleted = 0;
gsize i;
#ifndef G_DISABLE_ASSERT
gint version = hash_table->version;
#endif
for (i = 0; i < hash_table->size; i++)
{
guint node_hash = hash_table->hashes[i];
gpointer node_key = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
gpointer node_value = g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values);
if (HASH_IS_REAL (node_hash) &&
(* func) (node_key, node_value, user_data))
{
g_hash_table_remove_node (hash_table, i, notify);
deleted++;
}
#ifndef G_DISABLE_ASSERT
g_return_val_if_fail (version == hash_table->version, 0);
#endif
}
g_hash_table_maybe_resize (hash_table);
#ifndef G_DISABLE_ASSERT
if (deleted > 0)
hash_table->version++;
#endif
return deleted;
}
/**
* g_hash_table_foreach_remove:
* @hash_table: a #GHashTable
* @func: (scope call): the function to call for each key/value pair
* @user_data: user data to pass to the function
*
* Calls the given function for each key/value pair in the
* #GHashTable. If the function returns %TRUE, then the key/value
* pair is removed from the #GHashTable. If you supplied key or
* value destroy functions when creating the #GHashTable, they are
* used to free the memory allocated for the removed keys and values.
*
* See #GHashTableIter for an alternative way to loop over the
* key/value pairs in the hash table.
*
* Returns: the number of key/value pairs removed
*/
guint
g_hash_table_foreach_remove (GHashTable *hash_table,
GHRFunc func,
gpointer user_data)
{
g_return_val_if_fail (hash_table != NULL, 0);
g_return_val_if_fail (func != NULL, 0);
return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, TRUE);
}
/**
* g_hash_table_foreach_steal:
* @hash_table: a #GHashTable
* @func: (scope call): the function to call for each key/value pair
* @user_data: user data to pass to the function
*
* Calls the given function for each key/value pair in the
* #GHashTable. If the function returns %TRUE, then the key/value
* pair is removed from the #GHashTable, but no key or value
* destroy functions are called.
*
* See #GHashTableIter for an alternative way to loop over the
* key/value pairs in the hash table.
*
* Returns: the number of key/value pairs removed.
*/
guint
g_hash_table_foreach_steal (GHashTable *hash_table,
GHRFunc func,
gpointer user_data)
{
g_return_val_if_fail (hash_table != NULL, 0);
g_return_val_if_fail (func != NULL, 0);
return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, FALSE);
}
/**
* g_hash_table_foreach:
* @hash_table: a #GHashTable
* @func: (scope call): the function to call for each key/value pair
* @user_data: user data to pass to the function
*
* Calls the given function for each of the key/value pairs in the
* #GHashTable. The function is passed the key and value of each
* pair, and the given @user_data parameter. The hash table may not
* be modified while iterating over it (you can't add/remove
* items). To remove all items matching a predicate, use
* g_hash_table_foreach_remove().
*
* The order in which g_hash_table_foreach() iterates over the keys/values in
* the hash table is not defined.
*
* See g_hash_table_find() for performance caveats for linear
* order searches in contrast to g_hash_table_lookup().
*/
void
g_hash_table_foreach (GHashTable *hash_table,
GHFunc func,
gpointer user_data)
{
gsize i;
#ifndef G_DISABLE_ASSERT
gint version;
#endif
g_return_if_fail (hash_table != NULL);
g_return_if_fail (func != NULL);
#ifndef G_DISABLE_ASSERT
version = hash_table->version;
#endif
for (i = 0; i < hash_table->size; i++)
{
guint node_hash = hash_table->hashes[i];
gpointer node_key = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
gpointer node_value = g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values);
if (HASH_IS_REAL (node_hash))
(* func) (node_key, node_value, user_data);
#ifndef G_DISABLE_ASSERT
g_return_if_fail (version == hash_table->version);
#endif
}
}
/**
* g_hash_table_find:
* @hash_table: a #GHashTable
* @predicate: (scope call): function to test the key/value pairs for a certain property
* @user_data: user data to pass to the function
*
* Calls the given function for key/value pairs in the #GHashTable
* until @predicate returns %TRUE. The function is passed the key
* and value of each pair, and the given @user_data parameter. The
* hash table may not be modified while iterating over it (you can't
* add/remove items).
*
* Note, that hash tables are really only optimized for forward
* lookups, i.e. g_hash_table_lookup(). So code that frequently issues
* g_hash_table_find() or g_hash_table_foreach() (e.g. in the order of
* once per every entry in a hash table) should probably be reworked
* to use additional or different data structures for reverse lookups
* (keep in mind that an O(n) find/foreach operation issued for all n
* values in a hash table ends up needing O(n*n) operations).
*
* Returns: (nullable): The value of the first key/value pair is returned,
* for which @predicate evaluates to %TRUE. If no pair with the
* requested property is found, %NULL is returned.
*
* Since: 2.4
*/
gpointer
g_hash_table_find (GHashTable *hash_table,
GHRFunc predicate,
gpointer user_data)
{
gsize i;
#ifndef G_DISABLE_ASSERT
gint version;
#endif
gboolean match;
g_return_val_if_fail (hash_table != NULL, NULL);
g_return_val_if_fail (predicate != NULL, NULL);
#ifndef G_DISABLE_ASSERT
version = hash_table->version;
#endif
match = FALSE;
for (i = 0; i < hash_table->size; i++)
{
guint node_hash = hash_table->hashes[i];
gpointer node_key = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
gpointer node_value = g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values);
if (HASH_IS_REAL (node_hash))
match = predicate (node_key, node_value, user_data);
#ifndef G_DISABLE_ASSERT
g_return_val_if_fail (version == hash_table->version, NULL);
#endif
if (match)
return node_value;
}
return NULL;
}
/**
* g_hash_table_size:
* @hash_table: a #GHashTable
*
* Returns the number of elements contained in the #GHashTable.
*
* Returns: the number of key/value pairs in the #GHashTable.
*/
guint
g_hash_table_size (GHashTable *hash_table)
{
g_return_val_if_fail (hash_table != NULL, 0);
return hash_table->nnodes;
}
/**
* g_hash_table_get_keys:
* @hash_table: a #GHashTable
*
* Retrieves every key inside @hash_table. The returned data is valid
* until changes to the hash release those keys.
*
* This iterates over every entry in the hash table to build its return value.
* To iterate over the entries in a #GHashTable more efficiently, use a
* #GHashTableIter.
*
* Returns: (transfer container): a #GList containing all the keys
* inside the hash table. The content of the list is owned by the
* hash table and should not be modified or freed. Use g_list_free()
* when done using the list.
*
* Since: 2.14
*/
GList *
g_hash_table_get_keys (GHashTable *hash_table)
{
gsize i;
GList *retval;
g_return_val_if_fail (hash_table != NULL, NULL);
retval = NULL;
for (i = 0; i < hash_table->size; i++)
{
if (HASH_IS_REAL (hash_table->hashes[i]))
retval = g_list_prepend (retval, g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys));
}
return retval;
}
/**
* g_hash_table_get_keys_as_array:
* @hash_table: a #GHashTable
* @length: (out) (optional): the length of the returned array
*
* Retrieves every key inside @hash_table, as an array.
*
* The returned array is %NULL-terminated but may contain %NULL as a
* key. Use @length to determine the true length if it's possible that
* %NULL was used as the value for a key.
*
* Note: in the common case of a string-keyed #GHashTable, the return
* value of this function can be conveniently cast to (const gchar **).
*
* This iterates over every entry in the hash table to build its return value.
* To iterate over the entries in a #GHashTable more efficiently, use a
* #GHashTableIter.
*
* You should always free the return result with g_free(). In the
* above-mentioned case of a string-keyed hash table, it may be
* appropriate to use g_strfreev() if you call g_hash_table_steal_all()
* first to transfer ownership of the keys.
*
* Returns: (array length=length) (transfer container): a
* %NULL-terminated array containing each key from the table.
*
* Since: 2.40
**/
gpointer *
g_hash_table_get_keys_as_array (GHashTable *hash_table,
guint *length)
{
gpointer *result;
gsize i, j = 0;
result = g_new (gpointer, hash_table->nnodes + 1);
for (i = 0; i < hash_table->size; i++)
{
if (HASH_IS_REAL (hash_table->hashes[i]))
result[j++] = g_hash_table_fetch_key_or_value (hash_table->keys, i, hash_table->have_big_keys);
}
g_assert (j == hash_table->nnodes);
result[j] = NULL;
if (length)
*length = j;
return result;
}
/**
* g_hash_table_get_keys_as_ptr_array: (skip)
* @hash_table: a #GHashTable
*
* Retrieves every key inside @hash_table, as a #GPtrArray.
* The returned data is valid until changes to the hash release those keys.
*
* This iterates over every entry in the hash table to build its return value.
* To iterate over the entries in a #GHashTable more efficiently, use a
* #GHashTableIter.
*
* You should always unref the returned array with g_ptr_array_unref().
*
* Returns: (transfer container): a #GPtrArray containing each key from
* the table. Unref with g_ptr_array_unref() when done.
*
* Since: 2.76
**/
GPtrArray *
g_hash_table_get_keys_as_ptr_array (GHashTable *hash_table)
{
GPtrArray *array;
g_return_val_if_fail (hash_table != NULL, NULL);
array = g_ptr_array_sized_new (hash_table->size);
for (gsize i = 0; i < hash_table->size; ++i)
{
if (HASH_IS_REAL (hash_table->hashes[i]))
{
g_ptr_array_add (array, g_hash_table_fetch_key_or_value (
hash_table->keys, i, hash_table->have_big_keys));
}
}
g_assert (array->len == hash_table->nnodes);
return array;
}
/**
* g_hash_table_get_values:
* @hash_table: a #GHashTable
*
* Retrieves every value inside @hash_table. The returned data
* is valid until @hash_table is modified.
*
* This iterates over every entry in the hash table to build its return value.
* To iterate over the entries in a #GHashTable more efficiently, use a
* #GHashTableIter.
*
* Returns: (transfer container): a #GList containing all the values
* inside the hash table. The content of the list is owned by the
* hash table and should not be modified or freed. Use g_list_free()
* when done using the list.
*
* Since: 2.14
*/
GList *
g_hash_table_get_values (GHashTable *hash_table)
{
gsize i;
GList *retval;
g_return_val_if_fail (hash_table != NULL, NULL);
retval = NULL;
for (i = 0; i < hash_table->size; i++)
{
if (HASH_IS_REAL (hash_table->hashes[i]))
retval = g_list_prepend (retval, g_hash_table_fetch_key_or_value (hash_table->values, i, hash_table->have_big_values));
}
return retval;
}
/**
* g_hash_table_get_values_as_ptr_array: (skip)
* @hash_table: a #GHashTable
*
* Retrieves every value inside @hash_table, as a #GPtrArray.
* The returned data is valid until changes to the hash release those values.
*
* This iterates over every entry in the hash table to build its return value.
* To iterate over the entries in a #GHashTable more efficiently, use a
* #GHashTableIter.
*
* You should always unref the returned array with g_ptr_array_unref().
*
* Returns: (transfer container): a #GPtrArray containing each value from
* the table. Unref with g_ptr_array_unref() when done.
*
* Since: 2.76
**/
GPtrArray *
g_hash_table_get_values_as_ptr_array (GHashTable *hash_table)
{
GPtrArray *array;
g_return_val_if_fail (hash_table != NULL, NULL);
array = g_ptr_array_sized_new (hash_table->size);
for (gsize i = 0; i < hash_table->size; ++i)
{
if (HASH_IS_REAL (hash_table->hashes[i]))
{
g_ptr_array_add (array, g_hash_table_fetch_key_or_value (
hash_table->values, i, hash_table->have_big_values));
}
}
g_assert (array->len == hash_table->nnodes);
return array;
}
/* Hash functions.
*/
/**
* g_str_equal:
* @v1: (not nullable): a key
* @v2: (not nullable): a key to compare with @v1
*
* Compares two strings for byte-by-byte equality and returns %TRUE
* if they are equal. It can be passed to g_hash_table_new() as the
* @key_equal_func parameter, when using non-%NULL strings as keys in a
* #GHashTable.
*
* This function is typically used for hash table comparisons, but can be used
* for general purpose comparisons of non-%NULL strings. For a %NULL-safe string
* comparison function, see g_strcmp0().
*
* Returns: %TRUE if the two keys match
*/
gboolean
(g_str_equal) (gconstpointer v1,
gconstpointer v2)
{
const gchar *string1 = v1;
const gchar *string2 = v2;
return strcmp (string1, string2) == 0;
}
/**
* g_str_hash:
* @v: (not nullable): a string key
*
* Converts a string to a hash value.
*
* This function implements the widely used "djb" hash apparently
* posted by Daniel Bernstein to comp.lang.c some time ago. The 32
* bit unsigned hash value starts at 5381 and for each byte 'c' in
* the string, is updated: `hash = hash * 33 + c`. This function
* uses the signed value of each byte.
*
* It can be passed to g_hash_table_new() as the @hash_func parameter,
* when using non-%NULL strings as keys in a #GHashTable.
*
* Note that this function may not be a perfect fit for all use cases.
* For example, it produces some hash collisions with strings as short
* as 2.
*
* Returns: a hash value corresponding to the key
*/
guint
g_str_hash (gconstpointer v)
{
const signed char *p;
guint32 h = 5381;
for (p = v; *p != '\0'; p++)
h = (h << 5) + h + *p;
return h;
}
/**
* g_direct_hash:
* @v: (nullable): a #gpointer key
*
* Converts a gpointer to a hash value.
* It can be passed to g_hash_table_new() as the @hash_func parameter,
* when using opaque pointers compared by pointer value as keys in a
* #GHashTable.
*
* This hash function is also appropriate for keys that are integers
* stored in pointers, such as `GINT_TO_POINTER (n)`.
*
* Returns: a hash value corresponding to the key.
*/
guint
g_direct_hash (gconstpointer v)
{
return GPOINTER_TO_UINT (v);
}
/**
* g_direct_equal:
* @v1: (nullable): a key
* @v2: (nullable): a key to compare with @v1
*
* Compares two #gpointer arguments and returns %TRUE if they are equal.
* It can be passed to g_hash_table_new() as the @key_equal_func
* parameter, when using opaque pointers compared by pointer value as
* keys in a #GHashTable.
*
* This equality function is also appropriate for keys that are integers
* stored in pointers, such as `GINT_TO_POINTER (n)`.
*
* Returns: %TRUE if the two keys match.
*/
gboolean
g_direct_equal (gconstpointer v1,
gconstpointer v2)
{
return v1 == v2;
}
/**
* g_int_equal:
* @v1: (not nullable): a pointer to a #gint key
* @v2: (not nullable): a pointer to a #gint key to compare with @v1
*
* Compares the two #gint values being pointed to and returns
* %TRUE if they are equal.
* It can be passed to g_hash_table_new() as the @key_equal_func
* parameter, when using non-%NULL pointers to integers as keys in a
* #GHashTable.
*
* Note that this function acts on pointers to #gint, not on #gint
* directly: if your hash table's keys are of the form
* `GINT_TO_POINTER (n)`, use g_direct_equal() instead.
*
* Returns: %TRUE if the two keys match.
*/
gboolean
g_int_equal (gconstpointer v1,
gconstpointer v2)
{
return *((const gint*) v1) == *((const gint*) v2);
}
/**
* g_int_hash:
* @v: (not nullable): a pointer to a #gint key
*
* Converts a pointer to a #gint to a hash value.
* It can be passed to g_hash_table_new() as the @hash_func parameter,
* when using non-%NULL pointers to integer values as keys in a #GHashTable.
*
* Note that this function acts on pointers to #gint, not on #gint
* directly: if your hash table's keys are of the form
* `GINT_TO_POINTER (n)`, use g_direct_hash() instead.
*
* Returns: a hash value corresponding to the key.
*/
guint
g_int_hash (gconstpointer v)
{
return *(const gint*) v;
}
/**
* g_uint_equal:
* @v1: (not nullable): a pointer to a #guint key
* @v2: (not nullable): a pointer to a #guint key to compare with @v1
*
* Compares the two #guint values being pointed to and returns
* %TRUE if they are equal.
* It can be passed to g_hash_table_new() as the @key_equal_func
* parameter, when using non-%NULL pointers to integers as keys in a
* #GHashTable.
*
* Note that this function acts on pointers to #guint, not on #guint
* directly: if your hash table's keys are of the form
* `GUINT_TO_POINTER (n)`, use g_direct_equal() instead.
*
* Returns: %TRUE if the two keys match.
*/
gboolean
g_uint_equal (gconstpointer v1,
gconstpointer v2)
{
return *((const guint *) v1) == *((const guint *) v2);
}
/**
* g_uint_hash:
* @v: (not nullable): a pointer to a #guint key
*
* Converts a pointer to a #guint to a hash value.
* It can be passed to g_hash_table_new() as the @hash_func parameter,
* when using non-%NULL pointers to integer values as keys in a #GHashTable.
*
* Note that this function acts on pointers to #guint, not on #guint
* directly: if your hash table's keys are of the form
* `GUINT_TO_POINTER (n)`, use g_direct_hash() instead.
*
* Returns: a hash value corresponding to the key.
*/
guint
g_uint_hash (gconstpointer v)
{
return *(const guint *) v;
}
/**
* g_int64_equal:
* @v1: (not nullable): a pointer to a #gint64 key
* @v2: (not nullable): a pointer to a #gint64 key to compare with @v1
*
* Compares the two #gint64 values being pointed to and returns
* %TRUE if they are equal.
* It can be passed to g_hash_table_new() as the @key_equal_func
* parameter, when using non-%NULL pointers to 64-bit integers as keys in a
* #GHashTable.
*
* Returns: %TRUE if the two keys match.
*
* Since: 2.22
*/
gboolean
g_int64_equal (gconstpointer v1,
gconstpointer v2)
{
return *((const gint64*) v1) == *((const gint64*) v2);
}
/**
* g_int64_hash:
* @v: (not nullable): a pointer to a #gint64 key
*
* Converts a pointer to a #gint64 to a hash value.
*
* It can be passed to g_hash_table_new() as the @hash_func parameter,
* when using non-%NULL pointers to 64-bit integer values as keys in a
* #GHashTable.
*
* Returns: a hash value corresponding to the key.
*
* Since: 2.22
*/
guint
g_int64_hash (gconstpointer v)
{
const guint64 *bits = v;
return (guint) ((*bits >> 32) ^ (*bits & 0xffffffffU));
}
/**
* g_double_equal:
* @v1: (not nullable): a pointer to a #gdouble key
* @v2: (not nullable): a pointer to a #gdouble key to compare with @v1
*
* Compares the two #gdouble values being pointed to and returns
* %TRUE if they are equal.
* It can be passed to g_hash_table_new() as the @key_equal_func
* parameter, when using non-%NULL pointers to doubles as keys in a
* #GHashTable.
*
* Returns: %TRUE if the two keys match.
*
* Since: 2.22
*/
gboolean
g_double_equal (gconstpointer v1,
gconstpointer v2)
{
return *((const gdouble*) v1) == *((const gdouble*) v2);
}
/**
* g_double_hash:
* @v: (not nullable): a pointer to a #gdouble key
*
* Converts a pointer to a #gdouble to a hash value.
* It can be passed to g_hash_table_new() as the @hash_func parameter,
* It can be passed to g_hash_table_new() as the @hash_func parameter,
* when using non-%NULL pointers to doubles as keys in a #GHashTable.
*
* Returns: a hash value corresponding to the key.
*
* Since: 2.22
*/
guint
g_double_hash (gconstpointer v)
{
/* Same as g_int64_hash() */
const guint64 *bits = v;
return (guint) ((*bits >> 32) ^ (*bits & 0xffffffffU));
}
|