Skip to content

Commit

Permalink
Map API:
Browse files Browse the repository at this point in the history
* Fixed bug: avoid incrementing map size on value update
* Added map_itr_t family of functions

Stack API:
* Added stack_itr_t family of functions
  • Loading branch information
FedeDP committed Jul 15, 2019
1 parent 56d395a commit c6f5aed
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 11 deletions.
80 changes: 74 additions & 6 deletions Lib/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define MAP_PARAM_ASSERT(cond) MOD_RET_ASSERT(cond, MAP_WRONG_PARAM);
#define INITIAL_SIZE 256
#define MAX_CHAIN_LENGTH 8
#define MAP_ITR_INVALID -1

typedef struct {
const char *key;
Expand All @@ -28,6 +29,11 @@ struct _map {
map_dtor dtor;
};

struct _map_itr {
map_t *m;
int idx;
};

static unsigned long crc32(const unsigned char *s, unsigned int len);
static unsigned int hashmap_hash_int(const map_t *m, const char *keystring);
static int hashmap_hash(map_t *m, const char* key);
Expand Down Expand Up @@ -188,10 +194,15 @@ static map_ret_code hashmap_put(map_t *m, const char *key, void *value, const bo
/* Set the data */
m->data[index].data = value;
m->data[index].key = key;
m->data[index].in_use = true;
m->data[index].key_needs_free = needs_free;
m->data[index].val_needs_free = autofree;
m->size++;

/* In case of value update, avoid incrementing size */
if (! m->data[index].in_use) {
m->data[index].in_use = true;
m->size++;
}

return MAP_OK;
}

Expand Down Expand Up @@ -239,6 +250,63 @@ map_t *map_new(void) {
return m;
}

map_itr_t *map_itr_new(const map_t *m) {
MOD_RET_ASSERT(map_length(m) > 0, NULL);

map_itr_t *itr = memhook._malloc(sizeof(map_itr_t));
if (itr) {
itr->m = (map_t *)m;
itr->idx = MAP_ITR_INVALID;
itr = map_itr_next(itr); // find first used {key, value} pair
}
return itr;
}

map_itr_t *map_itr_next(map_itr_t *itr) {
MOD_RET_ASSERT(itr, NULL);

int i = itr->idx + 1;
itr->idx = MAP_ITR_INVALID;
for (; i < itr->m->table_size; i++) {
if (itr->m->data[i].in_use) {
itr->idx = i;
break;
}
}

/* Automatically free it */
if (itr->idx == MAP_ITR_INVALID) {
memhook._free(itr);
itr = NULL;
}
return itr;
}

map_ret_code map_itr_remove(const map_itr_t *itr) {
MAP_PARAM_ASSERT(itr);

clear_elem(itr->m, itr->idx);
return MAP_OK;
}

const char *map_itr_get_key(const map_itr_t *itr) {
MOD_RET_ASSERT(itr, NULL);

return itr->m->data[itr->idx].key;
}

void *map_itr_get_data(const map_itr_t *itr) {
MOD_RET_ASSERT(itr, NULL);

return itr->m->data[itr->idx].data;
}

map_ret_code map_itr_set_data(const map_itr_t *itr, void *value) {
MAP_PARAM_ASSERT(itr);

itr->m->data[itr->idx].data = value;
return MAP_OK;
}

/*
* Add a pointer to the hashmap with strdupped key if dupkey is true
Expand All @@ -256,8 +324,8 @@ map_ret_code map_put(map_t *m, const char *key, void *value, const bool dupkey,
* Get your pointer out of the hashmap with a key
*/
void *map_get(const map_t *m, const char *key) {
MOD_ASSERT(key, "Null key.", NULL);
MOD_ASSERT(map_length(m) > 0, "Empty or NULL map.", NULL);
MOD_RET_ASSERT(key, NULL);
MOD_RET_ASSERT(map_length(m) > 0, NULL);

/* Find data location */
int curr = hashmap_hash_int(m, key);
Expand All @@ -278,7 +346,7 @@ bool map_has_key(const map_t *m, const char *key) {

map_ret_code map_iterate(map_t *m, const map_cb fn, void *userptr) {
MAP_PARAM_ASSERT(fn);
MOD_ASSERT(map_length(m) > 0, "Empty or NULL map.", MAP_MISSING);
MOD_RET_ASSERT(map_length(m) > 0, MAP_MISSING);

/* Linear probing */
map_ret_code status = MAP_OK;
Expand All @@ -297,7 +365,7 @@ map_ret_code map_iterate(map_t *m, const map_cb fn, void *userptr) {
*/
map_ret_code map_remove(map_t *m, const char *key) {
MAP_PARAM_ASSERT(key);
MOD_ASSERT(map_length(m) > 0, "Empty or NULL map.", MAP_MISSING);
MOD_RET_ASSERT(map_length(m) > 0, MAP_MISSING);

/* Find key */
int curr = hashmap_hash_int(m, key);
Expand Down
9 changes: 9 additions & 0 deletions Lib/public/module/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,20 @@ typedef map_ret_code (*map_dtor)(void *);
/* Incomplete struct declaration for hashmap */
typedef struct _map map_t;

/* Incomplete struct declaration for hashmap iterator */
typedef struct _map_itr map_itr_t;

#ifdef __cplusplus
extern "C"{
#endif

_public_ map_t *map_new(void);
_public_ map_itr_t *map_itr_new(const map_t *m);
_public_ map_itr_t *map_itr_next(map_itr_t *itr);
_public_ map_ret_code map_itr_remove(const map_itr_t *itr);
_public_ const char *map_itr_get_key(const map_itr_t *itr);
_public_ void *map_itr_get_data(const map_itr_t *itr);
_public_ map_ret_code map_itr_set_data(const map_itr_t *itr, void *value);
_public_ map_ret_code map_iterate(map_t *m, const map_cb fn, void *userptr);
_public_ map_ret_code map_put(map_t *m, const char *key, void *value, const bool dupkey, const bool autofree);
_public_ void *map_get(const map_t *m, const char *key);
Expand Down
7 changes: 7 additions & 0 deletions Lib/public/module/stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@ typedef stack_ret_code(*stack_dtor)(void *);
/* Incomplete struct declaration for stack */
typedef struct _stack stack_t;

/* Incomplete struct declaration for stack iterator */
typedef struct _stack_itr stack_itr_t;

#ifdef __cplusplus
extern "C"{
#endif

_public_ stack_t *stack_new(void);
_public_ stack_itr_t *stack_itr_new(const stack_t *s);
_public_ stack_itr_t *stack_itr_next(stack_itr_t *itr);
_public_ void *stack_itr_get_data(const stack_itr_t *itr);
_public_ stack_ret_code stack_itr_set_data(const stack_itr_t *itr, void *value);
_public_ stack_ret_code stack_iterate(const stack_t *s, const stack_cb fn, void *userptr);
_public_ stack_ret_code stack_push(stack_t *s, void *data, bool autofree);
_public_ void *stack_pop(stack_t *s);
Expand Down
48 changes: 43 additions & 5 deletions Lib/stack.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "poll_priv.h"

#define STACK_PARAM_ASSERT(cond) MOD_RET_ASSERT(cond, STACK_WRONG_PARAM);
#define STACK_PARAM_ASSERT(cond) MOD_RET_ASSERT(cond, STACK_WRONG_PARAM);

typedef struct _elem {
void *userptr;
Expand All @@ -14,15 +14,53 @@ struct _stack {
stack_elem *data;
};

struct _stack_itr {
stack_elem *elem;
};

/** Public API **/

stack_t *stack_new(void) {
return memhook._calloc(1, sizeof(stack_t));
}

stack_itr_t *stack_itr_new(const stack_t *s) {
MOD_RET_ASSERT(stack_length(s) > 0, NULL);

stack_itr_t *itr = memhook._malloc(sizeof(stack_itr_t));
if (itr) {
itr->elem = s->data;
}
return itr;
}

stack_itr_t *stack_itr_next(stack_itr_t *itr) {
MOD_RET_ASSERT(itr, NULL);

itr->elem = itr->elem->prev;
if (!itr->elem) {
memhook._free(itr);
itr = NULL;
}
return itr;
}

void *stack_itr_get_data(const stack_itr_t *itr) {
MOD_RET_ASSERT(itr, NULL);

return itr->elem->userptr;
}

stack_ret_code stack_itr_set_data(const stack_itr_t *itr, void *value) {
STACK_PARAM_ASSERT(itr);

itr->elem->userptr = value;
return STACK_OK;
}

stack_ret_code stack_iterate(const stack_t *s, const stack_cb fn, void *userptr) {
STACK_PARAM_ASSERT(fn);
MOD_ASSERT(stack_length(s) > 0, "Empty or NULL stack.", STACK_MISSING);
MOD_RET_ASSERT(stack_length(s) > 0, STACK_MISSING);

stack_ret_code status = STACK_OK;
stack_elem *elem = s->data;
Expand Down Expand Up @@ -50,7 +88,7 @@ stack_ret_code stack_push(stack_t *s, void *data, bool autofree) {
}

void *stack_pop(stack_t *s) {
MOD_ASSERT(stack_length(s) > 0, "Empty or NULL stack.", NULL);
MOD_RET_ASSERT(stack_length(s) > 0, NULL);

stack_elem *elem = s->data;
s->data = s->data->prev;
Expand All @@ -61,13 +99,13 @@ void *stack_pop(stack_t *s) {
}

void *stack_peek(const stack_t *s) {
MOD_ASSERT(stack_length(s) > 0, "Empty or NULL stack.", NULL);
MOD_RET_ASSERT(stack_length(s) > 0, NULL);

return s->data->userptr; // return most recent element data
}

stack_ret_code stack_clear(stack_t *s) {
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);
STACK_PARAM_ASSERT(s);

stack_elem *elem = NULL;
while ((elem = s->data) && s->len > 0) {
Expand Down
11 changes: 11 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@
- [x] Rename pubsub_msg_t to ps_msg_t
- [x] Rename pubsub_priv_t to ps_priv_t

### Map
- [x] FIx: avoid incrementing map size on value update
- [x] Add map_itr_t interface
- [x] Add tests for new interface
- [ ] Add Doc

### Stack
- [X] Add stack_itr_t interface
- [x] Add tests for new interface
- [ ] Add Doc

### Generic
- [x] Add some diagnostic API, eg: module_dump() (to dump each module's state)
- [x] Add a module_load/unload function, to load a module from a compiled object at runtime
Expand Down
2 changes: 2 additions & 0 deletions tests/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ int main(void) {
cmocka_unit_test(test_map_put),
cmocka_unit_test(test_map_get),
cmocka_unit_test(test_map_length),
cmocka_unit_test(test_map_iterator),
cmocka_unit_test(test_map_remove),
cmocka_unit_test(test_map_clear),
cmocka_unit_test(test_map_free),
Expand All @@ -158,6 +159,7 @@ int main(void) {
cmocka_unit_test(test_stack_push),
cmocka_unit_test(test_stack_peek),
cmocka_unit_test(test_stack_length),
cmocka_unit_test(test_stack_iterator),
cmocka_unit_test(test_stack_pop),
cmocka_unit_test(test_stack_free)
};
Expand Down
20 changes: 20 additions & 0 deletions tests/test_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,26 @@ void test_map_length(void **state) {
assert_int_equal(len, 2);
}

void test_map_iterator(void **state) {
(void) state; /* unused */

/* NULL map */
map_itr_t *itr = map_itr_new(NULL);
assert_null(itr);

itr = map_itr_new(my_map);
assert_non_null(itr);

int count = map_length(my_map);
while (itr) {
count--;
printf("%s -> %p\n", map_itr_get_key(itr), map_itr_get_data(itr));
itr = map_itr_next(itr);
}

assert_int_equal(count, 0);
}

void test_map_remove(void **state) {
(void) state; /* unused */

Expand Down
1 change: 1 addition & 0 deletions tests/test_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
void test_map_put(void **state);
void test_map_get(void **state);
void test_map_length(void **state);
void test_map_iterator(void **state);
void test_map_remove(void **state);
void test_map_clear(void **state);
void test_map_free(void **state);
20 changes: 20 additions & 0 deletions tests/test_stack.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ void test_stack_length(void **state) {
assert_int_equal(len, 3);
}

void test_stack_iterator(void **state) {
(void) state; /* unused */

/* NULL stack */
stack_itr_t *itr = stack_itr_new(NULL);
assert_null(itr);

itr = stack_itr_new(my_st);
assert_non_null(itr);

int count = stack_length(my_st);
while (itr) {
count--;
printf("%p\n", stack_itr_get_data(itr));
itr = stack_itr_next(itr);
}

assert_int_equal(count, 0);
}

void test_stack_pop(void **state) {
(void) state; /* unused */

Expand Down
1 change: 1 addition & 0 deletions tests/test_stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
void test_stack_push(void **state);
void test_stack_peek(void **state);
void test_stack_length(void **state);
void test_stack_iterator(void **state);
void test_stack_pop(void **state);
void test_stack_free(void **state);

0 comments on commit c6f5aed

Please sign in to comment.