diff --git a/examples/hm_basic.c b/examples/hm_basic.c new file mode 100644 index 0000000..7169bdf --- /dev/null +++ b/examples/hm_basic.c @@ -0,0 +1,25 @@ +#include +#define LAZY_IMPL +#include "../lazy.h" + +void printHmIdx(void *hm, int k) { + typedef Lz_HM(int,int) HM; + HM map = *(HM*)hm; + if (lz_hm_exists(map,k)) { + printf("hm[%d] = %d\n", k, lz_hm_get(map,k)); + } else { + printf("hm[%d] = \n", k); + } +} + +int main() { + Lz_HM(int, int) hm; + lz_hm_init(hm); + + lz_hm_add(hm, 1, 2); + lz_hm_add(hm, 2, 4); + + printf("Hello World!\n"); + printHmIdx(&hm, 1); + printHmIdx(&hm, 3); +} diff --git a/examples/hm_findsumpair.c b/examples/hm_findsumpair.c new file mode 100644 index 0000000..d91db96 --- /dev/null +++ b/examples/hm_findsumpair.c @@ -0,0 +1,33 @@ +#include +#define LAZY_IMPL +#include "../lazy.h" + +// This is some CS problem I heard of +// You need to find any two indecies in the array which add to k +// Hashmaps are the main way to solve this better than O(n^2) +int main() { + int vals[] = {7, 12, 25, 30, 43, 60, 1000, 50, 38, 62, 50}; + int N = sizeof(vals)/sizeof(vals[0]); + int K = 100; + + Lz_HM(int,size_t) LUT; + lz_hm_init(LUT); + + for (size_t i = 0; i < N; ++i) { + lz_hm_add(LUT, vals[i], i); + } + + for (size_t i = 0; i < N; ++i) { + int v = vals[i]; + int other = K-v; + if (lz_hm_exists(LUT, other)) { + size_t otherIdx = lz_hm_get(LUT, other); + if (otherIdx == i) continue; + printf("Found pair: idx: %zu, %zu, vals %d, %d\n", + i, otherIdx, + v, other); + break; + } + } + return 0; +} diff --git a/lazy.h b/lazy.h index 2b73820..14064bd 100644 --- a/lazy.h +++ b/lazy.h @@ -2,6 +2,7 @@ #include #include #include +#include #define LZ_STR_FMT "%.*s" #define LZ_STR_PRINTF(slc) (int)slc.cnt, slc.data @@ -18,6 +19,10 @@ void lz_drop_left(Lz_Slc *src, size_t n); void lz_drop_right(Lz_Slc *src, size_t n); void lz_split_slc(Lz_Slc *src, char delim, Lz_Slc *dst); void lz_split_slc_typ(Lz_Slc *src, int (*classfunc)(int), Lz_Slc *dst); +size_t lz_hm_hash_void_set(void *hmdat, size_t e_size, size_t cap, + void *key, size_t k_size); +size_t lz_hm_hash_void_get(void *hmdat, size_t e_size, size_t cap, + void *key, size_t k_size); Lz_Slc lz_cstr_to_slc(char *dat); char *lz_cstr_dup(const char *s); @@ -85,8 +90,109 @@ char *lz_cstr_dup(const char *s); typedef Lz_DA(char) Lz_SB; +#define Lz_HM_Pair(K_t, V_t) struct {\ + size_t exists;\ + K_t key;\ + V_t val;\ +} + +#define Lz_HM(K_t, V_t) struct {\ + size_t cap;\ + size_t cnt;\ + size_t valsize;\ + size_t entrysize;\ + size_t tmphash;\ + V_t defval;\ + K_t tmpkey;\ + V_t tmpval;\ + Lz_HM_Pair(K_t, V_t) *data;\ +} + +#define lz_hm_init(hm) do {\ + (hm).cap = 256;\ + (hm).cnt = 0;\ + (hm).valsize = sizeof((*(hm).data).val);\ + (hm).entrysize = sizeof(*(hm).data);\ + (hm).data = malloc((hm).cap*(hm).entrysize);\ +} while (0) + + +#define lz_hm_hash_set(hm, k) (\ + (hm).tmpkey = k,\ + lz_hm_hash_void_set((hm).data, (hm).entrysize,(hm.cap),\ + &(hm).tmpkey, sizeof((hm).tmpkey))\ +) +#define lz_hm_hash_get(hm, k) (\ + (hm).tmpkey = k,\ + lz_hm_hash_void_get((hm).data, (hm).entrysize,(hm.cap),\ + &(hm).tmpkey, sizeof((hm).tmpkey))\ +) + +#define lz_hm_exists(hm, k) (\ + (hm).tmphash = lz_hm_hash_get(hm, k),\ + ((hm).tmphash != (size_t)-1)\ +) + +#define lz_hm_get(hm, k) (\ + (hm).tmphash = lz_hm_hash_get(hm, k),\ + ((hm).tmphash == (size_t)-1) ? (hm).defval : ((hm).data[(hm).tmphash].val)\ +) + +#define lz_hm_add(hm, k, v) do {\ + size_t idx = lz_hm_hash_set(hm, k);\ + (hm).data[idx].key = k;\ + (hm).data[idx].val = v;\ +} while(0) + #ifdef LAZY_IMPL +size_t lz_hm_hash_void_get(void *hmdat, size_t e_size, size_t cap, + void *key, size_t k_size) { + size_t hash = 0; + for (size_t i = 0; i < k_size; ++i) { + size_t b = (size_t)(((uint8_t*)key)[i]); + hash += b*31415 + 9265; //bytewise hash + hash %= cap; + } + + for (size_t i = 0; i < cap; ++i) { + size_t localhash = (hash + i) % cap; + size_t structOffset = e_size*localhash; + void *pairStruct = (hmdat + structOffset); + void *structKey = pairStruct + sizeof(size_t); + int diff = memcmp(structKey, key, k_size); + if (diff == 0) { + return localhash; + } + + size_t istaken = *((size_t*)pairStruct); + if (!istaken) { + return (size_t)-1; + } + } + assert(0 && "Overflown Hashmap"); + return 0; +} + +size_t lz_hm_hash_void_set(void *hmdat, size_t e_size, size_t cap, + void *key, size_t k_size) { + size_t hash = 0; + for (size_t i = 0; i < k_size; ++i) { + size_t b = (size_t)(((uint8_t*)key)[i]); + hash += b*31415 + 9265; //bytewise hash + hash %= cap; + } + + for (size_t i = 0; i < cap; ++i) { + size_t localhash = (hash + i) % cap; + size_t structOffset = e_size*localhash; + void *pairStruct = (hmdat + structOffset); + size_t istaken = *((size_t*)pairStruct); + if (!istaken) return localhash; + } + return (size_t)-1; +} + // Horribly enough, strdup is a gnu extension // Here's a portable implementation char *lz_cstr_dup(const char *s) {