#ifndef SLOWARR_H_ #define SLOWARR_H_ #ifndef SLOWARR_NAMESPACE #define SLOWARR_NAMESPACE(X) SLOWARR__##X #define SLOWARR_CXXT SlowArr #endif #ifndef SLOWARR_FUNC #define SLOWARR_FUNC /**/ #endif #ifndef SLOWARR_ASSERT_USER_ERROR #include #define SLOWARR_ASSERT_USER_ERROR(expr) assert(expr) #endif #ifndef SLOWARR_MEMZERO #include #define SLOWARR_MEMZERO(ptr, len) memset(ptr, 0, len) #endif #ifndef SLOWARR_MEMMOVE #include #define SLOWARR_MEMMOVE(dst, src, len) memmove(dst, src, len) #endif #ifdef SLOW_DEFINE_ACCESS #ifndef SLOW_DEFINE_ACCESS__DONE #define T(B, T) B##__##T #define F(B, T, f) B##__##T##__##f #define SLOW_DEFINE_ACCESS__DONE #endif #endif #ifndef SLOWARR_SZT #include #define SLOWARR_SZT size_t #endif #ifndef SLOWARR_REALLOC #include #define SLOWARR_REALLOC(ptr, old, news) realloc(ptr, news) #define SLOWARR_FREE(ptr, size) free(ptr) #endif #ifndef SLOWARR_GROWTH_RATE /** returns len * 1.5 */ #define SLOWARR_GROWTH_RATE(T, len) (((len) >> 1) + (len)) #endif #ifndef SLOWARR_CAP_FOR_FIRST_ELEM #define SLOWARR_CAP_FOR_FIRST_ELEM(T) (4) /* TODO: could do better */ #endif /* TODO */ #define SLOWARR_MANGLE(T) SLOWARR_NAMESPACE(T) #define SLOWARR_MANGLE_F(T, F) SLOWARR_NAMESPACE(T##__##F) #ifdef __cplusplus #define SLOWARR_BEGINC extern "C" { #define SLOWARR_ENDC } #else #define SLOWARR_BEGINC /**/ #define SLOWARR_ENDC /**/ #endif #ifndef SLOWARR_ON_MALLOC_FAIL #include #include #define SLOWARR_ON_MALLOC_FAIL(nb) \ do { \ fprintf(stderr, "\nmemory allocation of %lu bytes failed!\n", \ (unsigned long)nb); \ exit(1); \ } while (0) #endif #define SLOWARR__BORROWED (1 << 0) /** disable reallocation / freeing */ #define SLOWARR__ZEROIZE (1 << 1) /** for cryptography */ #ifdef __cplusplus template struct SLOWARR_CXXT { }; #define SLOWARR_CXX_HEADER(T) \ template <> \ struct SLOWARR_CXXT \ { \ SLOWARR_MANGLE(T) arr; \ \ T* begin() \ { \ return arr.data; \ } \ T* cbegin() const \ { \ return arr.data; \ } \ T* cend() const \ { \ return arr.data + arr.len; \ } \ T* end() \ { \ return cend(); \ } \ SLOWARR_SZT length() const \ { \ return arr.len; \ } \ }; #else #define SLOWARR_CXX_HEADER(T) /**/ #endif #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" #endif static void SLOWARR___REQUIRE_SEMI(void) {} #ifdef __GNUC__ #pragma GCC diagnostic pop #endif #define SLOWARR_REQUIRE_SEMI static void SLOWARR___REQUIRE_SEMI(void) #define SLOWARR_Header(T) \ SLOWARR_BEGINC \ /** usage: T(Arr,int) myarr = {0}; */ \ typedef struct \ { \ SLOWARR_SZT cap, len; \ T* data; \ unsigned char attr; \ } SLOWARR_MANGLE(T); \ SLOWARR_ENDC \ \ SLOWARR_CXX_HEADER(T) \ SLOWARR_BEGINC \ \ /** result can not be reallocated */ \ SLOWARR_FUNC SLOWARR_MANGLE(T) \ SLOWARR_MANGLE_F(T, borrow)(T * data, SLOWARR_SZT sz); \ \ /** usage: G(Arr,int,unsafeClear)(&arr) \ * this is marked unsafe, because it assumes that the elements don't need \ * to be destroyed each */ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, unsafeClear)(SLOWARR_MANGLE(T) * arr); \ \ /** resize to smallest cap required to hold current elems */ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, shrink)(SLOWARR_MANGLE(T) * arr); \ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, reserveTotal)(SLOWARR_MANGLE(T) * arr, \ SLOWARR_SZT num); \ \ SLOWARR_FUNC T* SLOWARR_MANGLE_F(T, pushRef)(SLOWARR_MANGLE(T) * arr); \ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, push)(SLOWARR_MANGLE(T) * arr, T val); \ \ /** fails if oob */ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, remove)(SLOWARR_MANGLE(T) * arr, \ T * out, SLOWARR_SZT i); \ \ SLOWARR_FUNC T SLOWARR_MANGLE_F(T, pop)(SLOWARR_MANGLE(T) * arr); \ \ SLOWARR_ENDC \ SLOWARR_REQUIRE_SEMI /** call this only once in your program. call SLOWARR_Header(T) first */ #define SLOWARR_Impl(T) \ SLOWARR_BEGINC \ \ /** result can not be reallocated */ \ SLOWARR_FUNC SLOWARR_MANGLE(T) \ SLOWARR_MANGLE_F(T, borrow)(T * data, SLOWARR_SZT sz) \ { \ SLOWARR_MANGLE(T) arr; \ arr.data = data; \ arr.cap = sz; \ arr.len = sz; \ arr.attr = SLOWARR__BORROWED; \ return arr; \ } \ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, unsafeClear)(SLOWARR_MANGLE(T) * arr) \ { \ if (arr->data) \ SLOWARR_FREE(arr->data, arr->cap); \ arr->data = (T*)(void*)0; \ arr->cap = 0; \ arr->len = 0; \ /* don't change attrs */ \ } \ \ /* TODO: could make this align the cap num for better perf */ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, shrink)(SLOWARR_MANGLE(T) * arr) \ { \ if (arr->attr & SLOWARR__BORROWED) \ return; \ \ if (arr->len == arr->cap) \ return; \ if (arr->attr & SLOWARR__ZEROIZE) \ SLOWARR_MEMZERO(arr->data + arr->len, \ (arr->cap - arr->len) * sizeof(T)); \ arr->data = (T*)SLOWARR_REALLOC(arr->data, arr->cap * sizeof(T), \ arr->len * sizeof(T)); \ arr->cap = arr->len; \ } \ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, reserveTotal)(SLOWARR_MANGLE(T) * arr, \ SLOWARR_SZT num) \ { \ void* n; \ if (num <= arr->cap) \ return; \ SLOWARR_ASSERT_USER_ERROR(!(arr->attr & SLOWARR__BORROWED)); \ n = SLOWARR_REALLOC(arr->data, sizeof(T) * arr->cap, sizeof(T) * num); \ if (!n) { \ if (arr->attr & SLOWARR__ZEROIZE) \ SLOWARR_MEMZERO(arr->data, arr->cap * sizeof(T)); \ SLOWARR_FREE(arr->data, arr->cap * sizeof(T)); \ SLOWARR_ON_MALLOC_FAIL(sizeof(T) * num); \ } \ arr->data = (T*)n; \ arr->cap = num; \ } \ \ SLOWARR_FUNC T* SLOWARR_MANGLE_F(T, pushRef)(SLOWARR_MANGLE(T) * arr) \ { \ if (arr->cap == 0) { \ SLOWARR_MANGLE_F(T, reserveTotal)(arr, SLOWARR_CAP_FOR_FIRST_ELEM(T)); \ } else if (arr->len + 1 > arr->cap) { \ SLOWARR_MANGLE_F(T, reserveTotal) \ (arr, SLOWARR_GROWTH_RATE(T, arr->len)); \ } \ return &arr->data[arr->len++]; \ } \ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, push)(SLOWARR_MANGLE(T) * arr, T val) \ { \ *SLOWARR_MANGLE_F(T, pushRef)(arr) = val; \ } \ \ SLOWARR_FUNC void SLOWARR_MANGLE_F(T, remove)(SLOWARR_MANGLE(T) * arr, \ T * out, SLOWARR_SZT i) \ { \ SLOWARR_SZT too_much; \ SLOWARR_ASSERT_USER_ERROR(i < arr->len); \ *out = arr->data[i]; \ SLOWARR_MEMMOVE(&arr->data[i], &arr->data[i + 1], \ sizeof(T) * (arr->len - (i + 1))); \ arr->len -= 1; \ too_much = arr->cap - arr->len; \ if (too_much > SLOWARR_GROWTH_RATE(T, arr->len)) { \ SLOWARR_MANGLE_F(T, shrink)(arr); \ } \ } \ \ SLOWARR_FUNC T SLOWARR_MANGLE_F(T, pop)(SLOWARR_MANGLE(T) * arr) \ { \ T temp; \ SLOWARR_MANGLE_F(T, remove)(arr, &temp, arr->len - 1); \ return temp; \ } \ \ SLOWARR_ENDC \ SLOWARR_REQUIRE_SEMI #endif