feat: add stack
This commit is contained in:
@@ -9,6 +9,7 @@ A small, personal C library for learning and experimentation.
|
||||
- Thread-safe dynamic strings
|
||||
- Thread-safe circular queues
|
||||
- Thread-safe vectors
|
||||
- Stack
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ src = files(
|
||||
'queue/myqueue.c',
|
||||
'string/mystring.c',
|
||||
'vector/myvector.c',
|
||||
'stack/mystack.c',
|
||||
)
|
||||
|
||||
testlib = files(
|
||||
@@ -20,6 +21,7 @@ testlib = files(
|
||||
'test/string/str2.c',
|
||||
'test/string/str3.c',
|
||||
'test/vector/v1.c',
|
||||
'test/stack/s1.c',
|
||||
)
|
||||
|
||||
sources = src + testlib
|
||||
|
||||
88
stack/mystack.c
Normal file
88
stack/mystack.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "mystack.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <threads.h>
|
||||
|
||||
stack_s *stack_new(size_t initial_capacity, size_t element_size) {
|
||||
if (element_size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stack_s *stack = (stack_s *)malloc(sizeof(stack_s));
|
||||
if (stack == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mtx_init(&stack->lock, mtx_recursive) != thrd_success) {
|
||||
free(stack);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate the vec data */
|
||||
stack->data = vec_new(initial_capacity, element_size);
|
||||
if (stack->data == NULL) {
|
||||
free(stack);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stack->elem_size = element_size;
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
void *stack_pop(stack_s *stack) {
|
||||
if (stack == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mtx_lock(&stack->lock) != thrd_success) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *elem = vec_pop(stack->data);
|
||||
|
||||
mtx_unlock(&stack->lock);
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
int stack_push(stack_s *stack, void *elem) {
|
||||
if (stack == NULL || elem == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mtx_lock(&stack->lock) != thrd_success) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = vec_push(stack->data, elem);
|
||||
|
||||
mtx_unlock(&stack->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *stack_top(stack_s *stack) {
|
||||
if (stack == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mtx_lock(&stack->lock) != thrd_success) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *elem = vec_get(stack->data, stack->data->size - 1);
|
||||
|
||||
mtx_unlock(&stack->lock);
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
void stack_free(stack_s *stack) {
|
||||
if (stack == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec_free(stack->data);
|
||||
free(stack);
|
||||
}
|
||||
25
stack/mystack.h
Normal file
25
stack/mystack.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef MYCLIB_STACK_H
|
||||
#define MYCLIB_STACK_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <threads.h>
|
||||
|
||||
#include "../vector/myvector.h"
|
||||
|
||||
typedef struct stack {
|
||||
vec_s *data;
|
||||
size_t elem_size;
|
||||
mtx_t lock;
|
||||
} stack_s;
|
||||
|
||||
stack_s *stack_new(size_t initial_capacity, size_t element_size);
|
||||
|
||||
void *stack_pop(stack_s *stack);
|
||||
|
||||
int stack_push(stack_s *stack, void *elem);
|
||||
|
||||
void *stack_top(stack_s *stack);
|
||||
|
||||
void stack_free(stack_s *stack);
|
||||
|
||||
#endif
|
||||
23
test/stack/s1.c
Normal file
23
test/stack/s1.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../stack/mystack.h"
|
||||
|
||||
|
||||
void test_s1(void) {
|
||||
stack_s *stack = stack_new(32, sizeof(int));
|
||||
int num = 10;
|
||||
stack_push(stack, &num);
|
||||
|
||||
num = 13;
|
||||
stack_push(stack, &num);
|
||||
|
||||
int *rv = (int *)stack_top(stack);
|
||||
assert(*rv == 13);
|
||||
free(rv);
|
||||
|
||||
rv = (int *)stack_pop(stack);
|
||||
assert(*rv == 13);
|
||||
free(rv);
|
||||
|
||||
stack_free(stack);
|
||||
19
test/test.c
19
test/test.c
@@ -5,15 +5,17 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void test_hm1();
|
||||
void test_hm1(void);
|
||||
|
||||
void test_q1();
|
||||
void test_q1(void);
|
||||
|
||||
void test_str1();
|
||||
void test_str2();
|
||||
void test_str3();
|
||||
void test_str1(void);
|
||||
void test_str2(void);
|
||||
void test_str3(void);
|
||||
|
||||
void test_v1();
|
||||
void test_v1(void);
|
||||
|
||||
void test_s1(void);
|
||||
|
||||
int main(void) {
|
||||
puts("==== [Running Hashmap tests] ====");
|
||||
@@ -38,5 +40,10 @@ int main(void) {
|
||||
puts("OK!");
|
||||
puts("");
|
||||
|
||||
puts("==== [Running Stack tests] ====");
|
||||
test_s1();
|
||||
puts("OK!");
|
||||
puts("");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../vector/myvector.h"
|
||||
@@ -15,11 +14,12 @@ static void multiply(size_t index, void *elem) {
|
||||
e->age = e->age * 2;
|
||||
}
|
||||
|
||||
/* Another way to use foreach */
|
||||
/* Another way to use foreach
|
||||
static void print(size_t index, void *elem) {
|
||||
my_elem_s *e = (my_elem_s *)elem;
|
||||
printf("%s (%d)\n", e->name, e->age);
|
||||
}
|
||||
*/
|
||||
|
||||
/* Compare function used to sort */
|
||||
int my_cmp(const void *a, const void *b) {
|
||||
@@ -70,13 +70,10 @@ void test_v1() {
|
||||
/* Iterate for each element */
|
||||
vec_foreach(v, multiply);
|
||||
/* Print each element */
|
||||
puts("Before sort:");
|
||||
vec_foreach(v, print);
|
||||
// vec_foreach(v, print);
|
||||
|
||||
/* Sort */
|
||||
vec_sort(v, my_cmp);
|
||||
puts("After sort:");
|
||||
vec_foreach(v, print);
|
||||
|
||||
/* Deallocate the vector */
|
||||
vec_free(v);
|
||||
|
||||
@@ -305,7 +305,13 @@ int vec_sort(vec_s *vec, int (*cmp)(const void *a, const void *b)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mtx_lock(&vec->lock) != thrd_success) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
qsort(vec->data, vec->size, vec->elem_size, cmp);
|
||||
|
||||
mtx_unlock(&vec->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user