-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3e637f9
Showing
13 changed files
with
1,717 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# http://www.gnu.org/software/automake | ||
|
||
Makefile.in | ||
/ar-lib | ||
/mdate-sh | ||
/py-compile | ||
/test-driver | ||
/ylwrap | ||
.deps/ | ||
.dirstamp | ||
|
||
# http://www.gnu.org/software/autoconf | ||
|
||
autom4te.cache | ||
/autoscan.log | ||
/autoscan-*.log | ||
/aclocal.m4 | ||
/compile | ||
/config.cache | ||
/config.guess | ||
/config.h.in | ||
/config.log | ||
/config.status | ||
/config.sub | ||
/configure | ||
/configure.scan | ||
/depcomp | ||
/install-sh | ||
/missing | ||
/stamp-h1 | ||
|
||
# https://www.gnu.org/software/libtool/ | ||
|
||
/ltmain.sh | ||
|
||
# http://www.gnu.org/software/texinfo | ||
|
||
/texinfo.tex | ||
|
||
# http://www.gnu.org/software/m4/ | ||
|
||
m4/libtool.m4 | ||
m4/ltoptions.m4 | ||
m4/ltsugar.m4 | ||
m4/ltversion.m4 | ||
m4/lt~obsolete.m4 | ||
|
||
# Generated Makefile | ||
# (meta build system like autotools, | ||
# can automatically generate from config.status script | ||
# (which is called by configure script)) | ||
Makefile | ||
|
||
test | ||
*.o | ||
.vscode | ||
libcrhash.a | ||
config.h | ||
INSTALL |
Empty file.
Large diffs are not rendered by default.
Oops, something went wrong.
Empty file.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
crhash_includedir = -I$(abs_top_srcdir)/include | ||
|
||
dist_doc_DATA = LICENSE \ | ||
README.md \ | ||
$(NULL) | ||
|
||
CRHASH_FILES = src/c_rhash.c \ | ||
src/c_rhash.h \ | ||
$(NULL) | ||
|
||
lib_LIBRARIES = libcrhash.a | ||
|
||
libcrhash_a_SOURCES = $(CRHASH_FILES) | ||
|
||
libcrhash_a_CFLAGS = $(crhash_includedir) | ||
|
||
bin_PROGRAMS = test | ||
test_LDADD = libcrhash.a | ||
|
||
test_SOURCES = src/tests.c | ||
test_CFLAGS = $(crhash_includedir) |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
AC_INIT([c_rbuf], [0.1]) | ||
AM_INIT_AUTOMAKE([subdir-objects]) | ||
AC_PROG_CC | ||
AC_PROG_RANLIB | ||
|
||
AC_CONFIG_FILES([Makefile]) | ||
|
||
AC_OUTPUT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#include <sys/types.h> | ||
#include <stdint.h> | ||
|
||
#ifndef DEFAULT_BIN_COUNT | ||
#define DEFAULT_BIN_COUNT 1000 | ||
#endif | ||
|
||
#define ITEMTYPE_UNSET (0x0) | ||
#define ITEMTYPE_STRING (0x1) | ||
#define ITEMTYPE_UINT8 (0x2) | ||
#define ITEMTYPE_OPAQUE_PTR (0x3) | ||
|
||
typedef struct c_rhash_s *c_rhash; | ||
|
||
c_rhash c_rhash_new(size_t bin_count); | ||
|
||
void c_rhash_destroy(c_rhash hash); | ||
|
||
int c_rhash_insert_str_ptr(c_rhash hash, const char *key, void *value); | ||
int c_rhash_insert_str_uint8(c_rhash hash, const char *key, uint8_t value); | ||
|
||
int c_rhash_get_ptr_by_str(c_rhash hash, const char *key, void **ret_val); | ||
int c_rhash_get_uint8_by_str(c_rhash hash, const char *key, uint8_t *ret_val); | ||
|
||
typedef struct { | ||
size_t bin; | ||
struct bin_item *item; | ||
int initialized; | ||
} c_rhash_iter_t; | ||
|
||
#define C_RHASH_ITER_T_INITIALIZER { .bin = 0, .item = NULL, .initialized = 0 } | ||
|
||
/* | ||
* goes trough whole hash map and returns every | ||
* type uint64 key present/stored | ||
* | ||
* it is not necessary to finish iterating and iterator can be reinitialized | ||
* there are no guarantees on the order in which the keys will come | ||
* behavior here is implementation dependent and can change any time | ||
* | ||
* returns: | ||
* 0 for every key and stores the key in *key | ||
* 1 on error or when all keys of this type has been already iterated over | ||
*/ | ||
int c_rhash_iter_uint64_keys(c_rhash hash, c_rhash_iter_t *iter, uint64_t *key); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
#include "c_rhash_internal.h" | ||
|
||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#ifdef DEBUG_VERBOSE | ||
#include <stdio.h> | ||
#endif | ||
|
||
#define c_rmalloc(...) malloc(__VA_ARGS__) | ||
#define c_rcalloc(...) calloc(__VA_ARGS__) | ||
#define c_rfree(...) free(__VA_ARGS__) | ||
|
||
static inline uint32_t simple_hash(const char *name) { | ||
unsigned char *s = (unsigned char *) name; | ||
uint32_t hval = 0x811c9dc5; | ||
while (*s) { | ||
hval *= 16777619; | ||
hval ^= (uint32_t) *s++; | ||
} | ||
return hval; | ||
} | ||
|
||
c_rhash c_rhash_new(size_t bin_count) { | ||
if (!bin_count) | ||
bin_count = 1000; | ||
|
||
c_rhash hash = c_rcalloc(1, sizeof(struct c_rhash_s) + (bin_count * sizeof(struct bin_ll*)) ); | ||
if (hash == NULL) | ||
return NULL; | ||
|
||
hash->bin_count = bin_count; | ||
hash->bins = (c_rhash_bin *)((char*)hash + sizeof(struct c_rhash_s)); | ||
|
||
return hash; | ||
} | ||
|
||
static size_t get_itemtype_len(uint8_t item_type, const void* item_data) { | ||
switch (item_type) { | ||
case ITEMTYPE_STRING: | ||
return strlen(item_data) + 1; | ||
case ITEMTYPE_UINT8: | ||
return 1; | ||
case ITEMTYPE_OPAQUE_PTR: | ||
return sizeof(void*); | ||
default: | ||
return 0; | ||
} | ||
} | ||
|
||
static int compare_bin_item(struct bin_item *item, uint8_t key_type, const void *key) { | ||
if (item->key_type != key_type) | ||
return 1; | ||
|
||
size_t key_value_len = get_itemtype_len(key_type, key); | ||
|
||
if(key_type == ITEMTYPE_STRING) { | ||
size_t new_key_value_len = get_itemtype_len(item->key_type, item->key); | ||
if (new_key_value_len != key_value_len) | ||
return 1; | ||
} | ||
|
||
if(memcmp(item->key, key, key_value_len) == 0) { | ||
return 0; | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
static int insert_into_bin(c_rhash_bin *bin, uint8_t key_type, const void *key, uint8_t value_type, const void *value) { | ||
struct bin_item *prev = NULL; | ||
while (*bin != NULL) { | ||
if (!compare_bin_item(*bin, key_type, key)) { | ||
#ifdef DEBUG_VERBOSE | ||
printf("Key already present! Updating value!\n"); | ||
#endif | ||
// TODO: optimize here if the new value is of different kind compared to the old one | ||
// in case it is not crazily bigger we can reuse the memory and avoid malloc and free | ||
c_rfree((*bin)->value); | ||
(*bin)->value_type = value_type; | ||
(*bin)->value = c_rmalloc(get_itemtype_len(value_type, value)); | ||
if ((*bin)->value == NULL) | ||
return 1; | ||
memcpy((*bin)->value, value, get_itemtype_len(value_type, value)); | ||
return 0; | ||
} | ||
prev = *bin; | ||
bin = &(*bin)->next; | ||
} | ||
|
||
if (*bin == NULL) | ||
*bin = c_rcalloc(1, sizeof(struct bin_item)); | ||
if (prev != NULL) | ||
prev->next = *bin; | ||
|
||
(*bin)->key_type = key_type; | ||
size_t len = get_itemtype_len(key_type, key); | ||
(*bin)->key = c_rmalloc(len); | ||
memcpy((*bin)->key, key, len); | ||
|
||
(*bin)->value_type = value_type; | ||
len = get_itemtype_len(value_type, value); | ||
(*bin)->value = c_rmalloc(len); | ||
memcpy((*bin)->value, value, len); | ||
return 0; | ||
} | ||
|
||
static inline uint32_t get_bin_idx_str(c_rhash hash, const char *key) { | ||
uint32_t nhash = simple_hash(key); | ||
return nhash % hash->bin_count; | ||
} | ||
|
||
static inline c_rhash_bin *get_binptr_by_str(c_rhash hash, const char *key) { | ||
return &hash->bins[get_bin_idx_str(hash, key)]; | ||
} | ||
|
||
int c_rhash_insert_str_ptr(c_rhash hash, const char *key, void *value) { | ||
c_rhash_bin *bin = get_binptr_by_str(hash, key); | ||
|
||
#ifdef DEBUG_VERBOSE | ||
if (bin != NULL) | ||
printf("COLLISION. There will be more than one item in bin idx=%d\n", nhash); | ||
#endif | ||
|
||
return insert_into_bin(bin, ITEMTYPE_STRING, key, ITEMTYPE_OPAQUE_PTR, &value); | ||
} | ||
|
||
int c_rhash_insert_str_uint8(c_rhash hash, const char *key, uint8_t value) { | ||
c_rhash_bin *bin = get_binptr_by_str(hash, key); | ||
|
||
#ifdef DEBUG_VERBOSE | ||
if (bin != NULL) | ||
printf("COLLISION. There will be more than one item in bin idx=%d\n", nhash); | ||
#endif | ||
|
||
return insert_into_bin(bin, ITEMTYPE_STRING, key, ITEMTYPE_UINT8, &value); | ||
} | ||
|
||
int c_rhash_get_uint8_by_str(c_rhash hash, const char *key, uint8_t *ret_val) { | ||
uint32_t nhash = get_bin_idx_str(hash, key); | ||
|
||
struct bin_item *bin = hash->bins[nhash]; | ||
|
||
while (bin) { | ||
if (bin->key_type == ITEMTYPE_STRING) { | ||
if (!strcmp(bin->key, key)) { | ||
*ret_val = *(uint8_t*)bin->value; | ||
return 0; | ||
} | ||
} | ||
bin = bin->next; | ||
} | ||
return 1; | ||
} | ||
|
||
int c_rhash_get_ptr_by_str(c_rhash hash, const char *key, void **ret_val) { | ||
uint32_t nhash = get_bin_idx_str(hash, key); | ||
|
||
struct bin_item *bin = hash->bins[nhash]; | ||
|
||
while (bin) { | ||
if (bin->key_type == ITEMTYPE_STRING) { | ||
if (!strcmp(bin->key, key)) { | ||
*ret_val = *((void**)bin->value); | ||
return 0; | ||
} | ||
} | ||
bin = bin->next; | ||
} | ||
return 1; | ||
} | ||
|
||
static void c_rhash_destroy_bin(c_rhash_bin bin) { | ||
struct bin_item *next; | ||
do { | ||
next = bin->next; | ||
c_rfree(bin->key); | ||
c_rfree(bin->value); | ||
c_rfree(bin); | ||
bin = next; | ||
} while (bin != NULL); | ||
} | ||
|
||
void c_rhash_destroy(c_rhash hash) { | ||
for (size_t i = 0; i < hash->bin_count; i++) { | ||
if (hash->bins[i] != NULL) | ||
c_rhash_destroy_bin(hash->bins[i]); | ||
} | ||
c_rfree(hash); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#include "c_rhash.h" | ||
|
||
struct bin_item { | ||
uint8_t key_type:4; | ||
void *key; | ||
uint8_t value_type:4; | ||
void *value; | ||
|
||
struct bin_item *next; | ||
}; | ||
|
||
typedef struct bin_item *c_rhash_bin; | ||
|
||
struct c_rhash_s { | ||
size_t bin_count; | ||
c_rhash_bin *bins; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#include "c_rhash.h" | ||
#include <stdio.h> | ||
|
||
#define KEY_1 "key1" | ||
#define KEY_2 "keya" | ||
|
||
int main(int argc, char *argv[]) { | ||
c_rhash hash = c_rhash_new(2); | ||
uint8_t val; | ||
c_rhash_insert_str_uint8(hash, KEY_1, 5); | ||
if(c_rhash_get_uint8_by_str(hash, KEY_1, &val)) | ||
printf(" key not found\n"); | ||
else | ||
printf(" value is %d\n", (int)val); | ||
c_rhash_insert_str_uint8(hash, KEY_2, 8); | ||
c_rhash_insert_str_uint8(hash, KEY_1, 6); | ||
|
||
if(c_rhash_get_uint8_by_str(hash, KEY_1, &val)) | ||
printf(" key not found\n"); | ||
else | ||
printf(" value is %d\n", (int)val); | ||
|
||
if(c_rhash_get_uint8_by_str(hash, KEY_2, &val)) | ||
printf(" key not found\n"); | ||
else | ||
printf(" value is %d\n", (int)val); | ||
c_rhash_destroy(hash); | ||
return 0; | ||
} |