diff --git a/cthreads.c b/cthreads.c index ed56e13..cd370b2 100644 --- a/cthreads.c +++ b/cthreads.c @@ -1,172 +1,198 @@ -#include "cthreads.h" - -typedef struct { - cthread_func_t func; - void *arg; -} _thr_internal_t; - -#ifdef _WIN32 -#define VC_EXTRALEAN -#include - -// == THREAD =========================================== - -static DWORD _thrFuncInternal(void *arg) { - _thr_internal_t *params = (_thr_internal_t *)arg; - cthread_func_t func = params->func; - void *argument = params->arg; - free(params); - return (DWORD)func(argument); -} - -cthread_t thrCreate(cthread_func_t func, void *arg) { - HANDLE thread = INVALID_HANDLE_VALUE; - _thr_internal_t *params = malloc(sizeof(_thr_internal_t)); - - if(params) { - params->func = func; - params->arg = arg; - - thread = CreateThread(NULL, 0, _thrFuncInternal, params, 0, NULL); - } - - return (cthread_t)thread; -} - -bool thrValid(cthread_t ctx) { - return (HANDLE)ctx != INVALID_HANDLE_VALUE; -} - -bool thrDetach(cthread_t ctx) { - return CloseHandle((HANDLE)ctx); -} - -cthread_t thrCurrent(void) { - return (cthread_t)GetCurrentThread(); -} - -int thrCurrentId(void) { - return GetCurrentThreadId(); -} - -int thrGetId(cthread_t ctx) { - return GetThreadId((HANDLE)ctx); -} - -void thrExit(int code) { - ExitThread(code); -} - -bool thrJoin(cthread_t ctx, int *code) { - if(!ctx) return false; - int return_code = WaitForSingleObject((HANDLE)ctx, INFINITE); - if(code) *code = return_code; - BOOL success = CloseHandle((HANDLE)ctx); - return return_code != WAIT_FAILED && success; -} - -// == MUTEX ============================================ - -cmutex_t mtxInit(void) { - CRITICAL_SECTION *crit_sec = malloc(sizeof(CRITICAL_SECTION)); - if(crit_sec) { - InitializeCriticalSection(crit_sec); - } - return (cmutex_t)crit_sec; - // return (cmutex_t)CreateMutexW(NULL, false, NULL); -} - -void mtxDestroy(cmutex_t ctx) { - DeleteCriticalSection((CRITICAL_SECTION *)ctx); - // CloseHandle((HANDLE)ctx); -} - -bool mtxValid(cmutex_t ctx) { - return (void *)ctx != NULL; -} - -bool mtxLock(cmutex_t ctx) { - EnterCriticalSection((CRITICAL_SECTION *)ctx); - return true; - // DWORD result = WaitForSingleObject((HANDLE)ctx, INFINITE); - // // TODO maybe remove abandoned? or return a enum? it'll hurt usability tho - // return result == WAIT_OBJECT_0 || result == WAIT_ABANDONED; -} - -bool mtxTryLock(cmutex_t ctx) { - return TryEnterCriticalSection((CRITICAL_SECTION *)ctx); - // int result = mtxTimedLock(ctx, 0); - // if(result == CMTX_TIMEDOUT) return CMTX_BUSY; - // return result; -} - -bool mtxUnlock(cmutex_t ctx) { - LeaveCriticalSection((CRITICAL_SECTION *)ctx); - return true; - // return ReleaseMutex((HANDLE)ctx); -} - - -#else -#include -#include -#include -#include -#include - -#define INT_TO_VOIDP(a) ((void *)((uintptr_t)(a))) - -static void *_thrFuncInternal(void *arg) { - _thr_internal_t *params = (_thr_internal_t *)arg; - cthread_func_t func = params->func; - void *argument = params->arg; - free(params); - return INT_TO_VOIDP(func(argument)); -} - -cthread_t thrCreate(cthread_func_t func, void *arg) { - pthread_t handle = (pthread_t)NULL; - - _thr_internal_t *params = malloc(sizeof(_thr_internal_t)); - - if(params) { - params->func = func; - params->arg = arg; - - int result = pthread_create(&handle, NULL, _thrFuncInternal, params); - if(result) handle = (pthread_t)NULL; - } - - return (cthread_t)handle; -} - -bool thrValid(cthread_t ctx) { - return (void *)ctx != NULL; -} - -bool thrDetach(cthread_t ctx) { - return pthread_detach((pthread_t)ctx) == 0; -} - -cthread_t thrCurrent(void) { - return (cthread_t)pthread_self(); -} - -int thrCurrentId(void) { - return (int)pthread_self(); -} - -int thrGetId(cthread_t ctx) { - return (int)ctx; -} - -void thrExit(int code) { - pthread_exit(INT_TO_VOIDP(code)); -} - -bool thrJoin(cthread_t ctx, int *code) { - void *result = code; - return pthread_join((pthread_t)ctx, &result) != 0; -} - +#include "cthreads.h" + +typedef struct { + cthread_func_t func; + void *arg; +} _thr_internal_t; + +#ifdef _WIN32 +#define VC_EXTRALEAN +#include + +// == THREAD =========================================== + +static DWORD _thrFuncInternal(void *arg) { + _thr_internal_t *params = (_thr_internal_t *)arg; + cthread_func_t func = params->func; + void *argument = params->arg; + free(params); + return (DWORD)func(argument); +} + +cthread_t thrCreate(cthread_func_t func, void *arg) { + HANDLE thread = INVALID_HANDLE_VALUE; + _thr_internal_t *params = malloc(sizeof(_thr_internal_t)); + + if(params) { + params->func = func; + params->arg = arg; + + thread = CreateThread(NULL, 0, _thrFuncInternal, params, 0, NULL); + } + + return (cthread_t)thread; +} + +bool thrValid(cthread_t ctx) { + return (HANDLE)ctx != INVALID_HANDLE_VALUE; +} + +bool thrDetach(cthread_t ctx) { + return CloseHandle((HANDLE)ctx); +} + +cthread_t thrCurrent(void) { + return (cthread_t)GetCurrentThread(); +} + +int thrCurrentId(void) { + return GetCurrentThreadId(); +} + +int thrGetId(cthread_t ctx) { + return GetThreadId((HANDLE)ctx); +} + +void thrExit(int code) { + ExitThread(code); +} + +bool thrJoin(cthread_t ctx, int *code) { + if(!ctx) return false; + int return_code = WaitForSingleObject((HANDLE)ctx, INFINITE); + if(code) *code = return_code; + BOOL success = CloseHandle((HANDLE)ctx); + return return_code != WAIT_FAILED && success; +} + +// == MUTEX ============================================ + +cmutex_t mtxInit(void) { + CRITICAL_SECTION *crit_sec = malloc(sizeof(CRITICAL_SECTION)); + if(crit_sec) { + InitializeCriticalSection(crit_sec); + } + return (cmutex_t)crit_sec; +} + +void mtxDestroy(cmutex_t ctx) { + DeleteCriticalSection((CRITICAL_SECTION *)ctx); +} + +bool mtxValid(cmutex_t ctx) { + return (void *)ctx != NULL; +} + +bool mtxLock(cmutex_t ctx) { + EnterCriticalSection((CRITICAL_SECTION *)ctx); + return true; +} + +bool mtxTryLock(cmutex_t ctx) { + return TryEnterCriticalSection((CRITICAL_SECTION *)ctx); +} + +bool mtxUnlock(cmutex_t ctx) { + LeaveCriticalSection((CRITICAL_SECTION *)ctx); + return true; +} + + +#else +#include +#include +#include +#include +#include + +// == THREAD =========================================== + +#define INT_TO_VOIDP(a) ((void *)((uintptr_t)(a))) + +static void *_thrFuncInternal(void *arg) { + _thr_internal_t *params = (_thr_internal_t *)arg; + cthread_func_t func = params->func; + void *argument = params->arg; + free(params); + return INT_TO_VOIDP(func(argument)); +} + +cthread_t thrCreate(cthread_func_t func, void *arg) { + pthread_t handle = (pthread_t)NULL; + + _thr_internal_t *params = malloc(sizeof(_thr_internal_t)); + + if(params) { + params->func = func; + params->arg = arg; + + int result = pthread_create(&handle, NULL, _thrFuncInternal, params); + if(result) handle = (pthread_t)NULL; + } + + return (cthread_t)handle; +} + +bool thrValid(cthread_t ctx) { + return (void *)ctx != NULL; +} + +bool thrDetach(cthread_t ctx) { + return pthread_detach((pthread_t)ctx) == 0; +} + +cthread_t thrCurrent(void) { + return (cthread_t)pthread_self(); +} + +int thrCurrentId(void) { + return (int)pthread_self(); +} + +int thrGetId(cthread_t ctx) { + return (int)ctx; +} + +void thrExit(int code) { + pthread_exit(INT_TO_VOIDP(code)); +} + +bool thrJoin(cthread_t ctx, int *code) { + void *result = code; + return pthread_join((pthread_t)ctx, &result) != 0; +} + +// == MUTEX ============================================ + +cmutex_t mtxInit(void) { + pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t)); + + if(mutex) { + int res = pthread_mutex_init(mutex, NULL); + if(res != 0) mutex = NULL; + } + + return (cmutex_t)mutex; +} + +void mtxDestroy(cmutex_t ctx) { + pthread_mutex_destroy((pthread_mutex_t *)ctx); +} + +bool mtxValid(cmutex_t ctx) { + return (void *)ctx != NULL; +} + +bool mtxLock(cmutex_t ctx) { + return pthread_mutex_lock((pthread_mutex_t *)ctx) == 0; +} + +bool mtxTryLock(cmutex_t ctx) { + return pthread_mutex_trylock((pthread_mutex_t *)ctx) == 0; +} + +bool mtxUnlock(cmutex_t ctx) { + return pthread_mutex_unlock((pthread_mutex_t *)ctx) == 0; +} + #endif \ No newline at end of file diff --git a/cthreads.h b/cthreads.h index e91f792..dbe5675 100644 --- a/cthreads.h +++ b/cthreads.h @@ -1,42 +1,42 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -// == THREAD =========================================== - -typedef uintptr_t cthread_t; - -typedef int (*cthread_func_t)(void *); - -cthread_t thrCreate(cthread_func_t func, void *arg); -bool thrValid(cthread_t ctx); -bool thrDetach(cthread_t ctx); - -cthread_t thrCurrent(void); -int thrCurrentId(void); -int thrGetId(cthread_t ctx); - -void thrExit(int code); -bool thrJoin(cthread_t ctx, int *code); - -// == MUTEX ============================================ - -typedef uintptr_t cmutex_t; - -cmutex_t mtxInit(void); -void mtxDestroy(cmutex_t ctx); - -bool mtxValid(cmutex_t ctx); - -bool mtxLock(cmutex_t ctx); -bool mtxTryLock(cmutex_t ctx); -bool mtxUnlock(cmutex_t ctx); - -#ifdef __cplusplus -} // extern "C" +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +// == THREAD =========================================== + +typedef uintptr_t cthread_t; + +typedef int (*cthread_func_t)(void *); + +cthread_t thrCreate(cthread_func_t func, void *arg); +bool thrValid(cthread_t ctx); +bool thrDetach(cthread_t ctx); + +cthread_t thrCurrent(void); +int thrCurrentId(void); +int thrGetId(cthread_t ctx); + +void thrExit(int code); +bool thrJoin(cthread_t ctx, int *code); + +// == MUTEX ============================================ + +typedef uintptr_t cmutex_t; + +cmutex_t mtxInit(void); +void mtxDestroy(cmutex_t ctx); + +bool mtxValid(cmutex_t ctx); + +bool mtxLock(cmutex_t ctx); +bool mtxTryLock(cmutex_t ctx); +bool mtxUnlock(cmutex_t ctx); + +#ifdef __cplusplus +} // extern "C" #endif \ No newline at end of file diff --git a/vec.h b/vec.h index 07493b2..ffdeda7 100644 --- a/vec.h +++ b/vec.h @@ -1,603 +1,603 @@ -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include - -/* - * Basic usage: - * #define T int - * // optional, if not defined all the names will be longer, e.g. - * // vec_int_t v = vec_intInit(); - * #define VEC_SHORT_NAME veci - * #include // undefines T - * [...] - * veci_t v = veciInit(); - * veciPush(&v, 10); - * veciEraseAt(&v, 0); - * veciFree(&v); - */ - -typedef int( *vec_cmp_fn_t)(const void *, const void *); - -#ifndef T -#error "Must define T before including vec.h" -#endif - -#define VEC_CAT(a, b) a ## b -#define VEC_PASTE(a, b) VEC_CAT(a, b) -#define TYPE(prefix, type) VEC_PASTE(VEC_PASTE(prefix, _), VEC_PASTE(type, _t)) -#define ITER(prefix, type) VEC_PASTE(VEC_PASTE(prefix, _), VEC_PASTE(type, _it_t)) - -#ifdef VEC_SHORT_NAME - #define VEC_T VEC_PASTE(VEC_SHORT_NAME, _t) - #define VEC_IT_T VEC_PASTE(VEC_SHORT_NAME, _it_t) - #define VEC VEC_SHORT_NAME -#else - #define VEC_T TYPE(vec, T) - #define VEC_IT_T ITER(vec, T) - #define VEC VEC_PASTE(vec, VEC_PASTE(_, T)) -#endif - -#define FUN(postfix) VEC_PASTE(VEC, postfix) - -#ifndef VEC_NO_DECLARATION - -typedef struct { - T *buf; - size_t size; - size_t allocated; -} VEC_T; - -#define vec_foreach(type, name, it, vec) \ - for(type *it = VEC_PASTE(name, Beg)(&vec); it < VEC_PASTE(name, End)(&vec); ++it) - -VEC_T FUN(Init)(void); -VEC_T FUN(InitArr)(T *arr, size_t len); -void FUN(Free)(VEC_T *ctx); - -VEC_T FUN(Move)(VEC_T *ctx); -VEC_T FUN(Copy)(VEC_T *ctx); - -T *FUN(Beg)(VEC_T *ctx); -T *FUN(End)(VEC_T *ctx); -T *FUN(Back)(VEC_T *ctx); -bool FUN(Empty)(VEC_T *ctx); - -void FUN(Realloc)(VEC_T *ctx, size_t needed); -void FUN(Reserve)(VEC_T *ctx, size_t newsize); -void FUN(ShrinkToFit)(VEC_T *ctx); - -void FUN(Clear)(VEC_T *ctx); -void FUN(ClearZero)(VEC_T *ctx); - -void FUN(InsertAt)(VEC_T *ctx, size_t index, T val); -void FUN(InsertAfter)(VEC_T *ctx, T *it, T val); -void FUN(InsertBefore)(VEC_T *ctx, T *it, T val); - -void FUN(InsertAtSw)(VEC_T *ctx, size_t index, T val); -void FUN(InsertAfterSw)(VEC_T *ctx, T *it, T val); -void FUN(InsertBeforeSw)(VEC_T *ctx, T *it, T val); - -// swaps with last -void FUN(Erase)(VEC_T *ctx, T *it); -void FUN(EraseAt)(VEC_T *ctx, size_t index); -// moves whole array back one -void FUN(EraseMv)(VEC_T *ctx, T *it); -void FUN(EraseAtMv)(VEC_T *ctx, size_t index); - -void FUN(Push)(VEC_T *ctx, T val); -void FUN(PushRef)(VEC_T *ctx, T *val); -T FUN(Pop)(VEC_T *ctx); - -void FUN(Resize)(VEC_T *ctx, size_t newcount, T val); -void FUN(ResizeRef)(VEC_T *ctx, size_t newcount, T *val); - -void FUN(EraseWhen)(VEC_T *ctx, T val); - -typedef bool (*TYPE(vec_erase_fn, T))(const T *val, void *udata); -void FUN(EraseIf)(VEC_T *ctx, TYPE(vec_erase_fn, T) cmp, void *udata); -void FUN(EraseIfMv)(VEC_T *ctx, TYPE(vec_erase_fn, T) cmp, void *udata); - -// typedef int (*TYPE(vec_sort_fn, T))(const T *a, const T *b); -void FUN(Sort)(VEC_T *ctx, vec_cmp_fn_t cmp); - -#endif // VEC_NO_DECLARATION - -#ifndef VEC_NO_IMPLEMENTATION - -inline -VEC_T FUN(Init)(void) { - return (VEC_T){ - .buf = NULL, - .size = 0, - .allocated = 0 - }; -} - -inline -VEC_T FUN(InitArr)(T *arr, size_t len) { - VEC_T v = FUN(Init)(); - FUN(Realloc)(&v, len); - memcpy(v.buf, arr, len * sizeof(T)); - v.size = len; - return v; -} - -inline -void FUN(Free)(VEC_T *ctx) { - free(ctx->buf); - ctx->buf = NULL; - ctx->size = 0; - ctx->allocated = 0; -} - -inline -VEC_T FUN(Move)(VEC_T *ctx) { - VEC_T mv = *ctx; - ctx->buf = NULL; - FUN(Free)(ctx); - return mv; -} - -inline -VEC_T FUN(Copy)(VEC_T *ctx) { - VEC_T cp = FUN(Init)(); - if(ctx->buf) { - FUN(Reserve)(&cp, ctx->size); - memcpy(cp.buf, ctx->buf, ctx->size * sizeof(T)); - cp.size = ctx->size; - } - return cp; -} - -inline -T *FUN(Beg)(VEC_T *ctx) { - return ctx->buf; -} - -inline -T *FUN(End)(VEC_T *ctx) { - return ctx->buf + ctx->size; -} - -inline -T *FUN(Back)(VEC_T *ctx) { - return ctx->buf ? &ctx->buf[ctx->size - 1] : NULL; -} - -inline -bool FUN(Empty)(VEC_T *ctx) { - return ctx->buf ? ctx->size == 0 : true; -} - -inline -void FUN(Realloc)(VEC_T *ctx, size_t needed) { - if((ctx->size + needed) >= ctx->allocated) { - ctx->allocated = (ctx->allocated * 2) + needed; - ctx->buf = (T *)realloc(ctx->buf, ctx->allocated * sizeof(T)); - } -} - -inline -void FUN(Reserve)(VEC_T *ctx, size_t newsize) { - if(ctx->allocated < newsize) { - ctx->allocated = newsize; - ctx->buf = (T *)realloc(ctx->buf, ctx->allocated * sizeof(T)); - } -} - -inline -void FUN(ShrinkToFit)(VEC_T *ctx) { - ctx->allocated = ctx->size; - ctx->buf = (T *)realloc(ctx->buf, ctx->allocated * sizeof(T)); -} - -inline -void FUN(Clear)(VEC_T *ctx) { - ctx->size = 0; -} - -inline -void FUN(ClearZero)(VEC_T *ctx) { - ctx->size = 0; - memset(ctx->buf, 0, ctx->allocated * sizeof(T)); -} - -inline -void FUN(InsertAt)(VEC_T *ctx, size_t index, T val) { - FUN(Realloc)(ctx, 1); - for(size_t i = ctx->size; i > index; --i) { - ctx->buf[i] = ctx->buf[i - 1]; - } - ctx->buf[index] = val; - ctx->size++; -} - -inline -void FUN(InsertAfter)(VEC_T *ctx, T *it, T val) { - size_t index = it - ctx->buf; - // insertAt acts as insertBefore, so we just add 1 - FUN(InsertAt)(ctx, index + 1, val); -} - -inline -void FUN(InsertBefore)(VEC_T *ctx, T *it, T val) { - size_t index = it - ctx->buf; - FUN(InsertAt)(ctx, index, val); -} - -inline -void FUN(InsertAtSw)(VEC_T *ctx, size_t index, T val) { - FUN(Realloc)(ctx, 1); - ctx->buf[ctx->size] = ctx->buf[index]; - ctx->buf[index] = val; - ctx->size++; -} - -inline -void FUN(InsertAfterSw)(VEC_T *ctx, T *it, T val) { - size_t index = it - ctx->buf; - // insertAt acts as insertBefore, so we just add 1 - FUN(InsertAtSw)(ctx, index + 1, val); -} - -inline -void FUN(InsertBeforeSw)(VEC_T *ctx, T *it, T val) { - size_t index = it - ctx->buf; - FUN(InsertAtSw)(ctx, index, val); -} - -inline -void FUN(Erase)(VEC_T *ctx, T *it) { - size_t index = it - ctx->buf; - FUN(EraseAt)(ctx, index); -} - -inline -void FUN(EraseAt)(VEC_T *ctx, size_t index) { - ctx->size--; - ctx->buf[index] = ctx->buf[ctx->size]; -} - -inline -void FUN(EraseMv)(VEC_T *ctx, T *it) { - size_t index = it - ctx->buf; - FUN(EraseAtMv)(ctx, index); -} - -inline -void FUN(EraseAtMv)(VEC_T *ctx, size_t index) { - ctx->size--; - for(size_t i = index; i < ctx->size; ++i) { - ctx->buf[i] = ctx->buf[i + 1]; - } -} - -inline -void FUN(Push)(VEC_T *ctx, T val) { - FUN(Realloc)(ctx, 1); - ctx->buf[ctx->size] = val; - ctx->size++; -} - -inline -void FUN(PushRef)(VEC_T *ctx, T *val) { - FUN(Realloc)(ctx, 1); - ctx->buf[ctx->size] = *val; - ctx->size++; -} - -inline -T FUN(Pop)(VEC_T *ctx) { - ctx->size--; - return ctx->buf[ctx->size]; -} - -inline -void FUN(Resize)(VEC_T *ctx, size_t newcount, T val) { - if(newcount <= ctx->size) { - ctx->size = newcount; - return; - } - FUN(Realloc)(ctx, newcount - ctx->size); - for(size_t i = ctx->size; i < newcount; ++i) { - ctx->buf[i] = val; - } - ctx->size = newcount; -} - -inline -void FUN(ResizeRef)(VEC_T *ctx, size_t newcount, T *val) { - if(newcount <= ctx->size) { - ctx->size = newcount; - } - FUN(Realloc)(ctx, newcount - ctx->size); - if(val) { - for(size_t i = ctx->size; i < newcount; ++i) { - ctx->buf[i] = *val; - } - } - ctx->size = newcount; -} - -#ifndef VEC_DISABLE_ERASE_WHEN - -inline -void FUN(EraseWhen)(VEC_T *ctx, T val) { - for(size_t i = 0; i < ctx->size; ++i) { - if(ctx->buf[i] == val) { - FUN(EraseAt)(ctx, i); - --i; - } - } -} - -#endif - -inline -void FUN(EraseIf)(VEC_T *ctx, TYPE(vec_erase_fn, T) cmp, void *udata) { - for(size_t i = 0; i < ctx->size; ++i) { - if(cmp(&ctx->buf[i], udata)) { - FUN(EraseAt)(ctx, i); - --i; - } - } -} - -inline -void FUN(EraseIfMv)(VEC_T *ctx, TYPE(vec_erase_fn, T) cmp, void *udata) { - for(size_t i = 0; i < ctx->size; ++i) { - if(cmp(&ctx->buf[i], udata)) { - FUN(EraseAtMv)(ctx, i); - --i; - } - } -} - -inline -void FUN(Sort)(VEC_T *ctx, vec_cmp_fn_t cmp) { - qsort(ctx->buf, ctx->size, sizeof(T), cmp); -} - -#endif // VEC_NO_IMPLEMENTATION - -#undef FUN -#undef VEC -#undef VEC_T -#undef TYPE -#undef VEC_SHORT_NAME -#undef T -#undef VEC_DISABLE_ERASE_WHEN -#undef VEC_NO_DECLARATION -#undef VEC_NO_IMPLEMENTATION - -#if 0 -// vec.h testing: - -#define T int -#define VEC_SHORT_NAME veci -#include -#define foreach(it, vec) vec_foreach(int, veci, it, vec) - -#define T char -#define VEC_SHORT_NAME vecc -#include -#include - - -#define PRINTVALS(v, s) \ - printf("{ "); \ - for(size_t i = 0; i < v.size; ++i) \ - printf(s " ", v.buf[i]); \ - printf("}\n"); - -#define PRINTVEC(v, s) \ - printf(#v ": {\n"); \ - printf("\tsize: %zu\n", v.size); \ - printf("\tallocated: %zu\n", v.allocated); \ - printf("\tvalues:"); \ - PRINTVALS(v, s); \ - printf("}\n"); \ - -#define PRINTVECI(v) PRINTVEC(v, "%d") -#define PRINTVALSI(v) PRINTVALS(v, "%d") - -bool veciEraseEven(const int *val, void *udata) { - return *val % 2 == 0; -} - -bool veciEraseHigher(const int *val, void *udata) { - return *val > 8; -} - -int main() { - debug("== TESTING INIT ==========================="); - { - veci_t v = veciInit(); - PRINTVECI(v); - veciFree(&v); - - v = veciInitArr((int[]){1, 2, 3, 4}, 4); - veciPush(&v, 25); - veciPush(&v, 13); - PRINTVECI(v); - veciFree(&v); - } - debug("== TESTING MOVE/COPY ======================"); - { - veci_t a = veciInitArr((int[]){1, 2, 3, 4}, 4); - info("before move"); - PRINTVECI(a); - info("after move"); - veci_t b = veciMove(&a); - PRINTVECI(a); - PRINTVECI(b); - veciFree(&a); - veciFree(&b); - - a = veciInitArr((int[]){1, 2, 3, 4}, 4); - b = veciCopy(&a); - info("copied"); - PRINTVECI(a); - PRINTVECI(b); - info("modified b"); - b.buf[2] = 9; - PRINTVECI(a); - PRINTVECI(b); - veciFree(&a); - veciFree(&b); - } - debug("== TESTING BACK ==========================="); - { - vecc_t v = veccInitArr((char[]){'a', 'b', 'c', 'd', 'e', 'f'}, 6); - - PRINTVEC(v, "%c"); - info("The last character is '%c'.", *veccBack(&v)); - - veccFree(&v); - } - debug("== TESTING EMPTY =========================="); - { - veci_t v = veciInit(); - info("Initially, vecEmpty(): %s", veciEmpty(&v) ? "true":"false"); - veciPush(&v, 42); - info("After adding elements, vecEmpty(): %s", veciEmpty(&v) ? "true":"false"); - veciFree(&v); - } - debug("== TESTING RESERVE/SHRINK_TO_FIT/CLEAR ===="); - { - veci_t v = veciInit(); - info("Default capacity: %zu", v.allocated); - veciResize(&v, 100, 0); - info("100 elements: %zu", v.allocated); - veciResize(&v, 50, 0); - info("after resize(50): %zu", v.allocated); - veciShrinkToFit(&v); - info("after shrinkToFit(): %zu", v.allocated); - veciClear(&v); - info("after clear(): %zu", v.allocated); - veciShrinkToFit(&v); - info("after shrinkToFit(): %zu", v.allocated); - for(int i = 1000; i < 1300; ++i) { - veciPush(&v, i); - } - info("after adding 300 elements: %zu", v.allocated); - veciShrinkToFit(&v); - info("after shrinkToFit(): %zu", v.allocated); - veciFree(&v); - } - debug("== TESTING ITERATORS ======================"); - { - veci_t v = veciInitArr((int[]){1, 2, 3, 4, 5}, 5); - PRINTVECI(v); - info("foreach:"); - for(int *it = veciBeg(&v); it != veciEnd(&v); ++it) { - printf("\t*it: %d\n", *it); - } - veciFree(&v); - } - debug("== TESTING INSERT ========================="); - { - veci_t v = veciInit(); - info("init with 3 100"); - veciResize(&v, 3, 100); - PRINTVALSI(v); - info("insert 200 at 0"); - veciInsertAt(&v, 0, 200); - PRINTVALSI(v); - info("insert 300 before beginning"); - veciInsertBefore(&v, veciBeg(&v), 300); - PRINTVALSI(v); - info("insert 400 after beg + 1"); - veciInsertAfter(&v, veciBeg(&v) + 1, 400); - PRINTVALSI(v); - info("insert swap 500 at 3"); - veciInsertAtSw(&v, 3, 500); - PRINTVALSI(v); - info("insert swap 600 before beg"); - veciInsertBeforeSw(&v, veciBeg(&v), 600); - PRINTVALSI(v); - info("insert swap 700 after end - 4"); - veciInsertAfterSw(&v, veciEnd(&v) - 4, 700); - PRINTVALSI(v); - - veciFree(&v); - } - debug("== TESTING ERASE =========================="); - { - veci_t v = veciInitArr((int[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 10); - info("initializing with number from 0 to 9"); - PRINTVALSI(v); - info("erasing beginning"); - veciErase(&v, veciBeg(&v)); - PRINTVALSI(v); - info("erasing index 5"); - veciEraseAt(&v, 5); - PRINTVALSI(v); - info("erasing mv end - 3"); - veciEraseMv(&v, veciEnd(&v) - 3); - PRINTVALSI(v); - info("erasing mv index 1"); - veciEraseAtMv(&v, 1); - PRINTVALSI(v); - info("erasing mv all even numbers"); - veciEraseIfMv(&v, veciEraseEven, NULL); - PRINTVALSI(v); - info("erasing numbers higher than 8"); - veciEraseIf(&v, veciEraseHigher, NULL); - PRINTVALSI(v); - - veciFree(&v); - } - debug("== TESTING CLEAR_ZERO ====================="); - { - veci_t v = veciInitArr((int[]){0, 1, 2, 3, 4, 5}, 6); - info("initialized from 0 to 6"); - PRINTVECI(v); - info("clearZero"); - size_t oldsize = v.size; - veciClearZero(&v); - for(int i = 0; i < oldsize; ++i) { - printf("\t%d > %d\n", i, v.buf[i]); - } - } - debug("== TESTING PUSH/PUSH_REF =================="); - { - veci_t v = veciInit(); - - info("pushing 10"); - veciPush(&v, 10); - int value = 50; - info("pushing reference to value: %d", value); - veciPushRef(&v, &value); - - info("vector holds: "); - printf("> "); - foreach(it, v) { - printf("%d ", *it); - } - printf("\n"); - - veciFree(&v); - } - debug("== TESTING POP ============================"); - { - vecc_t v = veccInitArr("hello world!", 12); - info("initialized with %.*s", (int)v.size, v.buf); - while(!veccEmpty(&v)) { - printf("pooped '%c'\n", veccPop(&v)); - printf("> [%.*s]\n", (int)v.size, v.buf); - } - veccFree(&v); - } -} - -#endif - -#ifdef __cplusplus -} // extern "C" +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/* + * Basic usage: + * #define T int + * // optional, if not defined all the names will be longer, e.g. + * // vec_int_t v = vec_intInit(); + * #define VEC_SHORT_NAME veci + * #include // undefines T + * [...] + * veci_t v = veciInit(); + * veciPush(&v, 10); + * veciEraseAt(&v, 0); + * veciFree(&v); + */ + +typedef int( *vec_cmp_fn_t)(const void *, const void *); + +#ifndef T +#error "Must define T before including vec.h" +#endif + +#define VEC_CAT(a, b) a ## b +#define VEC_PASTE(a, b) VEC_CAT(a, b) +#define TYPE(prefix, type) VEC_PASTE(VEC_PASTE(prefix, _), VEC_PASTE(type, _t)) +#define ITER(prefix, type) VEC_PASTE(VEC_PASTE(prefix, _), VEC_PASTE(type, _it_t)) + +#ifdef VEC_SHORT_NAME + #define VEC_T VEC_PASTE(VEC_SHORT_NAME, _t) + #define VEC_IT_T VEC_PASTE(VEC_SHORT_NAME, _it_t) + #define VEC VEC_SHORT_NAME +#else + #define VEC_T TYPE(vec, T) + #define VEC_IT_T ITER(vec, T) + #define VEC VEC_PASTE(vec, VEC_PASTE(_, T)) +#endif + +#define FUN(postfix) VEC_PASTE(VEC, postfix) + +#ifndef VEC_NO_DECLARATION + +typedef struct { + T *buf; + size_t size; + size_t allocated; +} VEC_T; + +#define vec_foreach(type, name, it, vec) \ + for(type *it = VEC_PASTE(name, Beg)(&vec); it < VEC_PASTE(name, End)(&vec); ++it) + +VEC_T FUN(Init)(void); +VEC_T FUN(InitArr)(T *arr, size_t len); +void FUN(Free)(VEC_T *ctx); + +VEC_T FUN(Move)(VEC_T *ctx); +VEC_T FUN(Copy)(VEC_T *ctx); + +T *FUN(Beg)(VEC_T *ctx); +T *FUN(End)(VEC_T *ctx); +T *FUN(Back)(VEC_T *ctx); +bool FUN(Empty)(VEC_T *ctx); + +void FUN(Realloc)(VEC_T *ctx, size_t needed); +void FUN(Reserve)(VEC_T *ctx, size_t newsize); +void FUN(ShrinkToFit)(VEC_T *ctx); + +void FUN(Clear)(VEC_T *ctx); +void FUN(ClearZero)(VEC_T *ctx); + +void FUN(InsertAt)(VEC_T *ctx, size_t index, T val); +void FUN(InsertAfter)(VEC_T *ctx, T *it, T val); +void FUN(InsertBefore)(VEC_T *ctx, T *it, T val); + +void FUN(InsertAtSw)(VEC_T *ctx, size_t index, T val); +void FUN(InsertAfterSw)(VEC_T *ctx, T *it, T val); +void FUN(InsertBeforeSw)(VEC_T *ctx, T *it, T val); + +// swaps with last +void FUN(Erase)(VEC_T *ctx, T *it); +void FUN(EraseAt)(VEC_T *ctx, size_t index); +// moves whole array back one +void FUN(EraseMv)(VEC_T *ctx, T *it); +void FUN(EraseAtMv)(VEC_T *ctx, size_t index); + +void FUN(Push)(VEC_T *ctx, T val); +void FUN(PushRef)(VEC_T *ctx, T *val); +T FUN(Pop)(VEC_T *ctx); + +void FUN(Resize)(VEC_T *ctx, size_t newcount, T val); +void FUN(ResizeRef)(VEC_T *ctx, size_t newcount, T *val); + +void FUN(EraseWhen)(VEC_T *ctx, T val); + +typedef bool (*TYPE(vec_erase_fn, T))(const T *val, void *udata); +void FUN(EraseIf)(VEC_T *ctx, TYPE(vec_erase_fn, T) cmp, void *udata); +void FUN(EraseIfMv)(VEC_T *ctx, TYPE(vec_erase_fn, T) cmp, void *udata); + +// typedef int (*TYPE(vec_sort_fn, T))(const T *a, const T *b); +void FUN(Sort)(VEC_T *ctx, vec_cmp_fn_t cmp); + +#endif // VEC_NO_DECLARATION + +#ifndef VEC_NO_IMPLEMENTATION + +inline +VEC_T FUN(Init)(void) { + return (VEC_T){ + .buf = NULL, + .size = 0, + .allocated = 0 + }; +} + +inline +VEC_T FUN(InitArr)(T *arr, size_t len) { + VEC_T v = FUN(Init)(); + FUN(Realloc)(&v, len); + memcpy(v.buf, arr, len * sizeof(T)); + v.size = len; + return v; +} + +inline +void FUN(Free)(VEC_T *ctx) { + free(ctx->buf); + ctx->buf = NULL; + ctx->size = 0; + ctx->allocated = 0; +} + +inline +VEC_T FUN(Move)(VEC_T *ctx) { + VEC_T mv = *ctx; + ctx->buf = NULL; + FUN(Free)(ctx); + return mv; +} + +inline +VEC_T FUN(Copy)(VEC_T *ctx) { + VEC_T cp = FUN(Init)(); + if(ctx->buf) { + FUN(Reserve)(&cp, ctx->size); + memcpy(cp.buf, ctx->buf, ctx->size * sizeof(T)); + cp.size = ctx->size; + } + return cp; +} + +inline +T *FUN(Beg)(VEC_T *ctx) { + return ctx->buf; +} + +inline +T *FUN(End)(VEC_T *ctx) { + return ctx->buf + ctx->size; +} + +inline +T *FUN(Back)(VEC_T *ctx) { + return ctx->buf ? &ctx->buf[ctx->size - 1] : NULL; +} + +inline +bool FUN(Empty)(VEC_T *ctx) { + return ctx->buf ? ctx->size == 0 : true; +} + +inline +void FUN(Realloc)(VEC_T *ctx, size_t needed) { + if((ctx->size + needed) >= ctx->allocated) { + ctx->allocated = (ctx->allocated * 2) + needed; + ctx->buf = (T *)realloc(ctx->buf, ctx->allocated * sizeof(T)); + } +} + +inline +void FUN(Reserve)(VEC_T *ctx, size_t newsize) { + if(ctx->allocated < newsize) { + ctx->allocated = newsize; + ctx->buf = (T *)realloc(ctx->buf, ctx->allocated * sizeof(T)); + } +} + +inline +void FUN(ShrinkToFit)(VEC_T *ctx) { + ctx->allocated = ctx->size; + ctx->buf = (T *)realloc(ctx->buf, ctx->allocated * sizeof(T)); +} + +inline +void FUN(Clear)(VEC_T *ctx) { + ctx->size = 0; +} + +inline +void FUN(ClearZero)(VEC_T *ctx) { + ctx->size = 0; + memset(ctx->buf, 0, ctx->allocated * sizeof(T)); +} + +inline +void FUN(InsertAt)(VEC_T *ctx, size_t index, T val) { + FUN(Realloc)(ctx, 1); + for(size_t i = ctx->size; i > index; --i) { + ctx->buf[i] = ctx->buf[i - 1]; + } + ctx->buf[index] = val; + ctx->size++; +} + +inline +void FUN(InsertAfter)(VEC_T *ctx, T *it, T val) { + size_t index = it - ctx->buf; + // insertAt acts as insertBefore, so we just add 1 + FUN(InsertAt)(ctx, index + 1, val); +} + +inline +void FUN(InsertBefore)(VEC_T *ctx, T *it, T val) { + size_t index = it - ctx->buf; + FUN(InsertAt)(ctx, index, val); +} + +inline +void FUN(InsertAtSw)(VEC_T *ctx, size_t index, T val) { + FUN(Realloc)(ctx, 1); + ctx->buf[ctx->size] = ctx->buf[index]; + ctx->buf[index] = val; + ctx->size++; +} + +inline +void FUN(InsertAfterSw)(VEC_T *ctx, T *it, T val) { + size_t index = it - ctx->buf; + // insertAt acts as insertBefore, so we just add 1 + FUN(InsertAtSw)(ctx, index + 1, val); +} + +inline +void FUN(InsertBeforeSw)(VEC_T *ctx, T *it, T val) { + size_t index = it - ctx->buf; + FUN(InsertAtSw)(ctx, index, val); +} + +inline +void FUN(Erase)(VEC_T *ctx, T *it) { + size_t index = it - ctx->buf; + FUN(EraseAt)(ctx, index); +} + +inline +void FUN(EraseAt)(VEC_T *ctx, size_t index) { + ctx->size--; + ctx->buf[index] = ctx->buf[ctx->size]; +} + +inline +void FUN(EraseMv)(VEC_T *ctx, T *it) { + size_t index = it - ctx->buf; + FUN(EraseAtMv)(ctx, index); +} + +inline +void FUN(EraseAtMv)(VEC_T *ctx, size_t index) { + ctx->size--; + for(size_t i = index; i < ctx->size; ++i) { + ctx->buf[i] = ctx->buf[i + 1]; + } +} + +inline +void FUN(Push)(VEC_T *ctx, T val) { + FUN(Realloc)(ctx, 1); + ctx->buf[ctx->size] = val; + ctx->size++; +} + +inline +void FUN(PushRef)(VEC_T *ctx, T *val) { + FUN(Realloc)(ctx, 1); + ctx->buf[ctx->size] = *val; + ctx->size++; +} + +inline +T FUN(Pop)(VEC_T *ctx) { + ctx->size--; + return ctx->buf[ctx->size]; +} + +inline +void FUN(Resize)(VEC_T *ctx, size_t newcount, T val) { + if(newcount <= ctx->size) { + ctx->size = newcount; + return; + } + FUN(Realloc)(ctx, newcount - ctx->size); + for(size_t i = ctx->size; i < newcount; ++i) { + ctx->buf[i] = val; + } + ctx->size = newcount; +} + +inline +void FUN(ResizeRef)(VEC_T *ctx, size_t newcount, T *val) { + if(newcount <= ctx->size) { + ctx->size = newcount; + } + FUN(Realloc)(ctx, newcount - ctx->size); + if(val) { + for(size_t i = ctx->size; i < newcount; ++i) { + ctx->buf[i] = *val; + } + } + ctx->size = newcount; +} + +#ifndef VEC_DISABLE_ERASE_WHEN + +inline +void FUN(EraseWhen)(VEC_T *ctx, T val) { + for(size_t i = 0; i < ctx->size; ++i) { + if(ctx->buf[i] == val) { + FUN(EraseAt)(ctx, i); + --i; + } + } +} + +#endif + +inline +void FUN(EraseIf)(VEC_T *ctx, TYPE(vec_erase_fn, T) cmp, void *udata) { + for(size_t i = 0; i < ctx->size; ++i) { + if(cmp(&ctx->buf[i], udata)) { + FUN(EraseAt)(ctx, i); + --i; + } + } +} + +inline +void FUN(EraseIfMv)(VEC_T *ctx, TYPE(vec_erase_fn, T) cmp, void *udata) { + for(size_t i = 0; i < ctx->size; ++i) { + if(cmp(&ctx->buf[i], udata)) { + FUN(EraseAtMv)(ctx, i); + --i; + } + } +} + +inline +void FUN(Sort)(VEC_T *ctx, vec_cmp_fn_t cmp) { + qsort(ctx->buf, ctx->size, sizeof(T), cmp); +} + +#endif // VEC_NO_IMPLEMENTATION + +#undef FUN +#undef VEC +#undef VEC_T +#undef TYPE +#undef VEC_SHORT_NAME +#undef T +#undef VEC_DISABLE_ERASE_WHEN +#undef VEC_NO_DECLARATION +#undef VEC_NO_IMPLEMENTATION + +#if 0 +// vec.h testing: + +#define T int +#define VEC_SHORT_NAME veci +#include +#define foreach(it, vec) vec_foreach(int, veci, it, vec) + +#define T char +#define VEC_SHORT_NAME vecc +#include +#include + + +#define PRINTVALS(v, s) \ + printf("{ "); \ + for(size_t i = 0; i < v.size; ++i) \ + printf(s " ", v.buf[i]); \ + printf("}\n"); + +#define PRINTVEC(v, s) \ + printf(#v ": {\n"); \ + printf("\tsize: %zu\n", v.size); \ + printf("\tallocated: %zu\n", v.allocated); \ + printf("\tvalues:"); \ + PRINTVALS(v, s); \ + printf("}\n"); \ + +#define PRINTVECI(v) PRINTVEC(v, "%d") +#define PRINTVALSI(v) PRINTVALS(v, "%d") + +bool veciEraseEven(const int *val, void *udata) { + return *val % 2 == 0; +} + +bool veciEraseHigher(const int *val, void *udata) { + return *val > 8; +} + +int main() { + debug("== TESTING INIT ==========================="); + { + veci_t v = veciInit(); + PRINTVECI(v); + veciFree(&v); + + v = veciInitArr((int[]){1, 2, 3, 4}, 4); + veciPush(&v, 25); + veciPush(&v, 13); + PRINTVECI(v); + veciFree(&v); + } + debug("== TESTING MOVE/COPY ======================"); + { + veci_t a = veciInitArr((int[]){1, 2, 3, 4}, 4); + info("before move"); + PRINTVECI(a); + info("after move"); + veci_t b = veciMove(&a); + PRINTVECI(a); + PRINTVECI(b); + veciFree(&a); + veciFree(&b); + + a = veciInitArr((int[]){1, 2, 3, 4}, 4); + b = veciCopy(&a); + info("copied"); + PRINTVECI(a); + PRINTVECI(b); + info("modified b"); + b.buf[2] = 9; + PRINTVECI(a); + PRINTVECI(b); + veciFree(&a); + veciFree(&b); + } + debug("== TESTING BACK ==========================="); + { + vecc_t v = veccInitArr((char[]){'a', 'b', 'c', 'd', 'e', 'f'}, 6); + + PRINTVEC(v, "%c"); + info("The last character is '%c'.", *veccBack(&v)); + + veccFree(&v); + } + debug("== TESTING EMPTY =========================="); + { + veci_t v = veciInit(); + info("Initially, vecEmpty(): %s", veciEmpty(&v) ? "true":"false"); + veciPush(&v, 42); + info("After adding elements, vecEmpty(): %s", veciEmpty(&v) ? "true":"false"); + veciFree(&v); + } + debug("== TESTING RESERVE/SHRINK_TO_FIT/CLEAR ===="); + { + veci_t v = veciInit(); + info("Default capacity: %zu", v.allocated); + veciResize(&v, 100, 0); + info("100 elements: %zu", v.allocated); + veciResize(&v, 50, 0); + info("after resize(50): %zu", v.allocated); + veciShrinkToFit(&v); + info("after shrinkToFit(): %zu", v.allocated); + veciClear(&v); + info("after clear(): %zu", v.allocated); + veciShrinkToFit(&v); + info("after shrinkToFit(): %zu", v.allocated); + for(int i = 1000; i < 1300; ++i) { + veciPush(&v, i); + } + info("after adding 300 elements: %zu", v.allocated); + veciShrinkToFit(&v); + info("after shrinkToFit(): %zu", v.allocated); + veciFree(&v); + } + debug("== TESTING ITERATORS ======================"); + { + veci_t v = veciInitArr((int[]){1, 2, 3, 4, 5}, 5); + PRINTVECI(v); + info("foreach:"); + for(int *it = veciBeg(&v); it != veciEnd(&v); ++it) { + printf("\t*it: %d\n", *it); + } + veciFree(&v); + } + debug("== TESTING INSERT ========================="); + { + veci_t v = veciInit(); + info("init with 3 100"); + veciResize(&v, 3, 100); + PRINTVALSI(v); + info("insert 200 at 0"); + veciInsertAt(&v, 0, 200); + PRINTVALSI(v); + info("insert 300 before beginning"); + veciInsertBefore(&v, veciBeg(&v), 300); + PRINTVALSI(v); + info("insert 400 after beg + 1"); + veciInsertAfter(&v, veciBeg(&v) + 1, 400); + PRINTVALSI(v); + info("insert swap 500 at 3"); + veciInsertAtSw(&v, 3, 500); + PRINTVALSI(v); + info("insert swap 600 before beg"); + veciInsertBeforeSw(&v, veciBeg(&v), 600); + PRINTVALSI(v); + info("insert swap 700 after end - 4"); + veciInsertAfterSw(&v, veciEnd(&v) - 4, 700); + PRINTVALSI(v); + + veciFree(&v); + } + debug("== TESTING ERASE =========================="); + { + veci_t v = veciInitArr((int[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 10); + info("initializing with number from 0 to 9"); + PRINTVALSI(v); + info("erasing beginning"); + veciErase(&v, veciBeg(&v)); + PRINTVALSI(v); + info("erasing index 5"); + veciEraseAt(&v, 5); + PRINTVALSI(v); + info("erasing mv end - 3"); + veciEraseMv(&v, veciEnd(&v) - 3); + PRINTVALSI(v); + info("erasing mv index 1"); + veciEraseAtMv(&v, 1); + PRINTVALSI(v); + info("erasing mv all even numbers"); + veciEraseIfMv(&v, veciEraseEven, NULL); + PRINTVALSI(v); + info("erasing numbers higher than 8"); + veciEraseIf(&v, veciEraseHigher, NULL); + PRINTVALSI(v); + + veciFree(&v); + } + debug("== TESTING CLEAR_ZERO ====================="); + { + veci_t v = veciInitArr((int[]){0, 1, 2, 3, 4, 5}, 6); + info("initialized from 0 to 6"); + PRINTVECI(v); + info("clearZero"); + size_t oldsize = v.size; + veciClearZero(&v); + for(int i = 0; i < oldsize; ++i) { + printf("\t%d > %d\n", i, v.buf[i]); + } + } + debug("== TESTING PUSH/PUSH_REF =================="); + { + veci_t v = veciInit(); + + info("pushing 10"); + veciPush(&v, 10); + int value = 50; + info("pushing reference to value: %d", value); + veciPushRef(&v, &value); + + info("vector holds: "); + printf("> "); + foreach(it, v) { + printf("%d ", *it); + } + printf("\n"); + + veciFree(&v); + } + debug("== TESTING POP ============================"); + { + vecc_t v = veccInitArr("hello world!", 12); + info("initialized with %.*s", (int)v.size, v.buf); + while(!veccEmpty(&v)) { + printf("pooped '%c'\n", veccPop(&v)); + printf("> [%.*s]\n", (int)v.size, v.buf); + } + veccFree(&v); + } +} + +#endif + +#ifdef __cplusplus +} // extern "C" #endif \ No newline at end of file