diff options
author | neal <neal> | 2008-02-08 10:01:41 +0000 |
---|---|---|
committer | neal <neal> | 2008-02-08 10:01:41 +0000 |
commit | f0271bdf0b422685f1ac0fbc378192b407e75efa (patch) | |
tree | b2ac8b52346e5b49528954d5a8191af8f18eac4b /libhurd-ihash | |
parent | 5669f84c020ae2c4f1c2b648aca643c114f69012 (diff) |
libhurd-ihash/
2008-02-08 Neal H. Walfield <neal@gnu.org>
* ihash.h: Include <bits/wordsize.h>.
(hurd_ihash_key64_t): New definition.
(struct _hurd_ihash_item64): New structure.
(struct hurd_ihash): Change items's type void *.
[__WORDSIZE == 32]: Add field large.
(_HURD_IHASH_LARGE): New macro.
(HURD_IHASH_INITIALIZER): Take additional argument large. Use it.
(hurd_ihash_init): Take additional argument large.
(hurd_ihash_buffer_size): Likewise.
(hurd_ihash_init_with_buffer): Likewise.
(hurd_ihash_create): Likewise.
(hurd_ihash_replace): Change key's type to hurd_ihash_key64_t.
(hurd_ihash_add): Likewise.
(hurd_ihash_find): Likewise.
(hurd_ihash_remove): Likewise.
(HURD_IHASH_ITERATE): Rewrite to properly handle both 32- and
64-bit keys.
* ihash.c (ITEM): New macro.
(VALUE): Likewise.
(KEY): Likewise.
(ITEM_SIZE): Likewise.
(index_empty): Use the above macros rather than accessing
HT->ITEMS directly.
(index_valid): Likewise and change key's type to a
hurd_ihash_key64_t.
(find_index): Likewise.
(replace_one): Likewise.
(hurd_ihash_replace): Likewise.
(hurd_ihash_find): Likewise.
(hurd_ihash_remove): Likewise.
(hurd_ihash_init_internal): Take additional argument large. Use
it.
(hurd_ihash_init): Likewise.
(hurd_ihash_init_with_buffer): Likewise.
(hurd_ihash_create): Likewise.
(hurd_ihash_buffer_size): Likewise.
* t-ihash.c: Include <assert.h>.
(main): Expect that TEST_LARGE is defined. Use it when calling
hurd_ihash_init. If true, add some tests with 64-bit keys.
* Makefile.am (TESTS): Add t-ihash64.
(check_PROGRAMS): Likewise.
(t_ihash_CPPFLAGS): Add -DTEST_LARGE=false.
(t_ihash64_SOURCES): New variable.
(t_ihash64_CPPFLAGS): Likewise.
viengoos/
2008-02-08 Neal H. Walfield <neal@gnu.org>
* thread.c (thread_init): Update use of
hurd_ihash_init_with_buffer to be consistent with new API.
* object.c (object_init): Likewise.
libpthread/
2008-02-08 Neal H. Walfield <neal@gnu.org>
* sysdeps/hurd/pt-setspecific.c (pthread_setspecific): Update use
of hurd_ihash_create to be consistent with API changes.
Diffstat (limited to 'libhurd-ihash')
-rw-r--r-- | libhurd-ihash/ChangeLog | 47 | ||||
-rw-r--r-- | libhurd-ihash/Makefile.am | 9 | ||||
-rw-r--r-- | libhurd-ihash/ihash.c | 130 | ||||
-rw-r--r-- | libhurd-ihash/ihash.h | 121 | ||||
-rw-r--r-- | libhurd-ihash/t-ihash.c | 30 |
5 files changed, 251 insertions, 86 deletions
diff --git a/libhurd-ihash/ChangeLog b/libhurd-ihash/ChangeLog index ec148f1..33ce1b8 100644 --- a/libhurd-ihash/ChangeLog +++ b/libhurd-ihash/ChangeLog @@ -1,3 +1,50 @@ +2008-02-08 Neal H. Walfield <neal@gnu.org> + + * ihash.h: Include <bits/wordsize.h>. + (hurd_ihash_key64_t): New definition. + (struct _hurd_ihash_item64): New structure. + (struct hurd_ihash): Change items's type void *. + [__WORDSIZE == 32]: Add field large. + (_HURD_IHASH_LARGE): New macro. + (HURD_IHASH_INITIALIZER): Take additional argument large. Use it. + (hurd_ihash_init): Take additional argument large. + (hurd_ihash_buffer_size): Likewise. + (hurd_ihash_init_with_buffer): Likewise. + (hurd_ihash_create): Likewise. + (hurd_ihash_replace): Change key's type to hurd_ihash_key64_t. + (hurd_ihash_add): Likewise. + (hurd_ihash_find): Likewise. + (hurd_ihash_remove): Likewise. + (HURD_IHASH_ITERATE): Rewrite to properly handle both 32- and + 64-bit keys. + * ihash.c (ITEM): New macro. + (VALUE): Likewise. + (KEY): Likewise. + (ITEM_SIZE): Likewise. + (index_empty): Use the above macros rather than accessing + HT->ITEMS directly. + (index_valid): Likewise and change key's type to a + hurd_ihash_key64_t. + (find_index): Likewise. + (replace_one): Likewise. + (hurd_ihash_replace): Likewise. + (hurd_ihash_find): Likewise. + (hurd_ihash_remove): Likewise. + (hurd_ihash_init_internal): Take additional argument large. Use + it. + (hurd_ihash_init): Likewise. + (hurd_ihash_init_with_buffer): Likewise. + (hurd_ihash_create): Likewise. + (hurd_ihash_buffer_size): Likewise. + * t-ihash.c: Include <assert.h>. + (main): Expect that TEST_LARGE is defined. Use it when calling + hurd_ihash_init. If true, add some tests with 64-bit keys. + * Makefile.am (TESTS): Add t-ihash64. + (check_PROGRAMS): Likewise. + (t_ihash_CPPFLAGS): Add -DTEST_LARGE=false. + (t_ihash64_SOURCES): New variable. + (t_ihash64_CPPFLAGS): Likewise. + 2008-01-24 Neal H. Walfield <neal@gnu.org> * Makefile.am (t_ihash_SOURCES): Add ihash.c. diff --git a/libhurd-ihash/Makefile.am b/libhurd-ihash/Makefile.am index d7a3913..72a0e56 100644 --- a/libhurd-ihash/Makefile.am +++ b/libhurd-ihash/Makefile.am @@ -35,8 +35,11 @@ libhurd_ihash_a_SOURCES = ihash.h ihash.c libhurd_ihash_nomalloc_a_CPPFLAGS = $(AM_CPPFLAGS) -DNO_MALLOC libhurd_ihash_nomalloc_a_SOURCES = ihash.h ihash.c -TESTS = t-ihash +TESTS = t-ihash t-ihash64 +check_PROGRAMS = t-ihash t-ihash64 -check_PROGRAMS = t-ihash t_ihash_SOURCES = t-ihash.c ihash.h ihash.c -t_ihash_CPPFLAGS = -DS_PRINTF=printf $(AM_CPPFLAGS) +t_ihash_CPPFLAGS = -DTEST_LARGE=false -DS_PRINTF=printf $(AM_CPPFLAGS) + +t_ihash64_SOURCES = t-ihash.c ihash.h ihash.c +t_ihash64_CPPFLAGS = -DTEST_LARGE=true -DS_PRINTF=printf $(AM_CPPFLAGS) diff --git a/libhurd-ihash/ihash.c b/libhurd-ihash/ihash.c index b16632b..4ba9aaf 100644 --- a/libhurd-ihash/ihash.c +++ b/libhurd-ihash/ihash.c @@ -82,22 +82,42 @@ static const unsigned int ihash_nsizes = (sizeof ihash_sizes / sizeof ihash_sizes[0]); +#define ITEM(ht, idx) \ + (_HURD_IHASH_LARGE (ht) \ + ? (void *) &((_hurd_ihash_item64_t) (ht)->items)[idx] \ + : (void *) &((_hurd_ihash_item_t) (ht)->items)[idx]) + +#define VALUE(ht, idx) \ + (_HURD_IHASH_LARGE (ht) \ + ? ((_hurd_ihash_item64_t) ITEM (ht, idx))->value \ + : ((_hurd_ihash_item_t) ITEM (ht, idx))->value) + +#define KEY(ht, idx) \ + (_HURD_IHASH_LARGE (ht) \ + ? ((_hurd_ihash_item64_t) ITEM (ht, idx))->key \ + : ((_hurd_ihash_item_t) ITEM (ht, idx))->key) + +#define ITEM_SIZE(large) \ + ((large) \ + ? sizeof (struct _hurd_ihash_item64) \ + : sizeof (struct _hurd_ihash_item)) + /* Return 1 if the slot with the index IDX in the hash table HT is empty, and 0 otherwise. */ static inline int index_empty (hurd_ihash_t ht, unsigned int idx) { - return ht->items[idx].value == _HURD_IHASH_EMPTY - || ht->items[idx].value == _HURD_IHASH_DELETED; + return VALUE (ht, idx) == _HURD_IHASH_EMPTY + || VALUE (ht, idx) == _HURD_IHASH_DELETED; } /* Return 1 if the index IDX in the hash table HT is occupied by the element with the key KEY. */ static inline int -index_valid (hurd_ihash_t ht, unsigned int idx, hurd_ihash_key_t key) +index_valid (hurd_ihash_t ht, unsigned int idx, hurd_ihash_key64_t key) { - return !index_empty (ht, idx) && ht->items[idx].key == key; + return !index_empty (ht, idx) && KEY (ht, idx) == key; } @@ -105,7 +125,7 @@ index_valid (hurd_ihash_t ht, unsigned int idx, hurd_ihash_key_t key) of that key. You must subsequently check with index_valid() if the returned index is valid. */ static inline int -find_index (hurd_ihash_t ht, hurd_ihash_key_t key) +find_index (hurd_ihash_t ht, hurd_ihash_key64_t key) { unsigned int idx; unsigned int i; @@ -114,7 +134,7 @@ find_index (hurd_ihash_t ht, hurd_ihash_key_t key) idx = key % ht->size; - if (ht->items[idx].value == _HURD_IHASH_EMPTY || ht->items[idx].key == key) + if (VALUE (ht, idx) == _HURD_IHASH_EMPTY || KEY (ht, idx) == key) return idx; /* Instead of calculating idx + 1, idx + 4, idx + 9, ..., idx + i^2, @@ -127,15 +147,15 @@ find_index (hurd_ihash_t ht, hurd_ihash_key_t key) do { up_idx = (up_idx + i) % ht->size; - if (ht->items[up_idx].value == _HURD_IHASH_EMPTY - || ht->items[up_idx].key == key) + if (VALUE (ht, up_idx) == _HURD_IHASH_EMPTY + || KEY (ht, up_idx) == key) return up_idx; if (down_idx < i) down_idx += ht->size; down_idx = (down_idx - i) % ht->size; - if (ht->items[down_idx].value == _HURD_IHASH_EMPTY - || ht->items[down_idx].key == key) + if (VALUE (ht, down_idx) == _HURD_IHASH_EMPTY + || KEY (ht, down_idx) == key) return down_idx; /* After (ht->size - 1) / 2 iterations, this will be 0. */ @@ -167,8 +187,11 @@ locp_remove (hurd_ihash_t ht, hurd_ihash_locp_t locp, bool cleanup) /* Initialize the hash table at address HT. */ static void -hurd_ihash_init_internal (hurd_ihash_t ht, intptr_t locp_offs) +hurd_ihash_init_internal (hurd_ihash_t ht, bool large, intptr_t locp_offs) { +#if __WORDSIZE == 32 + ht->large = large; +#endif ht->nr_items = 0; ht->size = 0; ht->locp_offset = locp_offs; @@ -178,19 +201,20 @@ hurd_ihash_init_internal (hurd_ihash_t ht, intptr_t locp_offs) #ifndef NO_MALLOC void -hurd_ihash_init (hurd_ihash_t ht, intptr_t locp_offs) +hurd_ihash_init (hurd_ihash_t ht, bool large, intptr_t locp_offs) { - hurd_ihash_init_internal (ht, locp_offs); + hurd_ihash_init_internal (ht, large, locp_offs); } #endif void -hurd_ihash_init_with_buffer (hurd_ihash_t ht, intptr_t locp_offs, +hurd_ihash_init_with_buffer (hurd_ihash_t ht, bool large, + intptr_t locp_offs, void *buffer, size_t size) { - hurd_ihash_init_internal (ht, locp_offs); + hurd_ihash_init_internal (ht, large, locp_offs); ht->items = buffer; - ht->size = size / sizeof (struct _hurd_ihash_item); + ht->size = size / ITEM_SIZE (_HURD_IHASH_LARGE (ht)); } @@ -220,13 +244,13 @@ hurd_ihash_destroy (hurd_ihash_t ht) memory allocation error occurs, ENOMEM is returned, otherwise 0. */ #ifndef NO_MALLOC error_t -hurd_ihash_create (hurd_ihash_t *ht, intptr_t locp_offs) +hurd_ihash_create (hurd_ihash_t *ht, bool large, intptr_t locp_offs) { *ht = malloc (sizeof (struct hurd_ihash)); if (*ht == NULL) return ENOMEM; - hurd_ihash_init (*ht, locp_offs); + hurd_ihash_init (*ht, large, locp_offs); return 0; } @@ -284,7 +308,7 @@ hurd_ihash_set_max_load (hurd_ihash_t ht, unsigned int max_load) division method with quadratic probe. This is guaranteed to try all slots in the hash table if the prime number is 3 mod 4. */ static inline int -replace_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value, +replace_one (hurd_ihash_t ht, hurd_ihash_key64_t key, hurd_ihash_value_t value, bool *had_value, hurd_ihash_value_t *old_value) { unsigned int idx; @@ -293,7 +317,7 @@ replace_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value, idx = key % ht->size; first_free = idx; - if (ht->items[idx].value != _HURD_IHASH_EMPTY && ht->items[idx].key != key) + if (VALUE (ht, idx) != _HURD_IHASH_EMPTY && KEY (ht, idx) != key) { /* Instead of calculating idx + 1, idx + 4, idx + 9, ..., idx + i^2, we add 1, 3, 5, 7, ... 2 * i - 1 to the previous index. @@ -305,14 +329,14 @@ replace_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value, do { up_idx = (up_idx + i) % ht->size; - if (ht->items[up_idx].value == _HURD_IHASH_EMPTY - || ht->items[up_idx].key == key) + if (VALUE (ht, up_idx) == _HURD_IHASH_EMPTY + || KEY (ht, up_idx) == key) { idx = up_idx; break; } if (first_free == idx - && ht->items[up_idx].value == _HURD_IHASH_DELETED) + && VALUE (ht, up_idx) == _HURD_IHASH_DELETED) first_free = up_idx; if (down_idx < i) @@ -322,14 +346,14 @@ replace_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value, down_idx += ht->size; else down_idx %= ht->size; - if (ht->items[down_idx].value == _HURD_IHASH_EMPTY - || ht->items[down_idx].key == key) + if (VALUE (ht, down_idx) == _HURD_IHASH_EMPTY + || KEY (ht, down_idx) == key) { idx = down_idx; break; } if (first_free == idx - && ht->items[down_idx].value == _HURD_IHASH_DELETED) + && VALUE (ht, down_idx) == _HURD_IHASH_DELETED) first_free = down_idx; /* After (ht->size - 1) / 2 iterations, this will be 0. */ @@ -345,8 +369,8 @@ replace_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value, *had_value = true; if (old_value) - *old_value = ht->items[idx].value; - locp_remove (ht, &ht->items[idx].value, !! old_value); + *old_value = VALUE (ht, idx); + locp_remove (ht, ITEM (ht, idx), !! old_value); } else { @@ -362,12 +386,27 @@ replace_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value, if (index_empty (ht, first_free)) { ht->nr_items++; - ht->items[first_free].value = value; - ht->items[first_free].key = key; - if (ht->locp_offset != HURD_IHASH_NO_LOCP) - *((hurd_ihash_locp_t) (((char *) value) + ht->locp_offset)) - = &ht->items[first_free].value; + if (_HURD_IHASH_LARGE (ht)) + { + _hurd_ihash_item64_t i = ITEM (ht, first_free); + i->value = value; + i->key = key; + + if (ht->locp_offset != HURD_IHASH_NO_LOCP) + *((hurd_ihash_locp_t) (((char *) value) + ht->locp_offset)) + = &i->value; + } + else + { + _hurd_ihash_item_t i = ITEM (ht, first_free); + i->value = value; + i->key = key; + + if (ht->locp_offset != HURD_IHASH_NO_LOCP) + *((hurd_ihash_locp_t) (((char *) value) + ht->locp_offset)) + = &i->value; + } return 1; } @@ -380,7 +419,7 @@ replace_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value, (LOAD_FACTOR must be between 1 and 100, a load factor of 0 implies the default load factor). */ size_t -hurd_ihash_buffer_size (size_t count, int max_load_factor) +hurd_ihash_buffer_size (size_t count, bool large, int max_load_factor) { if (max_load_factor == 0) max_load_factor = HURD_IHASH_MAX_LOAD_DEFAULT; @@ -398,7 +437,7 @@ hurd_ihash_buffer_size (size_t count, int max_load_factor) if (i == ihash_nsizes) return SIZE_MAX; /* Surely will be true momentarily. */ - return ihash_sizes[i] * sizeof (struct _hurd_ihash_item); + return ihash_sizes[i] * ITEM_SIZE (large); } /* Add ITEM to the hash table HT under the key KEY. If there already @@ -410,7 +449,7 @@ hurd_ihash_buffer_size (size_t count, int max_load_factor) *HAD_VALUE. If a memory allocation error occurs, ENOMEM is returned, otherwise 0. */ error_t -hurd_ihash_replace (hurd_ihash_t ht, hurd_ihash_key_t key, +hurd_ihash_replace (hurd_ihash_t ht, hurd_ihash_key64_t key, hurd_ihash_value_t item, bool *had_value, hurd_ihash_value_t *old_value) { @@ -432,14 +471,16 @@ hurd_ihash_replace (hurd_ihash_t ht, hurd_ihash_key_t key, int i; /* The hash table is too small, and we have to increase it. */ - size_t size = hurd_ihash_buffer_size (old_ht.size + 1, ht->max_load); + size_t size = hurd_ihash_buffer_size (old_ht.size + 1, + _HURD_IHASH_LARGE (ht), + ht->max_load); if (size >= SIZE_MAX) return ENOMEM; /* Surely will be true momentarily. */ ht->nr_items = 0; - ht->size = size / sizeof (struct _hurd_ihash_item); + ht->size = size / ITEM_SIZE (_HURD_IHASH_LARGE (ht)); /* calloc() will initialize all values to _HURD_IHASH_EMPTY implicitely. */ - ht->items = calloc (ht->size, sizeof (struct _hurd_ihash_item)); + ht->items = calloc (ht->size, ITEM_SIZE (_HURD_IHASH_LARGE (ht))); if (ht->items == NULL) { @@ -454,8 +495,7 @@ hurd_ihash_replace (hurd_ihash_t ht, hurd_ihash_key_t key, for (i = 0; i < old_ht.size; i++) if (!index_empty (&old_ht, i)) { - was_added = replace_one (ht, old_ht.items[i].key, - old_ht.items[i].value, + was_added = replace_one (ht, KEY (&old_ht, i), VALUE (&old_ht, i), had_value, old_value); assert (was_added); } @@ -475,14 +515,14 @@ hurd_ihash_replace (hurd_ihash_t ht, hurd_ihash_key_t key, /* Find and return the item in the hash table HT with key KEY, or NULL if it doesn't exist. */ hurd_ihash_value_t -hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key_t key) +hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key64_t key) { if (ht->size == 0) return NULL; else { int idx = find_index (ht, key); - return index_valid (ht, idx, key) ? ht->items[idx].value : NULL; + return index_valid (ht, idx, key) ? VALUE (ht, idx) : NULL; } } @@ -490,7 +530,7 @@ hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key_t key) /* Remove the entry with the key KEY from the hash table HT. If such an entry was found and removed, 1 is returned, otherwise 0. */ int -hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key_t key) +hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key64_t key) { if (ht->size != 0) { @@ -498,7 +538,7 @@ hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key_t key) if (index_valid (ht, idx, key)) { - locp_remove (ht, &ht->items[idx].value, true); + locp_remove (ht, ITEM (ht, idx), true); return 1; } } diff --git a/libhurd-ihash/ihash.h b/libhurd-ihash/ihash.h index c2332de..95e022c 100644 --- a/libhurd-ihash/ihash.h +++ b/libhurd-ihash/ihash.h @@ -27,6 +27,17 @@ #include <limits.h> #include <stdint.h> #include <stdbool.h> +/* If your system does not provide __WORDSIZE, you can also try + deriving it via <stdint.h>: + + #if UINT64_MAX == UINTPTR_MAX + # define __WORDSIZE 64 + #else + # define __WORDSIZE 32 + #endif + + Depending on how the constants are derived this might not work. */ +#include <bits/wordsize.h> /* The type of the values corresponding to the keys. Must be a @@ -44,6 +55,7 @@ typedef void *hurd_ihash_value_t; /* The type of integer we want to use for the keys. */ typedef uintptr_t hurd_ihash_key_t; +typedef uint64_t hurd_ihash_key64_t; /* The type of a location pointer, which is a pointer to the hash value stored in the hash table. */ @@ -66,15 +78,37 @@ struct _hurd_ihash_item }; typedef struct _hurd_ihash_item *_hurd_ihash_item_t; +struct _hurd_ihash_item64 +{ + /* The value of this hash item. Must be the first element of + the struct for the HURD_IHASH_ITERATE macro. */ + hurd_ihash_value_t value; + + /* The integer key of this hash item. */ + hurd_ihash_key64_t key; +}; +typedef struct _hurd_ihash_item64 *_hurd_ihash_item64_t; + struct hurd_ihash { /* The number of hashed elements. */ size_t nr_items; - /* An array of (key, value) pairs. */ - _hurd_ihash_item_t items; - - /* The length of the array ITEMS. */ +#if __WORDSIZE == 32 + /* Whether items is an array consisting of _hurd_ihash_item_t or + _hurd_ihash_item64_t elements. */ + bool large; +# define _HURD_IHASH_LARGE(ht) ((ht)->large) +#else + /* The machine word size is 64-bits. */ +# define _HURD_IHASH_LARGE(ht) (false) +#endif + + /* An array of (key, value) pairs (either _hurd_ihash_item_t or + _hurd_ihash_item64_t). */ + void *items; + + /* The length of the array ITEMS (in number of items, not bytes). */ size_t size; /* The offset of the location pointer from the hash value. */ @@ -101,30 +135,42 @@ typedef struct hurd_ihash *hurd_ihash_t; #define HURD_IHASH_NO_LOCP PTRDIFF_MIN /* The static initializer for a struct hurd_ihash. */ -#define HURD_IHASH_INITIALIZER(locp_offs) \ +#if __WORDSIZE == 32 +#define HURD_IHASH_INITIALIZER(locp_offs, large) \ { .nr_items = 0, .size = 0, .cleanup = (hurd_ihash_cleanup_t) 0, \ .max_load = HURD_IHASH_MAX_LOAD_DEFAULT, \ - .locp_offset = (locp_offs)} - -/* Initialize the hash table at address HT. If LOCP_OFFSET is not - HURD_IHASH_NO_LOCP, then this is an offset (in bytes) from the - address of a hash value where a location pointer can be found. The - location pointer must be of type hurd_ihash_locp_t and can be used - for fast removal with hurd_ihash_locp_remove(). This function is - not provided if compiled with NO_MALLOC. */ -void hurd_ihash_init (hurd_ihash_t ht, intptr_t locp_offs); + .locp_offset = (locp_offs), large = (large) } +#else +#define HURD_IHASH_INITIALIZER(locp_offs, large) \ + { .nr_items = 0, .size = 0, .cleanup = (hurd_ihash_cleanup_t) 0, \ + .max_load = HURD_IHASH_MAX_LOAD_DEFAULT, \ + .locp_offset = (locp_offs) } +#endif +/* Initialize the hash table at address HT. LARGE determines whether + the hash should uses 64-bit or machine word sized keys. If + LOCP_OFFSET is not HURD_IHASH_NO_LOCP, then this is an offset (in + bytes) from the address of a hash value where a location pointer + can be found. The location pointer must be of type + hurd_ihash_locp_t and can be used for fast removal with + hurd_ihash_locp_remove(). This function is not provided if + compiled with NO_MALLOC. */ +void hurd_ihash_init (hurd_ihash_t ht, bool large, intptr_t locp_offs); /* Return the size of a buffer (in bytes) that is appropriate for a - hash with COUNT elements and a load factor of LOAD_FACTOR + hash with COUNT elements, if LARGE, with 64-bit keys, otherwise + with machine-word sized keys, and a load factor of LOAD_FACTOR (LOAD_FACTOR must be between 1 and 100, a load factor of 0 implies the default load factor). */ -size_t hurd_ihash_buffer_size (size_t count, int max_load_factor); +size_t hurd_ihash_buffer_size (size_t count, bool large, int max_load_factor); /* Initialize a hash ala hurd_ihash_init but provide an initial buffer - BUFFER of size SIZE bytes. If not compiled with NO_MALLOC, the - memory is assumed to be allocated with malloc and may be freed if - the hash must be grown or when hurd_ihash_destroy is called. */ -void hurd_ihash_init_with_buffer (hurd_ihash_t ht, intptr_t locp_offs, + BUFFER of size SIZE bytes. LARGE determines whether the hash + should uses 64-bit or machine word sized keys. If not compiled + with NO_MALLOC, the memory is assumed to be allocated with malloc + and may be freed if the hash must be grown or when + hurd_ihash_destroy is called. */ +void hurd_ihash_init_with_buffer (hurd_ihash_t ht, bool large, + intptr_t locp_offs, void *buffer, size_t size); /* Destroy the hash table at address HT. This first removes all @@ -134,15 +180,17 @@ void hurd_ihash_init_with_buffer (hurd_ihash_t ht, intptr_t locp_offs, otherwise, any buffer in use if freed. */ void hurd_ihash_destroy (hurd_ihash_t ht); -/* Create a hash table, initialize it and return it in HT. If - LOCP_OFFSET is not HURD_IHASH_NO_LOCP, then this is an offset (in - bytes) from the address of a hash value where a location pointer - can be found. The location pointer must be of type - hurd_ihash_locp_t and can be used for fast removal with +/* Create a hash table, initialize it and return it in HT. LARGE + determines whether the hash should uses 64-bit or machine word + sized keys. If LOCP_OFFSET is not HURD_IHASH_NO_LOCP, then this is + an offset (in bytes) from the address of a hash value where a + location pointer can be found. The location pointer must be of + type hurd_ihash_locp_t and can be used for fast removal with hurd_ihash_locp_remove(). If a memory allocation error occurs, ENOMEM is returned, otherwise 0. This function is not provided if compiled with NO_MALLOC. */ -error_t hurd_ihash_create (hurd_ihash_t *ht, intptr_t locp_offs); +error_t hurd_ihash_create (hurd_ihash_t *ht, bool large, + intptr_t locp_offs); /* Destroy the hash table HT and release the memory allocated for it by hurd_ihash_create(). This function is not provided if compiled @@ -182,7 +230,7 @@ void hurd_ihash_set_max_load (hurd_ihash_t ht, unsigned int max_load); *HAD_VALUE. If a memory allocation error occurs, ENOMEM is returned, otherwise 0. */ error_t -hurd_ihash_replace (hurd_ihash_t ht, hurd_ihash_key_t key, +hurd_ihash_replace (hurd_ihash_t ht, hurd_ihash_key64_t key, hurd_ihash_value_t item, bool *had_value, hurd_ihash_value_t *old_value); @@ -191,7 +239,7 @@ hurd_ihash_replace (hurd_ihash_t ht, hurd_ihash_key_t key, it before overriding the value. If a memory allocation error occurs, ENOMEM is returned, otherwise 0. */ static inline error_t -hurd_ihash_add (hurd_ihash_t ht, hurd_ihash_key_t key, +hurd_ihash_add (hurd_ihash_t ht, hurd_ihash_key64_t key, hurd_ihash_value_t item) { return hurd_ihash_replace (ht, key, item, NULL, NULL); @@ -199,7 +247,7 @@ hurd_ihash_add (hurd_ihash_t ht, hurd_ihash_key_t key, /* Find and return the item in the hash table HT with key KEY, or NULL if it doesn't exist. */ -hurd_ihash_value_t hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key_t key); +hurd_ihash_value_t hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key64_t key); /* Iterate over all elements in the hash table. You use this macro with a block, for example like this: @@ -245,18 +293,21 @@ hurd_ihash_value_t hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key_t key); subexpression is always true). */ #define HURD_IHASH_ITERATE(ht, val) \ for (hurd_ihash_value_t val, \ - *_hurd_ihash_valuep = (ht)->size ? &(ht)->items[0].value : 0; \ - (ht)->size \ - && ((_hurd_ihash_item_t) _hurd_ihash_valuep) - &(ht)->items[0] \ - < (ht)->size \ + *_hurd_ihash_valuep = (ht)->items; \ + ((void *) _hurd_ihash_valuep \ + < (ht)->items + (ht)->size * (_HURD_IHASH_LARGE (ht) \ + ? sizeof (struct _hurd_ihash_item64) \ + : sizeof (struct _hurd_ihash_item))) \ && (val = *_hurd_ihash_valuep, 1); \ _hurd_ihash_valuep = (hurd_ihash_value_t *) \ - (((_hurd_ihash_item_t) _hurd_ihash_valuep) + 1)) \ + (_HURD_IHASH_LARGE (ht) \ + ? (void *) (((_hurd_ihash_item64_t) _hurd_ihash_valuep) + 1) \ + : (void *) (((_hurd_ihash_item_t) _hurd_ihash_valuep) + 1))) \ if (val != _HURD_IHASH_EMPTY && val != _HURD_IHASH_DELETED) /* Remove the entry with the key KEY from the hash table HT. If such an entry was found and removed, 1 is returned, otherwise 0. */ -int hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key_t key); +int hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key64_t key); /* Remove from the hast table HT the entry with the location pointer LOCP. That is, if the location pointer is stored in a field named diff --git a/libhurd-ihash/t-ihash.c b/libhurd-ihash/t-ihash.c index 56cb32e..e71ba95 100644 --- a/libhurd-ihash/t-ihash.c +++ b/libhurd-ihash/t-ihash.c @@ -1,5 +1,5 @@ /* t-ihash.c - Integer-keyed hash table function unit-tests. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007, 2008 Free Software Foundation, Inc. Written by Neal H. Walfield <neal@gnu.org>. This file is part of the GNU Hurd. @@ -21,6 +21,7 @@ #define _GNU_SOURCE #include <stdio.h> +#include <assert.h> const char program_name[] = "t-ihash"; @@ -45,7 +46,7 @@ main (int argc, char *argv[]) { struct hurd_ihash hash; - hurd_ihash_init (&hash, HURD_IHASH_NO_LOCP); + hurd_ihash_init (&hash, TEST_LARGE, HURD_IHASH_NO_LOCP); printf ("Testing hurd_ihash_add... "); @@ -55,12 +56,35 @@ main (int argc, char *argv[]) if (hurd_ihash_add (&hash, (hurd_ihash_key_t) k, (hurd_ihash_value_t) k) != 0) F ("failed to insert %d\n", k); +#if TEST_LARGE == true + for (k = 1; k < 100; k ++) + if (hurd_ihash_add (&hash, (hurd_ihash_key64_t) (1ULL << 33) + k, + (hurd_ihash_value_t) (1000 + k)) != 0) + F ("failed to insert %d\n", k); +#endif for (k = 1; k < 100; k ++) { v = hurd_ihash_find (&hash, (hurd_ihash_key_t) k); if (v != (hurd_ihash_value_t) k) F ("unexpected value %d for key %d\n", (int) v, k); } +#if TEST_LARGE == true + for (k = 1; k < 100; k ++) + { + v = hurd_ihash_find (&hash, (hurd_ihash_key64_t) (1ULL << 33) + k); + if (v != (hurd_ihash_value_t) (1000 + k)) + F ("unexpected value %d for key %d\n", (int) v, 1000 + k); + } +#endif + + int c = 0; + HURD_IHASH_ITERATE(&hash, i) + c ++; +#if TEST_LARGE == true + assert (c == 2 * 99); +#else + assert (c == 99); +#endif printf ("ok\n"); @@ -106,7 +130,7 @@ main (int argc, char *argv[]) int value; hurd_ihash_locp_t locp; }; - hurd_ihash_init (&hash, (int) &(((struct s *)0)->locp)); + hurd_ihash_init (&hash, TEST_LARGE, (int) &(((struct s *)0)->locp)); if (hurd_ihash_find (&hash, 1)) F ("Found object with key 1 in otherwise empty hash"); |