Added generic hashmaps and 2 examples using them
This commit is contained in:
parent
52d7e8a1c2
commit
0b34fb93a6
3 changed files with 164 additions and 0 deletions
25
examples/hm_basic.c
Normal file
25
examples/hm_basic.c
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#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/A>\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);
|
||||||
|
}
|
||||||
33
examples/hm_findsumpair.c
Normal file
33
examples/hm_findsumpair.c
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
106
lazy.h
106
lazy.h
|
|
@ -2,6 +2,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define LZ_STR_FMT "%.*s"
|
#define LZ_STR_FMT "%.*s"
|
||||||
#define LZ_STR_PRINTF(slc) (int)slc.cnt, slc.data
|
#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_drop_right(Lz_Slc *src, size_t n);
|
||||||
void lz_split_slc(Lz_Slc *src, char delim, Lz_Slc *dst);
|
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);
|
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);
|
Lz_Slc lz_cstr_to_slc(char *dat);
|
||||||
char *lz_cstr_dup(const char *s);
|
char *lz_cstr_dup(const char *s);
|
||||||
|
|
||||||
|
|
@ -85,8 +90,109 @@ char *lz_cstr_dup(const char *s);
|
||||||
|
|
||||||
typedef Lz_DA(char) Lz_SB;
|
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
|
#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
|
// Horribly enough, strdup is a gnu extension
|
||||||
// Here's a portable implementation
|
// Here's a portable implementation
|
||||||
char *lz_cstr_dup(const char *s) {
|
char *lz_cstr_dup(const char *s) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue