11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 31cb0ef41Sopenharmony_ci/* 41cb0ef41Sopenharmony_ci****************************************************************************** 51cb0ef41Sopenharmony_ci* Copyright (C) 1997-2016, International Business Machines 61cb0ef41Sopenharmony_ci* Corporation and others. All Rights Reserved. 71cb0ef41Sopenharmony_ci****************************************************************************** 81cb0ef41Sopenharmony_ci* Date Name Description 91cb0ef41Sopenharmony_ci* 03/22/00 aliu Adapted from original C++ ICU Hashtable. 101cb0ef41Sopenharmony_ci* 07/06/01 aliu Modified to support int32_t keys on 111cb0ef41Sopenharmony_ci* platforms with sizeof(void*) < 32. 121cb0ef41Sopenharmony_ci****************************************************************************** 131cb0ef41Sopenharmony_ci*/ 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci#include "uhash.h" 161cb0ef41Sopenharmony_ci#include "unicode/ustring.h" 171cb0ef41Sopenharmony_ci#include "cstring.h" 181cb0ef41Sopenharmony_ci#include "cmemory.h" 191cb0ef41Sopenharmony_ci#include "uassert.h" 201cb0ef41Sopenharmony_ci#include "ustr_imp.h" 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci/* This hashtable is implemented as a double hash. All elements are 231cb0ef41Sopenharmony_ci * stored in a single array with no secondary storage for collision 241cb0ef41Sopenharmony_ci * resolution (no linked list, etc.). When there is a hash collision 251cb0ef41Sopenharmony_ci * (when two unequal keys have the same hashcode) we resolve this by 261cb0ef41Sopenharmony_ci * using a secondary hash. The secondary hash is an increment 271cb0ef41Sopenharmony_ci * computed as a hash function (a different one) of the primary 281cb0ef41Sopenharmony_ci * hashcode. This increment is added to the initial hash value to 291cb0ef41Sopenharmony_ci * obtain further slots assigned to the same hash code. For this to 301cb0ef41Sopenharmony_ci * work, the length of the array and the increment must be relatively 311cb0ef41Sopenharmony_ci * prime. The easiest way to achieve this is to have the length of 321cb0ef41Sopenharmony_ci * the array be prime, and the increment be any value from 331cb0ef41Sopenharmony_ci * 1..length-1. 341cb0ef41Sopenharmony_ci * 351cb0ef41Sopenharmony_ci * Hashcodes are 32-bit integers. We make sure all hashcodes are 361cb0ef41Sopenharmony_ci * non-negative by masking off the top bit. This has two effects: (1) 371cb0ef41Sopenharmony_ci * modulo arithmetic is simplified. If we allowed negative hashcodes, 381cb0ef41Sopenharmony_ci * then when we computed hashcode % length, we could get a negative 391cb0ef41Sopenharmony_ci * result, which we would then have to adjust back into range. It's 401cb0ef41Sopenharmony_ci * simpler to just make hashcodes non-negative. (2) It makes it easy 411cb0ef41Sopenharmony_ci * to check for empty vs. occupied slots in the table. We just mark 421cb0ef41Sopenharmony_ci * empty or deleted slots with a negative hashcode. 431cb0ef41Sopenharmony_ci * 441cb0ef41Sopenharmony_ci * The central function is _uhash_find(). This function looks for a 451cb0ef41Sopenharmony_ci * slot matching the given key and hashcode. If one is found, it 461cb0ef41Sopenharmony_ci * returns a pointer to that slot. If the table is full, and no match 471cb0ef41Sopenharmony_ci * is found, it returns nullptr -- in theory. This would make the code 481cb0ef41Sopenharmony_ci * more complicated, since all callers of _uhash_find() would then 491cb0ef41Sopenharmony_ci * have to check for a nullptr result. To keep this from happening, we 501cb0ef41Sopenharmony_ci * don't allow the table to fill. When there is only one 511cb0ef41Sopenharmony_ci * empty/deleted slot left, uhash_put() will refuse to increase the 521cb0ef41Sopenharmony_ci * count, and fail. This simplifies the code. In practice, one will 531cb0ef41Sopenharmony_ci * seldom encounter this using default UHashtables. However, if a 541cb0ef41Sopenharmony_ci * hashtable is set to a U_FIXED resize policy, or if memory is 551cb0ef41Sopenharmony_ci * exhausted, then the table may fill. 561cb0ef41Sopenharmony_ci * 571cb0ef41Sopenharmony_ci * High and low water ratios control rehashing. They establish levels 581cb0ef41Sopenharmony_ci * of fullness (from 0 to 1) outside of which the data array is 591cb0ef41Sopenharmony_ci * reallocated and repopulated. Setting the low water ratio to zero 601cb0ef41Sopenharmony_ci * means the table will never shrink. Setting the high water ratio to 611cb0ef41Sopenharmony_ci * one means the table will never grow. The ratios should be 621cb0ef41Sopenharmony_ci * coordinated with the ratio between successive elements of the 631cb0ef41Sopenharmony_ci * PRIMES table, so that when the primeIndex is incremented or 641cb0ef41Sopenharmony_ci * decremented during rehashing, it brings the ratio of count / length 651cb0ef41Sopenharmony_ci * back into the desired range (between low and high water ratios). 661cb0ef41Sopenharmony_ci */ 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci/******************************************************************** 691cb0ef41Sopenharmony_ci * PRIVATE Constants, Macros 701cb0ef41Sopenharmony_ci ********************************************************************/ 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci/* This is a list of non-consecutive primes chosen such that 731cb0ef41Sopenharmony_ci * PRIMES[i+1] ~ 2*PRIMES[i]. (Currently, the ratio ranges from 1.81 741cb0ef41Sopenharmony_ci * to 2.18; the inverse ratio ranges from 0.459 to 0.552.) If this 751cb0ef41Sopenharmony_ci * ratio is changed, the low and high water ratios should also be 761cb0ef41Sopenharmony_ci * adjusted to suit. 771cb0ef41Sopenharmony_ci * 781cb0ef41Sopenharmony_ci * These prime numbers were also chosen so that they are the largest 791cb0ef41Sopenharmony_ci * prime number while being less than a power of two. 801cb0ef41Sopenharmony_ci */ 811cb0ef41Sopenharmony_cistatic const int32_t PRIMES[] = { 821cb0ef41Sopenharmony_ci 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 831cb0ef41Sopenharmony_ci 65521, 131071, 262139, 524287, 1048573, 2097143, 4194301, 8388593, 841cb0ef41Sopenharmony_ci 16777213, 33554393, 67108859, 134217689, 268435399, 536870909, 851cb0ef41Sopenharmony_ci 1073741789, 2147483647 /*, 4294967291 */ 861cb0ef41Sopenharmony_ci}; 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci#define PRIMES_LENGTH UPRV_LENGTHOF(PRIMES) 891cb0ef41Sopenharmony_ci#define DEFAULT_PRIME_INDEX 4 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci/* These ratios are tuned to the PRIMES array such that a resize 921cb0ef41Sopenharmony_ci * places the table back into the zone of non-resizing. That is, 931cb0ef41Sopenharmony_ci * after a call to _uhash_rehash(), a subsequent call to 941cb0ef41Sopenharmony_ci * _uhash_rehash() should do nothing (should not churn). This is only 951cb0ef41Sopenharmony_ci * a potential problem with U_GROW_AND_SHRINK. 961cb0ef41Sopenharmony_ci */ 971cb0ef41Sopenharmony_cistatic const float RESIZE_POLICY_RATIO_TABLE[6] = { 981cb0ef41Sopenharmony_ci /* low, high water ratio */ 991cb0ef41Sopenharmony_ci 0.0F, 0.5F, /* U_GROW: Grow on demand, do not shrink */ 1001cb0ef41Sopenharmony_ci 0.1F, 0.5F, /* U_GROW_AND_SHRINK: Grow and shrink on demand */ 1011cb0ef41Sopenharmony_ci 0.0F, 1.0F /* U_FIXED: Never change size */ 1021cb0ef41Sopenharmony_ci}; 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci/* 1051cb0ef41Sopenharmony_ci Invariants for hashcode values: 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci * DELETED < 0 1081cb0ef41Sopenharmony_ci * EMPTY < 0 1091cb0ef41Sopenharmony_ci * Real hashes >= 0 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci Hashcodes may not start out this way, but internally they are 1121cb0ef41Sopenharmony_ci adjusted so that they are always positive. We assume 32-bit 1131cb0ef41Sopenharmony_ci hashcodes; adjust these constants for other hashcode sizes. 1141cb0ef41Sopenharmony_ci*/ 1151cb0ef41Sopenharmony_ci#define HASH_DELETED ((int32_t) 0x80000000) 1161cb0ef41Sopenharmony_ci#define HASH_EMPTY ((int32_t) HASH_DELETED + 1) 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci#define IS_EMPTY_OR_DELETED(x) ((x) < 0) 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci/* This macro expects a UHashTok.pointer as its keypointer and 1211cb0ef41Sopenharmony_ci valuepointer parameters */ 1221cb0ef41Sopenharmony_ci#define HASH_DELETE_KEY_VALUE(hash, keypointer, valuepointer) UPRV_BLOCK_MACRO_BEGIN { \ 1231cb0ef41Sopenharmony_ci if (hash->keyDeleter != nullptr && keypointer != nullptr) { \ 1241cb0ef41Sopenharmony_ci (*hash->keyDeleter)(keypointer); \ 1251cb0ef41Sopenharmony_ci } \ 1261cb0ef41Sopenharmony_ci if (hash->valueDeleter != nullptr && valuepointer != nullptr) { \ 1271cb0ef41Sopenharmony_ci (*hash->valueDeleter)(valuepointer); \ 1281cb0ef41Sopenharmony_ci } \ 1291cb0ef41Sopenharmony_ci} UPRV_BLOCK_MACRO_END 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci/* 1321cb0ef41Sopenharmony_ci * Constants for hinting whether a key or value is an integer 1331cb0ef41Sopenharmony_ci * or a pointer. If a hint bit is zero, then the associated 1341cb0ef41Sopenharmony_ci * token is assumed to be an integer. 1351cb0ef41Sopenharmony_ci */ 1361cb0ef41Sopenharmony_ci#define HINT_BOTH_INTEGERS (0) 1371cb0ef41Sopenharmony_ci#define HINT_KEY_POINTER (1) 1381cb0ef41Sopenharmony_ci#define HINT_VALUE_POINTER (2) 1391cb0ef41Sopenharmony_ci#define HINT_ALLOW_ZERO (4) 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci/******************************************************************** 1421cb0ef41Sopenharmony_ci * PRIVATE Implementation 1431cb0ef41Sopenharmony_ci ********************************************************************/ 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_cistatic UHashTok 1461cb0ef41Sopenharmony_ci_uhash_setElement(UHashtable *hash, UHashElement* e, 1471cb0ef41Sopenharmony_ci int32_t hashcode, 1481cb0ef41Sopenharmony_ci UHashTok key, UHashTok value, int8_t hint) { 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci UHashTok oldValue = e->value; 1511cb0ef41Sopenharmony_ci if (hash->keyDeleter != nullptr && e->key.pointer != nullptr && 1521cb0ef41Sopenharmony_ci e->key.pointer != key.pointer) { /* Avoid double deletion */ 1531cb0ef41Sopenharmony_ci (*hash->keyDeleter)(e->key.pointer); 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci if (hash->valueDeleter != nullptr) { 1561cb0ef41Sopenharmony_ci if (oldValue.pointer != nullptr && 1571cb0ef41Sopenharmony_ci oldValue.pointer != value.pointer) { /* Avoid double deletion */ 1581cb0ef41Sopenharmony_ci (*hash->valueDeleter)(oldValue.pointer); 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci oldValue.pointer = nullptr; 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci /* Compilers should copy the UHashTok union correctly, but even if 1631cb0ef41Sopenharmony_ci * they do, memory heap tools (e.g. BoundsChecker) can get 1641cb0ef41Sopenharmony_ci * confused when a pointer is cloaked in a union and then copied. 1651cb0ef41Sopenharmony_ci * TO ALLEVIATE THIS, we use hints (based on what API the user is 1661cb0ef41Sopenharmony_ci * calling) to copy pointers when we know the user thinks 1671cb0ef41Sopenharmony_ci * something is a pointer. */ 1681cb0ef41Sopenharmony_ci if (hint & HINT_KEY_POINTER) { 1691cb0ef41Sopenharmony_ci e->key.pointer = key.pointer; 1701cb0ef41Sopenharmony_ci } else { 1711cb0ef41Sopenharmony_ci e->key = key; 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci if (hint & HINT_VALUE_POINTER) { 1741cb0ef41Sopenharmony_ci e->value.pointer = value.pointer; 1751cb0ef41Sopenharmony_ci } else { 1761cb0ef41Sopenharmony_ci e->value = value; 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci e->hashcode = hashcode; 1791cb0ef41Sopenharmony_ci return oldValue; 1801cb0ef41Sopenharmony_ci} 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci/** 1831cb0ef41Sopenharmony_ci * Assumes that the given element is not empty or deleted. 1841cb0ef41Sopenharmony_ci */ 1851cb0ef41Sopenharmony_cistatic UHashTok 1861cb0ef41Sopenharmony_ci_uhash_internalRemoveElement(UHashtable *hash, UHashElement* e) { 1871cb0ef41Sopenharmony_ci UHashTok empty; 1881cb0ef41Sopenharmony_ci U_ASSERT(!IS_EMPTY_OR_DELETED(e->hashcode)); 1891cb0ef41Sopenharmony_ci --hash->count; 1901cb0ef41Sopenharmony_ci empty.pointer = nullptr; empty.integer = 0; 1911cb0ef41Sopenharmony_ci return _uhash_setElement(hash, e, HASH_DELETED, empty, empty, 0); 1921cb0ef41Sopenharmony_ci} 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_cistatic void 1951cb0ef41Sopenharmony_ci_uhash_internalSetResizePolicy(UHashtable *hash, enum UHashResizePolicy policy) { 1961cb0ef41Sopenharmony_ci U_ASSERT(hash != nullptr); 1971cb0ef41Sopenharmony_ci U_ASSERT(((int32_t)policy) >= 0); 1981cb0ef41Sopenharmony_ci U_ASSERT(((int32_t)policy) < 3); 1991cb0ef41Sopenharmony_ci hash->lowWaterRatio = RESIZE_POLICY_RATIO_TABLE[policy * 2]; 2001cb0ef41Sopenharmony_ci hash->highWaterRatio = RESIZE_POLICY_RATIO_TABLE[policy * 2 + 1]; 2011cb0ef41Sopenharmony_ci} 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci/** 2041cb0ef41Sopenharmony_ci * Allocate internal data array of a size determined by the given 2051cb0ef41Sopenharmony_ci * prime index. If the index is out of range it is pinned into range. 2061cb0ef41Sopenharmony_ci * If the allocation fails the status is set to 2071cb0ef41Sopenharmony_ci * U_MEMORY_ALLOCATION_ERROR and all array storage is freed. In 2081cb0ef41Sopenharmony_ci * either case the previous array pointer is overwritten. 2091cb0ef41Sopenharmony_ci * 2101cb0ef41Sopenharmony_ci * Caller must ensure primeIndex is in range 0..PRIME_LENGTH-1. 2111cb0ef41Sopenharmony_ci */ 2121cb0ef41Sopenharmony_cistatic void 2131cb0ef41Sopenharmony_ci_uhash_allocate(UHashtable *hash, 2141cb0ef41Sopenharmony_ci int32_t primeIndex, 2151cb0ef41Sopenharmony_ci UErrorCode *status) { 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci UHashElement *p, *limit; 2181cb0ef41Sopenharmony_ci UHashTok emptytok; 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_ci if (U_FAILURE(*status)) return; 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci U_ASSERT(primeIndex >= 0 && primeIndex < PRIMES_LENGTH); 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci hash->primeIndex = static_cast<int8_t>(primeIndex); 2251cb0ef41Sopenharmony_ci hash->length = PRIMES[primeIndex]; 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_ci p = hash->elements = (UHashElement*) 2281cb0ef41Sopenharmony_ci uprv_malloc(sizeof(UHashElement) * hash->length); 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci if (hash->elements == nullptr) { 2311cb0ef41Sopenharmony_ci *status = U_MEMORY_ALLOCATION_ERROR; 2321cb0ef41Sopenharmony_ci return; 2331cb0ef41Sopenharmony_ci } 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci emptytok.pointer = nullptr; /* Only one of these two is needed */ 2361cb0ef41Sopenharmony_ci emptytok.integer = 0; /* but we don't know which one. */ 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci limit = p + hash->length; 2391cb0ef41Sopenharmony_ci while (p < limit) { 2401cb0ef41Sopenharmony_ci p->key = emptytok; 2411cb0ef41Sopenharmony_ci p->value = emptytok; 2421cb0ef41Sopenharmony_ci p->hashcode = HASH_EMPTY; 2431cb0ef41Sopenharmony_ci ++p; 2441cb0ef41Sopenharmony_ci } 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci hash->count = 0; 2471cb0ef41Sopenharmony_ci hash->lowWaterMark = (int32_t)(hash->length * hash->lowWaterRatio); 2481cb0ef41Sopenharmony_ci hash->highWaterMark = (int32_t)(hash->length * hash->highWaterRatio); 2491cb0ef41Sopenharmony_ci} 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_cistatic UHashtable* 2521cb0ef41Sopenharmony_ci_uhash_init(UHashtable *result, 2531cb0ef41Sopenharmony_ci UHashFunction *keyHash, 2541cb0ef41Sopenharmony_ci UKeyComparator *keyComp, 2551cb0ef41Sopenharmony_ci UValueComparator *valueComp, 2561cb0ef41Sopenharmony_ci int32_t primeIndex, 2571cb0ef41Sopenharmony_ci UErrorCode *status) 2581cb0ef41Sopenharmony_ci{ 2591cb0ef41Sopenharmony_ci if (U_FAILURE(*status)) return nullptr; 2601cb0ef41Sopenharmony_ci U_ASSERT(keyHash != nullptr); 2611cb0ef41Sopenharmony_ci U_ASSERT(keyComp != nullptr); 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci result->keyHasher = keyHash; 2641cb0ef41Sopenharmony_ci result->keyComparator = keyComp; 2651cb0ef41Sopenharmony_ci result->valueComparator = valueComp; 2661cb0ef41Sopenharmony_ci result->keyDeleter = nullptr; 2671cb0ef41Sopenharmony_ci result->valueDeleter = nullptr; 2681cb0ef41Sopenharmony_ci result->allocated = false; 2691cb0ef41Sopenharmony_ci _uhash_internalSetResizePolicy(result, U_GROW); 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci _uhash_allocate(result, primeIndex, status); 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci if (U_FAILURE(*status)) { 2741cb0ef41Sopenharmony_ci return nullptr; 2751cb0ef41Sopenharmony_ci } 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci return result; 2781cb0ef41Sopenharmony_ci} 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_cistatic UHashtable* 2811cb0ef41Sopenharmony_ci_uhash_create(UHashFunction *keyHash, 2821cb0ef41Sopenharmony_ci UKeyComparator *keyComp, 2831cb0ef41Sopenharmony_ci UValueComparator *valueComp, 2841cb0ef41Sopenharmony_ci int32_t primeIndex, 2851cb0ef41Sopenharmony_ci UErrorCode *status) { 2861cb0ef41Sopenharmony_ci UHashtable *result; 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_ci if (U_FAILURE(*status)) return nullptr; 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci result = (UHashtable*) uprv_malloc(sizeof(UHashtable)); 2911cb0ef41Sopenharmony_ci if (result == nullptr) { 2921cb0ef41Sopenharmony_ci *status = U_MEMORY_ALLOCATION_ERROR; 2931cb0ef41Sopenharmony_ci return nullptr; 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci _uhash_init(result, keyHash, keyComp, valueComp, primeIndex, status); 2971cb0ef41Sopenharmony_ci result->allocated = true; 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci if (U_FAILURE(*status)) { 3001cb0ef41Sopenharmony_ci uprv_free(result); 3011cb0ef41Sopenharmony_ci return nullptr; 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci return result; 3051cb0ef41Sopenharmony_ci} 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_ci/** 3081cb0ef41Sopenharmony_ci * Look for a key in the table, or if no such key exists, the first 3091cb0ef41Sopenharmony_ci * empty slot matching the given hashcode. Keys are compared using 3101cb0ef41Sopenharmony_ci * the keyComparator function. 3111cb0ef41Sopenharmony_ci * 3121cb0ef41Sopenharmony_ci * First find the start position, which is the hashcode modulo 3131cb0ef41Sopenharmony_ci * the length. Test it to see if it is: 3141cb0ef41Sopenharmony_ci * 3151cb0ef41Sopenharmony_ci * a. identical: First check the hash values for a quick check, 3161cb0ef41Sopenharmony_ci * then compare keys for equality using keyComparator. 3171cb0ef41Sopenharmony_ci * b. deleted 3181cb0ef41Sopenharmony_ci * c. empty 3191cb0ef41Sopenharmony_ci * 3201cb0ef41Sopenharmony_ci * Stop if it is identical or empty, otherwise continue by adding a 3211cb0ef41Sopenharmony_ci * "jump" value (moduloing by the length again to keep it within 3221cb0ef41Sopenharmony_ci * range) and retesting. For efficiency, there need enough empty 3231cb0ef41Sopenharmony_ci * values so that the searches stop within a reasonable amount of time. 3241cb0ef41Sopenharmony_ci * This can be changed by changing the high/low water marks. 3251cb0ef41Sopenharmony_ci * 3261cb0ef41Sopenharmony_ci * In theory, this function can return nullptr, if it is full (no empty 3271cb0ef41Sopenharmony_ci * or deleted slots) and if no matching key is found. In practice, we 3281cb0ef41Sopenharmony_ci * prevent this elsewhere (in uhash_put) by making sure the last slot 3291cb0ef41Sopenharmony_ci * in the table is never filled. 3301cb0ef41Sopenharmony_ci * 3311cb0ef41Sopenharmony_ci * The size of the table should be prime for this algorithm to work; 3321cb0ef41Sopenharmony_ci * otherwise we are not guaranteed that the jump value (the secondary 3331cb0ef41Sopenharmony_ci * hash) is relatively prime to the table length. 3341cb0ef41Sopenharmony_ci */ 3351cb0ef41Sopenharmony_cistatic UHashElement* 3361cb0ef41Sopenharmony_ci_uhash_find(const UHashtable *hash, UHashTok key, 3371cb0ef41Sopenharmony_ci int32_t hashcode) { 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci int32_t firstDeleted = -1; /* assume invalid index */ 3401cb0ef41Sopenharmony_ci int32_t theIndex, startIndex; 3411cb0ef41Sopenharmony_ci int32_t jump = 0; /* lazy evaluate */ 3421cb0ef41Sopenharmony_ci int32_t tableHash; 3431cb0ef41Sopenharmony_ci UHashElement *elements = hash->elements; 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ci hashcode &= 0x7FFFFFFF; /* must be positive */ 3461cb0ef41Sopenharmony_ci startIndex = theIndex = (hashcode ^ 0x4000000) % hash->length; 3471cb0ef41Sopenharmony_ci 3481cb0ef41Sopenharmony_ci do { 3491cb0ef41Sopenharmony_ci tableHash = elements[theIndex].hashcode; 3501cb0ef41Sopenharmony_ci if (tableHash == hashcode) { /* quick check */ 3511cb0ef41Sopenharmony_ci if ((*hash->keyComparator)(key, elements[theIndex].key)) { 3521cb0ef41Sopenharmony_ci return &(elements[theIndex]); 3531cb0ef41Sopenharmony_ci } 3541cb0ef41Sopenharmony_ci } else if (!IS_EMPTY_OR_DELETED(tableHash)) { 3551cb0ef41Sopenharmony_ci /* We have hit a slot which contains a key-value pair, 3561cb0ef41Sopenharmony_ci * but for which the hash code does not match. Keep 3571cb0ef41Sopenharmony_ci * looking. 3581cb0ef41Sopenharmony_ci */ 3591cb0ef41Sopenharmony_ci } else if (tableHash == HASH_EMPTY) { /* empty, end o' the line */ 3601cb0ef41Sopenharmony_ci break; 3611cb0ef41Sopenharmony_ci } else if (firstDeleted < 0) { /* remember first deleted */ 3621cb0ef41Sopenharmony_ci firstDeleted = theIndex; 3631cb0ef41Sopenharmony_ci } 3641cb0ef41Sopenharmony_ci if (jump == 0) { /* lazy compute jump */ 3651cb0ef41Sopenharmony_ci /* The jump value must be relatively prime to the table 3661cb0ef41Sopenharmony_ci * length. As long as the length is prime, then any value 3671cb0ef41Sopenharmony_ci * 1..length-1 will be relatively prime to it. 3681cb0ef41Sopenharmony_ci */ 3691cb0ef41Sopenharmony_ci jump = (hashcode % (hash->length - 1)) + 1; 3701cb0ef41Sopenharmony_ci } 3711cb0ef41Sopenharmony_ci theIndex = (theIndex + jump) % hash->length; 3721cb0ef41Sopenharmony_ci } while (theIndex != startIndex); 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci if (firstDeleted >= 0) { 3751cb0ef41Sopenharmony_ci theIndex = firstDeleted; /* reset if had deleted slot */ 3761cb0ef41Sopenharmony_ci } else if (tableHash != HASH_EMPTY) { 3771cb0ef41Sopenharmony_ci /* We get to this point if the hashtable is full (no empty or 3781cb0ef41Sopenharmony_ci * deleted slots), and we've failed to find a match. THIS 3791cb0ef41Sopenharmony_ci * WILL NEVER HAPPEN as long as uhash_put() makes sure that 3801cb0ef41Sopenharmony_ci * count is always < length. 3811cb0ef41Sopenharmony_ci */ 3821cb0ef41Sopenharmony_ci UPRV_UNREACHABLE_EXIT; 3831cb0ef41Sopenharmony_ci } 3841cb0ef41Sopenharmony_ci return &(elements[theIndex]); 3851cb0ef41Sopenharmony_ci} 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ci/** 3881cb0ef41Sopenharmony_ci * Attempt to grow or shrink the data arrays in order to make the 3891cb0ef41Sopenharmony_ci * count fit between the high and low water marks. hash_put() and 3901cb0ef41Sopenharmony_ci * hash_remove() call this method when the count exceeds the high or 3911cb0ef41Sopenharmony_ci * low water marks. This method may do nothing, if memory allocation 3921cb0ef41Sopenharmony_ci * fails, or if the count is already in range, or if the length is 3931cb0ef41Sopenharmony_ci * already at the low or high limit. In any case, upon return the 3941cb0ef41Sopenharmony_ci * arrays will be valid. 3951cb0ef41Sopenharmony_ci */ 3961cb0ef41Sopenharmony_cistatic void 3971cb0ef41Sopenharmony_ci_uhash_rehash(UHashtable *hash, UErrorCode *status) { 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ci UHashElement *old = hash->elements; 4001cb0ef41Sopenharmony_ci int32_t oldLength = hash->length; 4011cb0ef41Sopenharmony_ci int32_t newPrimeIndex = hash->primeIndex; 4021cb0ef41Sopenharmony_ci int32_t i; 4031cb0ef41Sopenharmony_ci 4041cb0ef41Sopenharmony_ci if (hash->count > hash->highWaterMark) { 4051cb0ef41Sopenharmony_ci if (++newPrimeIndex >= PRIMES_LENGTH) { 4061cb0ef41Sopenharmony_ci return; 4071cb0ef41Sopenharmony_ci } 4081cb0ef41Sopenharmony_ci } else if (hash->count < hash->lowWaterMark) { 4091cb0ef41Sopenharmony_ci if (--newPrimeIndex < 0) { 4101cb0ef41Sopenharmony_ci return; 4111cb0ef41Sopenharmony_ci } 4121cb0ef41Sopenharmony_ci } else { 4131cb0ef41Sopenharmony_ci return; 4141cb0ef41Sopenharmony_ci } 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ci _uhash_allocate(hash, newPrimeIndex, status); 4171cb0ef41Sopenharmony_ci 4181cb0ef41Sopenharmony_ci if (U_FAILURE(*status)) { 4191cb0ef41Sopenharmony_ci hash->elements = old; 4201cb0ef41Sopenharmony_ci hash->length = oldLength; 4211cb0ef41Sopenharmony_ci return; 4221cb0ef41Sopenharmony_ci } 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_ci for (i = oldLength - 1; i >= 0; --i) { 4251cb0ef41Sopenharmony_ci if (!IS_EMPTY_OR_DELETED(old[i].hashcode)) { 4261cb0ef41Sopenharmony_ci UHashElement *e = _uhash_find(hash, old[i].key, old[i].hashcode); 4271cb0ef41Sopenharmony_ci U_ASSERT(e != nullptr); 4281cb0ef41Sopenharmony_ci U_ASSERT(e->hashcode == HASH_EMPTY); 4291cb0ef41Sopenharmony_ci e->key = old[i].key; 4301cb0ef41Sopenharmony_ci e->value = old[i].value; 4311cb0ef41Sopenharmony_ci e->hashcode = old[i].hashcode; 4321cb0ef41Sopenharmony_ci ++hash->count; 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci } 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_ci uprv_free(old); 4371cb0ef41Sopenharmony_ci} 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_cistatic UHashTok 4401cb0ef41Sopenharmony_ci_uhash_remove(UHashtable *hash, 4411cb0ef41Sopenharmony_ci UHashTok key) { 4421cb0ef41Sopenharmony_ci /* First find the position of the key in the table. If the object 4431cb0ef41Sopenharmony_ci * has not been removed already, remove it. If the user wanted 4441cb0ef41Sopenharmony_ci * keys deleted, then delete it also. We have to put a special 4451cb0ef41Sopenharmony_ci * hashcode in that position that means that something has been 4461cb0ef41Sopenharmony_ci * deleted, since when we do a find, we have to continue PAST any 4471cb0ef41Sopenharmony_ci * deleted values. 4481cb0ef41Sopenharmony_ci */ 4491cb0ef41Sopenharmony_ci UHashTok result; 4501cb0ef41Sopenharmony_ci UHashElement* e = _uhash_find(hash, key, hash->keyHasher(key)); 4511cb0ef41Sopenharmony_ci U_ASSERT(e != nullptr); 4521cb0ef41Sopenharmony_ci result.pointer = nullptr; 4531cb0ef41Sopenharmony_ci result.integer = 0; 4541cb0ef41Sopenharmony_ci if (!IS_EMPTY_OR_DELETED(e->hashcode)) { 4551cb0ef41Sopenharmony_ci result = _uhash_internalRemoveElement(hash, e); 4561cb0ef41Sopenharmony_ci if (hash->count < hash->lowWaterMark) { 4571cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 4581cb0ef41Sopenharmony_ci _uhash_rehash(hash, &status); 4591cb0ef41Sopenharmony_ci } 4601cb0ef41Sopenharmony_ci } 4611cb0ef41Sopenharmony_ci return result; 4621cb0ef41Sopenharmony_ci} 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_cistatic UHashTok 4651cb0ef41Sopenharmony_ci_uhash_put(UHashtable *hash, 4661cb0ef41Sopenharmony_ci UHashTok key, 4671cb0ef41Sopenharmony_ci UHashTok value, 4681cb0ef41Sopenharmony_ci int8_t hint, 4691cb0ef41Sopenharmony_ci UErrorCode *status) { 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ci /* Put finds the position in the table for the new value. If the 4721cb0ef41Sopenharmony_ci * key is already in the table, it is deleted, if there is a 4731cb0ef41Sopenharmony_ci * non-nullptr keyDeleter. Then the key, the hash and the value are 4741cb0ef41Sopenharmony_ci * all put at the position in their respective arrays. 4751cb0ef41Sopenharmony_ci */ 4761cb0ef41Sopenharmony_ci int32_t hashcode; 4771cb0ef41Sopenharmony_ci UHashElement* e; 4781cb0ef41Sopenharmony_ci UHashTok emptytok; 4791cb0ef41Sopenharmony_ci 4801cb0ef41Sopenharmony_ci if (U_FAILURE(*status)) { 4811cb0ef41Sopenharmony_ci goto err; 4821cb0ef41Sopenharmony_ci } 4831cb0ef41Sopenharmony_ci U_ASSERT(hash != nullptr); 4841cb0ef41Sopenharmony_ci if ((hint & HINT_VALUE_POINTER) ? 4851cb0ef41Sopenharmony_ci value.pointer == nullptr : 4861cb0ef41Sopenharmony_ci value.integer == 0 && (hint & HINT_ALLOW_ZERO) == 0) { 4871cb0ef41Sopenharmony_ci /* Disallow storage of nullptr values, since nullptr is returned by 4881cb0ef41Sopenharmony_ci * get() to indicate an absent key. Storing nullptr == removing. 4891cb0ef41Sopenharmony_ci */ 4901cb0ef41Sopenharmony_ci return _uhash_remove(hash, key); 4911cb0ef41Sopenharmony_ci } 4921cb0ef41Sopenharmony_ci if (hash->count > hash->highWaterMark) { 4931cb0ef41Sopenharmony_ci _uhash_rehash(hash, status); 4941cb0ef41Sopenharmony_ci if (U_FAILURE(*status)) { 4951cb0ef41Sopenharmony_ci goto err; 4961cb0ef41Sopenharmony_ci } 4971cb0ef41Sopenharmony_ci } 4981cb0ef41Sopenharmony_ci 4991cb0ef41Sopenharmony_ci hashcode = (*hash->keyHasher)(key); 5001cb0ef41Sopenharmony_ci e = _uhash_find(hash, key, hashcode); 5011cb0ef41Sopenharmony_ci U_ASSERT(e != nullptr); 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci if (IS_EMPTY_OR_DELETED(e->hashcode)) { 5041cb0ef41Sopenharmony_ci /* Important: We must never actually fill the table up. If we 5051cb0ef41Sopenharmony_ci * do so, then _uhash_find() will return nullptr, and we'll have 5061cb0ef41Sopenharmony_ci * to check for nullptr after every call to _uhash_find(). To 5071cb0ef41Sopenharmony_ci * avoid this we make sure there is always at least one empty 5081cb0ef41Sopenharmony_ci * or deleted slot in the table. This only is a problem if we 5091cb0ef41Sopenharmony_ci * are out of memory and rehash isn't working. 5101cb0ef41Sopenharmony_ci */ 5111cb0ef41Sopenharmony_ci ++hash->count; 5121cb0ef41Sopenharmony_ci if (hash->count == hash->length) { 5131cb0ef41Sopenharmony_ci /* Don't allow count to reach length */ 5141cb0ef41Sopenharmony_ci --hash->count; 5151cb0ef41Sopenharmony_ci *status = U_MEMORY_ALLOCATION_ERROR; 5161cb0ef41Sopenharmony_ci goto err; 5171cb0ef41Sopenharmony_ci } 5181cb0ef41Sopenharmony_ci } 5191cb0ef41Sopenharmony_ci 5201cb0ef41Sopenharmony_ci /* We must in all cases handle storage properly. If there was an 5211cb0ef41Sopenharmony_ci * old key, then it must be deleted (if the deleter != nullptr). 5221cb0ef41Sopenharmony_ci * Make hashcodes stored in table positive. 5231cb0ef41Sopenharmony_ci */ 5241cb0ef41Sopenharmony_ci return _uhash_setElement(hash, e, hashcode & 0x7FFFFFFF, key, value, hint); 5251cb0ef41Sopenharmony_ci 5261cb0ef41Sopenharmony_ci err: 5271cb0ef41Sopenharmony_ci /* If the deleters are non-nullptr, this method adopts its key and/or 5281cb0ef41Sopenharmony_ci * value arguments, and we must be sure to delete the key and/or 5291cb0ef41Sopenharmony_ci * value in all cases, even upon failure. 5301cb0ef41Sopenharmony_ci */ 5311cb0ef41Sopenharmony_ci HASH_DELETE_KEY_VALUE(hash, key.pointer, value.pointer); 5321cb0ef41Sopenharmony_ci emptytok.pointer = nullptr; emptytok.integer = 0; 5331cb0ef41Sopenharmony_ci return emptytok; 5341cb0ef41Sopenharmony_ci} 5351cb0ef41Sopenharmony_ci 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_ci/******************************************************************** 5381cb0ef41Sopenharmony_ci * PUBLIC API 5391cb0ef41Sopenharmony_ci ********************************************************************/ 5401cb0ef41Sopenharmony_ci 5411cb0ef41Sopenharmony_ciU_CAPI UHashtable* U_EXPORT2 5421cb0ef41Sopenharmony_ciuhash_open(UHashFunction *keyHash, 5431cb0ef41Sopenharmony_ci UKeyComparator *keyComp, 5441cb0ef41Sopenharmony_ci UValueComparator *valueComp, 5451cb0ef41Sopenharmony_ci UErrorCode *status) { 5461cb0ef41Sopenharmony_ci 5471cb0ef41Sopenharmony_ci return _uhash_create(keyHash, keyComp, valueComp, DEFAULT_PRIME_INDEX, status); 5481cb0ef41Sopenharmony_ci} 5491cb0ef41Sopenharmony_ci 5501cb0ef41Sopenharmony_ciU_CAPI UHashtable* U_EXPORT2 5511cb0ef41Sopenharmony_ciuhash_openSize(UHashFunction *keyHash, 5521cb0ef41Sopenharmony_ci UKeyComparator *keyComp, 5531cb0ef41Sopenharmony_ci UValueComparator *valueComp, 5541cb0ef41Sopenharmony_ci int32_t size, 5551cb0ef41Sopenharmony_ci UErrorCode *status) { 5561cb0ef41Sopenharmony_ci 5571cb0ef41Sopenharmony_ci /* Find the smallest index i for which PRIMES[i] >= size. */ 5581cb0ef41Sopenharmony_ci int32_t i = 0; 5591cb0ef41Sopenharmony_ci while (i<(PRIMES_LENGTH-1) && PRIMES[i]<size) { 5601cb0ef41Sopenharmony_ci ++i; 5611cb0ef41Sopenharmony_ci } 5621cb0ef41Sopenharmony_ci 5631cb0ef41Sopenharmony_ci return _uhash_create(keyHash, keyComp, valueComp, i, status); 5641cb0ef41Sopenharmony_ci} 5651cb0ef41Sopenharmony_ci 5661cb0ef41Sopenharmony_ciU_CAPI UHashtable* U_EXPORT2 5671cb0ef41Sopenharmony_ciuhash_init(UHashtable *fillinResult, 5681cb0ef41Sopenharmony_ci UHashFunction *keyHash, 5691cb0ef41Sopenharmony_ci UKeyComparator *keyComp, 5701cb0ef41Sopenharmony_ci UValueComparator *valueComp, 5711cb0ef41Sopenharmony_ci UErrorCode *status) { 5721cb0ef41Sopenharmony_ci 5731cb0ef41Sopenharmony_ci return _uhash_init(fillinResult, keyHash, keyComp, valueComp, DEFAULT_PRIME_INDEX, status); 5741cb0ef41Sopenharmony_ci} 5751cb0ef41Sopenharmony_ci 5761cb0ef41Sopenharmony_ciU_CAPI UHashtable* U_EXPORT2 5771cb0ef41Sopenharmony_ciuhash_initSize(UHashtable *fillinResult, 5781cb0ef41Sopenharmony_ci UHashFunction *keyHash, 5791cb0ef41Sopenharmony_ci UKeyComparator *keyComp, 5801cb0ef41Sopenharmony_ci UValueComparator *valueComp, 5811cb0ef41Sopenharmony_ci int32_t size, 5821cb0ef41Sopenharmony_ci UErrorCode *status) { 5831cb0ef41Sopenharmony_ci 5841cb0ef41Sopenharmony_ci // Find the smallest index i for which PRIMES[i] >= size. 5851cb0ef41Sopenharmony_ci int32_t i = 0; 5861cb0ef41Sopenharmony_ci while (i<(PRIMES_LENGTH-1) && PRIMES[i]<size) { 5871cb0ef41Sopenharmony_ci ++i; 5881cb0ef41Sopenharmony_ci } 5891cb0ef41Sopenharmony_ci return _uhash_init(fillinResult, keyHash, keyComp, valueComp, i, status); 5901cb0ef41Sopenharmony_ci} 5911cb0ef41Sopenharmony_ci 5921cb0ef41Sopenharmony_ciU_CAPI void U_EXPORT2 5931cb0ef41Sopenharmony_ciuhash_close(UHashtable *hash) { 5941cb0ef41Sopenharmony_ci if (hash == nullptr) { 5951cb0ef41Sopenharmony_ci return; 5961cb0ef41Sopenharmony_ci } 5971cb0ef41Sopenharmony_ci if (hash->elements != nullptr) { 5981cb0ef41Sopenharmony_ci if (hash->keyDeleter != nullptr || hash->valueDeleter != nullptr) { 5991cb0ef41Sopenharmony_ci int32_t pos=UHASH_FIRST; 6001cb0ef41Sopenharmony_ci UHashElement *e; 6011cb0ef41Sopenharmony_ci while ((e = (UHashElement*) uhash_nextElement(hash, &pos)) != nullptr) { 6021cb0ef41Sopenharmony_ci HASH_DELETE_KEY_VALUE(hash, e->key.pointer, e->value.pointer); 6031cb0ef41Sopenharmony_ci } 6041cb0ef41Sopenharmony_ci } 6051cb0ef41Sopenharmony_ci uprv_free(hash->elements); 6061cb0ef41Sopenharmony_ci hash->elements = nullptr; 6071cb0ef41Sopenharmony_ci } 6081cb0ef41Sopenharmony_ci if (hash->allocated) { 6091cb0ef41Sopenharmony_ci uprv_free(hash); 6101cb0ef41Sopenharmony_ci } 6111cb0ef41Sopenharmony_ci} 6121cb0ef41Sopenharmony_ci 6131cb0ef41Sopenharmony_ciU_CAPI UHashFunction *U_EXPORT2 6141cb0ef41Sopenharmony_ciuhash_setKeyHasher(UHashtable *hash, UHashFunction *fn) { 6151cb0ef41Sopenharmony_ci UHashFunction *result = hash->keyHasher; 6161cb0ef41Sopenharmony_ci hash->keyHasher = fn; 6171cb0ef41Sopenharmony_ci return result; 6181cb0ef41Sopenharmony_ci} 6191cb0ef41Sopenharmony_ci 6201cb0ef41Sopenharmony_ciU_CAPI UKeyComparator *U_EXPORT2 6211cb0ef41Sopenharmony_ciuhash_setKeyComparator(UHashtable *hash, UKeyComparator *fn) { 6221cb0ef41Sopenharmony_ci UKeyComparator *result = hash->keyComparator; 6231cb0ef41Sopenharmony_ci hash->keyComparator = fn; 6241cb0ef41Sopenharmony_ci return result; 6251cb0ef41Sopenharmony_ci} 6261cb0ef41Sopenharmony_ciU_CAPI UValueComparator *U_EXPORT2 6271cb0ef41Sopenharmony_ciuhash_setValueComparator(UHashtable *hash, UValueComparator *fn){ 6281cb0ef41Sopenharmony_ci UValueComparator *result = hash->valueComparator; 6291cb0ef41Sopenharmony_ci hash->valueComparator = fn; 6301cb0ef41Sopenharmony_ci return result; 6311cb0ef41Sopenharmony_ci} 6321cb0ef41Sopenharmony_ci 6331cb0ef41Sopenharmony_ciU_CAPI UObjectDeleter *U_EXPORT2 6341cb0ef41Sopenharmony_ciuhash_setKeyDeleter(UHashtable *hash, UObjectDeleter *fn) { 6351cb0ef41Sopenharmony_ci UObjectDeleter *result = hash->keyDeleter; 6361cb0ef41Sopenharmony_ci hash->keyDeleter = fn; 6371cb0ef41Sopenharmony_ci return result; 6381cb0ef41Sopenharmony_ci} 6391cb0ef41Sopenharmony_ci 6401cb0ef41Sopenharmony_ciU_CAPI UObjectDeleter *U_EXPORT2 6411cb0ef41Sopenharmony_ciuhash_setValueDeleter(UHashtable *hash, UObjectDeleter *fn) { 6421cb0ef41Sopenharmony_ci UObjectDeleter *result = hash->valueDeleter; 6431cb0ef41Sopenharmony_ci hash->valueDeleter = fn; 6441cb0ef41Sopenharmony_ci return result; 6451cb0ef41Sopenharmony_ci} 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ciU_CAPI void U_EXPORT2 6481cb0ef41Sopenharmony_ciuhash_setResizePolicy(UHashtable *hash, enum UHashResizePolicy policy) { 6491cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 6501cb0ef41Sopenharmony_ci _uhash_internalSetResizePolicy(hash, policy); 6511cb0ef41Sopenharmony_ci hash->lowWaterMark = (int32_t)(hash->length * hash->lowWaterRatio); 6521cb0ef41Sopenharmony_ci hash->highWaterMark = (int32_t)(hash->length * hash->highWaterRatio); 6531cb0ef41Sopenharmony_ci _uhash_rehash(hash, &status); 6541cb0ef41Sopenharmony_ci} 6551cb0ef41Sopenharmony_ci 6561cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 6571cb0ef41Sopenharmony_ciuhash_count(const UHashtable *hash) { 6581cb0ef41Sopenharmony_ci return hash->count; 6591cb0ef41Sopenharmony_ci} 6601cb0ef41Sopenharmony_ci 6611cb0ef41Sopenharmony_ciU_CAPI void* U_EXPORT2 6621cb0ef41Sopenharmony_ciuhash_get(const UHashtable *hash, 6631cb0ef41Sopenharmony_ci const void* key) { 6641cb0ef41Sopenharmony_ci UHashTok keyholder; 6651cb0ef41Sopenharmony_ci keyholder.pointer = (void*) key; 6661cb0ef41Sopenharmony_ci return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.pointer; 6671cb0ef41Sopenharmony_ci} 6681cb0ef41Sopenharmony_ci 6691cb0ef41Sopenharmony_ciU_CAPI void* U_EXPORT2 6701cb0ef41Sopenharmony_ciuhash_iget(const UHashtable *hash, 6711cb0ef41Sopenharmony_ci int32_t key) { 6721cb0ef41Sopenharmony_ci UHashTok keyholder; 6731cb0ef41Sopenharmony_ci keyholder.integer = key; 6741cb0ef41Sopenharmony_ci return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.pointer; 6751cb0ef41Sopenharmony_ci} 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 6781cb0ef41Sopenharmony_ciuhash_geti(const UHashtable *hash, 6791cb0ef41Sopenharmony_ci const void* key) { 6801cb0ef41Sopenharmony_ci UHashTok keyholder; 6811cb0ef41Sopenharmony_ci keyholder.pointer = (void*) key; 6821cb0ef41Sopenharmony_ci return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.integer; 6831cb0ef41Sopenharmony_ci} 6841cb0ef41Sopenharmony_ci 6851cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 6861cb0ef41Sopenharmony_ciuhash_igeti(const UHashtable *hash, 6871cb0ef41Sopenharmony_ci int32_t key) { 6881cb0ef41Sopenharmony_ci UHashTok keyholder; 6891cb0ef41Sopenharmony_ci keyholder.integer = key; 6901cb0ef41Sopenharmony_ci return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.integer; 6911cb0ef41Sopenharmony_ci} 6921cb0ef41Sopenharmony_ci 6931cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 6941cb0ef41Sopenharmony_ciuhash_getiAndFound(const UHashtable *hash, 6951cb0ef41Sopenharmony_ci const void *key, 6961cb0ef41Sopenharmony_ci UBool *found) { 6971cb0ef41Sopenharmony_ci UHashTok keyholder; 6981cb0ef41Sopenharmony_ci keyholder.pointer = (void *)key; 6991cb0ef41Sopenharmony_ci const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); 7001cb0ef41Sopenharmony_ci *found = !IS_EMPTY_OR_DELETED(e->hashcode); 7011cb0ef41Sopenharmony_ci return e->value.integer; 7021cb0ef41Sopenharmony_ci} 7031cb0ef41Sopenharmony_ci 7041cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 7051cb0ef41Sopenharmony_ciuhash_igetiAndFound(const UHashtable *hash, 7061cb0ef41Sopenharmony_ci int32_t key, 7071cb0ef41Sopenharmony_ci UBool *found) { 7081cb0ef41Sopenharmony_ci UHashTok keyholder; 7091cb0ef41Sopenharmony_ci keyholder.integer = key; 7101cb0ef41Sopenharmony_ci const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); 7111cb0ef41Sopenharmony_ci *found = !IS_EMPTY_OR_DELETED(e->hashcode); 7121cb0ef41Sopenharmony_ci return e->value.integer; 7131cb0ef41Sopenharmony_ci} 7141cb0ef41Sopenharmony_ci 7151cb0ef41Sopenharmony_ciU_CAPI void* U_EXPORT2 7161cb0ef41Sopenharmony_ciuhash_put(UHashtable *hash, 7171cb0ef41Sopenharmony_ci void* key, 7181cb0ef41Sopenharmony_ci void* value, 7191cb0ef41Sopenharmony_ci UErrorCode *status) { 7201cb0ef41Sopenharmony_ci UHashTok keyholder, valueholder; 7211cb0ef41Sopenharmony_ci keyholder.pointer = key; 7221cb0ef41Sopenharmony_ci valueholder.pointer = value; 7231cb0ef41Sopenharmony_ci return _uhash_put(hash, keyholder, valueholder, 7241cb0ef41Sopenharmony_ci HINT_KEY_POINTER | HINT_VALUE_POINTER, 7251cb0ef41Sopenharmony_ci status).pointer; 7261cb0ef41Sopenharmony_ci} 7271cb0ef41Sopenharmony_ci 7281cb0ef41Sopenharmony_ciU_CAPI void* U_EXPORT2 7291cb0ef41Sopenharmony_ciuhash_iput(UHashtable *hash, 7301cb0ef41Sopenharmony_ci int32_t key, 7311cb0ef41Sopenharmony_ci void* value, 7321cb0ef41Sopenharmony_ci UErrorCode *status) { 7331cb0ef41Sopenharmony_ci UHashTok keyholder, valueholder; 7341cb0ef41Sopenharmony_ci keyholder.integer = key; 7351cb0ef41Sopenharmony_ci valueholder.pointer = value; 7361cb0ef41Sopenharmony_ci return _uhash_put(hash, keyholder, valueholder, 7371cb0ef41Sopenharmony_ci HINT_VALUE_POINTER, 7381cb0ef41Sopenharmony_ci status).pointer; 7391cb0ef41Sopenharmony_ci} 7401cb0ef41Sopenharmony_ci 7411cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 7421cb0ef41Sopenharmony_ciuhash_puti(UHashtable *hash, 7431cb0ef41Sopenharmony_ci void* key, 7441cb0ef41Sopenharmony_ci int32_t value, 7451cb0ef41Sopenharmony_ci UErrorCode *status) { 7461cb0ef41Sopenharmony_ci UHashTok keyholder, valueholder; 7471cb0ef41Sopenharmony_ci keyholder.pointer = key; 7481cb0ef41Sopenharmony_ci valueholder.integer = value; 7491cb0ef41Sopenharmony_ci return _uhash_put(hash, keyholder, valueholder, 7501cb0ef41Sopenharmony_ci HINT_KEY_POINTER, 7511cb0ef41Sopenharmony_ci status).integer; 7521cb0ef41Sopenharmony_ci} 7531cb0ef41Sopenharmony_ci 7541cb0ef41Sopenharmony_ci 7551cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 7561cb0ef41Sopenharmony_ciuhash_iputi(UHashtable *hash, 7571cb0ef41Sopenharmony_ci int32_t key, 7581cb0ef41Sopenharmony_ci int32_t value, 7591cb0ef41Sopenharmony_ci UErrorCode *status) { 7601cb0ef41Sopenharmony_ci UHashTok keyholder, valueholder; 7611cb0ef41Sopenharmony_ci keyholder.integer = key; 7621cb0ef41Sopenharmony_ci valueholder.integer = value; 7631cb0ef41Sopenharmony_ci return _uhash_put(hash, keyholder, valueholder, 7641cb0ef41Sopenharmony_ci HINT_BOTH_INTEGERS, 7651cb0ef41Sopenharmony_ci status).integer; 7661cb0ef41Sopenharmony_ci} 7671cb0ef41Sopenharmony_ci 7681cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 7691cb0ef41Sopenharmony_ciuhash_putiAllowZero(UHashtable *hash, 7701cb0ef41Sopenharmony_ci void *key, 7711cb0ef41Sopenharmony_ci int32_t value, 7721cb0ef41Sopenharmony_ci UErrorCode *status) { 7731cb0ef41Sopenharmony_ci UHashTok keyholder, valueholder; 7741cb0ef41Sopenharmony_ci keyholder.pointer = key; 7751cb0ef41Sopenharmony_ci valueholder.integer = value; 7761cb0ef41Sopenharmony_ci return _uhash_put(hash, keyholder, valueholder, 7771cb0ef41Sopenharmony_ci HINT_KEY_POINTER | HINT_ALLOW_ZERO, 7781cb0ef41Sopenharmony_ci status).integer; 7791cb0ef41Sopenharmony_ci} 7801cb0ef41Sopenharmony_ci 7811cb0ef41Sopenharmony_ci 7821cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 7831cb0ef41Sopenharmony_ciuhash_iputiAllowZero(UHashtable *hash, 7841cb0ef41Sopenharmony_ci int32_t key, 7851cb0ef41Sopenharmony_ci int32_t value, 7861cb0ef41Sopenharmony_ci UErrorCode *status) { 7871cb0ef41Sopenharmony_ci UHashTok keyholder, valueholder; 7881cb0ef41Sopenharmony_ci keyholder.integer = key; 7891cb0ef41Sopenharmony_ci valueholder.integer = value; 7901cb0ef41Sopenharmony_ci return _uhash_put(hash, keyholder, valueholder, 7911cb0ef41Sopenharmony_ci HINT_BOTH_INTEGERS | HINT_ALLOW_ZERO, 7921cb0ef41Sopenharmony_ci status).integer; 7931cb0ef41Sopenharmony_ci} 7941cb0ef41Sopenharmony_ci 7951cb0ef41Sopenharmony_ciU_CAPI void* U_EXPORT2 7961cb0ef41Sopenharmony_ciuhash_remove(UHashtable *hash, 7971cb0ef41Sopenharmony_ci const void* key) { 7981cb0ef41Sopenharmony_ci UHashTok keyholder; 7991cb0ef41Sopenharmony_ci keyholder.pointer = (void*) key; 8001cb0ef41Sopenharmony_ci return _uhash_remove(hash, keyholder).pointer; 8011cb0ef41Sopenharmony_ci} 8021cb0ef41Sopenharmony_ci 8031cb0ef41Sopenharmony_ciU_CAPI void* U_EXPORT2 8041cb0ef41Sopenharmony_ciuhash_iremove(UHashtable *hash, 8051cb0ef41Sopenharmony_ci int32_t key) { 8061cb0ef41Sopenharmony_ci UHashTok keyholder; 8071cb0ef41Sopenharmony_ci keyholder.integer = key; 8081cb0ef41Sopenharmony_ci return _uhash_remove(hash, keyholder).pointer; 8091cb0ef41Sopenharmony_ci} 8101cb0ef41Sopenharmony_ci 8111cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 8121cb0ef41Sopenharmony_ciuhash_removei(UHashtable *hash, 8131cb0ef41Sopenharmony_ci const void* key) { 8141cb0ef41Sopenharmony_ci UHashTok keyholder; 8151cb0ef41Sopenharmony_ci keyholder.pointer = (void*) key; 8161cb0ef41Sopenharmony_ci return _uhash_remove(hash, keyholder).integer; 8171cb0ef41Sopenharmony_ci} 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 8201cb0ef41Sopenharmony_ciuhash_iremovei(UHashtable *hash, 8211cb0ef41Sopenharmony_ci int32_t key) { 8221cb0ef41Sopenharmony_ci UHashTok keyholder; 8231cb0ef41Sopenharmony_ci keyholder.integer = key; 8241cb0ef41Sopenharmony_ci return _uhash_remove(hash, keyholder).integer; 8251cb0ef41Sopenharmony_ci} 8261cb0ef41Sopenharmony_ci 8271cb0ef41Sopenharmony_ciU_CAPI void U_EXPORT2 8281cb0ef41Sopenharmony_ciuhash_removeAll(UHashtable *hash) { 8291cb0ef41Sopenharmony_ci int32_t pos = UHASH_FIRST; 8301cb0ef41Sopenharmony_ci const UHashElement *e; 8311cb0ef41Sopenharmony_ci U_ASSERT(hash != nullptr); 8321cb0ef41Sopenharmony_ci if (hash->count != 0) { 8331cb0ef41Sopenharmony_ci while ((e = uhash_nextElement(hash, &pos)) != nullptr) { 8341cb0ef41Sopenharmony_ci uhash_removeElement(hash, e); 8351cb0ef41Sopenharmony_ci } 8361cb0ef41Sopenharmony_ci } 8371cb0ef41Sopenharmony_ci U_ASSERT(hash->count == 0); 8381cb0ef41Sopenharmony_ci} 8391cb0ef41Sopenharmony_ci 8401cb0ef41Sopenharmony_ciU_CAPI UBool U_EXPORT2 8411cb0ef41Sopenharmony_ciuhash_containsKey(const UHashtable *hash, const void *key) { 8421cb0ef41Sopenharmony_ci UHashTok keyholder; 8431cb0ef41Sopenharmony_ci keyholder.pointer = (void *)key; 8441cb0ef41Sopenharmony_ci const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); 8451cb0ef41Sopenharmony_ci return !IS_EMPTY_OR_DELETED(e->hashcode); 8461cb0ef41Sopenharmony_ci} 8471cb0ef41Sopenharmony_ci 8481cb0ef41Sopenharmony_ci/** 8491cb0ef41Sopenharmony_ci * Returns true if the UHashtable contains an item with this integer key. 8501cb0ef41Sopenharmony_ci * 8511cb0ef41Sopenharmony_ci * @param hash The target UHashtable. 8521cb0ef41Sopenharmony_ci * @param key An integer key stored in a hashtable 8531cb0ef41Sopenharmony_ci * @return true if the key is found. 8541cb0ef41Sopenharmony_ci */ 8551cb0ef41Sopenharmony_ciU_CAPI UBool U_EXPORT2 8561cb0ef41Sopenharmony_ciuhash_icontainsKey(const UHashtable *hash, int32_t key) { 8571cb0ef41Sopenharmony_ci UHashTok keyholder; 8581cb0ef41Sopenharmony_ci keyholder.integer = key; 8591cb0ef41Sopenharmony_ci const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); 8601cb0ef41Sopenharmony_ci return !IS_EMPTY_OR_DELETED(e->hashcode); 8611cb0ef41Sopenharmony_ci} 8621cb0ef41Sopenharmony_ci 8631cb0ef41Sopenharmony_ciU_CAPI const UHashElement* U_EXPORT2 8641cb0ef41Sopenharmony_ciuhash_find(const UHashtable *hash, const void* key) { 8651cb0ef41Sopenharmony_ci UHashTok keyholder; 8661cb0ef41Sopenharmony_ci const UHashElement *e; 8671cb0ef41Sopenharmony_ci keyholder.pointer = (void*) key; 8681cb0ef41Sopenharmony_ci e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); 8691cb0ef41Sopenharmony_ci return IS_EMPTY_OR_DELETED(e->hashcode) ? nullptr : e; 8701cb0ef41Sopenharmony_ci} 8711cb0ef41Sopenharmony_ci 8721cb0ef41Sopenharmony_ciU_CAPI const UHashElement* U_EXPORT2 8731cb0ef41Sopenharmony_ciuhash_nextElement(const UHashtable *hash, int32_t *pos) { 8741cb0ef41Sopenharmony_ci /* Walk through the array until we find an element that is not 8751cb0ef41Sopenharmony_ci * EMPTY and not DELETED. 8761cb0ef41Sopenharmony_ci */ 8771cb0ef41Sopenharmony_ci int32_t i; 8781cb0ef41Sopenharmony_ci U_ASSERT(hash != nullptr); 8791cb0ef41Sopenharmony_ci for (i = *pos + 1; i < hash->length; ++i) { 8801cb0ef41Sopenharmony_ci if (!IS_EMPTY_OR_DELETED(hash->elements[i].hashcode)) { 8811cb0ef41Sopenharmony_ci *pos = i; 8821cb0ef41Sopenharmony_ci return &(hash->elements[i]); 8831cb0ef41Sopenharmony_ci } 8841cb0ef41Sopenharmony_ci } 8851cb0ef41Sopenharmony_ci 8861cb0ef41Sopenharmony_ci /* No more elements */ 8871cb0ef41Sopenharmony_ci return nullptr; 8881cb0ef41Sopenharmony_ci} 8891cb0ef41Sopenharmony_ci 8901cb0ef41Sopenharmony_ciU_CAPI void* U_EXPORT2 8911cb0ef41Sopenharmony_ciuhash_removeElement(UHashtable *hash, const UHashElement* e) { 8921cb0ef41Sopenharmony_ci U_ASSERT(hash != nullptr); 8931cb0ef41Sopenharmony_ci U_ASSERT(e != nullptr); 8941cb0ef41Sopenharmony_ci if (!IS_EMPTY_OR_DELETED(e->hashcode)) { 8951cb0ef41Sopenharmony_ci UHashElement *nce = (UHashElement *)e; 8961cb0ef41Sopenharmony_ci return _uhash_internalRemoveElement(hash, nce).pointer; 8971cb0ef41Sopenharmony_ci } 8981cb0ef41Sopenharmony_ci return nullptr; 8991cb0ef41Sopenharmony_ci} 9001cb0ef41Sopenharmony_ci 9011cb0ef41Sopenharmony_ci/******************************************************************** 9021cb0ef41Sopenharmony_ci * UHashTok convenience 9031cb0ef41Sopenharmony_ci ********************************************************************/ 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ci/** 9061cb0ef41Sopenharmony_ci * Return a UHashTok for an integer. 9071cb0ef41Sopenharmony_ci */ 9081cb0ef41Sopenharmony_ci/*U_CAPI UHashTok U_EXPORT2 9091cb0ef41Sopenharmony_ciuhash_toki(int32_t i) { 9101cb0ef41Sopenharmony_ci UHashTok tok; 9111cb0ef41Sopenharmony_ci tok.integer = i; 9121cb0ef41Sopenharmony_ci return tok; 9131cb0ef41Sopenharmony_ci}*/ 9141cb0ef41Sopenharmony_ci 9151cb0ef41Sopenharmony_ci/** 9161cb0ef41Sopenharmony_ci * Return a UHashTok for a pointer. 9171cb0ef41Sopenharmony_ci */ 9181cb0ef41Sopenharmony_ci/*U_CAPI UHashTok U_EXPORT2 9191cb0ef41Sopenharmony_ciuhash_tokp(void* p) { 9201cb0ef41Sopenharmony_ci UHashTok tok; 9211cb0ef41Sopenharmony_ci tok.pointer = p; 9221cb0ef41Sopenharmony_ci return tok; 9231cb0ef41Sopenharmony_ci}*/ 9241cb0ef41Sopenharmony_ci 9251cb0ef41Sopenharmony_ci/******************************************************************** 9261cb0ef41Sopenharmony_ci * PUBLIC Key Hash Functions 9271cb0ef41Sopenharmony_ci ********************************************************************/ 9281cb0ef41Sopenharmony_ci 9291cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 9301cb0ef41Sopenharmony_ciuhash_hashUChars(const UHashTok key) { 9311cb0ef41Sopenharmony_ci const char16_t *s = (const char16_t *)key.pointer; 9321cb0ef41Sopenharmony_ci return s == nullptr ? 0 : ustr_hashUCharsN(s, u_strlen(s)); 9331cb0ef41Sopenharmony_ci} 9341cb0ef41Sopenharmony_ci 9351cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 9361cb0ef41Sopenharmony_ciuhash_hashChars(const UHashTok key) { 9371cb0ef41Sopenharmony_ci const char *s = (const char *)key.pointer; 9381cb0ef41Sopenharmony_ci return s == nullptr ? 0 : static_cast<int32_t>(ustr_hashCharsN(s, static_cast<int32_t>(uprv_strlen(s)))); 9391cb0ef41Sopenharmony_ci} 9401cb0ef41Sopenharmony_ci 9411cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 9421cb0ef41Sopenharmony_ciuhash_hashIChars(const UHashTok key) { 9431cb0ef41Sopenharmony_ci const char *s = (const char *)key.pointer; 9441cb0ef41Sopenharmony_ci return s == nullptr ? 0 : ustr_hashICharsN(s, static_cast<int32_t>(uprv_strlen(s))); 9451cb0ef41Sopenharmony_ci} 9461cb0ef41Sopenharmony_ci 9471cb0ef41Sopenharmony_ciU_CAPI UBool U_EXPORT2 9481cb0ef41Sopenharmony_ciuhash_equals(const UHashtable* hash1, const UHashtable* hash2){ 9491cb0ef41Sopenharmony_ci int32_t count1, count2, pos, i; 9501cb0ef41Sopenharmony_ci 9511cb0ef41Sopenharmony_ci if(hash1==hash2){ 9521cb0ef41Sopenharmony_ci return true; 9531cb0ef41Sopenharmony_ci } 9541cb0ef41Sopenharmony_ci 9551cb0ef41Sopenharmony_ci /* 9561cb0ef41Sopenharmony_ci * Make sure that we are comparing 2 valid hashes of the same type 9571cb0ef41Sopenharmony_ci * with valid comparison functions. 9581cb0ef41Sopenharmony_ci * Without valid comparison functions, a binary comparison 9591cb0ef41Sopenharmony_ci * of the hash values will yield random results on machines 9601cb0ef41Sopenharmony_ci * with 64-bit pointers and 32-bit integer hashes. 9611cb0ef41Sopenharmony_ci * A valueComparator is normally optional. 9621cb0ef41Sopenharmony_ci */ 9631cb0ef41Sopenharmony_ci if (hash1==nullptr || hash2==nullptr || 9641cb0ef41Sopenharmony_ci hash1->keyComparator != hash2->keyComparator || 9651cb0ef41Sopenharmony_ci hash1->valueComparator != hash2->valueComparator || 9661cb0ef41Sopenharmony_ci hash1->valueComparator == nullptr) 9671cb0ef41Sopenharmony_ci { 9681cb0ef41Sopenharmony_ci /* 9691cb0ef41Sopenharmony_ci Normally we would return an error here about incompatible hash tables, 9701cb0ef41Sopenharmony_ci but we return false instead. 9711cb0ef41Sopenharmony_ci */ 9721cb0ef41Sopenharmony_ci return false; 9731cb0ef41Sopenharmony_ci } 9741cb0ef41Sopenharmony_ci 9751cb0ef41Sopenharmony_ci count1 = uhash_count(hash1); 9761cb0ef41Sopenharmony_ci count2 = uhash_count(hash2); 9771cb0ef41Sopenharmony_ci if(count1!=count2){ 9781cb0ef41Sopenharmony_ci return false; 9791cb0ef41Sopenharmony_ci } 9801cb0ef41Sopenharmony_ci 9811cb0ef41Sopenharmony_ci pos=UHASH_FIRST; 9821cb0ef41Sopenharmony_ci for(i=0; i<count1; i++){ 9831cb0ef41Sopenharmony_ci const UHashElement* elem1 = uhash_nextElement(hash1, &pos); 9841cb0ef41Sopenharmony_ci const UHashTok key1 = elem1->key; 9851cb0ef41Sopenharmony_ci const UHashTok val1 = elem1->value; 9861cb0ef41Sopenharmony_ci /* here the keys are not compared, instead the key form hash1 is used to fetch 9871cb0ef41Sopenharmony_ci * value from hash2. If the hashes are equal then then both hashes should 9881cb0ef41Sopenharmony_ci * contain equal values for the same key! 9891cb0ef41Sopenharmony_ci */ 9901cb0ef41Sopenharmony_ci const UHashElement* elem2 = _uhash_find(hash2, key1, hash2->keyHasher(key1)); 9911cb0ef41Sopenharmony_ci const UHashTok val2 = elem2->value; 9921cb0ef41Sopenharmony_ci if(hash1->valueComparator(val1, val2)==false){ 9931cb0ef41Sopenharmony_ci return false; 9941cb0ef41Sopenharmony_ci } 9951cb0ef41Sopenharmony_ci } 9961cb0ef41Sopenharmony_ci return true; 9971cb0ef41Sopenharmony_ci} 9981cb0ef41Sopenharmony_ci 9991cb0ef41Sopenharmony_ci/******************************************************************** 10001cb0ef41Sopenharmony_ci * PUBLIC Comparator Functions 10011cb0ef41Sopenharmony_ci ********************************************************************/ 10021cb0ef41Sopenharmony_ci 10031cb0ef41Sopenharmony_ciU_CAPI UBool U_EXPORT2 10041cb0ef41Sopenharmony_ciuhash_compareUChars(const UHashTok key1, const UHashTok key2) { 10051cb0ef41Sopenharmony_ci const char16_t *p1 = (const char16_t*) key1.pointer; 10061cb0ef41Sopenharmony_ci const char16_t *p2 = (const char16_t*) key2.pointer; 10071cb0ef41Sopenharmony_ci if (p1 == p2) { 10081cb0ef41Sopenharmony_ci return true; 10091cb0ef41Sopenharmony_ci } 10101cb0ef41Sopenharmony_ci if (p1 == nullptr || p2 == nullptr) { 10111cb0ef41Sopenharmony_ci return false; 10121cb0ef41Sopenharmony_ci } 10131cb0ef41Sopenharmony_ci while (*p1 != 0 && *p1 == *p2) { 10141cb0ef41Sopenharmony_ci ++p1; 10151cb0ef41Sopenharmony_ci ++p2; 10161cb0ef41Sopenharmony_ci } 10171cb0ef41Sopenharmony_ci return (UBool)(*p1 == *p2); 10181cb0ef41Sopenharmony_ci} 10191cb0ef41Sopenharmony_ci 10201cb0ef41Sopenharmony_ciU_CAPI UBool U_EXPORT2 10211cb0ef41Sopenharmony_ciuhash_compareChars(const UHashTok key1, const UHashTok key2) { 10221cb0ef41Sopenharmony_ci const char *p1 = (const char*) key1.pointer; 10231cb0ef41Sopenharmony_ci const char *p2 = (const char*) key2.pointer; 10241cb0ef41Sopenharmony_ci if (p1 == p2) { 10251cb0ef41Sopenharmony_ci return true; 10261cb0ef41Sopenharmony_ci } 10271cb0ef41Sopenharmony_ci if (p1 == nullptr || p2 == nullptr) { 10281cb0ef41Sopenharmony_ci return false; 10291cb0ef41Sopenharmony_ci } 10301cb0ef41Sopenharmony_ci while (*p1 != 0 && *p1 == *p2) { 10311cb0ef41Sopenharmony_ci ++p1; 10321cb0ef41Sopenharmony_ci ++p2; 10331cb0ef41Sopenharmony_ci } 10341cb0ef41Sopenharmony_ci return (UBool)(*p1 == *p2); 10351cb0ef41Sopenharmony_ci} 10361cb0ef41Sopenharmony_ci 10371cb0ef41Sopenharmony_ciU_CAPI UBool U_EXPORT2 10381cb0ef41Sopenharmony_ciuhash_compareIChars(const UHashTok key1, const UHashTok key2) { 10391cb0ef41Sopenharmony_ci const char *p1 = (const char*) key1.pointer; 10401cb0ef41Sopenharmony_ci const char *p2 = (const char*) key2.pointer; 10411cb0ef41Sopenharmony_ci if (p1 == p2) { 10421cb0ef41Sopenharmony_ci return true; 10431cb0ef41Sopenharmony_ci } 10441cb0ef41Sopenharmony_ci if (p1 == nullptr || p2 == nullptr) { 10451cb0ef41Sopenharmony_ci return false; 10461cb0ef41Sopenharmony_ci } 10471cb0ef41Sopenharmony_ci while (*p1 != 0 && uprv_tolower(*p1) == uprv_tolower(*p2)) { 10481cb0ef41Sopenharmony_ci ++p1; 10491cb0ef41Sopenharmony_ci ++p2; 10501cb0ef41Sopenharmony_ci } 10511cb0ef41Sopenharmony_ci return (UBool)(*p1 == *p2); 10521cb0ef41Sopenharmony_ci} 10531cb0ef41Sopenharmony_ci 10541cb0ef41Sopenharmony_ci/******************************************************************** 10551cb0ef41Sopenharmony_ci * PUBLIC int32_t Support Functions 10561cb0ef41Sopenharmony_ci ********************************************************************/ 10571cb0ef41Sopenharmony_ci 10581cb0ef41Sopenharmony_ciU_CAPI int32_t U_EXPORT2 10591cb0ef41Sopenharmony_ciuhash_hashLong(const UHashTok key) { 10601cb0ef41Sopenharmony_ci return key.integer; 10611cb0ef41Sopenharmony_ci} 10621cb0ef41Sopenharmony_ci 10631cb0ef41Sopenharmony_ciU_CAPI UBool U_EXPORT2 10641cb0ef41Sopenharmony_ciuhash_compareLong(const UHashTok key1, const UHashTok key2) { 10651cb0ef41Sopenharmony_ci return (UBool)(key1.integer == key2.integer); 10661cb0ef41Sopenharmony_ci} 1067