From b07771669ae029d07b76a58ed526da7bc29ec27b Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sat, 7 Oct 2023 17:12:38 -0400 Subject: Add libalabaster Signed-off-by: Andrew Opalach --- include/al/array.h | 11 ++++ include/al/array_sort.h | 19 ++++++ include/al/array_typed.h | 151 ++++++++++++++++++++++++++++++++++++++++++++ include/al/atomic.h | 42 +++++++++++++ include/al/lib.h | 157 +++++++++++++++++++++++++++++++++++++++++++++ include/al/list.h | 132 ++++++++++++++++++++++++++++++++++++++ include/al/log.h | 31 +++++++++ include/al/random.h | 28 +++++++++ include/al/ring_buffer.h | 31 +++++++++ include/al/str.h | 161 +++++++++++++++++++++++++++++++++++++++++++++++ include/al/test.h | 142 +++++++++++++++++++++++++++++++++++++++++ include/al/types.h | 61 ++++++++++++++++++ include/al/wstr.h | 81 ++++++++++++++++++++++++ 13 files changed, 1047 insertions(+) create mode 100644 include/al/array.h create mode 100644 include/al/array_sort.h create mode 100644 include/al/array_typed.h create mode 100644 include/al/atomic.h create mode 100644 include/al/lib.h create mode 100644 include/al/list.h create mode 100644 include/al/log.h create mode 100644 include/al/random.h create mode 100644 include/al/ring_buffer.h create mode 100644 include/al/str.h create mode 100644 include/al/test.h create mode 100644 include/al/types.h create mode 100644 include/al/wstr.h (limited to 'include/al') diff --git a/include/al/array.h b/include/al/array.h new file mode 100644 index 0000000..07fd794 --- /dev/null +++ b/include/al/array.h @@ -0,0 +1,11 @@ +#ifndef _AL_ARRAY_H +#define _AL_ARRAY_H + +#include "lib.h" + +#define AL_ARRAY_MALLOC al_malloc +#define AL_ARRAY_REALLOC al_realloc +#define AL_ARRAY_FREE al_free +#include "../../src/array.c" + +#endif //_AL_ARRAY_H diff --git a/include/al/array_sort.h b/include/al/array_sort.h new file mode 100644 index 0000000..51011f4 --- /dev/null +++ b/include/al/array_sort.h @@ -0,0 +1,19 @@ +#ifndef _AL_ARRAY_SORT_H +#define _AL_ARRAY_SORT_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); + +#endif // _AL_ARRAY_SORT_H diff --git a/include/al/array_typed.h b/include/al/array_typed.h new file mode 100644 index 0000000..678aef4 --- /dev/null +++ b/include/al/array_typed.h @@ -0,0 +1,151 @@ +#ifndef _AL_ARRAY_TYPED_H +#define _AL_ARRAY_TYPED_H + +#ifndef HAVE_GNU_EXTENSIONS +#error "missing required GNU C extensions" +#endif + +#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_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) \ + { \ + return &al_array_data(N, __VA_ARGS__)(a)[i]; \ + } \ + static inline T *al_array_last(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a) \ + { \ + return al_array_at(N, __VA_ARGS__)(a, a->size - 1); \ + } \ + static void al_array_reserve(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 size); \ + static inline void al_array_push(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, T *value) \ + { \ + al_array_reserve(N, __VA_ARGS__)(a, a->size + 1); \ + *al_array_at(N, __VA_ARGS__)(a, a->size++) = *value; \ + } \ + static inline void al_array_pop(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, T *ret) \ + { \ + *ret = *al_array_at(N, __VA_ARGS__)(a, --a->size); \ + } \ + static inline void al_array_remove_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i) \ + { \ + if (UNLIKELY(i == a->size - 1)) { \ + a->size--; \ + } else { \ + al_memmove(al_array_at(N, __VA_ARGS__)(a, i), al_array_at(N, __VA_ARGS__)(a, i + 1), \ + sizeof(T) * (--a->size - i)); \ + } \ + } \ + static inline void al_array_pop_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i, T *ret) \ + { \ + *ret = *al_array_at(N, __VA_ARGS__)(a, i); \ + al_array_remove_at(N, __VA_ARGS__)(a, i); \ + } \ + static inline void al_array_insert(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, T *item, u32 i) \ + { \ + if (a->size > i) { \ + al_array_reserve(N, __VA_ARGS__)(a, a->size + 1); \ + al_memmove(al_array_at(N, __VA_ARGS__)(a, i + 1), al_array_at(N, __VA_ARGS__)(a, i), \ + sizeof(T) * (a->size - i)); \ + a->size++; \ + } else { \ + al_array_reserve(N, __VA_ARGS__)(a, i + 1); \ + a->size = i + 1; \ + } \ + *al_array_at(N, __VA_ARGS__)(a, i) = *item; \ + } \ + 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); \ + a->alloc = size; \ + } \ + static inline void al_array_free(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a) \ + { \ + if (a->data != NULL) al_free(a->data); \ + } + +#define AL_ARRAY_DEFINE(N, T) \ + typedef struct array(N) array(N); \ + struct array(N) { \ + u32 size; \ + u32 alloc; \ + T *data; \ + }; \ + static inline void al_array_init(N)(array(N) *a) \ + { \ + a->size = 0; \ + a->alloc = 0; \ + a->data = NULL; \ + } \ + static inline T *al_array_data(N)(array(N) *a) \ + { \ + return a->data; \ + } \ + AL_ARRAY_DEFINE_FUNCTIONS(N, T,) \ + static inline void al_array_reserve(N)(array(N) *a, u32 size) \ + { \ + _al_array_reserve_internal(N)(a, size); \ + } + +#define AL_ARRAY_INLINE_STORAGE_DEFINE(N, T, S) \ + typedef struct array(N, S) array(N, S); \ + struct array(N, S) { \ + u32 size; \ + u32 alloc; \ + T *data; \ + T inline_data[S]; \ + }; \ + static inline void al_array_init(N, S)(array(N, S) *a) \ + { \ + a->size = 0; \ + a->alloc = S; \ + a->data = NULL; \ + } \ + static inline T *al_array_data(N, S)(array(N, S) *a) \ + { \ + if (a->data) return a->data; \ + else return a->inline_data; \ + } \ + 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; \ + bool copy_inline = a->data == NULL; \ + _al_array_reserve_internal(N, S)(a, size); \ + 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 new file mode 100644 index 0000000..5a1b495 --- /dev/null +++ b/include/al/atomic.h @@ -0,0 +1,42 @@ +#ifndef _AL_ATOMIC_H +#define _AL_ATOMIC_H + +#include + +#include "types.h" + +#define AL_ATOMIC_RELAXED c89atomic_memory_order_relaxed +#define AL_ATOMIC_CONSUME c89atomic_memory_order_consume +#define AL_ATOMIC_ACQUIRE c89atomic_memory_order_acquire +#define AL_ATOMIC_RELEASE c89atomic_memory_order_release +#define AL_ATOMIC_ACQ_REL c89atomic_memory_order_acq_rel +#define AL_ATOMIC_SEQ_CST c89atomic_memory_order_seq_cst + +#define al_atomic_ptr_load(p, order) c89atomic_load_explicit_ptr(((volatile void **)p), order) +#define al_atomic_ptr_store(p, v, order) c89atomic_store_explicit_ptr(((volatile void **)p), (void *)v, order) + +#define atomic_size_t volatile c89atomic_uint64 +#define al_atomic_size_t_load(p, order) ((size_t)c89atomic_load_explicit_64(p, order)) +#define al_atomic_size_t_store(p, v, order) c89atomic_store_explicit_64(p, ((size_t)v), order) + +#define atomic_s64 volatile c89atomic_int64 +#define al_atomic_s64_load(p, order) ((s64)c89atomic_load_explicit_i64(p, order)) +#define al_atomic_s64_store(p, v, order) c89atomic_store_explicit_i64(p, ((s64)v), order) + +#define atomic_f64 volatile f64 +#define al_atomic_f64_load(p, order) ((f64)c89atomic_load_explicit_f64(p, order)) +#define al_atomic_f64_store(p, v, order) c89atomic_store_explicit_f64(p, ((f64)v), order) + +#define atomic_s32 volatile c89atomic_int32 +#define al_atomic_s32_load(p, order) ((s32)c89atomic_load_explicit_i32(p, order)) +#define al_atomic_s32_store(p, v, order) c89atomic_store_explicit_i32(p, ((s32)v), order) + +#define atomic_u8 volatile c89atomic_uint8 +#define al_atomic_u8_load(p, order) c89atomic_load_explicit_8(p, order) +#define al_atomic_u8_store(p, v, order) c89atomic_store_explicit_8(p, ((u8)v), order) + +#define atomic_bool volatile c89atomic_uint8 +#define al_atomic_bool_load(p, order) c89atomic_load_explicit_8(p, order) +#define al_atomic_bool_store(p, v, order) c89atomic_store_explicit_8(p, ((bool)v), order) + +#endif // _AL_ATOMIC_H diff --git a/include/al/lib.h b/include/al/lib.h new file mode 100644 index 0000000..360ba38 --- /dev/null +++ b/include/al/lib.h @@ -0,0 +1,157 @@ +#ifndef _AL_LIB_H +#define _AL_LIB_H + +#include "types.h" + +#if defined(__clang__) || defined(__GNUC__) +#define AL_UNUSED_FUNCTION_PUSH \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#define AL_UNUSED_FUNCTION_POP \ + _Pragma("GCC diagnostic pop") +#else +#define AL_UNUSED_FUNCTION_PUSH +#define AL_UNUSED_FUNCTION_POP +#endif + +#define AL_USE_STDLIB 1 + +#if AL_USE_STDLIB +#include +#include +#include +#include +#include + +void al_malloc_init(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 HAVE_POSIX_MEMALIGN +int al_posix_memalign(void **ptr, size_t alignment, size_t n); +#endif +void al_malloc_stats(u32 *current, u32 *max, u32 *total); +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 *)); + +#define al_memcpy memcpy +#define al_memmove memmove +#define al_memchr memchr +#define al_memcmp memcmp +#define al_memset memset +#define al_bzero bzero +#define al_strlen strlen +#ifdef _DEBUG_ +#define al_assert assert +#else +#define al_assert(expr) do { (void)sizeof(expr); } while (0) +#endif + +#define al_alloc_object(type) (type *)al_calloc(1, sizeof(type)) + +AL_UNUSED_FUNCTION_PUSH + +#define AL_FORCE_DISABLE_OUTPUT 0 + +static inline s32 al_printf(const char *fmt, ...) +{ +#if AL_FORCE_DISABLE_OUTPUT + return 0; +#else + va_list args; + va_start(args, fmt); + s32 ret = vprintf(fmt, args); + va_end(args); + return ret; +#endif +} + +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; + src--; + } + return NULL; +} + +AL_UNUSED_FUNCTION_POP +#endif + +#ifndef LIKELY +#ifdef HAVE_BUILTIN_EXPECT +#define LIKELY(x) __builtin_expect((x), 1) +#else +#define LIKELY(x) x +#endif +#endif + +#ifndef UNLIKELY +#ifdef HAVE_BUILTIN_EXPECT +#define UNLIKELY(x) __builtin_expect((x), 0) +#else +#define UNLIKELY(x) x +#endif +#endif + +#if __GNUC__ >= 3 +#define AL_MAX(a, b) \ +({ \ + __typeof__(a) _a = a; \ + __typeof__(b) _b = b; \ + _a > _b ? _a : _b; \ +}) +#define AL_MIN(a, b) \ +({ \ + __typeof__(a) _a = a; \ + __typeof__(b) _b = b; \ + _a < _b ? _a : _b; \ +}) +#else +#define AL_MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define AL_MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#define AL_CLAMP(n, lo, hi) AL_MIN(hi, AL_MAX(lo, n)) + +#define AL_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#ifndef _MSVC_ +#define AL_EMPTY_DEFAULT(...) AL_EMPTY_DEFAULT_0(__VA_ARGS__, , ) +#define AL_EMPTY_DEFAULT_0(FUNC, T, S, ...) FUNC(T, S) +#define AL_PASTER_EVALUATOR(X, Y) X##_##Y +#define AL_PASTER(X, Y) AL_PASTER_EVALUATOR(X, Y) +#endif + +AL_UNUSED_FUNCTION_PUSH + +static inline size_t al_next_power_of_two(size_t n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + return ++n; +} + +static inline bool al_isspace(char c) +{ + return (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'); +} + +static inline u32 al_u32_inc_wrap(u32 v) +{ + return (v == UINT32_MAX) ? 0 : v + 1; +} + +AL_UNUSED_FUNCTION_PUSH + +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 new file mode 100644 index 0000000..6e1ba29 --- /dev/null +++ b/include/al/list.h @@ -0,0 +1,132 @@ +#ifndef _AL_LIST_H +#define _AL_LIST_H + +#include "lib.h" + +#define AL_LIST_DEFINE(type, name) \ + AL_UNUSED_FUNCTION_PUSH \ + typedef struct list_##name list_##name; \ + struct list_##name { \ + type value; \ + list_##name *next; \ + list_##name *prev; \ + }; \ + 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) { \ + free(l); \ + } \ + 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) { \ + while (n-- > 0 && l) l = l->next; \ + return l; \ + } \ + 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) { \ + list_##name *last = list_last_##name(l); \ + node->prev = last; \ + last->next = node; \ + return l; \ + } else { \ + node->prev = NULL; \ + return node; \ + } \ + } \ + 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_before_##name(list_##name *l, list_##name *s, type value) { \ + if (!l) { \ + list_##name *node = list_new_node_##name(value); \ + node->next = NULL; \ + node->prev = NULL; \ + return node; \ + } else if (!s) { \ + return list_append_##name(l, value); \ + } else if (s == l) { \ + return list_prepend_##name(l, value); \ + } else { \ + list_##name *node = list_new_node_##name(value); \ + s->prev->next = node; \ + node->prev = s->prev; \ + node->next = s; \ + s->prev = node; \ + return l; \ + } \ + } \ + 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; \ + node->prev = NULL; \ + return node; \ + } else if (!s || !s->next) { \ + return list_append_##name(l, value); \ + } else { \ + list_##name *node = list_new_node_##name(value); \ + s->next->prev = node; \ + node->next = s->next; \ + node->prev = s; \ + s->next = node; \ + return l; \ + } \ + } \ + static inline list_##name *list_remove_##name(list_##name *l, list_##name *n) { \ + if (!l) return l; \ + else if (l == n) { \ + if (n->next) { \ + n->next->prev = NULL; \ + } \ + l = n->next; \ + list_free_node_##name(n); \ + } else { \ + n->prev->next = n->next; \ + if (n->next) { \ + n->next->prev = n->prev; \ + } \ + list_free_node_##name(n); \ + } \ + return l; \ + } \ + AL_UNUSED_FUNCTION_POP \ + +#define list(name) list_##name + +// Get element at nth position. +#define al_list_nth(name, list, n) list_nth_##name(list, n) +// Get the last element in the list. +#define al_list_last(name, list) list_last_##name(list) + +// Append value to the end of the list. +// If list is NULL, create new list. +#define al_list_append(name, list, value) list_append_##name(list, value) +// Prepend value to the front of the list. +// If list is NULL, create new list. +#define al_list_prepend(name, list, value) list_prepend_##name(list, value) + +// Insert value before/after sibling. +// If list is NULL, create and return new list. +// If sibiling is NULL (or sibiling->next in after case) append the value to the end of the list. +#define al_list_insert_before(name, list, sibling, value) list_insert_before_##name(list, sibling, value) +#define al_list_insert_after(name, list, sibling, value) list_insert_after_##name(list, sibling, value) + +#define al_list_remove(name, list, node) list_remove_##name(list, node) + +#define al_list_foreach(name, list, node) \ + for (list_##name *node = list; node; node = node->next) + +#endif // _AL_LIST_H diff --git a/include/al/log.h b/include/al/log.h new file mode 100644 index 0000000..8723635 --- /dev/null +++ b/include/al/log.h @@ -0,0 +1,31 @@ +#ifndef _AL_LOG_H +#define _AL_LOG_H + +#include +#include + +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +void al_set_print(void *userdata, s32 (*print_func)(void *, char *)); + +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); +s32 _al_log_nop(const char *section, const char *fmt, ...); + +#define al_log(level, section, fmt, ...) \ + _al_log(#level, section, __FILENAME__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__) +#define al_logv(level, section, fmt, args) \ + _al_logv(#level, section, __FILENAME__, __LINE__, __FUNCTION__, fmt, args) + +#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__) +#ifdef _DEBUG_ +#define al_log_debug(section, fmt, ...) al_log(debug, section, fmt, ##__VA_ARGS__) +#else +#define al_log_debug(section, fmt, ...) _al_log_nop(section, fmt, ##__VA_ARGS__) +#endif + +#endif //_AL_LOG_H diff --git a/include/al/random.h b/include/al/random.h new file mode 100644 index 0000000..f5210b6 --- /dev/null +++ b/include/al/random.h @@ -0,0 +1,28 @@ +#ifndef _AL_RANDOM_H +#define _AL_RANDOM_H + +#include "lib.h" + +#if AL_USE_STDLIB +#include +#endif + +static u16 _al_rand_value = 1; + +AL_UNUSED_FUNCTION_PUSH + +static void al_rand_init(void) +{ + srand((u32)time(NULL)); +} + +// TEMP: "Random" that guarantees we wont get collisions for the current use-case. +static u16 al_rand_u16(void) +{ + if (_al_rand_value == UINT16_MAX) _al_rand_value = 1; + return _al_rand_value++; +} + +AL_UNUSED_FUNCTION_POP + +#endif // _AL_RANDOM_H diff --git a/include/al/ring_buffer.h b/include/al/ring_buffer.h new file mode 100644 index 0000000..359d087 --- /dev/null +++ b/include/al/ring_buffer.h @@ -0,0 +1,31 @@ +#ifndef _AL_RING_BUFFER_H +#define _AL_RING_BUFFER_H + +#include "types.h" +#include "atomic.h" + +struct al_ring_buffer { + u8 *start; + u8 *end; + volatile u8 *read; + volatile u8 *write; +}; + +void al_ring_buffer_init(struct al_ring_buffer *buf, u8 *data, size_t length); + +size_t al_ring_buffer_space(struct al_ring_buffer *buf); +u8 *al_ring_buffer_write_chunk(struct al_ring_buffer *buf, size_t *size); +void al_ring_buffer_append(struct al_ring_buffer *buf, u8 *ptr, size_t n); + +size_t al_ring_buffer_occupied(struct al_ring_buffer *buf); +u8 *al_ring_buffer_read_chunk(struct al_ring_buffer *buf, size_t *size); +void al_ring_buffer_consume(struct al_ring_buffer *buf, u8 *ptr, size_t n); + +size_t al_ring_buffer_write(struct al_ring_buffer *buf, u8 *data, size_t n); +size_t al_ring_buffer_read(struct al_ring_buffer *buf, u8 *ptr, size_t n); +size_t al_ring_buffer_peek(struct al_ring_buffer *buf, u8 *ptr, size_t offset, size_t n); +size_t al_ring_buffer_discard(struct al_ring_buffer *buf, size_t n); + +void al_ring_buffer_reset(struct al_ring_buffer *buf); + +#endif // _AL_RING_BUFFER_H diff --git a/include/al/str.h b/include/al/str.h new file mode 100644 index 0000000..a43d4ba --- /dev/null +++ b/include/al/str.h @@ -0,0 +1,161 @@ +#ifndef _AL_STR_H +#define _AL_STR_H + +#include "lib.h" + +typedef struct { + char *data; + u32 len; + u32 alloc; +} str; + +#define AL_STR_EMPTY (str){ NULL, 0, 0 } + +#define al_str_at(s, i) (s)->data[i] +#define al_str_atr(s, i) (s)->data[(s)->len + i] + +#ifndef __cplusplus +#define al_str_c(s) (&((str){ ((char *)s), (u32)al_strlen(s), 0 })) +#define al_str_w(s, i, n) (&((str){ &(s)[i], ((u32)n), 0 })) +#define al_str_substr(s, start, end) al_str_w((s)->data, start, ((end) - (start))) +#else +#define al_str_cc(s) (((str){ ((char *)s), (u32)al_strlen(s), 0 })) +#define al_str_ww(s, i, n) (((str){ &(s)[i], ((u32)n), 0 })) +#define al_str_substr(s, start, end) al_str_ww((s)->data, start, ((end) - (start))) +#endif + +#define AL_STR_FMT "%.*s" +#define AL_STR_PRINTF(s) (s)->len, (s)->data +#define AL_STR_PRINTF_MAXLEN(s, l) AL_MIN((s)->len, (l)), (s)->data + +AL_UNUSED_FUNCTION_PUSH + +static inline void al_str_free(str *s) +{ + if (s->alloc > 0) al_free(s->data); +} + +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; + + s->data = (char *)((!s->data) ? al_malloc(size) : al_realloc(s->data, size)); + + return size; +} + +static inline void al_str_sized(str *s, u32 size) +{ + *s = AL_STR_EMPTY; + s->alloc = al_str_reserve(s, size); +} + +static inline void al_str_clone(str *dest, str *src) +{ + al_str_sized(dest, src->len); + al_memcpy(dest->data, src->data, src->len); + dest->len = src->len; +} + +static inline void al_str_from(str *s, const char *c_str) +{ + if (!c_str) { + *s = AL_STR_EMPTY; + return; + } + size_t len = al_strlen(c_str); + al_str_sized(s, (u32)len); + al_memcpy(s->data, c_str, len); + s->len = (u32)len; +} + +// Returned c_str must be free'd by the user. +static inline char *al_str_to_c_str(str *s) +{ + char *c = (char *)al_malloc(s->len + 1); + al_memcpy(c, s->data, s->len); + c[s->len] = '\0'; + return c; +} + +static inline void al_str_cat(str *s, str *c) +{ + s->alloc = al_str_reserve(s, s->len + c->len); + al_memcpy(s->data + s->len, c->data, c->len); + s->len += c->len; +} + +static inline void al_str_insert(str *s, str *c, u32 i) +{ + s->alloc = al_str_reserve(s, s->len + c->len); + char *_i = s->data + i; + al_memmove(_i + c->len, _i, s->len - i); + al_memcpy(_i, c->data, c->len); + s->len += c->len; +} + +static inline void al_str_prepend(str *s, str *c) +{ + al_str_insert(s, c, 0); +} + +static inline s32 al_str_cmp(str *s, str *c, u32 start, u32 len) +{ + if (start + len > s->len || len > c->len) { + return -1; + } + return al_memcmp(s->data + start, c->data, len); +} + +static inline bool al_str_eq(str *s, str *c) +{ + return al_str_cmp(s, c, 0, s->len > c->len ? s->len : c->len) == 0; +} + +static inline s32 al_str_find(str *s, char c) +{ + char *loc = (char *)al_memchr(s->data, c, s->len); + if (!loc) return -1; + return (s32)(loc - s->data); +} + +static inline s32 al_str_rfind(str *s, char c) +{ + char *loc = (char *)al_memrchr(s->data, c, s->len); + if (!loc) return -1; + return (s32)(loc - s->data); +} + +// extremely slow. +static inline s32 al_str_find_str(str *s, str *c) +{ + if (c->len > s->len) return -1; + for (u32 i = 0; i < s->len - c->len; i++) { + if (s->data[i] != c->data[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++) { + hash = ((hash << 5) + hash) + s->data[i]; /* hash * 33 + c */ + } + return hash; +} + +s64 al_str_to_long(str *s, s32 base); +bool al_str_tok(str *s, char sep, str *tok); +bool al_str_get_line(str *buffer, str *line); + +#endif // _AL_STR_H diff --git a/include/al/test.h b/include/al/test.h new file mode 100644 index 0000000..41395ce --- /dev/null +++ b/include/al/test.h @@ -0,0 +1,142 @@ +#ifndef _AL_TEST_H +#define _AL_TEST_H + +#include "types.h" +#include "lib.h" + +#define AL_TEST_START_GROUP(name) \ + al_printf("Group \""name"\":\n") + +#define AL_TEST_END_GROUP() \ + return true + +#define AL_TEST_RUN(test) \ + if (!test()) return false; + +#define AL_TEST_START(name) \ + al_printf(" "name"...") + +#define AL_TEST_END() \ + al_printf("OK\n"); \ + 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) + +#define AL_TEST_EQ(a, b, T) \ + AL_TEST_DEF(a, b, T, (AL_TEST_CMP_##T(_a, _b) != 0), \ + "is not equal to") + +#define AL_TEST_NEQ(a, b, T) \ + AL_TEST_DEF(a, b, T, (AL_TEST_CMP_##T(_a, _b) == 0), \ + "is equal to") + +#define AL_TEST_GT(a, b, T) \ + AL_TEST_DEF(a, b, T, (AL_TEST_CMP_##T(_a, _b) != 1), \ + "is less than or equal to") + +#define AL_TEST_GTE(a, b, T) \ + AL_TEST_DEF(a, b, T, (AL_TEST_CMP_##T(_a, _b) != 0 && AL_TEST_CMP_##T(_a, _b) != 1), \ + "is less than") + +#define AL_TEST_LT(a, b, T) \ + AL_TEST_DEF(a, b, T, (AL_TEST_CMP_##T(_a, _b) != -1), \ + "is greater than or equal to") + +#define AL_TEST_LTE(a, b, T) \ + AL_TEST_DEF(a, b, T, (AL_TEST_CMP_##T(_a, _b) != 0 && AL_TEST_CMP_##T(_a, _b) != -1), \ + "is greater than") + +#define AL_TEST_TRUE(a) \ + AL_TEST_DEF(a, true, bool, (AL_TEST_CMP_bool(_a, _b) != 0), \ + "is not") + +#define AL_TEST_FALSE(a) \ + AL_TEST_DEF(a, false, bool, (AL_TEST_CMP_bool(_a, _b) != 0), \ + "is not") + +static inline s32 al_test_bool_cmp(bool a, bool b) +{ + return (a == b) ? 0 : 1; +} + +#define AL_TEST_CMP_bool al_test_bool_cmp +#define AL_TEST_TYPE_bool bool + +#define AL_TEST_FMT_bool "%s" +#define AL_TEST_PRINTF_bool(b) (b ? "true" : "false") + +static inline s32 al_test_u32_cmp(u32 a, u32 b) +{ + if (a == b) return 0; + else if (a < b) return -1; + else return 1; +} + +#define AL_TEST_CMP_u32 al_test_u32_cmp +#define AL_TEST_TYPE_u32 u32 + +#define AL_TEST_FMT_u32 "%d" +#define AL_TEST_PRINTF_u32(i) i + +static inline s32 al_test_s32_cmp(s32 a, s32 b) +{ + if (a == b) return 0; + else if (a < b) return -1; + else return 1; +} + +#define AL_TEST_CMP_s32 al_test_s32_cmp +#define AL_TEST_TYPE_s32 s32 + +#define AL_TEST_FMT_s32 "%i" +#define AL_TEST_PRINTF_s32(i) i + +static inline s32 al_test_size_t_cmp(size_t a, size_t b) +{ + if (a == b) return 0; + else if (a < b) return -1; + else return 1; +} + +#define AL_TEST_CMP_s64 al_test_s64_cmp +#define AL_TEST_TYPE_s64 s64 + +#define AL_TEST_FMT_s64 "%li" +#define AL_TEST_PRINTF_s64(i) i + +static inline s32 al_test_s64_cmp(s64 a, s64 b) +{ + if (a == b) return 0; + else if (a < b) return -1; + else return 1; +} + +#define AL_TEST_CMP_size_t al_test_size_t_cmp +#define AL_TEST_TYPE_size_t size_t + +#define AL_TEST_FMT_size_t "%zu" +#define AL_TEST_PRINTF_size_t(i) i + +static inline s32 al_test_ptr_cmp(void *a, void *b) +{ + if (a == b) return 0; + else if (a < b) return -1; + else return 1; +} + +#define AL_TEST_CMP_ptr al_test_ptr_cmp +#define AL_TEST_TYPE_ptr void * + +#define AL_TEST_FMT_ptr "%p" +#define AL_TEST_PRINTF_ptr(i) i + +#endif // _AL_TEST_H diff --git a/include/al/types.h b/include/al/types.h new file mode 100644 index 0000000..c164127 --- /dev/null +++ b/include/al/types.h @@ -0,0 +1,61 @@ +#ifndef _AL_TYPES_H +#define _AL_TYPES_H + +#ifdef _POSIX_C_SOURCE +#if _POSIX_C_SOURCE < 200112L +#error "libalabaster requires _POSIX_C_SOURCE >= 200112L" +#endif +#else +#define _POSIX_C_SOURCE 200112L +#endif + +#ifdef _XOPEN_SOURCE +#if _XOPEN_SOURCE < 500 +#error "libalabaster requires _XOPEN_SOURCE >= 500" +#endif +#else +#define _XOPEN_SOURCE 500 +#endif + +#if _WIN32 || _WIN64 +#if _WIN64 +#define PTR_IS_64 +#else +#define PTR_IS_32 +#endif +#elif __GNUC__ +#if __x86_64__ || __ppc64__ +#define PTR_IS_64 +#else +#define PTR_IS_32 +#endif +#elif UINTPTR_MAX > UINT_MAX +#define PTR_IS_64 +#else +#define PTR_IS_32 +#endif + +#include +#include +#include +#include +#include + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef int64_t s64; + +typedef float f32; +typedef double f64; + +#ifdef _MSC_VER +#include +typedef SSIZE_T ssize_t; +#endif + +#endif // _AL_TYPES_H diff --git a/include/al/wstr.h b/include/al/wstr.h new file mode 100644 index 0000000..c2e8a07 --- /dev/null +++ b/include/al/wstr.h @@ -0,0 +1,81 @@ +#ifndef _AL_WSTR_H +#define _AL_WSTR_H + +#include "types.h" +#include "lib.h" +#include "str.h" + +#include + +typedef struct { + wchar_t *data; + u32 len; + u32 alloc; +} wstr; + +#define al_wstr_at(w, i) (w)->data[i] +#define al_wstr_atr(w, i) (w)->data[(w)->len + i] + +#define AL_WSTR_FMT "%.*ls" +#define AL_WSTR_PRINTF(w) (w)->len, (w)->data +#define AL_WSTR_PRINTF_MAXLEN(w, l) AL_MIN((w)->len, (l)), (w)->data + +static inline s32 al_wchar_width(wchar_t wc) +{ + return wcwidth(wc); +} + +static inline void al_wstr_free(wstr *w) +{ + if (w->alloc > 0) al_free(w->data); +} + +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; + + w->data = (wchar_t *)((!w->data) ? al_malloc(size) : al_realloc(w->data, size)); + + return size; +} + +static inline void al_wstr_sized(wstr *w, u32 size) +{ + w->len = 0; + w->alloc = 0; + w->data = NULL; + w->alloc = al_wstr_reserve(w, size * sizeof(wchar_t)); + al_memset(w->data, 0, w->alloc); +} + +static inline void al_wstr_from_cstr(wstr *w, char *c) +{ + size_t n = mbstowcs(NULL, c, 0) + 1; + al_wstr_sized(w, n); + w->len = mbstowcs(w->data, c, n); + w->data[w->len] = L'\0'; +} + +static inline void al_wstr_from_str(wstr *w, str *s) +{ + char *c_str = al_str_to_c_str(s); + al_wstr_from_cstr(w, c_str); + al_free(c_str); +} + +static inline s32 al_wstr_width(wstr *w) +{ + s32 width = 0; + for (u32 i = 0; i < w->len; i++) { + width += al_wchar_width(al_wstr_at(w, i)); + } + return width; +} + +#endif // _AL_WSTR_H -- cgit v1.2.3-101-g0448