提交 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 ...@@ -56,6 +56,22 @@ KS_BEGIN_EXTERN_C
#define KS_64BIT 1 #define KS_64BIT 1
#endif #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 <stdarg.h>
#include <time.h> #include <time.h>
#include <stdarg.h> #include <stdarg.h>
......
...@@ -75,7 +75,7 @@ KS_BEGIN_EXTERN_C ...@@ -75,7 +75,7 @@ KS_BEGIN_EXTERN_C
typedef uint16_t ks_port_t; typedef uint16_t ks_port_t;
typedef size_t ks_size_t; typedef size_t ks_size_t;
typedef unsigned char ks_byte_t;
typedef enum { typedef enum {
KS_STATUS_SUCCESS, KS_STATUS_SUCCESS,
KS_STATUS_FAIL, KS_STATUS_FAIL,
......
...@@ -64,6 +64,8 @@ struct ks_hash { ...@@ -64,6 +64,8 @@ struct ks_hash {
ks_rwl_t *rwl; ks_rwl_t *rwl;
ks_mutex_t *mutex; ks_mutex_t *mutex;
uint32_t readers; uint32_t readers;
ks_size_t keysize;
ks_hash_mode_t mode;
}; };
/*****************************************************************************/ /*****************************************************************************/
...@@ -72,13 +74,22 @@ struct ks_hash { ...@@ -72,13 +74,22 @@ struct ks_hash {
static inline unsigned int static inline unsigned int
hash(ks_hash_t *h, void *k) hash(ks_hash_t *h, void *k)
{ {
/* Aim to protect against poor hash functions by adding logic here unsigned int i;
* - logic taken from java 1.4 ks_hash source */
unsigned int i = h->hashfn(k); if (h->mode == KS_HASH_MODE_ARBITRARY) {
i += ~(i << 9); i = ks_hash_default_arbitrary(k, h->keysize, 13);
i ^= ((i >> 14) | (i << 18)); /* >>> */ } else {
i += (i << 4); i = h->hashfn(k);
i ^= ((i >> 10) | (i << 22)); /* >>> */ }
/* 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; return i;
} }
...@@ -146,6 +157,11 @@ KS_DECLARE(void) ks_hash_set_flags(ks_hash_t *h, ks_hash_flag_t flags) ...@@ -146,6 +157,11 @@ KS_DECLARE(void) ks_hash_set_flags(ks_hash_t *h, ks_hash_flag_t flags)
h->flags = 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) KS_DECLARE(void) ks_hash_set_destructor(ks_hash_t *h, ks_hash_destructor_t destructor)
{ {
h->destructor = destructor; h->destructor = destructor;
...@@ -159,6 +175,7 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize, ...@@ -159,6 +175,7 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize,
{ {
ks_hash_t *h; ks_hash_t *h;
unsigned int pindex, size = primes[0]; unsigned int pindex, size = primes[0];
ks_size_t keysize = 0;
switch(mode) { switch(mode) {
case KS_HASH_MODE_CASE_INSENSITIVE: case KS_HASH_MODE_CASE_INSENSITIVE:
...@@ -170,18 +187,24 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize, ...@@ -170,18 +187,24 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize,
ks_assert(eqf == NULL); ks_assert(eqf == NULL);
hashf = ks_hash_default_int; hashf = ks_hash_default_int;
eqf = ks_hash_equalkeys_int; eqf = ks_hash_equalkeys_int;
keysize = 4;
break; break;
case KS_HASH_MODE_INT64: case KS_HASH_MODE_INT64:
ks_assert(hashf == NULL); ks_assert(hashf == NULL);
ks_assert(eqf == NULL); ks_assert(eqf == NULL);
hashf = ks_hash_default_int64; hashf = ks_hash_default_int64;
eqf = ks_hash_equalkeys_int64; eqf = ks_hash_equalkeys_int64;
keysize = 8;
break; break;
case KS_HASH_MODE_PTR: case KS_HASH_MODE_PTR:
ks_assert(hashf == NULL); ks_assert(hashf == NULL);
ks_assert(eqf == NULL); ks_assert(eqf == NULL);
hashf = ks_hash_default_ptr; hashf = ks_hash_default_ptr;
eqf = ks_hash_equalkeys_ptr; eqf = ks_hash_equalkeys_ptr;
keysize = sizeof(void *);
break;
case KS_HASH_MODE_ARBITRARY:
keysize = sizeof(void *);
break; break;
default: default:
break; break;
...@@ -210,6 +233,8 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize, ...@@ -210,6 +233,8 @@ ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize,
h->pool = pool; h->pool = pool;
h->flags = flags; h->flags = flags;
h->destructor = destructor; h->destructor = destructor;
h->keysize = keysize;
h->mode = mode;
if ((flags & KS_HASH_FLAG_RWLOCK)) { if ((flags & KS_HASH_FLAG_RWLOCK)) {
ks_rwl_create(&h->rwl, h->pool); ks_rwl_create(&h->rwl, h->pool);
...@@ -303,6 +328,15 @@ ks_hash_count(ks_hash_t *h) ...@@ -303,6 +328,15 @@ ks_hash_count(ks_hash_t *h)
return h->entrycount; 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) { 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, /* TODO: consider compacting the table when the load factor drops enough,
* or provide a 'compact' method. */ * or provide a 'compact' method. */
...@@ -316,7 +350,7 @@ static void * _ks_hash_remove(ks_hash_t *h, void *k, unsigned int hashvalue, uns ...@@ -316,7 +350,7 @@ static void * _ks_hash_remove(ks_hash_t *h, void *k, unsigned int hashvalue, uns
e = *pE; e = *pE;
while (NULL != e) { while (NULL != e) {
/* Check hash value to short circuit heavier comparison */ /* 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; *pE = e->next;
h->entrycount--; h->entrycount--;
v = e->v; v = e->v;
...@@ -457,7 +491,7 @@ ks_hash_search(ks_hash_t *h, void *k, ks_locked_t locked) ...@@ -457,7 +491,7 @@ ks_hash_search(ks_hash_t *h, void *k, ks_locked_t locked)
e = h->table[index]; e = h->table[index];
while (NULL != e) { while (NULL != e) {
/* Check hash value to short circuit heavier comparison */ /* 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; v = e->v;
break; break;
} }
......
...@@ -120,16 +120,56 @@ int test2(void) ...@@ -120,16 +120,56 @@ int test2(void)
return 1; 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) int main(int argc, char **argv)
{ {
ks_init(); ks_init();
srand((unsigned)(time(NULL) - (unsigned)(intptr_t)ks_thread_self())); srand((unsigned)(time(NULL) - (unsigned)(intptr_t)ks_thread_self()));
plan(2); plan(3);
ok(test1()); ok(test1());
ok(test2()); ok(test2());
ok(test3());
ks_shutdown(); ks_shutdown();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论