diff --git a/rmutil/Makefile b/rmutil/Makefile index faba027..b203ed4 100644 --- a/rmutil/Makefile +++ b/rmutil/Makefile @@ -6,7 +6,7 @@ endif CFLAGS = -g -fPIC -lc -lm -O3 -std=gnu99 -I$(RM_INCLUDE_DIR) CC=gcc -OBJS=util.o strings.o sds.o +OBJS=util.o strings.o sds.o vector.o all: librmutil.a @@ -16,3 +16,8 @@ clean: librmutil.a: $(OBJS) ar rcs $@ $^ +test_vector: test_vector.o vector.o + $(CC) -o test_vector vector.o test_vector.o -lc -O0 + @(sh -c ./test_vector) + + diff --git a/rmutil/test_vector.c b/rmutil/test_vector.c new file mode 100644 index 0000000..3c32ad0 --- /dev/null +++ b/rmutil/test_vector.c @@ -0,0 +1,56 @@ +#include "vector.h" +#include +#include "assert.h" + +int main(int argc, char **argv) { + + + Vector *v = NewVector(int, 1); + + // Vector_Put(v, 0, 1); + // Vector_Put(v, 1, 3); + for (int i = 0; i < 10; i++) { + Vector_Push(v, i); + } + + for (int i = 0; i < Vector_Size(v); i++) { + int n; + int rc = Vector_Get(v, i, &n); + printf("%d %d\n", rc, n); + assert ( 1== rc ); + assert (n == i); + } + + Vector_Free(v); + + v = NewVector(char *, 0); + int N = 4; + char *strings[4] = {"hello", "world", "foo", "bar"}; + + for (int i = 0; i < N; i++) { + Vector_Push(v, strings[i]); + } + assert(Vector_Size(v) == N); + assert(Vector_Cap(v) >= N); + + for (int i = 0; i < Vector_Size(v); i++) { + char *x; + int rc = Vector_Get(v, i, &x); + assert (rc == 1); + assert (!strcmp(x, strings[i])); + } + + int rc = Vector_Get(v, 100, NULL); + assert (rc == 0); + + Vector_Free(v); + printf("PASS!"); + + return 0; + //Vector_Push(v, "hello"); + //Vector_Push(v, "world"); + // char *x = NULL; + // int rc = Vector_Getx(v, 0, &x); + // printf("rc: %d got %s\n", rc, x); + +} \ No newline at end of file diff --git a/rmutil/vector.c b/rmutil/vector.c new file mode 100644 index 0000000..9c8a531 --- /dev/null +++ b/rmutil/vector.c @@ -0,0 +1,64 @@ +#include "vector.h" +#include + + +int __vector_PushPtr(Vector *v, void *elem) { + if (v->top == v->cap - 1) { + Vector_Resize(v, v->cap ? v->cap*2 : 1); + } + + __vector_PutPtr(v, v->top, elem); + v->top++; + return v->top; +} + + +int Vector_Get(Vector *v, int pos, void *ptr) { + if (pos >= v->top) { + return 0; + } + memcpy(ptr, v->data + (pos * v->elemSize), v->elemSize); + return 1; +} + + +int __vector_PutPtr(Vector *v, int pos, void *elem) { + if (pos > v->cap) { + Vector_Resize(v, pos+1); + } + + memcpy(v->data + pos*v->elemSize, elem, v->elemSize); + if (pos > v->top) { + v->top = pos; + } + return 1; +} + + +int Vector_Resize(Vector *v, int newcap) { + int oldcap = v->cap; + v->cap = newcap; + + v->data = realloc(v->data, v->cap*v->elemSize); + int offset = v->top*v->elemSize; + memset(v->data + offset, 0, v->cap*v->elemSize - offset); + return v->cap; +} + + +Vector *__newVectorSize(size_t elemSize, size_t cap) { + printf("allocating %zd elems of %zd size\n", cap, elemSize); + Vector *vec = malloc(sizeof(Vector)); + vec->data = calloc(cap, elemSize); + vec->top = 0; + vec->elemSize = elemSize; + vec->cap = cap; + + return vec; +} + +void Vector_Free(Vector *v) { + free(v->data); + free(v); +} + \ No newline at end of file diff --git a/rmutil/vector.h b/rmutil/vector.h new file mode 100644 index 0000000..d88dac7 --- /dev/null +++ b/rmutil/vector.h @@ -0,0 +1,64 @@ +#ifndef __VECTOR_H__ +#define __VECTOR_H__ +#include +#include +#include + +/** +* Generic resizable vector that can be used if you just want to store stuff temporarily. +* Works like C++ std::vector with an underlying resizable buffer +*/ +typedef struct { + char *data; + int elemSize; + int cap; + int top; + int isPtr; +} Vector; + +// Create a new vector with element size. This should generally be used internall by the NewVector macro +Vector *__newVectorSize(size_t elemSize, size_t cap); + +// Put a pointer in the vector. To be used internall by the library +int __vector_PutPtr(Vector *v, int pos, void *elem); + +// Create a new vector for a given type and a given capacity. +// e.g. NewVector(int, 0) - empty vector of ints +#define NewVector(type, cap) __newVectorSize(sizeof(type), cap) + +// get the element at index pos. The value is copied in to ptr. If pos is outside the vector capacity, we return 0 +// otherwise 1 +int Vector_Get(Vector *v, int pos, void *ptr); + +//#define Vector_Getx(v, pos, ptr) pos < v->cap ? 1 : 0; *ptr = *(typeof(ptr))(v->data + v->elemSize*pos) + +// Put an element at pos. +// Note: If pos is outside the vector capacity, we resize it accordingly +#define Vector_Put(v, pos, elem) __vector_PutPtr(v, pos, &(typeof(elem)){elem}) + +// Push an element at the end of v, resizing it if needed. This macro wraps __vector_PushPtr +#define Vector_Push(v, elem) __vector_PushPtr(v, &(typeof(elem)){elem}) + +int __vector_PushPtr(Vector *v, void *elem); + +// resize capacity of v +int Vector_Resize(Vector *v, int newcap); + +// return the used size of the vector, regardless of capacity +inline int Vector_Size(Vector *v) { + return v->top; +} + +// return the actual capacity + inline int Vector_Cap(Vector *v) { + return v->cap; + } + + // free the vector and the underlying data. Does not release its elements if they are pointers + void Vector_Free(Vector *v); + + int __vecotr_PutPtr(Vector *v, int pos, void *elem); + + + +#endif \ No newline at end of file