diff --git a/icu4c/source/common/hash.h b/icu4c/source/common/hash.h index 2f3deaee5d5..581e706d055 100644 --- a/icu4c/source/common/hash.h +++ b/icu4c/source/common/hash.h @@ -50,6 +50,8 @@ public: void* remove(const UnicodeString& key); + const UHashElement* find(const UnicodeString& key) const; + const UHashElement* nextElement(int32_t& pos) const; }; @@ -111,6 +113,10 @@ inline void* Hashtable::remove(const UnicodeString& key) { return uhash_remove(hash, &key); } +inline const UHashElement* Hashtable::find(const UnicodeString& key) const { + return uhash_find(hash, &key); +} + inline const UHashElement* Hashtable::nextElement(int32_t& pos) const { return uhash_nextElement(hash, &pos); } diff --git a/icu4c/source/common/rbdata.cpp b/icu4c/source/common/rbdata.cpp index 78329415ec5..6a5a0ea8991 100644 --- a/icu4c/source/common/rbdata.cpp +++ b/icu4c/source/common/rbdata.cpp @@ -111,7 +111,7 @@ UBool TaggedList::nextElement(const UnicodeString*& key, int32_t& pos) const { const UHashElement *e = hash->nextElement(pos); if (e != NULL) { - key = (const UnicodeString*) e->key; + key = (const UnicodeString*) e->key.pointer; value = (const UnicodeString*) e->value; return TRUE; } else { diff --git a/icu4c/source/common/resbund.cpp b/icu4c/source/common/resbund.cpp index 489f28e3de7..663daf57fe1 100644 --- a/icu4c/source/common/resbund.cpp +++ b/icu4c/source/common/resbund.cpp @@ -318,12 +318,12 @@ ResourceBundle::~ResourceBundle() } } +#ifdef ICU_RESBUND_USE_DEPRECATES void -ResourceBundle::deleteValue(void *value) { - delete (ResourceBundleData *)value; +ResourceBundle::deleteValue(UHashKey value) { + delete (ResourceBundleData *)value.pointer; } -#ifdef ICU_RESBUND_USE_DEPRECATES void ResourceBundle::initItemCache(UErrorCode& error) { if(fItemCache == 0) { fItemCache = uhash_open(uhash_hashChars, uhash_compareChars, &error); diff --git a/icu4c/source/common/uhash.c b/icu4c/source/common/uhash.c index 730f440f616..64a10c21772 100644 --- a/icu4c/source/common/uhash.c +++ b/icu4c/source/common/uhash.c @@ -5,6 +5,8 @@ ****************************************************************************** * Date Name Description * 03/22/00 aliu Adapted from original C++ ICU Hashtable. +* 07/06/01 aliu Modified to support int32_t keys on +* platforms with sizeof(void*) < 32. ****************************************************************************** */ @@ -107,9 +109,10 @@ static const float RESIZE_POLICY_RATIO_TABLE[6] = { #define IS_EMPTY_OR_DELETED(x) ((x) < 0) -#define HASH_DELETE_KEY_VALUE(hash, key, value) \ - if (hash->keyDeleter != NULL && key != NULL) { \ - (*hash->keyDeleter)(key); \ +/* This macro expects a UHashKey.pointer as its keypointer parameter */ +#define HASH_DELETE_KEY_VALUE(hash, keypointer, value) \ + if (hash->keyDeleter != NULL && keypointer != NULL) { \ + (*hash->keyDeleter)(keypointer); \ } \ if (hash->valueDeleter != NULL && value != NULL) { \ (*hash->valueDeleter)(value); \ @@ -151,13 +154,21 @@ static void _uhash_allocate(UHashtable *hash, int32_t primeIndex, static void _uhash_rehash(UHashtable *hash); -static UHashElement* _uhash_find(const UHashtable *hash, const void* key, +static UHashElement* _uhash_find(const UHashtable *hash, UHashKey key, int32_t hashcode); +static void* _uhash_put(UHashtable *hash, + UHashKey key, + void* value, + UErrorCode *status); + +static void* _uhash_remove(UHashtable *hash, + UHashKey key); + static void* _uhash_internalRemoveElement(UHashtable *hash, UHashElement* e); static void* _uhash_setElement(UHashtable* hash, UHashElement* e, - int32_t hashcode, void* key, void* value); + int32_t hashcode, UHashKey key, void* value); static void _uhash_internalSetResizePolicy(UHashtable *hash, enum UHashResizePolicy policy); @@ -194,7 +205,7 @@ uhash_close(UHashtable *hash) { int32_t pos=-1; UHashElement *e; while ((e = (UHashElement*) uhash_nextElement(hash, &pos)) != NULL) { - HASH_DELETE_KEY_VALUE(hash, e->key, e->value); + HASH_DELETE_KEY_VALUE(hash, e->key.pointer, e->value); } } uprv_free(hash->elements); @@ -247,7 +258,17 @@ uhash_count(const UHashtable *hash) { U_CAPI void* uhash_get(const UHashtable *hash, const void* key) { - return _uhash_find(hash, key, hash->keyHasher(key))->value; + UHashKey keyholder; + keyholder.pointer = (void*) key; + return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value; +} + +U_CAPI void* +uhash_geti(const UHashtable *hash, + int32_t key) { + UHashKey keyholder; + keyholder.integer = key; + return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value; } U_CAPI void* @@ -255,85 +276,35 @@ uhash_put(UHashtable *hash, void* key, void* value, UErrorCode *status) { + UHashKey keyholder; + keyholder.pointer = key; + return _uhash_put(hash, keyholder, value, status); +} - /* Put finds the position in the table for the new value. If the - * key is already in the table, it is deleted, if there is a - * non-NULL keyDeleter. Then the key, the hash and the value are - * all put at the position in their respective arrays. - */ - int32_t hashcode; - UHashElement* e; - - if (U_FAILURE(*status)) { - goto err; - } - assert(hash != NULL); - if (value == NULL) { - /* Disallow storage of NULL values, since NULL is returned by - * get() to indicate an absent key. Storing NULL == removing. - */ - return uhash_remove(hash, key); - } - if (hash->count > hash->highWaterMark) { - _uhash_rehash(hash); - } - - hashcode = (*hash->keyHasher)(key); - e = _uhash_find(hash, key, hashcode); - assert(e != NULL); - - if (IS_EMPTY_OR_DELETED(e->hashcode)) { - /* Important: We must never actually fill the table up. If we - * do so, then _uhash_find() will return NULL, and we'll have - * to check for NULL after every call to _uhash_find(). To - * avoid this we make sure there is always at least one empty - * or deleted slot in the table. This only is a problem if we - * are out of memory and rehash isn't working. - */ - ++hash->count; - if (hash->count == hash->length) { - /* Don't allow count to reach length */ - --hash->count; - *status = U_MEMORY_ALLOCATION_ERROR; - goto err; - } - } - - /* We must in all cases handle storage properly. If there was an - * old key, then it must be deleted (if the deleter != NULL). - * Make hashcodes stored in table positive. - */ - return _uhash_setElement(hash, e, hashcode & 0x7FFFFFFF, key, value); - - err: - /* If the deleters are non-NULL, this method adopts its key and/or - * value arguments, and we must be sure to delete the key and/or - * value in all cases, even upon failure. - */ - HASH_DELETE_KEY_VALUE(hash, key, value); - return NULL; +void* +uhash_puti(UHashtable *hash, + int32_t key, + void* value, + UErrorCode *status) { + UHashKey keyholder; + keyholder.integer = key; + return _uhash_put(hash, keyholder, value, status); } U_CAPI void* uhash_remove(UHashtable *hash, const void* key) { - /* First find the position of the key in the table. If the object - * has not been removed already, remove it. If the user wanted - * keys deleted, then delete it also. We have to put a special - * hashcode in that position that means that something has been - * deleted, since when we do a find, we have to continue PAST any - * deleted values. - */ - void* result = NULL; - UHashElement* e = _uhash_find(hash, key, hash->keyHasher(key)); - assert(e != NULL); - if (!IS_EMPTY_OR_DELETED(e->hashcode)) { - result = _uhash_internalRemoveElement(hash, e); - if (hash->count < hash->lowWaterMark) { - _uhash_rehash(hash); - } - } - return result; + UHashKey keyholder; + keyholder.pointer = (void*) key; + return _uhash_remove(hash, keyholder); +} + +U_CAPI void* +uhash_removei(UHashtable *hash, + int32_t key) { + UHashKey keyholder; + keyholder.integer = key; + return _uhash_remove(hash, keyholder); } U_CAPI void @@ -349,6 +320,15 @@ uhash_removeAll(UHashtable *hash) { assert(hash->count == 0); } +U_CAPI const UHashElement* +uhash_find(const UHashtable *hash, const void* key) { + UHashKey keyholder; + const UHashElement *e; + keyholder.pointer = (void*) key; + e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder)); + return IS_EMPTY_OR_DELETED(e->hashcode) ? NULL : e; +} + U_CAPI const UHashElement* uhash_nextElement(const UHashtable *hash, int32_t *pos) { /* Walk through the array until we find an element that is not @@ -390,10 +370,10 @@ uhash_removeElement(UHashtable *hash, const UHashElement* e) { the output range. [LIU] */ -#define STRING_HASH(TYPE, STRLEN, DEREF) \ +#define STRING_HASH(TYPE, STR, STRLEN, DEREF) \ int32_t hash = 0; \ - if (key != NULL) { \ - const TYPE *p = (const TYPE*) key; \ + const TYPE *p = (const TYPE*) STR; \ + if (p != NULL) { \ int32_t len = STRLEN; \ int32_t inc = ((len - 32) / 32) + 1; \ const TYPE *limit = p + len; \ @@ -405,24 +385,24 @@ uhash_removeElement(UHashtable *hash, const UHashElement* e) { return hash U_CAPI int32_t -uhash_hashUChars(const void *key) { - STRING_HASH(UChar, u_strlen(p), *p); +uhash_hashUChars(const UHashKey key) { + STRING_HASH(UChar, key.pointer, u_strlen(p), *p); } /* Used by UnicodeString to compute its hashcode - Not public API. */ U_CAPI int32_t -uhash_hashUCharsN(const UChar *key, int32_t length) { - STRING_HASH(UChar, length, *p); +uhash_hashUCharsN(const UChar *str, int32_t length) { + STRING_HASH(UChar, str, length, *p); } U_CAPI int32_t -uhash_hashChars(const void *key) { - STRING_HASH(uint8_t, uprv_strlen((char*)p), *p); +uhash_hashChars(const UHashKey key) { + STRING_HASH(uint8_t, key.pointer, uprv_strlen((char*)p), *p); } U_CAPI int32_t -uhash_hashIChars(const void *key) { - STRING_HASH(uint8_t, uprv_strlen((char*)p), uprv_tolower(*p)); +uhash_hashIChars(const UHashKey key) { + STRING_HASH(uint8_t, key.pointer, uprv_strlen((char*)p), uprv_tolower(*p)); } /******************************************************************** @@ -430,9 +410,9 @@ uhash_hashIChars(const void *key) { ********************************************************************/ U_CAPI UBool -uhash_compareUChars(const void *key1, const void *key2) { - const UChar *p1 = (const UChar*) key1; - const UChar *p2 = (const UChar*) key2; +uhash_compareUChars(const UHashKey key1, const UHashKey key2) { + const UChar *p1 = (const UChar*) key1.pointer; + const UChar *p2 = (const UChar*) key2.pointer; if (p1 == p2) { return TRUE; } @@ -447,9 +427,9 @@ uhash_compareUChars(const void *key1, const void *key2) { } U_CAPI UBool -uhash_compareChars(const void *key1, const void *key2) { - const char *p1 = (const char*) key1; - const char *p2 = (const char*) key2; +uhash_compareChars(const UHashKey key1, const UHashKey key2) { + const char *p1 = (const char*) key1.pointer; + const char *p2 = (const char*) key2.pointer; if (p1 == p2) { return TRUE; } @@ -464,9 +444,9 @@ uhash_compareChars(const void *key1, const void *key2) { } U_CAPI UBool -uhash_compareIChars(const void *key1, const void *key2) { - const char *p1 = (const char*) key1; - const char *p2 = (const char*) key2; +uhash_compareIChars(const UHashKey key1, const UHashKey key2) { + const char *p1 = (const char*) key1.pointer; + const char *p2 = (const char*) key2.pointer; if (p1 == p2) { return TRUE; } @@ -485,13 +465,13 @@ uhash_compareIChars(const void *key1, const void *key2) { ********************************************************************/ U_CAPI int32_t -uhash_hashLong(const void *key) { - return (int32_t) key; +uhash_hashLong(const UHashKey key) { + return key.integer; } U_CAPI UBool -uhash_compareLong(const void *key1, const void *key2) { - return (UBool)(key1 == key2); +uhash_compareLong(const UHashKey key1, const UHashKey key2) { + return (UBool)(key1.integer == key2.integer); } /******************************************************************** @@ -554,6 +534,7 @@ _uhash_allocate(UHashtable *hash, UErrorCode *status) { UHashElement *p, *limit; + UHashKey emptykey; if (U_FAILURE(*status)) return; @@ -570,9 +551,12 @@ _uhash_allocate(UHashtable *hash, return; } + emptykey.pointer = NULL; /* Only one of these two is needed */ + emptykey.integer = 0; /* but we don't know which one. */ + limit = p + hash->length; while (p < limit) { - p->key = NULL; + p->key = emptykey; p->value = NULL; p->hashcode = HASH_EMPTY; ++p; @@ -665,7 +649,7 @@ _uhash_rehash(UHashtable *hash) { * hash) is relatively prime to the table length. */ static UHashElement* -_uhash_find(const UHashtable *hash, const void* key, +_uhash_find(const UHashtable *hash, UHashKey key, int32_t hashcode) { int32_t firstDeleted = -1; /* assume invalid index */ @@ -717,13 +701,99 @@ _uhash_find(const UHashtable *hash, const void* key, } static void* -_uhash_setElement(UHashtable *hash, UHashElement* e, - int32_t hashcode, void* key, void* value) { +_uhash_put(UHashtable *hash, + UHashKey key, + void* value, + UErrorCode *status) { - void* oldKey = e->key; + /* Put finds the position in the table for the new value. If the + * key is already in the table, it is deleted, if there is a + * non-NULL keyDeleter. Then the key, the hash and the value are + * all put at the position in their respective arrays. + */ + int32_t hashcode; + UHashElement* e; + + if (U_FAILURE(*status)) { + goto err; + } + assert(hash != NULL); + if (value == NULL) { + /* Disallow storage of NULL values, since NULL is returned by + * get() to indicate an absent key. Storing NULL == removing. + */ + return _uhash_remove(hash, key); + } + if (hash->count > hash->highWaterMark) { + _uhash_rehash(hash); + } + + hashcode = (*hash->keyHasher)(key); + e = _uhash_find(hash, key, hashcode); + assert(e != NULL); + + if (IS_EMPTY_OR_DELETED(e->hashcode)) { + /* Important: We must never actually fill the table up. If we + * do so, then _uhash_find() will return NULL, and we'll have + * to check for NULL after every call to _uhash_find(). To + * avoid this we make sure there is always at least one empty + * or deleted slot in the table. This only is a problem if we + * are out of memory and rehash isn't working. + */ + ++hash->count; + if (hash->count == hash->length) { + /* Don't allow count to reach length */ + --hash->count; + *status = U_MEMORY_ALLOCATION_ERROR; + goto err; + } + } + + /* We must in all cases handle storage properly. If there was an + * old key, then it must be deleted (if the deleter != NULL). + * Make hashcodes stored in table positive. + */ + return _uhash_setElement(hash, e, hashcode & 0x7FFFFFFF, key, value); + + err: + /* If the deleters are non-NULL, this method adopts its key and/or + * value arguments, and we must be sure to delete the key and/or + * value in all cases, even upon failure. + */ + HASH_DELETE_KEY_VALUE(hash, key.pointer, value); + return NULL; +} + +static void* +_uhash_remove(UHashtable *hash, + UHashKey key) { + /* First find the position of the key in the table. If the object + * has not been removed already, remove it. If the user wanted + * keys deleted, then delete it also. We have to put a special + * hashcode in that position that means that something has been + * deleted, since when we do a find, we have to continue PAST any + * deleted values. + */ + void* result = NULL; + UHashElement* e = _uhash_find(hash, key, hash->keyHasher(key)); + assert(e != NULL); + if (!IS_EMPTY_OR_DELETED(e->hashcode)) { + result = _uhash_internalRemoveElement(hash, e); + if (hash->count < hash->lowWaterMark) { + _uhash_rehash(hash); + } + } + return result; +} + +static void* +_uhash_setElement(UHashtable *hash, UHashElement* e, + int32_t hashcode, UHashKey key, void* value) { + + void* oldKey = e->key.pointer; void* oldValue = e->value; if (hash->keyDeleter != NULL && oldKey != NULL && - oldKey != key) { /* Avoid double deletion */ + oldKey != key.pointer) { /* Avoid double deletion */ (*hash->keyDeleter)(oldKey); } if (oldValue == value) { /* Avoid double deletion */ @@ -733,6 +803,10 @@ _uhash_setElement(UHashtable *hash, UHashElement* e, (*hash->valueDeleter)(oldValue); oldValue = NULL; } + /* Compilers should copy the UHashKey union correctly. If they do + * not, replace this line with e->key.pointer = key.pointer for + * platforms with sizeof(void*) >= sizeof(int32_t), e->key.integer + * = key.integer otherwise. */ e->key = key; e->value = value; e->hashcode = hashcode; @@ -744,9 +818,11 @@ _uhash_setElement(UHashtable *hash, UHashElement* e, */ static void* _uhash_internalRemoveElement(UHashtable *hash, UHashElement* e) { + UHashKey emptykey; assert(!IS_EMPTY_OR_DELETED(e->hashcode)); --hash->count; - return _uhash_setElement(hash, e, HASH_DELETED, NULL, NULL); + emptykey.pointer = NULL; emptykey.integer = 0; + return _uhash_setElement(hash, e, HASH_DELETED, emptykey, NULL); } static void diff --git a/icu4c/source/common/uhash.h b/icu4c/source/common/uhash.h index de41fe17606..ac634e8a42c 100644 --- a/icu4c/source/common/uhash.h +++ b/icu4c/source/common/uhash.h @@ -5,6 +5,8 @@ ****************************************************************************** * Date Name Description * 03/22/00 aliu Adapted from original C++ ICU Hashtable. +* 07/06/01 aliu Modified to support int32_t keys on +* platforms with sizeof(void*) < 32. ****************************************************************************** */ @@ -73,12 +75,39 @@ U_CDECL_BEGIN +/** + * A key within the hashtable. The key may be either a 32-bit + * integral value or an opaque void* pointer. The void* pointer may + * be smaller than 32 bits (e.g. 24 bits) or may be larger (e.g. 64 + * bits). The hashing and comparison functions take a pointer to a + * UHashKey, but the deleter receives the void* pointer within it. + * + * Because a UHashKey is the size of a native pointer or a 32-bit + * integer, we pass it around by value. + */ +union UHashKey { + void* pointer; + int32_t integer; +}; +typedef union UHashKey UHashKey; + +/** + * This is a single hash element. + */ +struct UHashElement { + /* Reorder these elements to pack nicely if necessary */ + int32_t hashcode; + void* value; + UHashKey key; +}; +typedef struct UHashElement UHashElement; + /** * A hashing function. * @param key A key stored in a hashtable * @return A NON-NEGATIVE hash code for parm. */ -typedef int32_t (* U_CALLCONV UHashFunction)(const void* key); +typedef int32_t (* U_CALLCONV UHashFunction)(const UHashKey key); /** * A key comparison function. @@ -86,8 +115,8 @@ typedef int32_t (* U_CALLCONV UHashFunction)(const void* key); * @param key2 A key stored in a hashtable * @return TRUE if the two keys are equal. */ -typedef UBool (* U_CALLCONV UKeyComparator)(const void* key1, - const void* key2); +typedef UBool (* U_CALLCONV UKeyComparator)(const UHashKey key1, + const UHashKey key2); /** * A function called by uhash_remove, @@ -97,19 +126,6 @@ typedef UBool (* U_CALLCONV UKeyComparator)(const void* key1, */ typedef void (* U_CALLCONV UObjectDeleter)(void* obj); -/** - * This is a single hash element. These should pack nicely - * into exactly 24 bytes. If this is not true, then split - * the elements array into 3 separate arrays for the hash, - * key, and value. - */ -struct UHashElement { - int32_t hashcode; - void* key; - void* value; -}; -typedef struct UHashElement UHashElement; - /** * This specifies whether or not, and how, the hastable resizes itself. * See uhash_setResizePolicy(). @@ -282,26 +298,43 @@ uhash_put(UHashtable *hash, void *value, UErrorCode *status); +/* NEW */ +U_CAPI void* +uhash_puti(UHashtable *hash, + int32_t key, + void* value, + UErrorCode *status); + /** * Get an item from a UHashtable. * @param hash The target UHashtable. - * @param key The hash code of the desired value. + * @param key A key stored in a hashtable * @return The requested item, or 0 if not found. */ U_CAPI void* uhash_get(const UHashtable *hash, const void *key); +/* NEW */ +U_CAPI void* +uhash_geti(const UHashtable *hash, + int32_t key); + /** * Remove an item from a UHashtable. * @param hash The target UHashtable. - * @param key The hash code of the value to be removed. + * @param key A key stored in a hashtable * @return The item removed, or 0 if not found. */ U_CAPI void* uhash_remove(UHashtable *hash, const void *key); +/* NEW */ +U_CAPI void* +uhash_removei(UHashtable *hash, + int32_t key); + /** * Remove all items from a UHashtable. * @param hash The target UHashtable. @@ -309,6 +342,20 @@ uhash_remove(UHashtable *hash, U_CAPI void uhash_removeAll(UHashtable *hash); +/** + * Locate an element of a UHashtable. The caller must not modify the + * returned object. The primary use of this function is to obtain the + * stored key when it may not be identical to the search key. For + * example, if the compare function is a case-insensitive string + * compare, then the hash key may be desired in order to obtain the + * canonical case corresponding to a search key. + * @param hash The target UHashtable. + * @param key A key stored in a hashtable + * @return a hash element, or NULL if the key is not found. + */ +U_CAPI const UHashElement* +uhash_find(const UHashtable *hash, const void* key); + /** * Iterate through the elements of a UHashtable. The caller must not * modify the returned object. However, uhash_removeElement() may be @@ -352,7 +399,7 @@ uhash_removeElement(UHashtable *hash, const UHashElement* e); * @return A hash code for the key. */ U_CAPI int32_t -uhash_hashUChars(const void *key); +uhash_hashUChars(const UHashKey key); /** * Generate a hash code for a null-terminated char* string. If the @@ -362,7 +409,7 @@ uhash_hashUChars(const void *key); * @return A hash code for the key. */ U_CAPI int32_t -uhash_hashChars(const void *key); +uhash_hashChars(const UHashKey key); /* Used by UnicodeString to compute its hashcode - Not public API. */ U_CAPI int32_t @@ -376,28 +423,28 @@ uhash_hashUCharsN(const UChar *key, int32_t length); * @return A hash code for the key. */ U_CAPI int32_t -uhash_hashIChars(const void *key); +uhash_hashIChars(const UHashKey key); /** * Comparator for null-terminated UChar* strings. Use together with * uhash_hashUChars. */ U_CAPI UBool -uhash_compareUChars(const void *key1, const void *key2); +uhash_compareUChars(const UHashKey key1, const UHashKey key2); /** * Comparator for null-terminated char* strings. Use together with * uhash_hashChars. */ U_CAPI UBool -uhash_compareChars(const void *key1, const void *key2); +uhash_compareChars(const UHashKey key1, const UHashKey key2); /** * Case-insensitive comparator for null-terminated char* strings. Use * together with uhash_hashIChars. */ U_CAPI UBool -uhash_compareIChars(const void *key1, const void *key2); +uhash_compareIChars(const UHashKey key1, const UHashKey key2); /******************************************************************** * UnicodeString Support Functions @@ -407,27 +454,27 @@ uhash_compareIChars(const void *key1, const void *key2); * Hash function for UnicodeString* keys. */ U_CAPI int32_t -uhash_hashUnicodeString(const void *key); +uhash_hashUnicodeString(const UHashKey key); /** * Hash function for UnicodeString* keys (case insensitive). * Make sure to use together with uhash_compareCaselessUnicodeString. */ U_CAPI int32_t -uhash_hashCaselessUnicodeString(const void *key); +uhash_hashCaselessUnicodeString(const UHashKey key); /** * Comparator function for UnicodeString* keys. */ U_CAPI UBool -uhash_compareUnicodeString(const void *key1, const void *key2); +uhash_compareUnicodeString(const UHashKey key1, const UHashKey key2); /** * Comparator function for UnicodeString* keys (case insensitive). * Make sure to use together with uhash_hashCaselessUnicodeString. */ U_CAPI UBool -uhash_compareCaselessUnicodeString(const void *key1, const void *key2); +uhash_compareCaselessUnicodeString(const UHashKey key1, const UHashKey key2); /** * Deleter function for UnicodeString* keys or values. @@ -443,13 +490,13 @@ uhash_deleteUnicodeString(void *obj); * Hash function for 32-bit integer keys. */ U_CAPI int32_t -uhash_hashLong(const void *key); +uhash_hashLong(const UHashKey key); /** * Comparator function for 32-bit integer keys. */ U_CAPI UBool -uhash_compareLong(const void *key1, const void *key2); +uhash_compareLong(const UHashKey key1, const UHashKey key2); /******************************************************************** * Other Support Functions diff --git a/icu4c/source/common/uhash_us.cpp b/icu4c/source/common/uhash_us.cpp index d254d7a6b09..033247d0253 100644 --- a/icu4c/source/common/uhash_us.cpp +++ b/icu4c/source/common/uhash_us.cpp @@ -5,6 +5,8 @@ ****************************************************************************** * Date Name Description * 03/22/00 aliu Creation. +* 07/06/01 aliu Modified to support int32_t keys on +* platforms with sizeof(void*) < 32. ****************************************************************************** */ @@ -16,18 +18,20 @@ ********************************************************************/ U_CAPI int32_t -uhash_hashUnicodeString(const void *key) { - return (key == NULL) ? 0 : ((UnicodeString*)key)->hashCode(); +uhash_hashUnicodeString(const UHashKey key) { + const UnicodeString *str = (const UnicodeString*) key.pointer; + return (str == NULL) ? 0 : str->hashCode(); } U_CAPI int32_t -uhash_hashCaselessUnicodeString(const void *key) { - if (key == NULL) { +uhash_hashCaselessUnicodeString(const UHashKey key) { + const UnicodeString *str = (const UnicodeString*) key.pointer; + if (str == NULL) { return 0; } // Inefficient; a better way would be to have a hash function in // UnicodeString that does case folding on the fly. - UnicodeString copy(*(UnicodeString*) key); + UnicodeString copy(*str); return copy.foldCase().hashCode(); } @@ -37,24 +41,27 @@ uhash_deleteUnicodeString(void *obj) { } U_CAPI UBool -uhash_compareUnicodeString(const void *key1, const void *key2) { - if (key1 == key2) { +uhash_compareUnicodeString(const UHashKey key1, const UHashKey key2) { + const UnicodeString *str1 = (const UnicodeString*) key1.pointer; + const UnicodeString *str2 = (const UnicodeString*) key2.pointer; + if (str1 == str2) { return TRUE; } - if (key1 == NULL || key2 == NULL) { + if (str1 == NULL || str2 == NULL) { return FALSE; } - return *((UnicodeString*) key1) == *((UnicodeString*) key2); + return *str1 == *str2; } U_CAPI UBool -uhash_compareCaselessUnicodeString(const void *key1, const void *key2) { - if (key1 == key2) { +uhash_compareCaselessUnicodeString(const UHashKey key1, const UHashKey key2) { + const UnicodeString *str1 = (const UnicodeString*) key1.pointer; + const UnicodeString *str2 = (const UnicodeString*) key2.pointer; + if (str1 == str2) { return TRUE; } - if (key1 == NULL || key2 == NULL) { + if (str1 == NULL || str2 == NULL) { return FALSE; } - return ((UnicodeString*) key1)->caseCompare(*(UnicodeString*)key2, - U_FOLD_CASE_DEFAULT) == 0; + return str1->caseCompare(*str2, U_FOLD_CASE_DEFAULT) == 0; } diff --git a/icu4c/source/common/unicode/resbund.h b/icu4c/source/common/unicode/resbund.h index 882115c43d7..fe3efcbec50 100644 --- a/icu4c/source/common/unicode/resbund.h +++ b/icu4c/source/common/unicode/resbund.h @@ -62,6 +62,7 @@ class ResourceBundle; #ifdef ICU_RESBUND_USE_DEPRECATES struct UHashtable; +union UHashKey; #endif /** @@ -563,10 +564,10 @@ private: UErrorCode& status); private: - static void U_CALLCONV deleteValue(void* value); Locale fRealLocale; #ifdef ICU_RESBUND_USE_DEPRECATES + static void U_CALLCONV deleteValue(UHashKey value); UHashtable* fItemCache; #endif diff --git a/icu4c/source/common/uresbund.c b/icu4c/source/common/uresbund.c index f376dd7b46b..5c08186065f 100644 --- a/icu4c/source/common/uresbund.c +++ b/icu4c/source/common/uresbund.c @@ -37,18 +37,25 @@ static UBool isMutexInited = FALSE; static UMTX resbMutex = NULL; /* INTERNAL: hashes an entry */ -static int32_t hashEntry(const void *parm) { - UResourceDataEntry *b = (UResourceDataEntry *)parm; - return uhash_hashChars(b->fName)+37*uhash_hashChars(b->fPath); +static int32_t hashEntry(const UHashKey parm) { + UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer; + UHashKey namekey, pathkey; + namekey.pointer = b->fName; + pathkey.pointer = b->fPath; + return uhash_hashChars(namekey)+37*uhash_hashChars(pathkey); } /* INTERNAL: compares two entries */ -static UBool compareEntries(const void *p1, const void *p2) { - UResourceDataEntry *b1 = (UResourceDataEntry *)p1; - UResourceDataEntry *b2 = (UResourceDataEntry *)p2; - - return (UBool)(uhash_compareChars(b1->fName, b2->fName) & - uhash_compareChars(b1->fPath, b2->fPath)); +static UBool compareEntries(const UHashKey p1, const UHashKey p2) { + UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer; + UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer; + UHashKey name1, name2, path1, path2; + name1.pointer = b1->fName; + name2.pointer = b2->fName; + path1.pointer = b1->fPath; + path2.pointer = b2->fPath; + return (UBool)(uhash_compareChars(name1, name2) & + uhash_compareChars(path1, path2)); } @@ -177,7 +184,7 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE char aliasName[100] = { 0 }; int32_t aliasLen = 0; UBool isAlias = FALSE; - + UHashKey hashkey; if(U_FAILURE(*status)) { return NULL; @@ -202,7 +209,8 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE find.fPath = (char *)myPath; /* calculate the hash value of the entry */ - hashValue = hashEntry((const void *)&find); + hashkey.pointer = (void *)&find; + hashValue = hashEntry(hashkey); /* check to see if we already have this entry */ r = (UResourceDataEntry *)uhash_get(cache, &find); diff --git a/icu4c/source/i18n/rbt_data.cpp b/icu4c/source/i18n/rbt_data.cpp index 03dce619ffa..626532f7b74 100644 --- a/icu4c/source/i18n/rbt_data.cpp +++ b/icu4c/source/i18n/rbt_data.cpp @@ -40,7 +40,7 @@ TransliterationRuleData::TransliterationRuleData(const TransliterationRuleData& while ((e = other.variableNames->nextElement(pos)) != 0) { UnicodeString* value = new UnicodeString(*(const UnicodeString*)e->value); - variableNames->put(*(UnicodeString*)e->key, value, status); + variableNames->put(*(UnicodeString*)e->key.pointer, value, status); } } diff --git a/icu4c/source/i18n/sortkey.cpp b/icu4c/source/i18n/sortkey.cpp index 43849102a84..1514c5df7b0 100644 --- a/icu4c/source/i18n/sortkey.cpp +++ b/icu4c/source/i18n/sortkey.cpp @@ -305,7 +305,9 @@ CollationKey::hashCode() const if (fHashCode == kInvalidHashCode) { - ((CollationKey *)this)->fHashCode = uhash_hashChars(fBytes); + UHashKey key; + key.pointer = fBytes; + ((CollationKey *)this)->fHashCode = uhash_hashChars(key); #if 0 // We compute the hash by iterating sparsely over 64 (at most) characters // spaced evenly through the string. For each character, we multiply the diff --git a/icu4c/source/i18n/translit.cpp b/icu4c/source/i18n/translit.cpp index cd65fcc8a54..f961e5e349a 100644 --- a/icu4c/source/i18n/translit.cpp +++ b/icu4c/source/i18n/translit.cpp @@ -907,6 +907,18 @@ UChar Transliterator::filteredCharAt(const Replaceable& text, int32_t i) const { (localFilter->contains(c = text.charAt(i)) ? c : (UChar)0xFFFE); } +// TODO Move this into the class +/** + * Comparison function for UVector. + */ +static UBool +_compareCaselessUnicodeString(const void* a, const void* b) { + UHashKey s, t; + s.pointer = (void*) a; + t.pointer = (void*) b; + return uhash_compareCaselessUnicodeString(s, t); +} + void Transliterator::initializeCache(void) { // Lock first, check init boolean second Mutex lock(&cacheMutex); @@ -920,7 +932,7 @@ void Transliterator::initializeCache(void) { // That way if the resource is absent, we will at least // have a valid cache object. cacheIDs.setDeleter(uhash_deleteUnicodeString); - cacheIDs.setComparer(uhash_compareCaselessUnicodeString); + cacheIDs.setComparer(_compareCaselessUnicodeString); /* The following code parses the index table located in * icu/data/translit_index.txt. The index is an n x 4 table diff --git a/icu4c/source/i18n/ucol_sol.c b/icu4c/source/i18n/ucol_sol.c index 7bf7db75d95..261b90588bc 100644 --- a/icu4c/source/i18n/ucol_sol.c +++ b/icu4c/source/i18n/ucol_sol.c @@ -24,10 +24,10 @@ const UChar *rulesToParse = 0; int32_t -uhash_hashTokens(const void *k) { +uhash_hashTokens(const UHashKey k) { int32_t hash = 0; - if (k != NULL) { - uint32_t key = (uint32_t)k; + uint32_t key = (uint32_t)k.integer; + if (key != 0) { int32_t len = (key & 0xFF000000)>>24; int32_t inc = ((len - 32) / 32) + 1; @@ -42,9 +42,9 @@ uhash_hashTokens(const void *k) { return hash; } -UBool uhash_compareTokens(const void *key1, const void *key2) { - uint32_t p1 = (uint32_t) key1; - uint32_t p2 = (uint32_t) key2; +UBool uhash_compareTokens(const UHashKey key1, const UHashKey key2) { + uint32_t p1 = (uint32_t) key1.integer; + uint32_t p2 = (uint32_t) key2.integer; const UChar *s1 = (p1 & 0x00FFFFFF) + rulesToParse; const UChar *s2 = (p2 & 0x00FFFFFF) + rulesToParse; uint32_t s1L = ((p1 & 0xFF000000) >> 24); diff --git a/icu4c/source/i18n/ucol_sol.h b/icu4c/source/i18n/ucol_sol.h index ba72118448d..bb61a098b24 100644 --- a/icu4c/source/i18n/ucol_sol.h +++ b/icu4c/source/i18n/ucol_sol.h @@ -21,9 +21,10 @@ #define UCOL_SOL_H #include "unicode/utypes.h" +#include "uhash.h" -U_CFUNC int32_t uhash_hashTokens(const void *k); -U_CFUNC UBool uhash_compareTokens(const void *key1, const void *key2); +U_CFUNC int32_t uhash_hashTokens(const UHashKey k); +U_CFUNC UBool uhash_compareTokens(const UHashKey key1, const UHashKey key2); U_CFUNC void deleteToken(void *token); #endif diff --git a/icu4c/source/i18n/ucol_tok.cpp b/icu4c/source/i18n/ucol_tok.cpp index 02778982264..c0f2a34b088 100644 --- a/icu4c/source/i18n/ucol_tok.cpp +++ b/icu4c/source/i18n/ucol_tok.cpp @@ -650,7 +650,7 @@ uint32_t ucol_tok_assembleTokenList(UColTokenParser *src, UErrorCode *status) { key = newCharsLen << 24 | charsOffset; /* 4 Lookup each source in the CharsToToken map, and find a sourceToken */ - sourceToken = (UColToken *)uhash_get(uchars2tokens, (void *)key); + sourceToken = (UColToken *)uhash_geti(uchars2tokens, (int32_t)key); if(newStrength != UCOL_TOK_RESET) { if(lastToken == NULL) { /* this means that rules haven't started properly */ @@ -670,7 +670,7 @@ uint32_t ucol_tok_assembleTokenList(UColTokenParser *src, UErrorCode *status) { sourceToken->previous = NULL; sourceToken->noOfCEs = 0; sourceToken->noOfExpCEs = 0; - uhash_put(uchars2tokens, (void *)sourceToken->source, sourceToken, status); + uhash_puti(uchars2tokens, (int32_t)sourceToken->source, sourceToken, status); } else { /* we could have fished out a reset here */ if(sourceToken->strength != UCOL_TOK_RESET && lastToken != sourceToken) { @@ -808,7 +808,7 @@ uint32_t ucol_tok_assembleTokenList(UColTokenParser *src, UErrorCode *status) { while(searchCharsLen > 1 && sourceToken == NULL) { searchCharsLen--; key = searchCharsLen << 24 | charsOffset; - sourceToken = (UColToken *)uhash_get(uchars2tokens, (void *)key); + sourceToken = (UColToken *)uhash_geti(uchars2tokens, (int32_t)key); } if(sourceToken != NULL) { expandNext = (newCharsLen - searchCharsLen) << 24 | (charsOffset + searchCharsLen); @@ -920,7 +920,7 @@ uint32_t ucol_tok_assembleTokenList(UColTokenParser *src, UErrorCode *status) { ListList[src->resultLen].reset = sourceToken; src->resultLen++; - uhash_put(uchars2tokens, (void *)sourceToken->source, sourceToken, status); + uhash_puti(uchars2tokens, (int32_t)sourceToken->source, sourceToken, status); } else { /* reset to something already in rules */ top = FALSE; } diff --git a/icu4c/source/test/cintltst/chashtst.c b/icu4c/source/test/cintltst/chashtst.c index 852013f7ceb..1ff9f07aced 100644 --- a/icu4c/source/test/cintltst/chashtst.c +++ b/icu4c/source/test/cintltst/chashtst.c @@ -22,9 +22,9 @@ static void TestBasic(void); static void TestOtherAPI(void); -static int32_t hashChars(const void* key); +static int32_t hashChars(const UHashKey key); -static UBool isEqualChars(const void* key1, const void* key2); +static UBool isEqualChars(const UHashKey key1, const UHashKey key2); static void _put(UHashtable* hash, const char* key, @@ -41,6 +41,42 @@ static void _remove(UHashtable* hash, void addHashtableTest(TestNode** root); +/********************************************************************** + * UHashKey wrapper functions + *********************************************************************/ + +static UBool +_compareChars(void* a, void* b) { + UHashKey s, t; + s.pointer = a; + t.pointer = b; + return uhash_compareChars(s, t); +} + +static UBool +_compareIChars(void* a, void* b) { + UHashKey s, t; + s.pointer = a; + t.pointer = b; + return uhash_compareIChars(s, t); +} + +static UBool +_compareUChars(void* a, void* b) { + UHashKey s, t; + s.pointer = a; + t.pointer = b; + return uhash_compareUChars(s, t); +} + +static UBool +_compareLong(int32_t a, int32_t b) { + UHashKey s, t; + s.integer = a; + t.integer = b; + return uhash_compareLong(s, t); +} + /********************************************************************** * FW Registration *********************************************************************/ @@ -93,16 +129,16 @@ static void TestBasic(void) { _get(hash, omega, 48); _get(hash, two, 200); - if(uhash_compareChars((void*)one, (void*)three) == TRUE || - uhash_compareChars((void*)one, (void*)one2) != TRUE || - uhash_compareChars((void*)one, (void*)one) != TRUE || - uhash_compareChars((void*)one, NULL) == TRUE ) { + if(_compareChars((void*)one, (void*)three) == TRUE || + _compareChars((void*)one, (void*)one2) != TRUE || + _compareChars((void*)one, (void*)one) != TRUE || + _compareChars((void*)one, NULL) == TRUE ) { log_err("FAIL: compareChars failed\n"); } - if(uhash_compareIChars((void*)one, (void*)three) == TRUE || - uhash_compareIChars((void*)one, (void*)one) != TRUE || - uhash_compareIChars((void*)one, (void*)one2) != TRUE || - uhash_compareIChars((void*)one, NULL) == TRUE ) { + if(_compareIChars((void*)one, (void*)three) == TRUE || + _compareIChars((void*)one, (void*)one) != TRUE || + _compareIChars((void*)one, (void*)one2) != TRUE || + _compareIChars((void*)one, NULL) == TRUE ) { log_err("FAIL: compareIChars failed\n"); } @@ -177,10 +213,10 @@ static void TestOtherAPI(void){ log_err("FAIL: uhash_put() with value!=NULL didn't replace the key value pair\n"); } - if(uhash_compareUChars((void*)one, (void*)two) == TRUE || - uhash_compareUChars((void*)one, (void*)one) != TRUE || - uhash_compareUChars((void*)one, (void*)one2) != TRUE || - uhash_compareUChars((void*)one, NULL) == TRUE ) { + if(_compareUChars((void*)one, (void*)two) == TRUE || + _compareUChars((void*)one, (void*)one) != TRUE || + _compareUChars((void*)one, (void*)one2) != TRUE || + _compareUChars((void*)one, NULL) == TRUE ) { log_err("FAIL: compareUChars failed\n"); } @@ -191,27 +227,27 @@ static void TestOtherAPI(void){ uhash_setKeyComparator(hash, uhash_compareLong); uhash_setKeyHasher(hash, uhash_hashLong); - uhash_put(hash, (void*)1001, (void*)1, &status); - uhash_put(hash, (void*)1002, (void*)2, &status); - uhash_put(hash, (void*)1003, (void*)3, &status); - if(uhash_compareLong((void*)1001, (void*)1002) == TRUE || - uhash_compareLong((void*)1001, (void*)1001) != TRUE || - uhash_compareLong((void*)1001, NULL) == TRUE ) { + uhash_puti(hash, 1001, (void*)1, &status); + uhash_puti(hash, 1002, (void*)2, &status); + uhash_puti(hash, 1003, (void*)3, &status); + if(_compareLong(1001, 1002) == TRUE || + _compareLong(1001, 1001) != TRUE || + _compareLong(1001, 0) == TRUE ) { log_err("FAIL: compareLong failed\n"); } /*set the resize policy to just GROW and SHRINK*/ /*how to test this??*/ uhash_setResizePolicy(hash, U_GROW_AND_SHRINK); - uhash_put(hash, (void*)1004, (void*)4, &status); - uhash_put(hash, (void*)1005, (void*)5, &status); - uhash_put(hash, (void*)1006, (void*)6, &status); + uhash_puti(hash, 1004, (void*)4, &status); + uhash_puti(hash, 1005, (void*)5, &status); + uhash_puti(hash, 1006, (void*)6, &status); if(uhash_count(hash) != 6){ log_err("FAIL: uhash_count() failed. Expected: 6, Got: %d\n", uhash_count(hash)); } - if((int32_t)uhash_remove(hash, (void*)1004) != 4){ + if((int32_t)uhash_removei(hash, 1004) != 4){ log_err("FAIL: uhash_remove failed\n"); } - if((int32_t)uhash_remove(hash, (void*)1004) != 0){ + if((int32_t)uhash_removei(hash, 1004) != 0){ log_err("FAIL: uhash_remove failed\n"); } uhash_close(hash); @@ -225,14 +261,14 @@ static void TestOtherAPI(void){ * This hash function is designed to collide a lot to test key equality * resolution. It only uses the first char. */ -static int32_t hashChars(const void* key) { - return *(const char*) key; +static int32_t hashChars(const UHashKey key) { + return *(const char*) key.pointer; } -static UBool isEqualChars(const void* key1, const void* key2) { - return (UBool)((key1 != NULL) && - (key2 != NULL) && - (uprv_strcmp((const char*)key1, (const char*)key2) == 0)); +static UBool isEqualChars(const UHashKey key1, const UHashKey key2) { + return (UBool)((key1.pointer != NULL) && + (key2.pointer != NULL) && + (uprv_strcmp((const char*)key1.pointer, (const char*)key2.pointer) == 0)); } /********************************************************************** diff --git a/icu4c/source/test/intltest/sfwdchit.cpp b/icu4c/source/test/intltest/sfwdchit.cpp index c78eeabf9f0..2cf9f3a51f6 100644 --- a/icu4c/source/test/intltest/sfwdchit.cpp +++ b/icu4c/source/test/intltest/sfwdchit.cpp @@ -88,7 +88,9 @@ UBool SimpleFwdCharIterator::operator==(const ForwardCharacterIterator& that) co int32_t SimpleFwdCharIterator::hashCode(void) const { if (fHashCode == kInvalidHashCode) { - ((SimpleFwdCharIterator *)this)->fHashCode = uhash_hashUChars(fStart); + UHashKey key; + key.pointer = fStart; + ((SimpleFwdCharIterator *)this)->fHashCode = uhash_hashUChars(key); } return fHashCode; }