Compare commits

..

No commits in common. "9daffd4ed1883ea50ae94b14275b46937cc348ce" and "5e4ae41113e63004bd131010853e5265b31302d3" have entirely different histories.

5 changed files with 241 additions and 459 deletions

2
.gitignore vendored
View file

@ -1,3 +1 @@
test test
.cache
compile_commands.json

View file

@ -8,8 +8,8 @@ Example of working with a singly linked list (sll):
char *a = "one"; char *a = "one";
char *b = "two"; char *b = "two";
ds_sll_t *ll = ds_sll_init(); ds_sll_t *ll = ds_sll_init();
ds_sll_append(ll, a); // [ "one" ] ds_sll_insert(ll, a); // [ "one" ]
ds_sll_append(ll, b); // [ "one", "two" ] ds_sll_insert(ll, b); // [ "one", "two" ]
ds_ll_foreach(ds_sll_t, ll) { ds_ll_foreach(ds_sll_t, ll) {
puts(cur->data); puts(cur->data);
// one // one
@ -45,20 +45,6 @@ ds_hmp_free(&hmp, NULL);
free(b); free(b);
``` ```
## Stack
```c
char *a = "a";
char *b = "b";
ds_stack_t *stack = ds_stack_init();
ds_stack_push(stack, a); // [ "a" ]
ds_stack_push(stack, b); // [ "b", "a" ]
ds_stack_peek(stack, 0); // "b"
ds_stack_pop(stack); // "b"
ds_stack_pop(stack); // "a"
free(stack);
```
# TODO # TODO
- [ ] more data structures - [ ] more data structures
- [x] tests - [x] tests

477
ds.c
View file

@ -6,13 +6,13 @@
ds_sll_t ds_sll_t
*ds_sll_init(void) *ds_sll_init(void)
{ {
return ds_sll_new_node(NULL); return ds_sll_new_node(NULL);
} }
ds_dll_t ds_dll_t
*ds_dll_init(void) *ds_dll_init(void)
{ {
return ds_dll_new_node(NULL); return ds_dll_new_node(NULL);
} }
ds_sll_t ds_sll_t
@ -40,227 +40,167 @@ ds_dll_t
} }
int int
ds_sll_add(ds_sll_t **ll, void *data, unsigned x) ds_sll_insert(ds_sll_t *ll, void *data)
{ {
int i; if (!ll || !data) {
ds_sll_t *cur, *prev, *new; return -1;
if (!ll || !data) { }
return -1;
}
for (i = 0, cur = *ll; cur; prev = cur, cur = cur->next, i++) { ds_ll_foreach(ds_sll_t, ll) {
if (i == x) { if (!cur->data) {
if (!cur->data) { cur->data = data;
cur->data = data; return 0;
return 0; } else if (!cur->next) {
} cur->next = ds_sll_new_node(data);
new = ds_sll_new_node(data); return 0;
new->next = cur; }
if (i == 0) { }
*ll = new;
} else {
prev->next = new;
}
return 0;
}
}
return -1; return -1;
} }
int int
ds_dll_add(ds_dll_t **ll, void *data, unsigned x) ds_dll_insert(ds_dll_t *ll, void *data)
{ {
int i; if (!ll || !data) {
ds_dll_t *cur, *new; return -1;
if (!ll || !data) { }
return -1;
}
for (i = 0, cur = *ll; cur; cur = cur->next, i++) { ds_ll_foreach(ds_dll_t, ll) {
if (i == x) { if (!cur->data) {
if (!cur->data) { cur->data = data;
cur->data = data; return 0;
return 0; } else if (!cur->next) {
} cur->next = ds_dll_new_node(data);
new = ds_dll_new_node(data); cur->next->prev = cur;
new->next = cur; return 0;
new->prev = cur->prev; }
cur->prev = new; }
if (i == 0) {
*ll = new;
} else {
cur->prev->next = new;
}
return 0;
}
}
return -1; return -1;
}
int
ds_sll_append(ds_sll_t *ll, void *data)
{
if (!ll || !data) {
return -1;
}
ds_ll_foreach(ds_sll_t, ll) {
if (!cur->data) {
cur->data = data;
return 0;
} else if (!cur->next) {
cur->next = ds_sll_new_node(data);
return 0;
}
}
return -1;
}
int
ds_dll_append(ds_dll_t *ll, void *data)
{
if (!ll || !data) {
return -1;
}
ds_ll_foreach(ds_dll_t, ll) {
if (!cur->data) {
cur->data = data;
return 0;
} else if (!cur->next) {
cur->next = ds_dll_new_node(data);
cur->next->prev = cur;
return 0;
}
}
return -1;
} }
void void
*ds_sll_remove(ds_sll_t **ll, unsigned idx) *ds_sll_remove(ds_sll_t **ll, unsigned idx)
{ {
int i; int i;
void *data; void *data;
ds_sll_t *cur, *rm; ds_sll_t *cur, *rm;
rm = NULL; rm = NULL;
if (!ll || !*ll) { if (!ll || !*ll) {
return NULL; return NULL;
} }
if (idx == 0) { if (idx == 0) {
rm = *ll; rm = *ll;
*ll = rm->next; *ll = rm->next;
} else { } else {
for (i = -1, cur = *ll; cur; i++, cur = cur->next) { for (i = -1, cur = *ll; cur; i++, cur = cur->next) {
if (idx == i + 1) { if (idx == i + 1) {
rm = cur->next; rm = cur->next;
break; break;
} }
} }
if (!rm) { if (!rm) {
return NULL; return NULL;
} }
cur->next = rm->next; cur->next = rm->next;
} }
data = rm->data; data = rm->data;
free(rm); free(rm);
return data; return data;
} }
void void
*ds_dll_remove(ds_dll_t **ll, unsigned idx) *ds_dll_remove(ds_dll_t **ll, unsigned idx)
{ {
int i; int i;
void *data; void *data;
ds_dll_t *cur, *rm; ds_dll_t *cur, *rm;
rm = NULL; rm = NULL;
if (!ll || !*ll) { if (!ll || !*ll) {
return NULL; return NULL;
} }
if (idx == 0) { if (idx == 0) {
rm = *ll; rm = *ll;
*ll = rm->next; *ll = rm->next;
if (rm->next) { if (rm->next) {
rm->next->prev = NULL; rm->next->prev = NULL;
} }
} else { } else {
for (i = 0, cur = *ll; cur; i++, cur = cur->next) { for (i = 0, cur = *ll; cur; i++, cur = cur->next) {
if (i == idx) { if (i == idx) {
rm = cur; rm = cur;
break; break;
} }
} }
if (!rm) { if (!rm) {
return NULL; return NULL;
} }
rm->prev->next = rm->next; rm->prev->next = rm->next;
if (rm->next) { if (rm->next) {
rm->next->prev = rm->prev; rm->next->prev = rm->prev;
} }
} }
data = rm->data; data = rm->data;
free(rm); free(rm);
return data; return data;
} }
ds_hmp_t ds_hmp_t
*ds_hmp_init(int data_len) *ds_hmp_init(int data_len)
{ {
ds_hmp_t *hmp; ds_hmp_t *hmp;
if (!data_len) { if (!data_len) {
return NULL; return NULL;
} }
hmp = calloc(1, sizeof(ds_hmp_t)); hmp = calloc(1, sizeof(ds_hmp_t));
hmp->data_len = data_len; hmp->data_len = data_len;
hmp->data = calloc(data_len, sizeof(ds_sll_t **)); hmp->data = calloc(data_len, sizeof(ds_sll_t **));
return hmp; return hmp;
} }
int int
ds_hmp_free(ds_hmp_t **hmp, void kv_callback(_ds_hmp_kv_t *kv)) ds_hmp_free(ds_hmp_t **hmp, void kv_callback(_ds_hmp_kv_t *kv))
{ {
int i; int i;
_ds_hmp_kv_t *kv; _ds_hmp_kv_t *kv;
ds_sll_t *ll; ds_sll_t *ll;
if (!hmp || !*hmp) { if (!hmp || !*hmp) {
return -1; return -1;
} }
for (i = 0; i < (*hmp)->data_len; i++) { for (i = 0; i < (*hmp)->data_len; i++) {
ll = (*hmp)->data[i]; ll = (*hmp)->data[i];
while (ll && ll->data) { while (ll && ll->data) {
if ((kv = ds_sll_remove(&ll, 0))) { if ((kv = ds_sll_remove(&ll, 0))) {
if (kv_callback) { if (kv_callback) {
kv_callback(kv); kv_callback(kv);
} }
free(kv); free(kv);
} }
} }
if (ll) { if (ll) {
free(ll); free(ll);
} }
} }
free((*hmp)->data); free((*hmp)->data);
free(*hmp); free(*hmp);
return 0; return 0;
} }
int int
@ -279,144 +219,91 @@ _ds_hmp_gen_hash(char *str)
int int
ds_hmp_insert(ds_hmp_t *hmp, char *key, void *data) ds_hmp_insert(ds_hmp_t *hmp, char *key, void *data)
{ {
_ds_hmp_kv_t *kv; _ds_hmp_kv_t *kv;
ds_sll_t *ll; ds_sll_t *ll;
unsigned hash_pos; unsigned hash_pos;
if (!hmp || !key || !data) { if (!hmp || !key || !data) {
return -1; return -1;
} }
kv = malloc(sizeof(_ds_hmp_kv_t)); kv = malloc(sizeof(_ds_hmp_kv_t));
kv->key = key; kv->key = key;
kv->val = data; kv->val = data;
hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len; hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len;
if (!hmp->data[hash_pos]) { if (!hmp->data[hash_pos]) {
hmp->data[hash_pos] = ds_sll_init(); hmp->data[hash_pos] = ds_sll_init();
if (!hmp->data[hash_pos]) { if (!hmp->data[hash_pos]) {
return -1; return -1;
} }
} }
/* get the ll and put the data into it */ /* get the ll and put the data into it */
ll = hmp->data[hash_pos]; ll = hmp->data[hash_pos];
if (ds_sll_append(ll, kv) != 0) { if (ds_sll_insert(ll, kv) != 0) {
return -1; return -1;
} }
return 0; return 0;
} }
void void
*ds_hmp_get(ds_hmp_t *hmp, char *key) *ds_hmp_get(ds_hmp_t *hmp, char *key)
{ {
ds_sll_t *cur, *ll; ds_sll_t *cur, *ll;
unsigned hash_pos; unsigned hash_pos;
if (!hmp || !key) { if (!hmp || !key) {
return NULL; return NULL;
} }
hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len; hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len;
ll = hmp->data[hash_pos]; ll = hmp->data[hash_pos];
if (!ll) { if (!ll) {
return NULL; return NULL;
} }
ds_ll_foreach(ds_sll_t, ll) { ds_ll_foreach(ds_sll_t, ll) {
if (strcmp(((_ds_hmp_kv_t *)cur->data)->key, key) == 0) { if (strcmp(((_ds_hmp_kv_t *)cur->data)->key, key) == 0) {
return ((_ds_hmp_kv_t *)cur->data)->val; return ((_ds_hmp_kv_t *)cur->data)->val;
} }
} }
return NULL; return NULL;
} }
void void
*ds_hmp_remove(ds_hmp_t *hmp, char *key) *ds_hmp_remove(ds_hmp_t *hmp, char *key)
{ {
int i; int i;
void *data; void *data;
unsigned hash_pos; unsigned hash_pos;
ds_sll_t *ll, *cur; ds_sll_t *ll, *cur;
_ds_hmp_kv_t *kv; _ds_hmp_kv_t *kv;
if (!hmp || !key) { if (!hmp || !key) {
return NULL; return NULL;
} }
hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len; hash_pos = _ds_hmp_gen_hash(key) % hmp->data_len;
ll = hmp->data[hash_pos]; ll = hmp->data[hash_pos];
if (!ll) { if (!ll) {
return NULL; return NULL;
} }
for (i = 0, cur = ll; cur; i++, cur = cur->next) { for (i = 0, cur = ll; cur; i++, cur = cur->next) {
if (strcmp(((_ds_hmp_kv_t *)cur->data)->key, key) == 0) { if (strcmp(((_ds_hmp_kv_t *)cur->data)->key, key) == 0) {
kv = ds_sll_remove(&ll, i); kv = ds_sll_remove(&ll, i);
hmp->data[hash_pos] = ll; hmp->data[hash_pos] = ll;
if (!kv) { if (!kv) {
return NULL; return NULL;
} }
data = kv->val; data = kv->val;
free(kv); free(kv);
return data; return data;
} }
} }
return NULL; return NULL;
}
ds_stack_t
*ds_stack_init(void)
{
ds_stack_t *stack = malloc(sizeof(ds_stack_t));
stack->n = 0;
return stack;
}
int
ds_stack_push(ds_stack_t *stack, void *data)
{
if (stack->n == 0) {
stack->items = ds_sll_new_node(data);
stack->n++;
return 0;
}
int r = ds_sll_add(&stack->items, data, 0);
if (!r) {
stack->n++;
}
return r;
}
void
*ds_stack_pop(ds_stack_t *stack)
{
void *r = ds_sll_remove(&stack->items, 0);
if (r != NULL) {
stack->n--;
}
return r;
}
void
*ds_stack_peek(ds_stack_t *stack, unsigned x)
{
int i;
ds_sll_t *cur;
if (x > stack->n) {
return NULL;
}
for (cur = stack->items, i = 0; cur; cur = cur->next, i++) {
if (i == x) {
return cur->data;
}
}
return NULL;
} }

76
ds.h
View file

@ -14,19 +14,14 @@ typedef struct _ds_dll {
typedef struct { typedef struct {
ds_sll_t **data; ds_sll_t **data;
unsigned data_len; unsigned data_len;
} ds_hmp_t; } ds_hmp_t;
typedef struct { typedef struct {
char *key; char *key;
void *val; void *val;
} _ds_hmp_kv_t; } _ds_hmp_kv_t;
typedef struct {
unsigned n;
ds_sll_t *items;
} ds_stack_t;
#define ds_ll_foreach(t, ll) for (t *cur = ll; cur; cur = cur->next) #define ds_ll_foreach(t, ll) for (t *cur = ll; cur; cur = cur->next)
/** /**
@ -60,46 +55,24 @@ ds_sll_t *ds_sll_new_node(void *data);
ds_dll_t *ds_dll_new_node(void *data); ds_dll_t *ds_dll_new_node(void *data);
/** /**
* @brief data to add at x of a singly linked list. This will use * @brief data to insert into a singly linked list. This will use
* ds_sll_new_node to create the node for you. * ds_sll_new_node to create the node for you.
* *
* @param ll singly linked list * @param ll singly linked list
* @param data data you want to add * @param data data you want to add
* @param x the position to add it at
* @return 0 on success * @return 0 on success
*/ */
int ds_sll_add(ds_sll_t **ll, void *data, unsigned x); int ds_sll_insert(ds_sll_t *ll, void *data);
/** /**
* @brief data to add at x of a doubly linked list. This will use * @brief data to insert into a doubly linked list. This will use
* ds_dll_new_node to create the node for you. * ds_sll_new_node to create the node for you.
* *
* @param ll doubly linked list * @param ll doubly linked list
* @param data data you want to add * @param data data you want to add
* @param x the position to add it at
* @return 0 on success * @return 0 on success
*/ */
int ds_dll_add(ds_dll_t **ll, void *data, unsigned x); int ds_dll_insert(ds_dll_t *ll, void *data);
/**
* @brief data to append to the end of a singly linked list. This will use
* ds_sll_new_node to create the node for you.
*
* @param ll singly linked list
* @param data data you want to append
* @return 0 on success
*/
int ds_sll_append(ds_sll_t *ll, void *data);
/**
* @brief data to append to the end of a doubly linked list. This will use
* ds_dll_new_node to create the node for you.
*
* @param ll doubly linked list
* @param data data you want to append
* @return 0 on success
*/
int ds_dll_append(ds_dll_t *ll, void *data);
/** /**
* @brief remove an index from a singly linked list * @brief remove an index from a singly linked list
@ -173,37 +146,4 @@ void *ds_hmp_get(ds_hmp_t *hmp, char *key);
*/ */
void *ds_hmp_remove(ds_hmp_t *hmp, char *key); void *ds_hmp_remove(ds_hmp_t *hmp, char *key);
/**
* @brief initialize a new stack
*
* @return the stack
*/
ds_stack_t *ds_stack_init(void);
/**
* @brief push new data onto the stack
*
* @param stack the stack
* @param data the data
* @return 0 on success
*/
int ds_stack_push(ds_stack_t *stack, void *data);
/**
* @brief pop the data off the top of the stack
*
* @param stack the stack
* @return the data
*/
void *ds_stack_pop(ds_stack_t *stack);
/**
* @brief peek forward x items
*
* @param stack the stack
* @param x how many items to look ahead
* @return the data or NULL if out of range
*/
void *ds_stack_peek(ds_stack_t *stack, unsigned x);
#endif #endif

127
test.c
View file

@ -1,102 +1,73 @@
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "ds.h" #include "ds.h"
#define test(name, tests) do { \ #define test(name, tests) do { \
const char *_test_name = name; \ const char *_test_name = name; \
int _tests_passed = 0; \ int _tests_passed = 0; \
int _tests = 0; \ int _tests = 0; \
tests \ tests \
_tests_passed += _tests; \ _tests_passed += _tests; \
printf("%s: %d/%d tests passed\n", name, _tests_passed, _tests); \ printf("%s: %d/%d tests passed\n", name, _tests_passed, _tests); \
} while (0) } while (0)
#define it(message, test) do { \ #define it(message, test) do { \
_tests++; \ _tests++; \
if (!(test)) { \ if (!(test)) { \
printf("%s %s FAILED @ %s:%d\n", _test_name, message, __FILE__, __LINE__); \ printf("%s %s FAILED\n", _test_name, message); \
printf(" -> test condition: (%s)\n", #test); \ _tests_passed--; \
_tests_passed--; \ } \
} \
} while (0) } while (0)
typedef struct { typedef struct {
int num; int num;
char *str; char *str;
} complex; } complex;
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
test("sll", test("sll",
char *a = "a"; char *a = "one";
char *b = "b";
ds_sll_t *tmp; ds_sll_t *tmp;
it("creates a new linked list", tmp = ds_sll_init()); it("ensures creates a new linked list", tmp = ds_sll_init());
free(tmp); free(tmp);
ds_sll_t *ll = ds_sll_new_node(a); ds_sll_t *ll = ds_sll_new_node(a);
it("appends an invalid item", ds_sll_append(ll, NULL) == -1); it("inserts an invalid item", ds_sll_insert(ll, NULL) == -1);
it("removes an invalid index", ds_sll_remove(&ll, 1234) == NULL); it("removes an invalid index", ds_sll_remove(&ll, 1234) == NULL);
it("adds an item to the beginning", ds_sll_add(&ll, b, 0) == 0); it("removes an item", a == ds_sll_remove(&ll, 0));
it("removes an item", b == ds_sll_remove(&ll, 0)); );
ds_sll_remove(&ll, 0);
);
test("dll", test("dll",
char *a = "a"; char *a = "one";
char *b = "b";
ds_dll_t *tmp; ds_dll_t *tmp;
it("creates a new linked list", tmp = ds_dll_init()); it("ensures creates a new linked list", tmp = ds_dll_init());
free(tmp); free(tmp);
ds_dll_t *ll = ds_dll_new_node(a); ds_dll_t *ll = ds_dll_new_node(a);
it("appends an invalid item", ds_dll_append(ll, NULL) == -1); it("inserts an invalid item", ds_dll_insert(ll, NULL) == -1);
it("removes an invalid index", ds_dll_remove(&ll, 1234) == NULL); it("removes an invalid index", ds_dll_remove(&ll, 1234) == NULL);
it("adds an item to the beginning", ds_dll_add(&ll, b, 0) == 0); it("removes an item", a == ds_dll_remove(&ll, 0));
it("removes an item", b == ds_dll_remove(&ll, 0)); );
ds_dll_remove(&ll, 0);
);
test("hmp", test("hmp",
complex *a = calloc(1, sizeof(complex)); complex *a = calloc(1, sizeof(complex));
a->num = 1; a->num = 1;
a->str = "abc"; a->str = "abc";
ds_hmp_t *hmp = ds_hmp_init(101); ds_hmp_t *hmp = ds_hmp_init(101);
it("inserts an item", ds_hmp_insert(hmp, a->str, a) == 0); it("inserts an item", ds_hmp_insert(hmp, a->str, a) == 0);
it("generates a hash", _ds_hmp_gen_hash("a") == 177670); it("generates a hash", _ds_hmp_gen_hash("a") == 177670);
it("removes a non-existent item", ds_hmp_remove(hmp, "???") == NULL); it("removes a non-existent item", ds_hmp_remove(hmp, "???") == NULL);
it("removes an invalid item", ds_hmp_remove(hmp, NULL) == NULL); it("removes an invalid item", ds_hmp_remove(hmp, NULL) == NULL);
it("removes an item", a == ds_hmp_remove(hmp, a->str)); it("removes an item", a == ds_hmp_remove(hmp, a->str));
ds_hmp_free(&hmp, NULL); ds_hmp_free(&hmp, NULL);
free(a); free(a);
); );
test("stack",
char *a = "a";
char *b = "b";
char *c = "c";
ds_stack_t *stack = ds_stack_init();
it("pushes an item", ds_stack_push(stack, a) == 0);
it("pops an item", ds_stack_pop(stack) == a);
ds_stack_push(stack, b);
ds_stack_push(stack, c);
it("peeks ahead", ds_stack_peek(stack, 0) == c);
it("peeks past the stack", ds_stack_peek(stack, INT_MAX) == NULL);
ds_stack_pop(stack);
ds_stack_pop(stack);
free(stack);
);
} }