219 lines
5.6 KiB
C
219 lines
5.6 KiB
C
#include "simpleHash.h"
|
|
|
|
uint32_t mySimpleHash(const char* data, size_t n, uint32_t seed) {
|
|
// Similar to murmur hash
|
|
const uint32_t m = 0xc6a4a793;
|
|
const uint32_t r = 24;
|
|
const char* limit = data + n;
|
|
uint32_t h = seed ^ (n * m);
|
|
|
|
// Pick up four bytes at a time
|
|
while (data + 4 <= limit) {
|
|
// uint32_t w = DecodeFixed32(data);
|
|
uint32_t w;
|
|
memcpy(&w, data, 4);
|
|
|
|
data += 4;
|
|
h += w;
|
|
h *= m;
|
|
h ^= (h >> 16);
|
|
}
|
|
|
|
// Pick up remaining bytes
|
|
switch (limit - data) {
|
|
case 3:
|
|
h += (unsigned char)(data[2]) << 16;
|
|
do {
|
|
} while (0);
|
|
case 2:
|
|
h += (unsigned char)(data[1]) << 8;
|
|
do {
|
|
} while (0);
|
|
case 1:
|
|
h += (unsigned char)(data[0]);
|
|
h *= m;
|
|
h ^= (h >> r);
|
|
break;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
int insertCStrSimpleHash(struct SimpleHash* ths, char* key, char* data) {
|
|
return insertSimpleHash(ths, key, strlen(key) + 1, data, strlen(data) + 1);
|
|
}
|
|
|
|
int removeCStrSimpleHash(struct SimpleHash* ths, char* key) { return removeSimpleHash(ths, key, strlen(key) + 1); }
|
|
|
|
SimpleHashNode** findCStrSimpleHash(struct SimpleHash* ths, char* key) {
|
|
return findSimpleHash(ths, key, strlen(key) + 1);
|
|
}
|
|
|
|
int insertSimpleHash(struct SimpleHash* ths, char* key, size_t keyLen, char* data, size_t dataLen) {
|
|
SimpleHashNode** pp = ths->find(ths, key, keyLen);
|
|
if (*pp != NULL) {
|
|
fprintf(stderr, "insertSimpleHash, already has key \n");
|
|
return -1;
|
|
}
|
|
|
|
SimpleHashNode* node = malloc(sizeof(*node));
|
|
node->hashCode = ths->hashFunc(key, keyLen);
|
|
node->key = malloc(keyLen);
|
|
node->keyLen = keyLen;
|
|
memcpy(node->key, key, keyLen);
|
|
node->data = malloc(dataLen);
|
|
node->dataLen = dataLen;
|
|
memcpy(node->data, data, dataLen);
|
|
node->next = NULL;
|
|
|
|
// printf("insertSimpleHash: <%s, %ld, %s, %ld, %u> \n", node->key, node->keyLen, node->data, node->dataLen,
|
|
// node->hashCode);
|
|
|
|
size_t index = node->hashCode & (ths->length - 1);
|
|
|
|
SimpleHashNode* ptr = ths->table[index];
|
|
if (ptr != NULL) {
|
|
node->next = ptr;
|
|
ths->table[index] = node;
|
|
|
|
} else {
|
|
ths->table[index] = node;
|
|
}
|
|
ths->elems++;
|
|
if (ths->elems > 2 * ths->length) {
|
|
ths->resize(ths);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int removeSimpleHash(struct SimpleHash* ths, char* key, size_t keyLen) {
|
|
SimpleHashNode** pp = ths->find(ths, key, keyLen);
|
|
if (*pp == NULL) {
|
|
fprintf(stderr, "removeSimpleHash, key not exist \n");
|
|
return -1;
|
|
}
|
|
|
|
SimpleHashNode* del = *pp;
|
|
*pp = del->next;
|
|
free(del->key);
|
|
free(del->data);
|
|
free(del);
|
|
ths->elems--;
|
|
|
|
return 0;
|
|
}
|
|
|
|
SimpleHashNode** findSimpleHash(struct SimpleHash* ths, char* key, size_t keyLen) {
|
|
uint32_t hashCode = ths->hashFunc(key, keyLen);
|
|
// size_t index = hashCode % ths->length;
|
|
size_t index = hashCode & (ths->length - 1);
|
|
|
|
// printf("findSimpleHash: %s %ld %u \n", key, keyLen, hashCode);
|
|
|
|
SimpleHashNode** pp = &(ths->table[index]);
|
|
while (*pp != NULL && ((*pp)->hashCode != hashCode || memcmp(key, (*pp)->key, keyLen) != 0)) {
|
|
pp = &((*pp)->next);
|
|
}
|
|
|
|
return pp;
|
|
}
|
|
|
|
void printCStrSimpleHash(struct SimpleHash* ths) {
|
|
printf("\n--- printCStrSimpleHash: elems:%d length:%d \n", ths->elems, ths->length);
|
|
for (size_t i = 0; i < ths->length; ++i) {
|
|
SimpleHashNode* ptr = ths->table[i];
|
|
if (ptr != NULL) {
|
|
printf("%zu: ", i);
|
|
while (ptr != NULL) {
|
|
printf("<%u, %s, %ld, %s, %ld> ", ptr->hashCode, (char*)ptr->key, ptr->keyLen, (char*)ptr->data, ptr->dataLen);
|
|
ptr = ptr->next;
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
printf("---------------\n");
|
|
}
|
|
|
|
void destroySimpleHash(struct SimpleHash* ths) {
|
|
for (size_t i = 0; i < ths->length; ++i) {
|
|
SimpleHashNode* ptr = ths->table[i];
|
|
while (ptr != NULL) {
|
|
SimpleHashNode* tmp = ptr;
|
|
ptr = ptr->next;
|
|
free(tmp->key);
|
|
free(tmp->data);
|
|
free(tmp);
|
|
}
|
|
}
|
|
|
|
ths->length = 0;
|
|
ths->elems = 0;
|
|
free(ths->table);
|
|
free(ths);
|
|
}
|
|
|
|
void resizeSimpleHash(struct SimpleHash* ths) {
|
|
uint32_t new_length = ths->length;
|
|
while (new_length < ths->elems) {
|
|
new_length *= 2;
|
|
}
|
|
|
|
printf("resizeSimpleHash: %p from %u to %u \n", ths, ths->length, new_length);
|
|
|
|
SimpleHashNode** new_table = malloc(new_length * sizeof(SimpleHashNode*));
|
|
memset(new_table, 0, new_length * sizeof(SimpleHashNode*));
|
|
|
|
uint32_t count = 0;
|
|
for (uint32_t i = 0; i < ths->length; i++) {
|
|
if (ths->table[i] == NULL) {
|
|
continue;
|
|
}
|
|
|
|
SimpleHashNode* it = ths->table[i];
|
|
while (it != NULL) {
|
|
SimpleHashNode* move_node = it;
|
|
it = it->next;
|
|
|
|
// move move_node
|
|
move_node->next = NULL;
|
|
size_t index = move_node->hashCode & (new_length - 1);
|
|
|
|
SimpleHashNode* ptr = new_table[index];
|
|
if (ptr != NULL) {
|
|
move_node->next = ptr;
|
|
new_table[index] = move_node;
|
|
} else {
|
|
new_table[index] = move_node;
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
|
|
assert(ths->elems == count);
|
|
free(ths->table);
|
|
ths->table = new_table;
|
|
ths->length = new_length;
|
|
}
|
|
|
|
uint32_t simpleHashFunc(const char* key, size_t keyLen) { return mySimpleHash(key, keyLen, 1); }
|
|
|
|
struct SimpleHash* newSimpleHash(size_t length) {
|
|
struct SimpleHash* ths = malloc(sizeof(*ths));
|
|
|
|
ths->length = length;
|
|
ths->elems = 0;
|
|
ths->table = malloc(length * sizeof(SimpleHashNode*));
|
|
memset(ths->table, 0, length * sizeof(SimpleHashNode*));
|
|
|
|
ths->insert = insertSimpleHash;
|
|
ths->remove = removeSimpleHash;
|
|
ths->find = findSimpleHash;
|
|
ths->insert_cstr = insertCStrSimpleHash;
|
|
ths->remove_cstr = removeCStrSimpleHash;
|
|
ths->find_cstr = findCStrSimpleHash;
|
|
ths->print_cstr = printCStrSimpleHash;
|
|
ths->destroy = destroySimpleHash;
|
|
ths->resize = resizeSimpleHash;
|
|
ths->hashFunc = simpleHashFunc;
|
|
}
|