提交 a0180288 authored 作者: Anthony Minessale's avatar Anthony Minessale

FS-9803 #resolve [Add support for arbitrary data as hash keys]

上级 44d69cb2
......@@ -56,6 +56,22 @@ KS_BEGIN_EXTERN_C
#define KS_64BIT 1
#endif
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
__BYTE_ORDER == __LITTLE_ENDIAN) || \
(defined(i386) || defined(__i386__) || defined(__i486__) || \
defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
# define KS_LITTLE_ENDIAN 1
# define KS_BIG_ENDIAN 0
#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
__BYTE_ORDER == __BIG_ENDIAN) || \
(defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
# define KS_LITTLE_ENDIAN 0
# define KS_BIG_ENDIAN 1
#else
# define KS_LITTLE_ENDIAN 0
# define KS_BIG_ENDIAN 0
#endif
#include <stdarg.h>
#include <time.h>
#include <stdarg.h>
......
......@@ -75,7 +75,7 @@ KS_BEGIN_EXTERN_C
typedef uint16_t ks_port_t;
typedef size_t ks_size_t;
typedef unsigned char ks_byte_t;
typedef enum {
KS_STATUS_SUCCESS,
KS_STATUS_FAIL,
......
......@@ -64,6 +64,8 @@ struct ks_hash {
ks_rwl_t *rwl;
ks_mutex_t *mutex;
uint32_t readers;
ks_size_t keysize;
ks_hash_mode_t mode;
};
/*****************************************************************************/
......@@ -72,13 +74,22 @@ struct ks_hash {
static inline unsigned int
hash(ks_hash_t *h, void *k)
{
/* Aim to protect against poor hash functions by adding logic here
* - logic taken from java 1.4 ks_hash source */
unsigned int i = h->hashfn(k);
i += ~(i << 9);
i ^= ((i >> 14) | (i << 18)); /* >>> */
i += (i << 4);
i ^= ((i >> 10) | (i << 22)); /* >>> */
unsigned int i;
if (h->mode == KS_HASH_MODE_ARBITRARY) {
i = ks_hash_default_arbitrary(k, h->keysize, 13);
} else {
i = h->hashfn(k);
}
/* Aim to protect against poor hash functions by adding logic here
* - logic taken from java 1.4 hash source */
i += ~(i << 9);
i ^= ((i >> 14) | (i << 18)); /* >>> */
i += (i << 4);
i ^= ((i >> 10) | (i << 22)); /* >>> */
return i;
}
......@@ -146,6 +157,11 @@ KS_DECLARE(void) ks_hash_set_flags(ks_hash_t *h, ks_hash_flag_t flags)
h->flags = flags;
}
KS_DECLARE(void) ks_hash_set_keysize(ks_hash_t *h, ks_size_t keysize)
{
h->keysize = keysize;
}
KS_DECLARE(void) ks_hash_set_destructor(ks_hash_t *h, ks_hash_destructor_t destructor)
{
h->destructor = destructor;
......@@ -159,6 +175,7 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize,
{
ks_hash_t *h;
unsigned int pindex, size = primes[0];
ks_size_t keysize = 0;
switch(mode) {
case KS_HASH_MODE_CASE_INSENSITIVE:
......@@ -170,18 +187,24 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize,
ks_assert(eqf == NULL);
hashf = ks_hash_default_int;
eqf = ks_hash_equalkeys_int;
keysize = 4;
break;
case KS_HASH_MODE_INT64:
ks_assert(hashf == NULL);
ks_assert(eqf == NULL);
hashf = ks_hash_default_int64;
eqf = ks_hash_equalkeys_int64;
keysize = 8;
break;
case KS_HASH_MODE_PTR:
ks_assert(hashf == NULL);
ks_assert(eqf == NULL);
hashf = ks_hash_default_ptr;
eqf = ks_hash_equalkeys_ptr;
keysize = sizeof(void *);
break;
case KS_HASH_MODE_ARBITRARY:
keysize = sizeof(void *);
break;
default:
break;
......@@ -210,6 +233,8 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize,
h->pool = pool;
h->flags = flags;
h->destructor = destructor;
h->keysize = keysize;
h->mode = mode;
if ((flags & KS_HASH_FLAG_RWLOCK)) {
ks_rwl_create(&h->rwl, h->pool);
......@@ -303,6 +328,15 @@ ks_hash_count(ks_hash_t *h)
return h->entrycount;
}
static int key_equals(ks_hash_t *h, void *k1, void *k2)
{
if (h->mode == KS_HASH_MODE_ARBITRARY) {
return !memcmp(k1, k2, h->keysize);
} else {
return h->eqfn(k1, k2);
}
}
static void * _ks_hash_remove(ks_hash_t *h, void *k, unsigned int hashvalue, unsigned int index) {
/* TODO: consider compacting the table when the load factor drops enough,
* or provide a 'compact' method. */
......@@ -316,7 +350,7 @@ static void * _ks_hash_remove(ks_hash_t *h, void *k, unsigned int hashvalue, uns
e = *pE;
while (NULL != e) {
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
if ((hashvalue == e->h) && (key_equals(h, k, e->k))) {
*pE = e->next;
h->entrycount--;
v = e->v;
......@@ -457,7 +491,7 @@ ks_hash_search(ks_hash_t *h, void *k, ks_locked_t locked)
e = h->table[index];
while (NULL != e) {
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
if ((hashvalue == e->h) && (key_equals(h, k, e->k))) {
v = e->v;
break;
}
......
......@@ -120,16 +120,56 @@ int test2(void)
return 1;
}
#include "sodium.h"
#define TEST3_SIZE 20
int test3(void)
{
ks_pool_t *pool;
ks_hash_t *hash;
ks_byte_t data[TEST3_SIZE];
ks_byte_t data2[TEST3_SIZE];
ks_byte_t data3[TEST3_SIZE];
char *A, *B, *C;
ks_pool_open(&pool);
ks_hash_create(&hash, KS_HASH_MODE_ARBITRARY, KS_HASH_FLAG_NONE, pool);
ks_hash_set_keysize(hash, TEST3_SIZE);
randombytes_buf(data, sizeof(data));
randombytes_buf(data2, sizeof(data2));
ks_hash_insert(hash, data, "FOO");
ks_hash_insert(hash, data2, "BAR");
ks_hash_insert(hash, data3, "BAZ");
A = (char *)ks_hash_search(hash, data, KS_UNLOCKED);
B = (char *)ks_hash_search(hash, data2, KS_UNLOCKED);
C = (char *)ks_hash_search(hash, data3, KS_UNLOCKED);
printf("RESULT [%s][%s][%s]\n", A, B, C);
ks_hash_destroy(&hash);
ks_pool_close(&pool);
return !strcmp(A, "FOO") && !strcmp(B, "BAR") && !strcmp(C, "BAZ");
}
int main(int argc, char **argv)
{
ks_init();
srand((unsigned)(time(NULL) - (unsigned)(intptr_t)ks_thread_self()));
plan(2);
plan(3);
ok(test1());
ok(test2());
ok(test3());
ks_shutdown();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论