Sherman-Morrison/include/vfc_hashmap.h

249 lines
6.4 KiB
C

/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* Copyright 2012 Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#define HASH_MULTIPLIER 31
static const unsigned int hashmap_prime_1 = 73;
static const unsigned int hashmap_prime_2 = 5009;
#ifndef __VFC_HASHMAP_HEADER__
struct vfc_hashmap_st {
size_t nbits;
size_t mask;
size_t capacity;
size_t *items;
size_t nitems;
size_t n_deleted_items;
};
typedef struct vfc_hashmap_st *vfc_hashmap_t;
// allocate and initialize the map
vfc_hashmap_t vfc_hashmap_create();
// get the value at an index of a map
size_t get_value_at(size_t *items, size_t i);
// get the key at an index of a map
size_t get_key_at(size_t *items, size_t i);
// set the value at an index of a map
void set_value_at(size_t *items, size_t value, size_t i);
// set the key at an index of a map
void set_key_at(size_t *items, size_t key, size_t i);
// free the map
void vfc_hashmap_destroy(vfc_hashmap_t map);
// insert an element in the map
void vfc_hashmap_insert(vfc_hashmap_t map, size_t key, void *item);
// remove an element of the map
void vfc_hashmap_remove(vfc_hashmap_t map, size_t key);
// test if an element is in the map
char vfc_hashmap_have(vfc_hashmap_t map, size_t key);
// get an element of the map
void *vfc_hashmap_get(vfc_hashmap_t map, size_t key);
// get the number of elements in the map
size_t vfc_hashmap_num_items(vfc_hashmap_t map);
// Hash function
size_t vfc_hashmap_str_function(const char *id);
#endif
/***************** Verificarlo hashmap FUNCTIONS ********************
* The following set of functions are used in backends and wrapper
* to stock and access quickly internal data.
*******************************************************************/
// free the map
void vfc_hashmap_destroy(vfc_hashmap_t map) {
if (map) {
free(map->items);
}
free(map);
}
// allocate and initialize the map
vfc_hashmap_t vfc_hashmap_create() {
vfc_hashmap_t map = (vfc_hashmap_t)calloc(1, sizeof(struct vfc_hashmap_st));
if (map == NULL) {
return NULL;
}
map->nbits = 3;
map->capacity = (size_t)(1 << map->nbits);
map->mask = map->capacity - 1;
// an item is now a value and a key
map->items = (size_t *)calloc(map->capacity, 2 * sizeof(size_t));
if (map->items == NULL) {
vfc_hashmap_destroy(map);
return NULL;
}
map->nitems = 0;
map->n_deleted_items = 0;
return map;
}
size_t get_value_at(size_t *items, size_t i) { return items[i * 2]; }
size_t get_key_at(size_t *items, size_t i) { return items[(i * 2) + 1]; }
void set_value_at(size_t *items, size_t value, size_t i) {
items[i * 2] = value;
}
void set_key_at(size_t *items, size_t key, size_t i) {
items[(i * 2) + 1] = key;
}
// add a member in the table
static int hashmap_add_member(vfc_hashmap_t map, size_t key, void *item) {
size_t value = (size_t)item;
size_t ii;
if (value == 0 || value == 1) {
return -1;
}
ii = map->mask & (hashmap_prime_1 * key);
while (get_value_at(map->items, ii) != 0 &&
get_value_at(map->items, ii) != 1) {
if (get_value_at(map->items, ii) == value) {
return 0;
} else {
/* search free slot */
ii = map->mask & (ii + hashmap_prime_2);
}
}
map->nitems++;
if (get_value_at(map->items, ii) == 1) {
map->n_deleted_items--;
}
set_value_at(map->items, value, ii);
set_key_at(map->items, key, ii);
return 1;
}
// rehash the table if necessary
static void maybe_rehash_map(vfc_hashmap_t map) {
size_t *old_items;
size_t old_capacity, ii;
if (map->nitems + map->n_deleted_items >= (double)map->capacity * 0.85) {
old_items = map->items;
old_capacity = map->capacity;
map->nbits++;
map->capacity = (size_t)(1 << map->nbits);
map->mask = map->capacity - 1;
map->items = (size_t *)calloc(map->capacity, 2 * sizeof(size_t));
map->nitems = 0;
map->n_deleted_items = 0;
for (ii = 0; ii < old_capacity; ii++) {
hashmap_add_member(map, get_key_at(old_items, ii),
(void *)get_value_at(old_items, ii));
}
free(old_items);
}
}
// insert an element in the map
void vfc_hashmap_insert(vfc_hashmap_t map, size_t key, void *item) {
hashmap_add_member(map, key, item);
maybe_rehash_map(map);
}
// remove an element of the map
void vfc_hashmap_remove(vfc_hashmap_t map, size_t key) {
size_t ii = map->mask & (hashmap_prime_1 * key);
while (get_value_at(map->items, ii) != 0) {
if (get_key_at(map->items, ii) == key) {
set_value_at(map->items, 1, ii);
map->nitems--;
map->n_deleted_items++;
break;
} else {
ii = map->mask & (ii + hashmap_prime_2);
}
}
}
// test if an element is in the map
char vfc_hashmap_have(vfc_hashmap_t map, size_t key) {
size_t ii = map->mask & (hashmap_prime_1 * key);
while (get_value_at(map->items, ii) != 0) {
if (get_key_at(map->items, ii) == key) {
return 1;
} else {
ii = map->mask & (ii + hashmap_prime_2);
}
}
return 0;
}
// get an element of the map
void *vfc_hashmap_get(vfc_hashmap_t map, size_t key) {
size_t ii = map->mask & (hashmap_prime_1 * key);
while (get_value_at(map->items, ii) != 0) {
if (get_key_at(map->items, ii) == key) {
return (void *)get_value_at(map->items, ii);
} else {
ii = map->mask & (ii + hashmap_prime_2);
}
}
return NULL;
}
// get the number of elements in the map
size_t vfc_hashmap_num_items(vfc_hashmap_t map) { return map->nitems; }
// Hash function for strings
size_t vfc_hashmap_str_function(const char *id) {
unsigned const char *us;
us = (unsigned const char *)id;
size_t index = 0;
while (*us != '\0') {
index = index * HASH_MULTIPLIER + *us;
us++;
}
return index;
}
// Free the hashmap
void vfc_hashmap_free(vfc_hashmap_t map) {
for (int ii = 0; ii < map->capacity; ii++)
if (get_value_at(map->items, ii) != 0 && get_value_at(map->items, ii) != 0)
free((void *)get_value_at(map->items, ii));
}