#include "include/ptrhash.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct ph_table *ph_init(size_t size)
{
struct ph_table *p;
if (size == 0 || (size & (size-1)) != 0) {
fprintf(stderr, "ph_init: size must be power of two.\n");
return NULL;
}
p = malloc(sizeof(*p) + size*sizeof(void*));
if (!p) {
fprintf(stderr, "ph_init: unable to allocate memory.\n");
return NULL;
}
p->mask = size-1;
p->count = 0;
memset(p->buckets, 0, size*sizeof(void*));
return p;
}
int ph_add_generic(struct ph_table *h, void *value, size_t keyoff, size_t keylen)
{
uint32_t i, h0 = 1u, h1 = 3u;
const size_t mask = h->mask;
if (h->count >= mask) return -1;
__ph_hash(value + keyoff, keylen, &h0, &h1);
h1 |= 1u;
while (1) {
i = h0 & mask;
if (!h->buckets[i] || h->buckets[i] == PH_ENTRY_DELETED) {
h->buckets[i] = value;
h->count++;
break;
}
else if (!memcmp(h->buckets[i] + keyoff, value + keyoff, keylen)) {
return 1;
}
else {
h0 += h1;
}
}
return 0;
}
void *ph_get_generic(struct ph_table *h, const void *key, size_t keyoff, size_t keylen)
{
uint32_t i, h0 = 1u, h1 = 3u;
void *entry;
int64_t first_grave = -1;
const size_t mask = h->mask;
__ph_hash(key, keylen, &h0, &h1);
h1 |= 1u;
while (1) {
i = h0 & mask;
entry = h->buckets[i];
if (entry) {
if (entry == PH_ENTRY_DELETED) {
if (first_grave == -1)
first_grave = i;
}
else if (!memcmp(entry + keyoff, key, keylen)) {
if (first_grave != -1) {
h->buckets[first_grave] = entry;
h->buckets[i] = PH_ENTRY_DELETED;
}
return entry;
}
h0 += h1;
}
else
break;
}
return NULL;
}
void *ph_remove_generic(struct ph_table *h, const void *key, size_t keyoff, size_t keylen)
{
void *entry;
uint32_t i, h0 = 1u, h1 = 3u;
const size_t mask = h->mask;
__ph_hash(key, keylen, &h0, &h1);
h1 |= 1u;
while (1) {
i = h0 & mask;
entry = h->buckets[i];
if (entry) {
if (entry != PH_ENTRY_DELETED && !memcmp(entry + keyoff, key, keylen)) {
h->buckets[i] = PH_ENTRY_DELETED;
--h->count;
return entry;
}
h0 += h1;
}
else
break;
}
return NULL;
}