Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
underhood committed Dec 12, 2022
0 parents commit 3e637f9
Show file tree
Hide file tree
Showing 13 changed files with 1,717 additions and 0 deletions.
59 changes: 59 additions & 0 deletions .gitignore
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 added AUTHORS
Empty file.
674 changes: 674 additions & 0 deletions COPYING

Large diffs are not rendered by default.

Empty file added ChangeLog
Empty file.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions Makefile.am
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 added NEWS
Empty file.
Empty file added README.md
Empty file.
8 changes: 8 additions & 0 deletions configure.ac
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
45 changes: 45 additions & 0 deletions include/c_rhash.h
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);
190 changes: 190 additions & 0 deletions src/c_rhash.c
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);
}
17 changes: 17 additions & 0 deletions src/c_rhash_internal.h
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;
};
29 changes: 29 additions & 0 deletions src/tests.c
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;
}

0 comments on commit 3e637f9

Please sign in to comment.