1
1
mirror of https://github.com/theoludwig/libcproject.git synced 2024-12-11 21:13:00 +01:00

perf: use SipHash 1-3 algorithm for hash_map

This commit is contained in:
Théo LUDWIG 2023-06-25 20:03:02 +02:00
parent baea00fdac
commit 016bfeb47f
Signed by: theoludwig
GPG Key ID: ADFE5A563D718F3B
2 changed files with 119 additions and 6 deletions

View File

@ -1,12 +1,123 @@
#include "hash_map.h" #include "hash_map.h"
#define ROTATE_LEFT(x, b) (((x) << (b)) | ((x) >> (64 - (b))))
uint64_t hash(string_t key, size_t capacity) { uint64_t hash(string_t key, size_t capacity) {
uint64_t hash_value = 0; size_t key_length = string_get_length(key);
for (size_t iteration = 0; iteration < capacity; iteration++) { const uint64_t c = 0x736f6d6570736575;
hash_value += key[iteration]; uint64_t v0 = 0x736f6d6570736575 ^ c;
hash_value *= key[iteration]; uint64_t v1 = 0x646f72616e646f6d ^ c;
uint64_t v2 = 0x6c7967656e657261 ^ c;
uint64_t v3 = 0x7465646279746573 ^ c;
uint64_t k1;
uint64_t m;
uint8_t *message = (uint8_t *)key;
size_t remaining = key_length;
uint64_t hash;
message += sizeof(uint64_t);
k1 = *(uint64_t *)message;
if (key_length % sizeof(uint64_t) != 0) {
memcpy(&k1, key + (key_length - sizeof(uint64_t)), sizeof(uint64_t));
} }
return hash_value % capacity;
while (remaining >= 8) {
memcpy(&m, message, sizeof(uint64_t));
v3 ^= m;
for (int i = 0; i < 2; i++) {
v0 += v1;
v2 += v3;
v1 = ROTATE_LEFT(v1, 13);
v3 = ROTATE_LEFT(v3, 16);
v1 ^= v0;
v3 ^= v2;
v0 = ROTATE_LEFT(v0, 32);
v2 += v1;
v0 += v3;
v1 = ROTATE_LEFT(v1, 17);
v3 = ROTATE_LEFT(v3, 21);
v1 ^= v2;
v3 ^= v0;
v2 = ROTATE_LEFT(v2, 32);
}
v0 ^= m;
remaining -= sizeof(uint64_t);
message += sizeof(uint64_t);
}
m = (uint64_t)remaining << 56;
switch (remaining) {
case 7:
m |= (uint64_t)message[6] << 48;
break;
case 6:
m |= (uint64_t)message[5] << 40;
break;
case 5:
m |= (uint64_t)message[4] << 32;
break;
case 4:
m |= (uint64_t)message[3] << 24;
break;
case 3:
m |= (uint64_t)message[2] << 16;
break;
case 2:
m |= (uint64_t)message[1] << 8;
break;
case 1:
m |= (uint64_t)message[0];
break;
default:
break;
}
v3 ^= m;
for (int i = 0; i < 2; i++) {
v0 += v1;
v2 += v3;
v1 = ROTATE_LEFT(v1, 13);
v3 = ROTATE_LEFT(v3, 16);
v1 ^= v0;
v3 ^= v2;
v0 = ROTATE_LEFT(v0, 32);
v2 += v1;
v0 += v3;
v1 = ROTATE_LEFT(v1, 17);
v3 = ROTATE_LEFT(v3, 21);
v1 ^= v2;
v3 ^= v0;
v2 = ROTATE_LEFT(v2, 32);
}
v0 ^= m;
v2 ^= 0xff;
for (int i = 0; i < 4; i++) {
v0 += v1;
v2 += v3;
v1 = ROTATE_LEFT(v1, 13);
v3 = ROTATE_LEFT(v3, 16);
v1 ^= v0;
v3 ^= v2;
v0 = ROTATE_LEFT(v0, 32);
v2 += v1;
v0 += v3;
v1 = ROTATE_LEFT(v1, 17);
v3 = ROTATE_LEFT(v3, 21);
v1 ^= v2;
v3 ^= v0;
v2 = ROTATE_LEFT(v2, 32);
}
hash = v0 ^ v1 ^ v2 ^ v3;
return hash % capacity;
} }
struct hash_map *hash_map_initialization() { struct hash_map *hash_map_initialization() {

View File

@ -4,6 +4,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "linked_list.h" #include "linked_list.h"
#include "string.h" #include "string.h"
@ -32,7 +33,8 @@ struct hash_map_item {
}; };
/** /**
* @brief Hash function. * @brief Hash function (using SipHash 1-3 algorithm).
* @link https://en.wikipedia.org/wiki/SipHash
* @param key * @param key
* @param capacity * @param capacity
* @since v2.0.0 * @since v2.0.0