Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sc_map_shrink() #81

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion map/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ if (SC_BUILD_TEST)

add_executable(${PROJECT_NAME}_test map_test.c sc_map.c)

target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_MAP_MAX=140000ul)
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_MAP_MAX=262144ul)

if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND SC_USE_WRAP)
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
Expand Down
115 changes: 115 additions & 0 deletions map/map_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ void test_32()
assert(sc_map_found(&map));

sc_map_term_32(&map);

assert(sc_map_init_32(&map, 0, 0));
for (int i = 0; i < 128; i++) {
sc_map_put_32(&map, i, i);
}
for (int i = 0; i < 123; i++) {
sc_map_del_32(&map, i);
}
sc_map_shrink_32(&map);
assert(map.cap == 8);
sc_map_term_32(&map);

}

void test_64()
Expand Down Expand Up @@ -233,6 +245,17 @@ void test_64()
assert(sc_map_found(&map));

sc_map_term_64(&map);

assert(sc_map_init_64(&map, 0, 0));
for (int i = 0; i < 128; i++) {
sc_map_put_64(&map, i, i);
}
for (int i = 0; i < 123; i++) {
sc_map_del_64(&map, i);
}
sc_map_shrink_64(&map);
assert(map.cap == 8);
sc_map_term_64(&map);
}

void test_64v()
Expand Down Expand Up @@ -309,6 +332,17 @@ void test_64v()
assert(sc_map_found(&map));

sc_map_term_64v(&map);

assert(sc_map_init_64v(&map, 0, 0));
for (int i = 0; i < 128; i++) {
sc_map_put_64v(&map, i, "");
}
for (int i = 0; i < 123; i++) {
sc_map_del_64v(&map, i);
}
sc_map_shrink_64v(&map);
assert(map.cap == 8);
sc_map_term_64v(&map);
}

void test_64s()
Expand Down Expand Up @@ -384,6 +418,17 @@ void test_64s()
assert(sc_map_found(&map));

sc_map_term_64s(&map);

assert(sc_map_init_64s(&map, 0, 0));
for (int i = 0; i < 128; i++) {
sc_map_put_64s(&map, i, "");
}
for (int i = 0; i < 123; i++) {
sc_map_del_64s(&map, i);
}
sc_map_shrink_64s(&map);
assert(map.cap == 8);
sc_map_term_64s(&map);
}

void test_str()
Expand Down Expand Up @@ -489,6 +534,17 @@ void test_str()
assert(sc_map_found(&map));

sc_map_term_str(&map);

assert(sc_map_init_str(&map, 0, 0));
for (int i = 0; i < 15; i++) {
sc_map_put_str(&map, &arr[i], "");
}
for (int i = 0; i < 9; i++) {
sc_map_del_str(&map, &arr[i]);
}
sc_map_shrink_str(&map);
assert(map.cap == 8);
sc_map_term_str(&map);
}

void test_sv()
Expand Down Expand Up @@ -592,6 +648,17 @@ void test_sv()
assert(sc_map_found(&map));

sc_map_term_sv(&map);

assert(sc_map_init_sv(&map, 0, 0));
for (int i = 0; i < 15; i++) {
sc_map_put_sv(&map, &arr[i], "");
}
for (int i = 0; i < 9; i++) {
sc_map_del_sv(&map, &arr[i]);
}
sc_map_shrink_sv(&map);
assert(map.cap == 8);
sc_map_term_sv(&map);
}

void test_s64()
Expand Down Expand Up @@ -700,6 +767,18 @@ void test_s64()
assert(sc_map_found(&map));

sc_map_term_s64(&map);

assert(sc_map_init_s64(&map, 0, 0));
for (int i = 0; i < 15; i++) {
sc_map_put_s64(&map, &arr[i], i);
}
for (int i = 0; i < 9; i++) {
sc_map_del_s64(&map, &arr[i]);
}
sc_map_shrink_s64(&map);
assert(map.cap == 8);

sc_map_term_s64(&map);
}

void test0()
Expand Down Expand Up @@ -1526,6 +1605,41 @@ void fail_test_s64(void)
}
#endif

void shrink_test()
{
struct sc_map_32 map;

sc_map_init_32(&map, 0, 75);

for (int i = 0; i < 32; i++) {
sc_map_put_32(&map, i, i);
}

sc_map_shrink_32(&map);
assert(map.cap == 64);

for (int i = 0; i < 32; i++) {
sc_map_del_32(&map, i);
}

sc_map_shrink_32(&map);
assert(map.cap == 1);

for (int i = 0; i < 32; i++) {
sc_map_put_32(&map, i, i);
sc_map_shrink_32(&map);
}
assert(map.cap == 64);

for (int i = 0; i < 24; i++) {
sc_map_del_32(&map, i);
sc_map_shrink_32(&map);
}
assert(map.cap == 16);

sc_map_term_32(&map);
}

int main()
{
example();
Expand All @@ -1551,6 +1665,7 @@ int main()
test_str();
test_sv();
test_s64();
shrink_test();

return 0;
}
88 changes: 55 additions & 33 deletions map/sc_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@
#define SC_MAP_MAX UINT32_MAX
#endif

static uint32_t sc_map_pow2(uint32_t v)
{
if (v < 8) {
return 8;
}

v--;
for (uint32_t i = 1; i < sizeof(v) * 8; i *= 2) {
v |= v >> i;
}
v++;

return v;
}

#define sc_map_def_strkey(name, K, V, cmp, hash_fn) \
bool sc_map_cmp_##name(struct sc_map_item_##name *t, K key, \
uint32_t hash) \
Expand Down Expand Up @@ -90,25 +105,10 @@
.cap = 1, \
.mem = (struct sc_map_item_##name *) &empty_items_##name[1]}; \
\
static void *sc_map_alloc_##name(uint32_t *cap, uint32_t factor) \
static void *sc_map_alloc_##name(uint32_t cap) \
{ \
uint32_t v = *cap; \
struct sc_map_item_##name *t; \
\
if (*cap > SC_MAP_MAX / factor) { \
return NULL; \
} \
\
/* Find next power of two */ \
v = v < 8 ? 8 : (v * factor); \
v--; \
for (uint32_t i = 1; i < sizeof(v) * 8; i *= 2) { \
v |= v >> i; \
} \
v++; \
\
*cap = v; \
t = sc_map_calloc(sizeof(*t), v + 1); \
t = sc_map_calloc(sizeof(*t), cap + 1); \
return t ? &t[1] : NULL; \
} \
\
Expand All @@ -124,11 +124,12 @@
\
if (cap == 0) { \
*m = sc_map_empty_##name; \
m->load_fac = f; \
m->load_fac = ((double) f / 100); \
return true; \
} \
\
t = sc_map_alloc_##name(&cap, 1); \
cap = sc_map_pow2(cap); \
t = sc_map_alloc_##name(cap); \
if (t == NULL) { \
return false; \
} \
Expand All @@ -137,8 +138,8 @@
m->size = 0; \
m->used = false; \
m->cap = cap; \
m->load_fac = f; \
m->remap = (uint32_t) (m->cap * ((double) m->load_fac / 100)); \
m->load_fac = ((double) f / 100); \
m->remap = (uint32_t) (m->cap * m->load_fac); \
\
return true; \
} \
Expand Down Expand Up @@ -168,17 +169,12 @@
} \
} \
\
static bool sc_map_remap_##name(struct sc_map_##name *m) \
static bool sc_map_remap_##name(struct sc_map_##name *m, uint32_t cap) \
{ \
uint32_t pos, cap, mod; \
uint32_t pos, mod; \
struct sc_map_item_##name *new; \
\
if (m->size < m->remap) { \
return true; \
} \
\
cap = m->cap; \
new = sc_map_alloc_##name(&cap, 2); \
new = sc_map_alloc_##name(cap); \
if (new == NULL) { \
return false; \
} \
Expand Down Expand Up @@ -207,7 +203,7 @@
\
m->mem = new; \
m->cap = cap; \
m->remap = (uint32_t) (m->cap * ((double) m->load_fac / 100)); \
m->remap = (uint32_t) (m->cap * m->load_fac); \
\
return true; \
} \
Expand All @@ -219,9 +215,13 @@
\
m->oom = false; \
\
if (!sc_map_remap_##name(m)) { \
m->oom = true; \
return 0; \
if (m->size == m->remap) { \
if (m->cap == SC_MAP_MAX || \
!sc_map_remap_##name(m, \
sc_map_pow2(m->cap * 2))) { \
m->oom = true; \
return 0; \
} \
} \
\
if (key == 0) { \
Expand Down Expand Up @@ -336,6 +336,28 @@
\
return ret; \
} \
} \
\
void sc_map_shrink_##name(struct sc_map_##name *m) \
{ \
uint32_t v; \
\
if (m->size == 0) { \
uint32_t fac = m->load_fac; \
sc_map_term_##name(m); \
sc_map_init_##name(m, 0, fac); \
return; \
} \
\
m->oom = false; \
\
v = m->size + (uint32_t) (m->size * (1 - m->load_fac)); \
v = sc_map_pow2(v); \
if (v == m->cap) { \
return; \
} \
\
m->oom = !sc_map_remap_##name(m, v); \
}

static uint32_t sc_map_hash_32(uint32_t a)
Expand Down
12 changes: 10 additions & 2 deletions map/sc_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@
struct sc_map_item_##name *mem; \
uint32_t cap; \
uint32_t size; \
uint32_t load_fac; \
uint32_t remap; \
bool used; \
bool oom; \
bool found; \
double load_fac; \
}; \
\
/** \
Expand Down Expand Up @@ -111,6 +111,13 @@
*/ \
void sc_map_clear_##name(struct sc_map_##name *map); \
\
/** \
* Shrink underlying array in the hashmap if possible. \
* \
* @param map map \
*/ \
void sc_map_shrink_##name(struct sc_map_##name *map); \
\
/** \
* Put element to the map \
* \
Expand All @@ -129,7 +136,7 @@
* Get element \
* \
* @param map map \
* @param K key \ \
* @param K key \
* @return current value if exists. \
* call sc_map_found() to see if returned value if valid. \
*/ \
Expand Down Expand Up @@ -158,6 +165,7 @@
/**
* @param map map
* @return true if put operation failed with out of memory
* if shrink operation failed with out of memory
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d1

*/
#define sc_map_oom(map) ((map)->oom)

Expand Down