summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2024-12-22 18:27:58 -0500
committerAndrew Opalach <andrew@akon.city> 2024-12-22 18:27:58 -0500
commit42c161bbeb30c17c1ef39f84e13e54ff207f09da (patch)
treeb5d69e36ef2cbe1e5435b5d70c6bfde6b5cb90c8
parentec924efb4168f906efe8978a6c083d63e550ae3f (diff)
downloadlibalabaster-42c161bbeb30c17c1ef39f84e13e54ff207f09da.tar.gz
libalabaster-42c161bbeb30c17c1ef39f84e13e54ff207f09da.tar.bz2
libalabaster-42c161bbeb30c17c1ef39f84e13e54ff207f09da.zip
all: Major cleanup and pass on readability
Signed-off-by: Andrew Opalach <andrew@akon.city>
-rw-r--r--include/al/array_sort.h29
-rw-r--r--include/al/array_typed.h78
-rw-r--r--include/al/atomic.h2
-rw-r--r--include/al/lib.h46
-rw-r--r--include/al/list.h39
-rw-r--r--include/al/log.h30
-rw-r--r--include/al/macros.h38
-rw-r--r--include/al/str.h38
-rw-r--r--include/al/test.h22
-rw-r--r--include/al/types.h4
-rw-r--r--include/al/wstr.h42
-rw-r--r--src/array.c166
-rw-r--r--src/lib.c211
-rw-r--r--src/log.c104
-rw-r--r--src/ring_buffer.c7
-rw-r--r--src/str.c39
-rw-r--r--tests/array.c7
-rw-r--r--tests/array_typed.c5
-rw-r--r--tests/str.c52
19 files changed, 558 insertions, 401 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 <al/types.h>
#include <al/lib.h>
-#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_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) \
- do { \
- al_array_reserve(arr, (arr).size + 1); \
- al_array_at(arr, (arr).size++) = item; \
- } while (0)
+#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) \
- 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_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_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_at(arr, i, r) \
+AL_MACRO_WRAP \
+({ \
+ r = al_array_at(arr, i); \
+ al_array_remove_at(arr, i); \
+})
-#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(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_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_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_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_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,11 +34,16 @@ 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);
al_array_free(arr);
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
@@ -43,6 +43,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);
al_array_free(u32, 64)(&arr);
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 *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 line;
- al_memset(&line, 0, sizeof(str));
- u32 c = 0;
+ 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") };
- 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++]));
- }
+ 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, (u32)ARRAY_SIZE(lines_array), u32);
+ AL_TEST_EQ(c, lines_array_size, u32);
- lines = al_str_c("");
+ lines = al_str_c("");
- al_memset(&line, 0, sizeof(str));
- c = 0;
+ 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++;
+ 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();