From 42c161bbeb30c17c1ef39f84e13e54ff207f09da Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sun, 22 Dec 2024 18:27:58 -0500 Subject: all: Major cleanup and pass on readability Signed-off-by: Andrew Opalach --- include/al/array_sort.h | 29 +++---- include/al/array_typed.h | 78 +++++++++--------- include/al/atomic.h | 2 +- include/al/lib.h | 46 +++++++---- include/al/list.h | 39 +++++---- include/al/log.h | 30 ++++--- include/al/macros.h | 38 +++++---- include/al/str.h | 38 ++++----- include/al/test.h | 22 ++--- include/al/types.h | 4 +- include/al/wstr.h | 42 +++++----- src/array.c | 178 +++++++++++++++++++++++---------------- src/lib.c | 211 +++++++++++++++++++++++++++-------------------- src/log.c | 104 +++++++++++++---------- src/ring_buffer.c | 7 +- src/str.c | 39 ++++----- tests/array.c | 7 +- tests/array_typed.c | 5 ++ tests/str.c | 64 ++++++++------ 19 files changed, 570 insertions(+), 413 deletions(-) diff --git a/include/al/array_sort.h b/include/al/array_sort.h index 18b00f5..b6d7468 100644 --- a/include/al/array_sort.h +++ b/include/al/array_sort.h @@ -3,20 +3,21 @@ #include "lib.h" -#define AL_INSERSION_SORT(data, type, count, cmp) \ - do { \ - s32 i = 1; \ - while (i < (s32)count) { \ - s32 j = i - 1; \ - type x = data[i]; \ - while (j >= 0 && cmp(&data[j], &x) > 0) { \ - data[j + 1] = data[j]; \ - j--; \ - } \ - data[j + 1] = x; \ - i++; \ - } \ - } while (0) +#define AL_INSERSION_SORT(data, type, count, cmp) \ +AL_MACRO_WRAP \ +({ \ + s32 i = 1; \ + while (i < (s32)count) { \ + s32 j = i - 1; \ + type x = data[i]; \ + while (j >= 0 && cmp(&data[j], &x) > 0) { \ + data[j + 1] = data[j]; \ + j--; \ + } \ + data[j + 1] = x; \ + i++; \ + } \ +}) #ifdef AL_USE_STDLIB #define AL_STDLIB_QSORT(data, type, count, cmp) qsort(data, count, sizeof(type), cmp) diff --git a/include/al/array_typed.h b/include/al/array_typed.h index ae93bf4..2904b33 100644 --- a/include/al/array_typed.h +++ b/include/al/array_typed.h @@ -7,38 +7,38 @@ #include "macros.h" -#define AL_ARRAY_EMPTY_DEFAULT_0(FUNC, T, S, ...) FUNC(T, S) -#define AL_ARRAY_EMPTY_DEFAULT(...) AL_ARRAY_EMPTY_DEFAULT_0(__VA_ARGS__, , ) -#define AL_ARRAY_PASTER_EVALUATOR(X, Y) X##_##Y -#define AL_ARRAY_PASTER(X, Y) AL_ARRAY_PASTER_EVALUATOR(X, Y) +#define AL_EMPTY_DEFAULT_0(FUNC, T, S, ...) FUNC(T, S) +#define AL_EMPTY_DEFAULT(...) AL_EMPTY_DEFAULT_0(__VA_ARGS__, , ) +#define AL_PASTER_EVALUATOR(X, Y) X##_##Y +#define AL_PASTER(X, Y) AL_PASTER_EVALUATOR(X, Y) -#define _array(N, ...) AL_ARRAY_PASTER(array, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_init(N, ...) AL_ARRAY_PASTER(_array_init, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_data(N, ...) AL_ARRAY_PASTER(_array_data, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_reserve(N, ...) AL_ARRAY_PASTER(_array_reserve, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define __al_array_reserve_internal(N, ...) AL_ARRAY_PASTER(_array_reserve_internal, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_at(N, ...) AL_ARRAY_PASTER(_array_at, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_last(N, ...) AL_ARRAY_PASTER(_array_last, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_push(N, ...) AL_ARRAY_PASTER(_array_push, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_pop(N, ...) AL_ARRAY_PASTER(_array_pop, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_remove_at(N, ...) AL_ARRAY_PASTER(_array_remove_at, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_pop_at(N, ...) AL_ARRAY_PASTER(_array_pop_at, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_insert(N, ...) AL_ARRAY_PASTER(_array_insert, AL_ARRAY_PASTER(N, __VA_ARGS__)) -#define _al_array_free(N, ...) AL_ARRAY_PASTER(_array_free, AL_ARRAY_PASTER(N, __VA_ARGS__)) +#define _array(N, ...) AL_PASTER(array, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_init(N, ...) AL_PASTER(_array_init, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_data(N, ...) AL_PASTER(_array_data, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_reserve(N, ...) AL_PASTER(_array_reserve, AL_PASTER(N, __VA_ARGS__)) +#define __al_array_reserve_internal(N, ...) AL_PASTER(_array_reserve_internal, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_at(N, ...) AL_PASTER(_array_at, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_last(N, ...) AL_PASTER(_array_last, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_push(N, ...) AL_PASTER(_array_push, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_pop(N, ...) AL_PASTER(_array_pop, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_remove_at(N, ...) AL_PASTER(_array_remove_at, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_pop_at(N, ...) AL_PASTER(_array_pop_at, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_insert(N, ...) AL_PASTER(_array_insert, AL_PASTER(N, __VA_ARGS__)) +#define _al_array_free(N, ...) AL_PASTER(_array_free, AL_PASTER(N, __VA_ARGS__)) -#define array(...) AL_ARRAY_EMPTY_DEFAULT(_array, __VA_ARGS__) -#define al_array_init(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_init, __VA_ARGS__) -#define al_array_data(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_data, __VA_ARGS__) -#define _al_array_reserve_internal(...) AL_ARRAY_EMPTY_DEFAULT(__al_array_reserve_internal, __VA_ARGS__) -#define al_array_reserve(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_reserve, __VA_ARGS__) -#define al_array_at(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_at, __VA_ARGS__) -#define al_array_last(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_last, __VA_ARGS__) -#define al_array_push(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_push, __VA_ARGS__) -#define al_array_pop(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_pop, __VA_ARGS__) -#define al_array_remove_at(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_remove_at, __VA_ARGS__) -#define al_array_pop_at(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_pop_at, __VA_ARGS__) -#define al_array_insert(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_insert, __VA_ARGS__) -#define al_array_free(...) AL_ARRAY_EMPTY_DEFAULT(_al_array_free, __VA_ARGS__) +#define array(...) AL_EMPTY_DEFAULT(_array, __VA_ARGS__) +#define al_array_init(...) AL_EMPTY_DEFAULT(_al_array_init, __VA_ARGS__) +#define al_array_data(...) AL_EMPTY_DEFAULT(_al_array_data, __VA_ARGS__) +#define _al_array_reserve_internal(...) AL_EMPTY_DEFAULT(__al_array_reserve_internal, __VA_ARGS__) +#define al_array_reserve(...) AL_EMPTY_DEFAULT(_al_array_reserve, __VA_ARGS__) +#define al_array_at(...) AL_EMPTY_DEFAULT(_al_array_at, __VA_ARGS__) +#define al_array_last(...) AL_EMPTY_DEFAULT(_al_array_last, __VA_ARGS__) +#define al_array_push(...) AL_EMPTY_DEFAULT(_al_array_push, __VA_ARGS__) +#define al_array_pop(...) AL_EMPTY_DEFAULT(_al_array_pop, __VA_ARGS__) +#define al_array_remove_at(...) AL_EMPTY_DEFAULT(_al_array_remove_at, __VA_ARGS__) +#define al_array_pop_at(...) AL_EMPTY_DEFAULT(_al_array_pop_at, __VA_ARGS__) +#define al_array_insert(...) AL_EMPTY_DEFAULT(_al_array_insert, __VA_ARGS__) +#define al_array_free(...) AL_EMPTY_DEFAULT(_al_array_free, __VA_ARGS__) #define AL_ARRAY_DEFINE_FUNCTIONS(N, T, ...) \ static inline T *al_array_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i) \ @@ -88,13 +88,11 @@ } \ static inline void _al_array_reserve_internal(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 size) \ { \ - if (size < al_grow_limit) { \ - size = al_next_power_of_two(size + 1); \ - } else { \ - size = (size + al_grow_limit) & ~al_grow_limit; \ - } \ - if (a->alloc >= size) return; \ - a->data = (!a->data) ? al_malloc(sizeof(T) * size) : al_realloc(a->data, sizeof(T) * size); \ + if (a->alloc >= size) \ + return; \ + size = size < al_grow_step ? al_next_power_of_two(size) : \ + (size + al_grow_step) & ~al_grow_step; \ + a->data = (T *)(!a->data ? al_malloc(sizeof(T) * size) : al_realloc(a->data, sizeof(T) * size)); \ a->alloc = size; \ } \ static inline void al_array_free(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a) \ @@ -147,12 +145,12 @@ AL_ARRAY_DEFINE_FUNCTIONS(N, T, S) \ static inline void al_array_reserve(N, S)(array(N, S) *a, u32 size) \ { \ - if (S >= size) return; \ + if (S >= size) \ + return; \ bool copy_inline = a->data == NULL; \ _al_array_reserve_internal(N, S)(a, size); \ - if (UNLIKELY(copy_inline)) { \ + if (UNLIKELY(copy_inline)) \ al_memcpy(a->data, a->inline_data, sizeof(T) * a->size); \ - } \ } #endif // _AL_ARRAY_TYPED_H diff --git a/include/al/atomic.h b/include/al/atomic.h index a8bb6b2..f30b6e8 100644 --- a/include/al/atomic.h +++ b/include/al/atomic.h @@ -51,7 +51,7 @@ typedef f32 c89atomic_f32; static inline T al_atomic_sub(T)(atomic(T) *a, T value, s32 order) \ { \ return c89atomic_fetch_sub_explicit_##S(a, value, order); \ - } \ + } #if defined C89ATOMIC_64BIT AL_ATOMIC_DEFINE(size_t, uint64, 64) diff --git a/include/al/lib.h b/include/al/lib.h index e13a7c7..6b72ff9 100644 --- a/include/al/lib.h +++ b/include/al/lib.h @@ -9,10 +9,10 @@ #if defined __GNUC__ || defined __clang__ #define AL_UNUSED_FUNCTION_PUSH \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wunused-function\"") + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunused-function\"") #define AL_UNUSED_FUNCTION_POP \ - _Pragma("GCC diagnostic pop") + _Pragma("GCC diagnostic pop") #else #define AL_UNUSED_FUNCTION_PUSH #define AL_UNUSED_FUNCTION_POP @@ -32,21 +32,29 @@ void al_malloc_close(void); void *al_malloc(size_t n); void *al_calloc(size_t n, size_t size); void *al_realloc(void *ptr, size_t n); -void al_free(void *ptr); #ifdef AL_HAVE_POSIX_MEMALIGN -int al_posix_memalign(void **ptr, size_t alignment, size_t n); +s32 al_posix_memalign(void **ptr, size_t alignment, size_t n); #endif -void al_malloc_stats(u32 *current, u32 *peak, u32 *total); +void al_free(void *ptr); void al_set_alloc(void *(*malloc_func)(size_t), void *(*calloc_func)(size_t, size_t), - void *(*realloc_func)(void *, size_t), void (*free_func)(void *)); + void *(*realloc_func)(void *, size_t), +#ifdef AL_HAVE_POSIX_MEMALIGN + s32 (*posix_memalign_func)(void **, size_t, size_t), +#endif + void (*free_func)(void *), void (*lock_func)(void), void (*unlock_func)(void)); +void al_malloc_stats(size_t *current, size_t *peak, size_t *total); #else +#ifdef AL_USE_STDLIB #define al_malloc malloc #define al_calloc calloc #define al_realloc realloc -#define al_free free #ifdef AL_HAVE_POSIX_MEMALIGN #define al_posix_memalign posix_memalign #endif +#define al_free free +#else +#error "libalabaster configuration is malloc-less" +#endif #endif #define al_memcpy memcpy @@ -64,10 +72,12 @@ void al_set_alloc(void *(*malloc_func)(size_t), void *(*calloc_func)(size_t, siz #define al_assert(expr) do { (void)sizeof(expr); } while (0) // NOLINT(bugprone-sizeof-expression) #endif -#define al_assert_and_return(expr) do { \ - al_assert(expr); \ - return false; \ -} while(0) +#define al_assert_and_return(expr) \ +AL_MACRO_WRAP \ +({ \ + al_assert(false); \ + return expr; \ +}) #define al_alloc_object(type) (type *)al_calloc(1, sizeof(type)) @@ -104,7 +114,8 @@ static inline void *al_memrchr(const void *s, s32 c, size_t n) const u8 *src = (const u8 *)s + n - 1; u8 d = (u8)c; while (n--) { - if (*src == d) return (void *)src; + if (*src == d) + return (void *)src; src--; } return NULL; @@ -123,13 +134,14 @@ AL_UNUSED_FUNCTION_POP AL_UNUSED_FUNCTION_PUSH -static inline size_t al_next_power_of_two(size_t n) +static inline u32 al_next_power_of_two(u32 n) { n--; n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; + n |= n >> 16; return ++n; } @@ -180,8 +192,12 @@ static inline u16 al_u16_add_wrap(u16 v, u16 add) AL_UNUSED_FUNCTION_POP +// Once a growing allocation expands past this number, +// only grow in multiples of it. +extern u32 al_grow_step; + +// Defaults to 4KB. extern size_t al_page_size; -extern size_t al_grow_limit; void al_set_page_size(size_t size); #endif // _AL_LIB_H diff --git a/include/al/list.h b/include/al/list.h index f6a1181..52628a4 100644 --- a/include/al/list.h +++ b/include/al/list.h @@ -11,25 +11,28 @@ list_##name *next; \ list_##name *prev; \ }; \ - static inline list_##name *list_new_node_##name(type value) { \ + static inline list_##name *list_new_node_##name(type value) \ + { \ list_##name *node = (list_##name *)al_malloc(sizeof(list_##name)); \ node->value = value; \ return node; \ } \ - static inline void list_free_node_##name(list_##name *l) { \ + static inline void list_free_node_##name(list_##name *l) \ + { \ free(l); \ } \ - static inline list_##name *list_last_##name(list_##name *l) { \ - if (l) { \ - while (l->next) l = l->next; \ - } \ + static inline list_##name *list_last_##name(list_##name *l) \ + { \ + if (l) while (l->next) l = l->next; \ return l; \ } \ - static inline list_##name *list_nth_##name(list_##name *l, u32 n) { \ + static inline list_##name *list_nth_##name(list_##name *l, u32 n) \ + { \ while (n-- > 0 && l) l = l->next; \ return l; \ } \ - static inline list_##name *list_append_##name(list_##name *l, type value) { \ + static inline list_##name *list_append_##name(list_##name *l, type value) \ + { \ list_##name *node = list_new_node_##name(value); \ node->next = NULL; \ if (l) { \ @@ -42,14 +45,16 @@ return node; \ } \ } \ - static inline list_##name *list_prepend_##name(list_##name *l, type value) { \ + static inline list_##name *list_prepend_##name(list_##name *l, type value) \ + { \ list_##name *node = list_new_node_##name(value); \ node->next = l; \ node->prev = NULL; \ if (l) l->prev = node; \ return node; \ } \ - static inline list_##name *list_insert_after_##name(list_##name *l, list_##name *s, type value) { \ + static inline list_##name *list_insert_after_##name(list_##name *l, list_##name *s, type value) \ + { \ if (!l) { \ list_##name *node = list_new_node_##name(value); \ node->next = NULL; \ @@ -66,7 +71,8 @@ return l; \ } \ } \ - static inline list_##name *list_insert_before_##name(list_##name *l, list_##name *s, type value) { \ + static inline list_##name *list_insert_before_##name(list_##name *l, list_##name *s, type value) \ + { \ if (!l) { \ list_##name *node = list_new_node_##name(value); \ node->next = NULL; \ @@ -85,24 +91,23 @@ return l; \ } \ } \ - static inline list_##name *list_remove_##name(list_##name *l, list_##name *n) { \ + static inline list_##name *list_remove_##name(list_##name *l, list_##name *n) \ + { \ if (!l) return l; \ else if (l == n) { \ - if (n->next) { \ + if (n->next) \ n->next->prev = NULL; \ - } \ l = n->next; \ list_free_node_##name(n); \ } else { \ n->prev->next = n->next; \ - if (n->next) { \ + if (n->next) \ n->next->prev = n->prev; \ - } \ list_free_node_##name(n); \ } \ return l; \ } \ - AL_UNUSED_FUNCTION_POP \ + AL_UNUSED_FUNCTION_POP #define list(name) list_##name diff --git a/include/al/log.h b/include/al/log.h index 9f5dc91..53ffbea 100644 --- a/include/al/log.h +++ b/include/al/log.h @@ -4,22 +4,30 @@ #include #include -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) -#define __LOCATION__ __FILENAME__, __LINE__, __FUNCTION__ +#define __LOCATION__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__ -void al_set_print(s32 (*print_func)(void *, char *), void *userdata); +#define AL_LOG_MESSAGE_SIZE 256 -s32 _al_log(const char *level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, ...); -s32 _al_logv(const char *level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, va_list args); +enum { + AL_LOG_INFO = 0, + AL_LOG_WARN, + AL_LOG_ERROR, + AL_LOG_DEBUG +}; -#define al_log(level, section, fmt, ...) _al_log(level, section, __LOCATION__, fmt, ##__VA_ARGS__); -#define al_logv(level, section, fmt, args) _al_logv(level, section, __LOCATION__, fmt, args); +void al_set_print(s32 (*print_func)(void *, u8, char *), void *userdata); -#define al_log_info(section, fmt, ...) al_log("info", section, fmt, ##__VA_ARGS__) -#define al_log_warn(section, fmt, ...) al_log("warn", section, fmt, ##__VA_ARGS__) -#define al_log_error(section, fmt, ...) al_log("error", section, fmt, ##__VA_ARGS__) +s32 _al_log(u8 level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, ...); +s32 _al_logv(u8 level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, va_list args); + +#define al_log(level, section, fmt, ...) _al_log(level, section, __LOCATION__, fmt, ##__VA_ARGS__) +#define al_logv(level, section, fmt, args) _al_logv(level, section, __LOCATION__, fmt, args) + +#define al_log_info(section, fmt, ...) al_log(AL_LOG_INFO, section, fmt, ##__VA_ARGS__) +#define al_log_warn(section, fmt, ...) al_log(AL_LOG_WARN, section, fmt, ##__VA_ARGS__) +#define al_log_error(section, fmt, ...) al_log(AL_LOG_ERROR, section, fmt, ##__VA_ARGS__) #ifdef _DEBUG_ -#define al_log_debug(section, fmt, ...) al_log("debug", section, fmt, ##__VA_ARGS__) +#define al_log_debug(section, fmt, ...) al_log(AL_LOG_DEBUG, section, fmt, ##__VA_ARGS__) #else AL_UNUSED_FUNCTION_PUSH diff --git a/include/al/macros.h b/include/al/macros.h index b767191..477eef3 100644 --- a/include/al/macros.h +++ b/include/al/macros.h @@ -1,6 +1,8 @@ #ifndef _AL_MACROS_H #define _AL_MACROS_H +#define AL_MACRO_WRAP(c) do { c } while(0) + #if defined LIKELY || defined UNLIKELY #error "Conflicting definitions for LIKELY/UNLIKELY" #endif @@ -21,45 +23,51 @@ #error "Conflicting definitions for common macros" #endif -#define MAX(a, b) \ +#ifdef AL_HAVE_GNU_EXTENSIONS +#define MIN(a, b) \ ({ \ __typeof__(a) _a = a; \ __typeof__(b) _b = b; \ (void)(&_a == &_b); \ - _a > _b ? _a : _b; \ + _a < _b ? _a : _b; \ }) - -#define MIN(a, b) \ +#define MAX(a, b) \ ({ \ __typeof__(a) _a = a; \ __typeof__(b) _b = b; \ (void)(&_a == &_b); \ - _a < _b ? _a : _b; \ + _a > _b ? _a : _b; \ }) +#define CLAMP(n, lo, hi) MIN(hi, MAX(lo, n)) +#endif +/* +// Compatible/Pedantic min/max. +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) #define CLAMP(n, lo, hi) MIN(hi, MAX(lo, n)) +*/ -#define SWAP(a, b) do { \ +#define SWAP(a, b) \ +AL_MACRO_WRAP \ +({ \ __typeof__(a) tmp = a; \ a = b; \ b = tmp; \ -} while (0) +}) #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define BOOLSTR(b) ((b) ? "true" : "false") -#if defined KB || defined MB || defined GB || defined TB || defined PB || defined EB +#if defined KB || defined MB || defined GB || defined TB #error "Conflicting definitions for byte size macros" #endif -// http://www.blackbeltcoder.com/Articles/controls/precisely-defining-kilobytes-megabytes-and-gigabytes -#define KB(n) (((u64)0x400)*((u64)(n))) -#define MB(n) (((u64)0x100000)*((u64)(n))) -#define GB(n) (((u64)0x40000000)*((u64)(n))) -#define TB(n) (((u64)0x10000000000)*((u64)(n))) -#define PB(n) (((u64)0x4000000000000)*((u64)(n))) -#define EB(n) (((u64)0x1000000000000000)*((u64)(n))) +#define KB(n) ((n) << 10) +#define MB(n) ((n) << 20) +#define GB(n) ((n) << 30) +#define TB(n) (((u64)n) << 40) #if defined __counted_by || defined __sized_by #error "Conflicting definitions for common attributes" diff --git a/include/al/str.h b/include/al/str.h index 0878f5b..8a7746e 100644 --- a/include/al/str.h +++ b/include/al/str.h @@ -39,15 +39,14 @@ static inline void al_str_free(str *s) static inline u32 al_str_reserve(str *s, u32 size) { - if (size < al_grow_limit) { - size = (u32)al_next_power_of_two(size + 1); - } else { - size = (u32)((size + al_grow_limit) & ~al_grow_limit); - } + if (size <= s->alloc) + return s->alloc; - if (size <= s->alloc) return s->alloc; + size = size < al_grow_step ? al_next_power_of_two(size) : + (size + al_grow_step) & ~al_grow_step; - s->data = (char *)((!s->data) ? al_malloc(size) : al_realloc(s->data, size)); + s->data = (char *)(!s->data ? al_malloc(size) : al_realloc(s->data, size)); + al_assert(s->data); return size; } @@ -67,10 +66,6 @@ static inline void al_str_clone(str *dest, str *src) static inline void al_str_from(str *s, const char *c_str) { - if (!c_str) { - *s = al_str_zero(); - return; - } size_t len = al_strlen(c_str); al_str_sized(s, (u32)len); al_memcpy(s->data, c_str, len); @@ -114,12 +109,11 @@ static inline void al_str_prepend(str *s, str *c) al_str_insert(s, 0, c); } -static inline s32 al_str_cmp(str *s, str *c, u32 start, u32 len) +static inline s32 al_str_cmp(str *s, str *c, u32 i, u32 len) { - if (start + len > s->len || len > c->len) { + if (i + len > s->len || len > c->len) return -1; - } - return al_memcmp(&al_str_at(s, start), c->data, len); + return al_memcmp(&al_str_at(s, i), c->data, len); } static inline bool al_str_eq(str *s, str *c) @@ -144,22 +138,24 @@ static inline s32 al_str_rfind(str *s, char c) // extremely slow. static inline s32 al_str_find_str(str *s, str *c) { - if (c->len > s->len) return -1; + if (c->len > s->len) + return -1; + for (u32 i = 0; i < s->len - c->len; i++) { - if (al_str_at(s, i) != al_str_at(c, 0)) continue; - if (al_str_cmp(s, c, i, c->len) == 0) { + if (al_str_at(s, i) != al_str_at(c, 0)) + continue; + if (al_str_cmp(s, c, i, c->len) == 0) return i; - } } + return -1; } static inline u32 al_str_hash(str *s) { u32 hash = 5381; - for (u32 i = 0; i < s->len; i++) { + for (u32 i = 0; i < s->len; i++) hash = ((hash << 5) + hash) + al_str_at(s, i); /* hash * 33 + c */ - } return hash; } diff --git a/include/al/test.h b/include/al/test.h index aa4d28b..da4f024 100644 --- a/include/al/test.h +++ b/include/al/test.h @@ -2,6 +2,7 @@ #define _AL_TEST_H #include "lib.h" +#include "macros.h" #define AL_TEST_START_GROUP(name) \ al_printf("Group \""name"\":\n") @@ -20,15 +21,16 @@ return true #define AL_TEST_DEF(a, b, T, cmp, explain) \ - do { \ - AL_TEST_TYPE_##T _a = a; \ - AL_TEST_TYPE_##T _b = b; \ - if (cmp) { \ - al_printf("FAIL "#a"("AL_TEST_FMT_##T") "explain" "#b"("AL_TEST_FMT_##T")\n", \ - AL_TEST_PRINTF_##T(_a), AL_TEST_PRINTF_##T(_b)); \ - return false; \ - } \ - } while (0) +AL_MACRO_WRAP \ +({ \ + AL_TEST_TYPE_##T _a = a; \ + AL_TEST_TYPE_##T _b = b; \ + if (cmp) { \ + al_printf("FAIL "#a"("AL_TEST_FMT_##T") "explain" "#b"("AL_TEST_FMT_##T")\n", \ + AL_TEST_PRINTF_##T(_a), AL_TEST_PRINTF_##T(_b)); \ + return false; \ + } \ +}) #define AL_TEST_EQ(a, b, T) \ AL_TEST_DEF(a, b, T, (AL_TEST_CMP_##T(_a, _b) != 0), \ @@ -71,7 +73,7 @@ static inline s32 al_test_bool_cmp(bool a, bool b) #define AL_TEST_TYPE_bool bool #define AL_TEST_FMT_bool "%s" -#define AL_TEST_PRINTF_bool(b) (b ? "true" : "false") +#define AL_TEST_PRINTF_bool(b) BOOLSTR(b) static inline s32 al_test_u16_cmp(u16 a, u16 b) { diff --git a/include/al/types.h b/include/al/types.h index fc2bb10..3398700 100644 --- a/include/al/types.h +++ b/include/al/types.h @@ -36,8 +36,8 @@ typedef uint64_t u64; typedef float f32; typedef double f64; -// `long` can be a distinctly different size based on the toolchain we're using. -// Use `long` and `ulong`, if needed, for API compatibility. +// long can be a distinctly different size based on the toolchain we are using. +// Use long and ulong, if needed, for API compatibility. typedef unsigned long ulong; #ifdef _MSC_VER diff --git a/include/al/wstr.h b/include/al/wstr.h index 1168e2d..b6d7afd 100644 --- a/include/al/wstr.h +++ b/include/al/wstr.h @@ -45,15 +45,14 @@ static inline void al_wstr_free(wstr *w) static inline u32 al_wstr_reserve(wstr *w, u32 size) { - if (size < al_grow_limit) { - size = al_next_power_of_two(size + 1); - } else { - size = (size + al_grow_limit) & ~al_grow_limit; - } + if (size <= w->alloc) + return w->alloc; - if (size <= w->alloc) return w->alloc; + size = size < al_grow_step ? al_next_power_of_two(size) : + (size + al_grow_step) & ~al_grow_step; - w->data = (wchar_t *)((!w->data) ? al_malloc(size) : al_realloc(w->data, size)); + w->data = (wchar_t *)(!w->data ? al_malloc(size) : al_realloc(w->data, size)); + al_assert(w->data); return size; } @@ -62,13 +61,13 @@ static inline void al_wstr_sized(wstr *w, u32 size) { *w = al_wstr_zero(); w->alloc = al_wstr_reserve(w, size * sizeof(wchar_t)); - al_memset(w->data, 0, w->alloc); } static inline void al_wstr_clone(wstr *dest, wstr *src) { - al_wstr_sized(dest, src->len); - al_memcpy(dest->data, src->data, src->len * sizeof(wchar_t)); + u32 len = src->len + 1; + al_wstr_sized(dest, len); + al_memcpy(dest->data, src->data, len * sizeof(wchar_t)); dest->len = src->len; } @@ -76,9 +75,10 @@ static inline void al_wstr_from_cstr(wstr *w, char *c) { #ifdef AL_HAVE_WIDE_STRING mbstate_t mbstate = { 0 }; - size_t n = mbsrtowcs(NULL, (const char **)&c, 0, &mbstate) + 1; - al_wstr_sized(w, n); - w->len = mbsrtowcs(w->data, (const char **)&c, n, &mbstate); + size_t len = mbsrtowcs(NULL, (const char **)&c, 0, &mbstate); + al_wstr_sized(w, (u32)(len + 1)); + w->len = (u32)mbsrtowcs(w->data, (const char **)&c, len, &mbstate); + al_assert(w->len == (u32)len); w->data[w->len] = L'\0'; #else (void)c; @@ -96,12 +96,14 @@ static inline void al_wstr_from_str(wstr *w, str *s) static inline void al_wstr_to_str(wstr *w, str *s) { #ifdef AL_HAVE_WIDE_STRING + wchar_t *data = w->data; mbstate_t mbstate = { 0 }; - u32 len = wcsrtombs(NULL, (const wchar_t **)&w->data, 0, &mbstate); - al_str_sized(s, len); + size_t len = wcsrtombs(NULL, (const wchar_t **)&w->data, 0, &mbstate); + al_str_sized(s, (u32)len); // Excludes the null terminator. - wcsrtombs(s->data, (const wchar_t **)&w->data, len, &mbstate); - s->len = len; + s->len = (u32)wcsrtombs(s->data, (const wchar_t **)&w->data, len, &mbstate); + al_assert(s->len == (u32)len); + w->data = data; #else (void)s; (void)w; @@ -134,7 +136,8 @@ static inline s32 al_wstr_cmp(wstr *w, wstr *c, u32 start, u32 len) static inline s32 al_wstr_find(wstr *w, wchar_t c) { for (s32 i = 0; i < (s32)w->len; i++) { - if (al_wstr_at(w, i) == c) return i; + if (al_wstr_at(w, i) == c) + return i; } return -1; } @@ -142,7 +145,8 @@ static inline s32 al_wstr_find(wstr *w, wchar_t c) static inline s32 al_wstr_rfind(wstr *w, wchar_t c) { for (s32 i = (s32)w->len - 1; i >= 0; i--) { - if (al_wstr_at(w, i) == c) return i; + if (al_wstr_at(w, i) == c) + return i; } return -1; } diff --git a/src/array.c b/src/array.c index 14db581..0459c96 100644 --- a/src/array.c +++ b/src/array.c @@ -13,7 +13,7 @@ } #define al_array_init(arr) ((arr).size = 0, (arr).alloc = 0, (arr).data = NULL) -#define al_array_item_size(arr) (sizeof(*(arr).data)) // NOLINT(bugprone-sizeof-expression) +#define al_array_item_size(arr) sizeof(*(arr).data) // NOLINT(bugprone-sizeof-expression) #define al_array_is_empty(arr) ((arr).size == 0) @@ -23,62 +23,99 @@ #define al_array_reserve(arr, size) \ ((arr).alloc = _al_array_reserve((void *)&(arr).data, al_array_item_size(arr), (arr).alloc, size)) -#define al_array_clone(dest, src) \ - do { \ - al_array_init(dest); \ - al_array_reserve(dest, (src).size); \ - (dest).size = (src).size; \ - al_memcpy(&al_array_at(dest, 0), &al_array_at(src, 0), \ - al_array_item_size(dest) * (dest).size); \ - } while (0) - -#define al_array_push(arr, item) \ - do { \ - al_array_reserve(arr, (arr).size + 1); \ - al_array_at(arr, (arr).size++) = item; \ - } while (0) - -#define al_array_insert(arr, i, item) \ - do { \ - if ((arr).size > i) { \ - al_array_reserve(arr, (arr).size + 1); \ - al_memmove(&al_array_at(arr, i + 1), &al_array_at(arr, i), \ - al_array_item_size(arr) * ((arr).size - i)); \ - (arr).size++; \ - } else { \ - al_array_reserve(arr, i + 1); \ - (arr).size = i + 1; \ - } \ - al_array_at(arr, i) = item; \ - } while (0) - -#define al_array_pop_at(arr, i, r) \ - do { \ - r = al_array_at((arr), i); \ - al_array_remove_at((arr), i); \ - } while (0) - -#define al_array_pop(arr) (al_array_at(arr, --(arr).size)) -#define al_array_pop_front(arr) al_array_pop_at(arr, 0) - -#define al_array_remove_at(arr, i) \ - do { \ - if (i == (arr).size - 1) { \ - (arr).size--; \ - } else { \ - al_memmove(&al_array_at(arr, i), &al_array_at(arr, i + 1), \ - al_array_item_size(arr) * (--(arr).size - i)); \ - } \ - } while (0) - -#define al_array_remove_range(arr, i, e) \ - do { \ - if (e != (arr).size) { \ - al_memmove(&al_array_at(arr, i), &al_array_at(arr, e), \ - al_array_item_size(arr) * ((arr).size - e)); \ - } \ - (arr).size -= e - i; \ - } while (0) +#define al_array_clone(dest, src) \ +AL_MACRO_WRAP \ +({ \ + al_array_init(dest); \ + al_array_reserve(dest, (src).size); \ + (dest).size = (src).size; \ + al_memcpy(&al_array_at(dest, 0), &al_array_at(src, 0), \ + al_array_item_size(dest) * (dest).size); \ +}) + +#define al_array_push(arr, item) \ +AL_MACRO_WRAP \ +({ \ + al_array_reserve(arr, (arr).size + 1); \ + al_array_at(arr, (arr).size++) = item; \ +}) + +#define al_array_insert(arr, i, item) \ +AL_MACRO_WRAP \ +({ \ + if ((arr).size > i) { \ + al_array_reserve(arr, (arr).size + 1); \ + al_memmove(&al_array_at(arr, i + 1), &al_array_at(arr, i), \ + al_array_item_size(arr) * ((arr).size - i)); \ + (arr).size++; \ + } else { \ + al_array_reserve(arr, i + 1); \ + (arr).size = i + 1; \ + } \ + al_array_at(arr, i) = item; \ +}) + +#define al_array_pop(arr) al_array_at(arr, --(arr).size) +#define al_array_pop_at(arr, i, r) \ +AL_MACRO_WRAP \ +({ \ + r = al_array_at(arr, i); \ + al_array_remove_at(arr, i); \ +}) + +#define al_array_remove(arr, elem) \ +AL_MACRO_WRAP \ +({ \ + for (u32 i = 0; i < (arr).size; i++) { \ + if (al_array_at(arr, i) == elem) { \ + al_array_remove_at(arr, i); \ + break; \ + } \ + } \ +}) + +#define al_array_check_remove(arr, elem, removed) \ +AL_MACRO_WRAP \ +({ \ + removed = false; \ + for (u32 i = 0; i < (arr).size; i++) { \ + if (al_array_at(arr, i) == elem) { \ + al_array_remove_at(arr, i); \ + removed = true; \ + break; \ + } \ + } \ +}) + +#define al_array_remove_all(arr, elem) \ +AL_MACRO_WRAP \ +({ \ + for (u32 i = (arr).size; i-- > 0;) { \ + if (al_array_at(arr, i) == elem) \ + al_array_remove_at(arr, i); \ + } \ +}) + +#define al_array_remove_at(arr, i) \ +AL_MACRO_WRAP \ +({ \ + if (i == (arr).size - 1) { \ + (arr).size--; \ + } else { \ + al_memmove(&al_array_at(arr, i), &al_array_at(arr, i + 1), \ + al_array_item_size(arr) * (--(arr).size - i)); \ + } \ +}) + +#define al_array_remove_range(arr, i, e) \ +AL_MACRO_WRAP \ +({ \ + if (e != (arr).size) { \ + al_memmove(&al_array_at(arr, i), &al_array_at(arr, e), \ + al_array_item_size(arr) * ((arr).size - e)); \ + } \ + (arr).size -= e - i; \ +}) #ifdef AL_USE_STDLIB #define al_array_sort(arr, type, cmp) AL_STDLIB_QSORT((arr).data, type, (arr).size, cmp) @@ -98,26 +135,25 @@ #define al_array_foreach_ptr(arr, i, item) \ for (u32 i = 0; (i < (arr).size && (item = &al_array_at(arr, i), 1)); i++) -#define al_array_remove_at_iter(arr, i) \ - do { \ - al_array_remove_at(arr, i); \ - i--; \ - } while (0) +#define al_array_foreach_ptr_rev(arr, i, item) \ + for (u32 i = (arr).size; (i-- > 0 && (item = &al_array_at(arr, i), 1));) + +#define al_array_remove_at_iter(arr, i) \ +AL_MACRO_WRAP \ +({ \ + al_array_remove_at(arr, i); \ + i--; \ +}) AL_UNUSED_FUNCTION_PUSH static inline u32 _al_array_reserve(void **ptr, u32 item_size, u32 prev_size, u32 size) { - if (size < al_grow_limit) { - size = (u32)al_next_power_of_two(size + 1); - } else { - size = (u32)((size + al_grow_limit) & ~al_grow_limit); - } - - if (size <= prev_size) { - al_assert(prev_size > 0); + if (size <= prev_size) return prev_size; - } + + size = size < al_grow_step ? al_next_power_of_two(size) : + (size + al_grow_step) & ~al_grow_step; *ptr = (!*ptr) ? AL_ARRAY_MALLOC(item_size * size) : AL_ARRAY_REALLOC(*ptr, item_size * size); al_assert(*ptr); diff --git a/src/lib.c b/src/lib.c index 78b7fdf..9a658cf 100644 --- a/src/lib.c +++ b/src/lib.c @@ -2,28 +2,30 @@ // https://forum.vcfed.org/index.php?threads/c-item-size-check-at-compile-time.1244920/ #define AL_ASSERT_TYPE_SIZE(type, size) \ - typedef char type##__size_test[( !!(sizeof(type) == size) )*2-1] + typedef char type##__size_test[(!!(sizeof(type) == size)) * 2 - 1] AL_ASSERT_TYPE_SIZE(int, 4); AL_ASSERT_TYPE_SIZE(unsigned, 4); #ifdef AL_MEMORY_TRACKING -#ifdef AL_USE_STDLIB -static void *(*_al_malloc)(size_t) = malloc; -static void *(*_al_calloc)(size_t, size_t) = calloc; -static void *(*_al_realloc)(void *, size_t) = realloc; -static void (*_al_free)(void *) = free; +static void *(*_al_malloc)(size_t) = NULL; +static void *(*_al_calloc)(size_t, size_t) = NULL; +static void *(*_al_realloc)(void *, size_t) = NULL; +static void (*_al_free)(void *) = NULL; #ifdef AL_HAVE_POSIX_MEMALIGN -s32 (*_al_posix_memalign)(void **, size_t, size_t) = posix_memalign; +s32 (*_al_posix_memalign)(void **, size_t, size_t) = NULL; #endif -// Testing allocation tracking stuff (Very scuffed, not thread-safe!). -struct alloc_t { +static void (*_al_malloc_lock)(void) = NULL; +static void (*_al_malloc_unlock)(void) = NULL; + +// Testing allocation tracking stuff (Very scuffed). +struct al_alloc_t { void *ptr; size_t size; }; -// Use stdlib allocation for the allocation tracking array. +// Use stdlib malloc for the allocation tracking array. // This avoids a circular dependency and also keeps allocations // from the memory tracking code out of the stats. #include "../include/al/types.h" @@ -32,10 +34,18 @@ struct alloc_t { #define AL_ARRAY_FREE free #include "array.c" -static array(struct alloc_t) allocations; -static u32 currently_allocated = 0; -static u32 peak_allocated = 0; -static u32 total_allocated = 0; +static array(struct al_alloc_t) allocations; +static size_t current_alloc = 0; +static size_t peak_alloc = 0; +static size_t total_alloc = 0; + +#define total_changed_by(n) \ + total_alloc += (n); \ + +#define current_changed_by(n) \ + current_alloc += (n); \ + if (current_alloc > peak_alloc) \ + peak_alloc = current_alloc; void al_malloc_init(void) { @@ -49,127 +59,152 @@ void al_malloc_close(void) void *al_malloc(size_t n) { + al_printf("**al_malloc(%zu)\n", n); + void *ptr = _al_malloc(n); - printf("**al_malloc(%zu)\n", n); - struct alloc_t a = { - .ptr = ptr, - .size = n - }; - total_allocated += a.size; - currently_allocated += a.size; - if (currently_allocated > peak_allocated) { - peak_allocated = currently_allocated; - } - al_array_push(allocations, a); + + _al_malloc_lock(); + + total_changed_by(n); + current_changed_by(n); + + al_array_push(allocations, ((struct al_alloc_t){ ptr, n })); + + _al_malloc_unlock(); + return ptr; } void *al_calloc(size_t n, size_t size) { + al_printf("**al_calloc(%zu, %zu)\n", n, size); + void *ptr = _al_calloc(n, size); - printf("**al_calloc(%zu, %zu)\n", n, size); - struct alloc_t a = { - .ptr = ptr, - .size = n * size - }; - total_allocated += a.size; - currently_allocated += a.size; - if (currently_allocated > peak_allocated) { - peak_allocated = currently_allocated; - } - al_array_push(allocations, a); + + size_t real_size = n * size; + + _al_malloc_lock(); + + total_changed_by(real_size); + current_changed_by(real_size); + + al_array_push(allocations, ((struct al_alloc_t){ ptr, real_size })); + + _al_malloc_unlock(); + return ptr; } void *al_realloc(void *ptr, size_t n) { - void *nptr = _al_realloc(ptr, n); - printf("**al_realloc(%p, %zu)\n", ptr, n); - for (u32 i = 0; i < allocations.size; i++) { - struct alloc_t *a = &al_array_at(allocations, i); - if (a->ptr == ptr) { - currently_allocated += (ssize_t)n - (ssize_t)a->size; - if (currently_allocated > peak_allocated) { - peak_allocated = currently_allocated; - } - a->ptr = nptr; - a->size = n; - } - } + al_printf("**al_realloc(%p, %zu)\n", ptr, n); + + void *new_ptr = _al_realloc(ptr, n); + + _al_malloc_lock(); + + total_changed_by(n); + if (!ptr) { - struct alloc_t a = { - .ptr = nptr, - .size = n - }; - currently_allocated += a.size; - if (currently_allocated > peak_allocated) { - peak_allocated = currently_allocated; + current_changed_by(n); + al_array_push(allocations, ((struct al_alloc_t){ ptr, n })); + } else { + struct al_alloc_t *alloc; + al_array_foreach_ptr(allocations, i, alloc) { + if (alloc->ptr == ptr) { + ptrdiff_t diff = (ptrdiff_t)n - (ptrdiff_t)alloc->size; + current_changed_by(diff); + alloc->ptr = new_ptr; + alloc->size = n; + break; + } } - al_array_push(allocations, a); } - total_allocated += n; - return nptr; + + _al_malloc_unlock(); + + return new_ptr; } void al_free(void *ptr) { - printf("**al_free(%p)\n", ptr); - for (u32 i = 0; i < allocations.size; i++) { - struct alloc_t *a = &al_array_at(allocations, i); - if (a->ptr == ptr) { - currently_allocated -= a->size; + al_printf("**al_free(%p)\n", ptr); + + _al_malloc_lock(); + + bool found = false; + struct al_alloc_t *alloc; + al_array_foreach_ptr(allocations, i, alloc) { + if (alloc->ptr == ptr) { + current_changed_by(-alloc->size); al_array_remove_at(allocations, i); + found = true; break; } } + al_assert(found); + + _al_malloc_unlock(); + _al_free(ptr); } #ifdef AL_HAVE_POSIX_MEMALIGN s32 al_posix_memalign(void **ptr, size_t alignment, size_t n) { - s32 res = _al_posix_memalign(ptr, alignment, n); - size_t actual_size = (n + alignment) - ((n + alignment) % alignment); - printf("**al_posix_memalign(%zu, %zu(%zu))\n", alignment, n, actual_size); - struct alloc_t a = { - .ptr = *ptr, - .size = actual_size - }; - total_allocated += actual_size; - currently_allocated += actual_size; - if (currently_allocated > peak_allocated) { - peak_allocated = currently_allocated; - } - al_array_push(allocations, a); - return res; + size_t real_size = (n + alignment) - ((n + alignment) % alignment); + al_printf("**al_posix_memalign(%zu, %zu(%zu))\n", alignment, n, real_size); + + s32 result = _al_posix_memalign(ptr, alignment, n); + + _al_malloc_lock(); + + total_changed_by(real_size); + current_changed_by(real_size); + + al_array_push(allocations, ((struct al_alloc_t){ *ptr, real_size })); + + _al_malloc_unlock(); + + return result; } #endif -void al_malloc_stats(u32 *current, u32 *peak, u32 *total) +void al_malloc_stats(size_t *current, size_t *peak, size_t *total) { - *current = currently_allocated; - *peak = peak_allocated; - *total = total_allocated; + _al_malloc_lock(); + + *current = current_alloc; + *peak = peak_alloc; + *total = total_alloc; + + _al_malloc_unlock(); } void al_set_alloc(void *(*malloc_func)(size_t), void *(*calloc_func)(size_t, size_t), - void *(*realloc_func)(void *, size_t), void (*free_func)(void *)) + void *(*realloc_func)(void *, size_t), +#ifdef AL_HAVE_POSIX_MEMALIGN + s32 (*posix_memalign_func)(void **, size_t, size_t), +#endif + void (*free_func)(void *), void (*lock_func)(void), void (*unlock_func)(void)) { _al_malloc = malloc_func; _al_calloc = calloc_func; _al_realloc = realloc_func; +#ifdef AL_HAVE_POSIX_MEMALIGN + _al_posix_memalign = posix_memalign_func; +#endif _al_free = free_func; + _al_malloc_lock = lock_func; + _al_malloc_unlock = unlock_func; } #endif -#endif -// Default to 4KB. -size_t al_page_size = 0x1000; -size_t al_grow_limit = 0xfff; +u32 al_grow_step = 0xfff; +size_t al_page_size = 0x1000; void al_set_page_size(size_t size) { al_assert(size > 0); al_page_size = size; - al_grow_limit = al_page_size - 1; } diff --git a/src/log.c b/src/log.c index 40cfd4b..436ac16 100644 --- a/src/log.c +++ b/src/log.c @@ -8,46 +8,70 @@ #define AL_LOG_TEMPLATE "%s:%d %s(): %s -> " #endif -#define AL_LOG_MESSAGE_MAX 511 +#define AL_LOG_MESSAGE_MAX (AL_LOG_MESSAGE_SIZE - 1) // Space for newline. -#ifndef AL_LOG_SKIP -static s32 al_print_default(void *userdata, char *message) -{ - (void)userdata; - s32 ret = al_printf("%*.*s\n", 0, AL_LOG_MESSAGE_MAX, message); - al_free(message); - return ret; -} - -static s32 (*_al_print)(void *, char *) = al_print_default; -static void *_al_log_userdata = NULL; - -void al_set_print(s32 (*print_func)(void *, char *), void *userdata) +#ifndef AL_FORCE_DISABLE_OUTPUT +static const char *levels[] = { "info", "warn", "error", "debug" }; +static inline const char *get_color_for_level(u8 level) { - _al_print = print_func; - _al_log_userdata = userdata; +#define NORMAL "\x1B[0m" +#define RED "\x1B[31m" +#define GREEN "\x1B[32m" +#define YELLOW "\x1B[33m" +#define BLUE "\x1B[34m" +#define MAGENTA "\x1B[35m" +#define CYAN "\x1B[36m" +#define WHITE "\x1B[37m" +#define RESET "\033[0m" + switch (level) { + case AL_LOG_ERROR: return RED; + case AL_LOG_WARN: return YELLOW; + default: return NORMAL; + } } +#endif -#ifndef AL_FORCE_DISABLE_OUTPUT -static char *get_buffer(const char *level, const char *section, const char *fmt, const char *name, const s32 line, const char *func, va_list args) +#if !defined AL_FORCE_DISABLE_OUTPUT && !defined AL_LOG_SKIP +static char *get_message_buffer(u8 level, const char *section, const char *fmt, const char *name, const s32 line, const char *func, va_list args) { - char *buffer = al_malloc(AL_LOG_MESSAGE_MAX + 1); + char *buffer = al_malloc(AL_LOG_MESSAGE_SIZE); #ifdef AL_LOG_USE_SECTION - s32 prefix = al_snprintf(buffer, AL_LOG_MESSAGE_MAX, AL_LOG_TEMPLATE, name, line, func, level, section); + s32 prefix = al_snprintf(buffer, AL_LOG_MESSAGE_MAX, AL_LOG_TEMPLATE, name, line, func, levels[level], section); #else (void)section; - s32 prefix = al_snprintf(buffer, AL_LOG_MESSAGE_MAX, AL_LOG_TEMPLATE, name, line, func, level); + s32 prefix = al_snprintf(buffer, AL_LOG_MESSAGE_MAX, AL_LOG_TEMPLATE, name, line, func, levels[level]); #endif al_vsnprintf(buffer + prefix, AL_LOG_MESSAGE_MAX - prefix, fmt, args); buffer[strcspn(buffer, "\r\n")] = '\0'; return buffer; } + +s32 al_print_default(void *userdata, u8 level, char *message) +{ + (void)userdata; +#ifndef _WIN32 + s32 ret = al_printf("%s%*.*s\n", get_color_for_level(level), 0, AL_LOG_MESSAGE_SIZE, message); +#else + (void)level; + s32 ret = al_printf("%*.*s\n", 0, AL_LOG_MESSAGE_SIZE, message); #endif + al_free(message); + return ret; +} + +static s32 (*_al_print)(void *, u8, char *) = al_print_default; +static void *_al_log_userdata = NULL; + +void al_set_print(s32 (*print_func)(void *, u8, char *), void *userdata) +{ + _al_print = print_func; + _al_log_userdata = userdata; +} #else -void al_set_print(s32 (*print_func)(void *, char *), void *userdata) { (void)print_func; (void)userdata; } +void al_set_print(s32 (*print_func)(void *, u8, char *), void *userdata) { (void)print_func; (void)userdata; } #endif -s32 _al_log(const char *level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, ...) +s32 _al_logv(u8 level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, va_list args) { #ifdef AL_FORCE_DISABLE_OUTPUT (void)level; @@ -56,28 +80,31 @@ s32 _al_log(const char *level, const char *section, const char *name, const s32 (void)line; (void)func; (void)fmt; + (void)args; return 0; #else - va_list args; - va_start(args, fmt); if (!section) section = ""; #ifdef AL_LOG_SKIP - s32 ret = al_printf(AL_LOG_TEMPLATE, name, line, func, level, section); + s32 ret = al_printf(get_color_for_level(level)); +#ifdef AL_LOG_USE_SECTION + ret += al_printf(AL_LOG_TEMPLATE, name, line, func, level, section); +#else + ret += al_printf(AL_LOG_TEMPLATE, name, line, func, level); +#endif ret += al_vprintf(fmt, args); if (strcspn(fmt, "\r\n") == al_strlen(fmt)) ret += al_printf("\n"); #else - char *buffer = get_buffer(level, section, fmt, name, line, func, args); + char *buffer = get_message_buffer(level, section, fmt, name, line, func, args); #endif - va_end(args); #ifdef AL_LOG_SKIP return ret; #else - return _al_print(_al_log_userdata, buffer); + return _al_print(_al_log_userdata, level, buffer); #endif #endif } -s32 _al_logv(const char *level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, va_list args) +s32 _al_log(u8 level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, ...) { #ifdef AL_FORCE_DISABLE_OUTPUT (void)level; @@ -86,21 +113,12 @@ s32 _al_logv(const char *level, const char *section, const char *name, const s32 (void)line; (void)func; (void)fmt; - (void)args; return 0; #else - if (!section) section = ""; -#ifdef AL_LOG_SKIP - s32 ret = al_printf(AL_LOG_TEMPLATE, name, line, func, level, section); - ret += al_vprintf(fmt, args); - if (strcspn(fmt, "\r\n") == al_strlen(fmt)) ret += al_printf("\n"); -#else - char *buffer = get_buffer(level, section, fmt, name, line, func, args); -#endif -#ifdef AL_LOG_SKIP + va_list args; + va_start(args, fmt); + s32 ret = _al_logv(level, section, name, line, func, fmt, args); + va_end(args); return ret; -#else - return _al_print(_al_log_userdata, buffer); -#endif #endif } diff --git a/src/ring_buffer.c b/src/ring_buffer.c index a96584f..cf72d2b 100644 --- a/src/ring_buffer.c +++ b/src/ring_buffer.c @@ -119,11 +119,15 @@ size_t al_ring_buffer_peek(struct al_ring_buffer *buf, u8 *ptr, size_t offset, s if (rp <= wp) { rp += offset; + size = MIN(wp - rp, (ptrdiff_t)n); - if (size < 0) return 0; + if (size < 0) + return 0; + al_memcpy(ptr, rp, size); } else { rp += offset; + size = MIN(buf->end - rp, (ptrdiff_t)n); if (size > 0) { al_memcpy(ptr, rp, size); @@ -133,6 +137,7 @@ size_t al_ring_buffer_peek(struct al_ring_buffer *buf, u8 *ptr, size_t offset, s rp = buf->start - size; size = 0; } + ptrdiff_t wrap = MIN(wp - rp, (ptrdiff_t)n); if (wrap > 0) { al_memcpy(ptr + size, rp, wrap); diff --git a/src/str.c b/src/str.c index e8e417d..2cde190 100644 --- a/src/str.c +++ b/src/str.c @@ -16,10 +16,9 @@ s64 al_str_to_long(str *s, s32 base) i++; } - if ((base == 16 && al_str_at(s, i) == '0' && // 0xbecd - (al_str_at(s, i + 1) == 'x' || al_str_at(s, i + 1) == 'X')) || - (base == 2 && al_str_at(s, i) == '0' && // 0b01011101 - (al_str_at(s, i + 1) == 'b' || al_str_at(s, i + 1) == 'B'))) { + if (al_str_at(s, i) == '0' && + ((base == 16 && (al_str_at(s, i + 1) == 'x' || al_str_at(s, i + 1) == 'X')) || + (base == 2 && (al_str_at(s, i + 1) == 'b' || al_str_at(s, i + 1) == 'B')))) { i += 2; } @@ -32,26 +31,23 @@ s64 al_str_to_long(str *s, s32 base) for (; i < s->len; i++) { char c = al_str_at(s, i); - if (c >= '0' && c <= '9') { - c -= '0'; - } else if (c >= 'A' && c <= 'Z') { - c -= 'A' - 10; - } else if (c >= 'a' && c <= 'z') { - c -= 'a' - 10; - } else { - // Character not valid when expressing a number. + if (c >= '0' && c <= '9') c -= '0'; + else if (c >= 'A' && c <= 'Z') c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') c -= 'a' - 10; + else { + // Character not valid for expressing a number. error = true; break; } - // Character invalid for given base or trying to add the next digit - // would cause an overflow/underflow. if (c >= base || ret > cutoff || (ret == cutoff && c > add_limit)) { + // Either the character is invalid for the requested base or + // attempting to add it would cause an overflow. error = true; break; } - ret = (ret * base) + c; + ret = ret * base + c; } if (error) ret = neg ? INT64_MIN : INT64_MAX; @@ -64,20 +60,21 @@ bool al_str_get_line(str *buffer, char sep, str *line) { u32 bytes = 0; + // line must be zero'd before calling get_line() for the first time. if (line->data == NULL) { *line = *buffer; - } else if ((bytes = (u32)((line->data += line->len + 1) - buffer->data)) >= buffer->len) { - // Move to the start of the assumed next line. If bytes >= buffer->len, - // there is no next line. - return false; + } else { + // Move to the start of the next line, if it exists. + line->data += line->len + 1; + if ((bytes = line->data - buffer->data) >= buffer->len) + return false; // No more lines. } - // Remaining bytes. bytes = buffer->len - bytes; char *nl = (char *)al_memchr(line->data, sep, bytes); - // If !nl, move to the end of the buffer. + // If we couldn't find a separator, move to the end of the buffer. line->len = !nl ? bytes : (u32)(nl - line->data); return true; diff --git a/tests/array.c b/tests/array.c index 1e70074..08d29eb 100644 --- a/tests/array.c +++ b/tests/array.c @@ -34,10 +34,15 @@ static bool array_test_reserve(void) al_array_reserve(arr, 64); AL_TEST_NEQ((void *)arr.data, NULL, ptr); - AL_TEST_EQ(arr.alloc, 128, u32); + AL_TEST_EQ(arr.alloc, 64, u32); al_array_reserve(arr, 128); + AL_TEST_NEQ((void *)arr.data, NULL, ptr); + AL_TEST_EQ(arr.alloc, 128, u32); + + al_array_reserve(arr, 129); + AL_TEST_NEQ((void *)arr.data, NULL, ptr); AL_TEST_EQ(arr.alloc, 256, u32); diff --git a/tests/array_typed.c b/tests/array_typed.c index 1c401d4..edaa52b 100644 --- a/tests/array_typed.c +++ b/tests/array_typed.c @@ -42,6 +42,11 @@ static bool array_test_reserve(void) al_array_reserve(u32, 64)(&arr, 128); + AL_TEST_NEQ((void *)arr.data, NULL, ptr); + AL_TEST_EQ(arr.alloc, 128, u32); + + al_array_reserve(u32, 64)(&arr, 129); + AL_TEST_NEQ((void *)arr.data, NULL, ptr); AL_TEST_EQ(arr.alloc, 256, u32); diff --git a/tests/str.c b/tests/str.c index 00d0c98..72ed81f 100644 --- a/tests/str.c +++ b/tests/str.c @@ -122,29 +122,47 @@ static bool str_test_get_line(void) { AL_TEST_START("str_get_line"); - str *lines = al_str_c("test\nasdf\ntest2\na\n"); - str *lines_array[] = { al_str_c("test"), al_str_c("asdf"), al_str_c("test2"), al_str_c("a") }; - - str line; - al_memset(&line, 0, sizeof(str)); - u32 c = 0; - - for (; al_str_get_line(lines, '\n', &line); ) { - AL_TEST_LT(c, (u32)ARRAY_SIZE(lines_array), u32); - AL_TEST_TRUE(al_str_eq(&line, lines_array[c++])); - } - - AL_TEST_EQ(c, (u32)ARRAY_SIZE(lines_array), u32); - - lines = al_str_c(""); - - al_memset(&line, 0, sizeof(str)); - c = 0; - - for (; al_str_get_line(lines, '\n', &line); ) { - AL_TEST_LT(c, 1, u32); - AL_TEST_EQ(line.len, 0, u32); - c++; + str *lines0 = al_str_c("test\nasdf\ntest2\na\n "); + str *lines_array0[] = { al_str_c("test"), al_str_c("asdf"), al_str_c("test2"), al_str_c("a"), al_str_c(" ") }; + + str *lines1 = al_str_c("test\nasdf\ntest2\na\n"); + str *lines_array1[] = { al_str_c("test"), al_str_c("asdf"), al_str_c("test2"), al_str_c("a") }; + + str *lines; + str **lines_array; + u32 lines_array_size; + + for (u32 i = 0; i < 2; i++) { + if (i == 0) { + lines = lines0; + lines_array = lines_array0; + lines_array_size = (u32)ARRAY_SIZE(lines_array0); + } else if (i == 1) { + lines = lines1; + lines_array = lines_array1; + lines_array_size = (u32)ARRAY_SIZE(lines_array1); + } + + str line = al_str_zero(); + u32 c = 0; + + for (; al_str_get_line(lines, '\n', &line); ) { + AL_TEST_LT(c, lines_array_size, u32); + AL_TEST_TRUE(al_str_eq(&line, lines_array[c++])); + } + + AL_TEST_EQ(c, lines_array_size, u32); + + lines = al_str_c(""); + + al_memset(&line, 0, sizeof(str)); + c = 0; + + for (; al_str_get_line(lines, '\n', &line); ) { + AL_TEST_LT(c, 1, u32); + AL_TEST_EQ(line.len, 0, u32); + c++; + } } AL_TEST_END(); -- cgit v1.2.3-101-g0448