summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2025-01-17 11:20:17 -0500
committerAndrew Opalach <andrew@akon.city> 2025-01-17 11:20:17 -0500
commit209310c561d89c9ed2040aa7053b320d32cc393c (patch)
treecb26e18d275fa1d37afa903134e90e7c4c260484
parent27b5e13d75c58d5e32538a4b5aef65ab86f4bb38 (diff)
downloadlibalabaster-209310c561d89c9ed2040aa7053b320d32cc393c.tar.gz
libalabaster-209310c561d89c9ed2040aa7053b320d32cc393c.tar.bz2
libalabaster-209310c561d89c9ed2040aa7053b320d32cc393c.zip
all: Consider types and numerical limits
- Vastly improve tests. - Change array/str/wstr APIs. - Use ptrdiff_t instead of size_t in ring buffer. - Make random seed thread-local. - Log now uses a static thread-local buffer instead of a malloc'd buffer. Signed-off-by: Andrew Opalach <andrew@akon.city>
-rw-r--r--include/al/array_sort.h37
-rw-r--r--include/al/array_typed.h116
-rw-r--r--include/al/atomic.h6
-rw-r--r--include/al/lib.h37
-rw-r--r--include/al/log.h4
-rw-r--r--include/al/macros.h30
-rw-r--r--include/al/random.h15
-rw-r--r--include/al/ring_buffer.h22
-rw-r--r--include/al/str.h128
-rw-r--r--include/al/test.h49
-rw-r--r--include/al/types.h3
-rw-r--r--include/al/wstr.h119
-rw-r--r--meson.build6
-rwxr-xr-xscripts/line_count.sh3
-rw-r--r--src/array.c244
-rw-r--r--src/lib.c19
-rw-r--r--src/log.c45
-rw-r--r--src/random.c4
-rw-r--r--src/ring_buffer.c68
-rw-r--r--src/str.c47
-rw-r--r--tests/array.c427
-rw-r--r--tests/array.h2
-rw-r--r--tests/array_typed.c223
-rw-r--r--tests/array_typed.h2
-rw-r--r--tests/common.h12
-rw-r--r--tests/lib.c132
-rw-r--r--tests/main.c27
-rw-r--r--tests/ring_buffer.c177
-rw-r--r--tests/str.c358
-rw-r--r--tests/str.h2
30 files changed, 1366 insertions, 998 deletions
diff --git a/include/al/array_sort.h b/include/al/array_sort.h
index b6d7468..f10766f 100644
--- a/include/al/array_sort.h
+++ b/include/al/array_sort.h
@@ -3,24 +3,39 @@
#include "lib.h"
+/* https://en.wikipedia.org/wiki/Insertion_sort
+i ← 1
+while i < length(A)
+ x ← A[i]
+ j ← i
+ while j > 0 and A[j-1] > x
+ A[j] ← A[j-1]
+ j ← j - 1
+ end while
+ A[j] ← x
+ i ← i + 1
+end while
+*/
+
#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--; \
+{ \
+ u32 i = 1, k; \
+ type x; \
+ while (i < count) { \
+ k = i; \
+ x = (data)[i]; \
+ while (k > 0 && cmp(&(data)[k - 1], &x) > 0) { \
+ (data)[k] = (data)[k - 1]; \
+ k--; \
} \
- data[j + 1] = x; \
+ (data)[k] = x; \
i++; \
} \
-})
+} AL_MACRO_END
#ifdef AL_USE_STDLIB
-#define AL_STDLIB_QSORT(data, type, count, cmp) qsort(data, count, sizeof(type), cmp)
+#define AL_STDLIB_QSORT(data, type, count, cmp) qsort(data, (size_t)count, sizeof(type), cmp)
#endif
#endif // _AL_ARRAY_SORT_H
diff --git a/include/al/array_typed.h b/include/al/array_typed.h
index 75b9d83..e7a4f80 100644
--- a/include/al/array_typed.h
+++ b/include/al/array_typed.h
@@ -39,118 +39,110 @@
#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) \
+ static inline T *al_array_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i) \
{ \
- return &al_array_data(N, __VA_ARGS__)(a)[i]; \
+ return &al_array_data(N, __VA_ARGS__)(array)[i]; \
} \
- static inline T *al_array_last(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a) \
+ static inline T *al_array_last(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array) \
{ \
- return al_array_at(N, __VA_ARGS__)(a, a->size - 1); \
+ return al_array_at(N, __VA_ARGS__)(array, array->count - 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) \
+ static void al_array_reserve(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 count); \
+ static inline void al_array_push(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, T value) \
{ \
- al_array_reserve(N, __VA_ARGS__)(a, a->size + 1); \
- *al_array_at(N, __VA_ARGS__)(a, a->size++) = *value; \
+ al_array_reserve(N, __VA_ARGS__)(array, array->count + 1); \
+ *al_array_at(N, __VA_ARGS__)(array, array->count++) = value; \
} \
- static inline void al_array_pop(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, T *ret) \
+ static inline void al_array_insert(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i, T item) \
{ \
- *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)); \
+ al_array_reserve(N, __VA_ARGS__)(array, array->count + 1); \
+ if (i != array->count - 1) { \
+ al_memmove(al_array_at(N, __VA_ARGS__)(array, i + 1), al_array_at(N, __VA_ARGS__)(array, i), \
+ (array->count - i) * sizeof(T)); \
} \
+ array->count++; \
+ *al_array_at(N, __VA_ARGS__)(array, i) = item; \
} \
- static inline void al_array_pop_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i, T *ret) \
+ static inline void al_array_pop(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, T *ret) \
{ \
- *ret = *al_array_at(N, __VA_ARGS__)(a, i); \
- al_array_remove_at(N, __VA_ARGS__)(a, i); \
+ *ret = *al_array_at(N, __VA_ARGS__)(array, --array->count); \
} \
- static inline void al_array_insert(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i, T *item) \
+ static inline void al_array_remove_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, 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++; \
+ if (UNLIKELY(i == array->count - 1)) { \
+ array->count--; \
} else { \
- al_array_reserve(N, __VA_ARGS__)(a, i + 1); \
- a->size = i + 1; \
+ al_memmove(al_array_at(N, __VA_ARGS__)(array, i), al_array_at(N, __VA_ARGS__)(array, i + 1), \
+ (--array->count - i) * sizeof(T)); \
} \
- *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) \
+ static inline T al_array_pop_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i) \
{ \
- 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; \
+ T ret = *al_array_at(N, __VA_ARGS__)(array, i); \
+ al_array_remove_at(N, __VA_ARGS__)(array, i); \
+ return ret; \
+ } \
+ static inline void _al_array_reserve_internal(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 size) \
+ { \
+ array->alloc = al_default_growing_allocation((void **)&array->data, array->alloc, size, al_malloc, al_realloc); \
} \
- static inline void al_array_free(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a) \
+ static inline void al_array_free(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array) \
{ \
- if (a->data != NULL) al_free(a->data); \
+ if (array->data != NULL) al_free(array->data); \
}
#define AL_ARRAY_DEFINE(N, T) \
typedef struct array(N) array(N); \
struct array(N) { \
- u32 size; \
+ u32 count; \
u32 alloc; \
T *data; \
}; \
- static inline void al_array_init(N)(array(N) *a) \
+ static inline void al_array_init(N)(array(N) *array) \
{ \
- a->size = 0; \
- a->alloc = 0; \
- a->data = NULL; \
+ array->count = 0; \
+ array->alloc = 0; \
+ array->data = NULL; \
} \
- static inline T *al_array_data(N)(array(N) *a) \
+ static inline T *al_array_data(N)(array(N) *array) \
{ \
- return a->data; \
+ return array->data; \
} \
AL_ARRAY_DEFINE_FUNCTIONS(N, T,) \
- static inline void al_array_reserve(N)(array(N) *a, u32 size) \
+ static inline void al_array_reserve(N)(array(N) *array, u32 count) \
{ \
- _al_array_reserve_internal(N)(a, size); \
+ _al_array_reserve_internal(N)(array, count * sizeof(T)); \
}
#define AL_ARRAY_INLINE_STORAGE_DEFINE(N, T, S) \
typedef struct array(N, S) array(N, S); \
struct array(N, S) { \
- u32 size; \
+ u32 count; \
u32 alloc; \
T *data; \
T inline_data[S]; \
}; \
- static inline void al_array_init(N, S)(array(N, S) *a) \
+ static inline void al_array_init(N, S)(array(N, S) *array) \
{ \
- a->size = 0; \
- a->alloc = S; \
- a->data = NULL; \
+ array->count = 0; \
+ array->alloc = S * sizeof(T); \
+ array->data = NULL; \
} \
- static inline T *al_array_data(N, S)(array(N, S) *a) \
+ static inline T *al_array_data(N, S)(array(N, S) *array) \
{ \
- if (a->data) return a->data; \
- else return a->inline_data; \
+ if (array->data) return array->data; \
+ else return array->inline_data; \
} \
AL_ARRAY_DEFINE_FUNCTIONS(N, T, S) \
- static inline void al_array_reserve(N, S)(array(N, S) *a, u32 size) \
+ static inline void al_array_reserve(N, S)(array(N, S) *array, u32 count) \
{ \
- if (S >= size) { \
+ if (S >= count) { \
return; \
} \
- bool copy_inline = a->data == NULL; \
- _al_array_reserve_internal(N, S)(a, size); \
+ bool copy_inline = array->data == NULL; \
+ _al_array_reserve_internal(N, S)(array, count * sizeof(T)); \
if (UNLIKELY(copy_inline)) { \
- al_memcpy(a->data, a->inline_data, sizeof(T) * a->size); \
+ al_memcpy(array->data, array->inline_data, array->count * sizeof(T)); \
} \
}
diff --git a/include/al/atomic.h b/include/al/atomic.h
index adb25c0..5c4ccc4 100644
--- a/include/al/atomic.h
+++ b/include/al/atomic.h
@@ -1,10 +1,10 @@
#ifndef _AL_ATOMIC_H
#define _AL_ATOMIC_H
-#include <c89atomic.h>
-
#include "lib.h"
+#include <c89atomic.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
@@ -58,8 +58,10 @@ typedef f32 c89atomic_f32;
#if defined C89ATOMIC_64BIT
AL_ATOMIC_DEFINE(size_t, uint64, 64)
+AL_ATOMIC_DEFINE(ptrdiff_t, int64, i64)
#elif defined C89ATOMIC_32BIT
AL_ATOMIC_DEFINE(size_t, uint32, 32)
+AL_ATOMIC_DEFINE(ptrdiff_t, int32, i32)
#endif
AL_ATOMIC_DEFINE(u64, uint64, 64);
AL_ATOMIC_DEFINE_EXT(u64, uint64, 64);
diff --git a/include/al/lib.h b/include/al/lib.h
index 30f54b0..4f03235 100644
--- a/include/al/lib.h
+++ b/include/al/lib.h
@@ -4,6 +4,9 @@
#include "types.h"
#include "macros.h"
+// Piggyback off c89atomic for pointer size macros.
+#include <c89atomic.h>
+
#define AL_USE_STDLIB
//#define AL_MEMORY_TRACKING
//#define AL_FORCE_DISABLE_OUTPUT
@@ -72,8 +75,10 @@ void al_malloc_stats(size_t *current, size_t *peak, size_t *total);
#define al_memset memset
#define al_bzero bzero
#define al_strlen strlen
+#define al_strndup strndup
#define al_snprintf snprintf
#define al_vsnprintf vsnprintf
+#define al_fflush fflush
#ifdef _DEBUG_
#define al_assert assert
#else
@@ -82,15 +87,22 @@ void al_malloc_stats(size_t *current, size_t *peak, size_t *total);
#define al_assert_and_return(...) \
AL_MACRO_WRAP \
-({ \
+{ \
al_assert(false); \
return __VA_ARGS__; \
-})
+} AL_MACRO_END
#define al_alloc_object(type) (type *)al_calloc(1, sizeof(type))
AL_UNUSED_FUNCTION_PUSH
+// https://stackoverflow.com/a/66346831
+static inline size_t al_strnlen(const char *s, size_t n)
+{
+ const char *p = (const char *)memchr(s, '\0', n);
+ return p ? (size_t)(p - s) : n;
+}
+
static inline s32 al_printf(const char *fmt, ...)
{
#ifdef AL_FORCE_DISABLE_OUTPUT
@@ -184,11 +196,21 @@ static inline u32 al_u32_inc_wrap(u32 v)
return (v == UINT32_MAX) ? 0 : v + 1;
}
+static inline u32 al_u32_dec_wrap(u32 v)
+{
+ return (v == 0) ? UINT32_MAX : v - 1;
+}
+
static inline u16 al_u16_inc_wrap(u16 v)
{
return (v == UINT16_MAX) ? 0 : v + 1;
}
+static inline u32 al_add_wrap(u32 v, u32 add, u32 max)
+{
+ return (v > max - add) ? (add - (max - v)) : v + add;
+}
+
static inline u32 al_u32_add_wrap(u32 v, u32 add)
{
return (v > UINT32_MAX - add) ? (add - (UINT32_MAX - v)) : v + add;
@@ -196,15 +218,24 @@ static inline u32 al_u32_add_wrap(u32 v, u32 add)
static inline u16 al_u16_add_wrap(u16 v, u16 add)
{
- return (v > UINT16_MAX - add) ? (add - (UINT16_MAX - v)) : v + add;
+ return (v > UINT16_MAX - add) ? (u16)(add - (UINT16_MAX - v)) : v + add;
}
AL_UNUSED_FUNCTION_POP
+#if defined C89ATOMIC_64BIT
+#define MAX_ALLOC_32 UINT32_MAX
+#elif defined C89ATOMIC_32BIT
+#define MAX_ALLOC_32 ((INT32_MAX - 1) / 4)
+#endif
+
// Once a growing allocation expands past this number,
// only grow in multiples of it.
extern u32 al_grow_step;
+u32 al_default_growing_allocation(void **ptr, u32 prev_size, u32 size,
+ void *(*malloc_func)(size_t), void *(*realloc_func)(void *, size_t));
+
// Defaults to 4KB.
extern size_t al_page_size;
void al_set_page_size(size_t size);
diff --git a/include/al/log.h b/include/al/log.h
index 53ffbea..fbd5e48 100644
--- a/include/al/log.h
+++ b/include/al/log.h
@@ -1,12 +1,14 @@
#ifndef _AL_LOG_H
#define _AL_LOG_H
+// https://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
+
#include <al/types.h>
#include <al/lib.h>
#define __LOCATION__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__
-#define AL_LOG_MESSAGE_SIZE 256
+#define AL_LOG_MESSAGE_SIZE 256u
enum {
AL_LOG_INFO = 0,
diff --git a/include/al/macros.h b/include/al/macros.h
index 81fb581..715718a 100644
--- a/include/al/macros.h
+++ b/include/al/macros.h
@@ -1,7 +1,8 @@
#ifndef _AL_MACROS_H
#define _AL_MACROS_H
-#define AL_MACRO_WRAP(c) do { c } while(0)
+#define AL_MACRO_WRAP do {
+#define AL_MACRO_END } while(0)
#define AL_PASTER_EVALUATOR(X, Y) X##_##Y
#define AL_PASTER(X, Y) AL_PASTER_EVALUATOR(X, Y)
@@ -42,22 +43,24 @@
_a > _b ? _a : _b; \
})
#define CLAMP(n, lo, hi) MIN(hi, MAX(lo, n))
-#endif
-
-/*
+#else
// Compatible/Pedantic min/max.
+/*
+#error "MIN/MAX/CLAMP should not be used in this mode as they\
+ differ in behavior without support for statement expressions"
+*/
#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))
-*/
+#endif
#define SWAP(a, b) \
AL_MACRO_WRAP \
-({ \
+{ \
__typeof__(a) tmp = a; \
a = b; \
b = tmp; \
-})
+} AL_MACRO_END
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@@ -76,19 +79,26 @@ AL_MACRO_WRAP \
#error "Conflicting definitions for common attributes"
#endif
-#if __has_attribute(__counted_by__)
+// https://github.com/google/double-conversion/pull/131/files
+#ifdef __has_attribute
+#define AL_HAS_ATTRIBUTE(x) __has_attribute(x)
+#else
+#define AL_HAS_ATTRIBUTE(x) 0
+#endif
+
+#if AL_HAS_ATTRIBUTE(__counted_by__)
#define __counted_by(member) __attribute__((__counted_by__(member)))
#else
#define __counted_by(member)
#endif
-#if __has_attribute(__sized_by__)
+#if AL_HAS_ATTRIBUTE(__sized_by__)
#define __sized_by(member) __attribute__((__sized_by__(member)))
#else
#define __sized_by(member)
#endif
-#ifdef _MSVC_
+#ifdef _MSC_VER
#define __thread __declspec(thread)
#endif
diff --git a/include/al/random.h b/include/al/random.h
index 358a915..3d0d7cb 100644
--- a/include/al/random.h
+++ b/include/al/random.h
@@ -2,20 +2,27 @@
#define _AL_RANDOM_H
#include "lib.h"
-
-#include <time.h>
+#include "macros.h"
#define AL_RAND_MAX RAND_MAX
AL_UNUSED_FUNCTION_PUSH
-static void al_rand_init(void)
+extern u32 al_rand_seed;
+extern __thread bool al_rand_set;
+
+static void al_rand_init(u32 seed)
{
- srand((u32)time(NULL));
+ al_rand_seed = seed;
}
static s32 al_rand(void)
{
+ if (UNLIKELY(!al_rand_set)) {
+ // srand() is thread-local on Windows CRT.
+ srand(al_rand_seed);
+ al_rand_set = true;
+ }
return rand();
}
diff --git a/include/al/ring_buffer.h b/include/al/ring_buffer.h
index acfe4b0..32292e9 100644
--- a/include/al/ring_buffer.h
+++ b/include/al/ring_buffer.h
@@ -10,20 +10,20 @@ struct al_ring_buffer {
u8 *write;
};
-void al_ring_buffer_init(struct al_ring_buffer *buf, u8 *data, size_t length);
+void al_ring_buffer_init(struct al_ring_buffer *buf, u8 *data, ptrdiff_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);
+ptrdiff_t al_ring_buffer_space(struct al_ring_buffer *buf);
+u8 *al_ring_buffer_write_chunk(struct al_ring_buffer *buf, ptrdiff_t *size);
+void al_ring_buffer_append(struct al_ring_buffer *buf, u8 *ptr, ptrdiff_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);
+ptrdiff_t al_ring_buffer_occupied(struct al_ring_buffer *buf);
+u8 *al_ring_buffer_read_chunk(struct al_ring_buffer *buf, ptrdiff_t *size);
+void al_ring_buffer_consume(struct al_ring_buffer *buf, u8 *ptr, ptrdiff_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);
+ptrdiff_t al_ring_buffer_write(struct al_ring_buffer *buf, u8 *data, ptrdiff_t n);
+ptrdiff_t al_ring_buffer_read(struct al_ring_buffer *buf, u8 *ptr, ptrdiff_t n);
+ptrdiff_t al_ring_buffer_peek(struct al_ring_buffer *buf, u8 *ptr, ptrdiff_t offset, ptrdiff_t n);
+ptrdiff_t al_ring_buffer_discard(struct al_ring_buffer *buf, ptrdiff_t n);
void al_ring_buffer_reset(struct al_ring_buffer *buf);
diff --git a/include/al/str.h b/include/al/str.h
index 74cf922..5ee51d0 100644
--- a/include/al/str.h
+++ b/include/al/str.h
@@ -5,31 +5,33 @@
#include "macros.h"
typedef struct {
- u32 len;
+ u32 length;
u32 alloc;
char *__sized_by(alloc) data;
} str;
-#define al_str_zero() (str){ 0, 0, NULL }
+#define al_str_null() ((str){ 0, 0, NULL })
+#define al_str_npos ((u32)-1)
#define al_str_at(s, i) (s)->data[i]
-#define al_str_atr(s, i) (s)->data[(s)->len + i]
+#define al_str_atr(s, i) (s)->data[(s)->length - (i)]
-#define al_string_if_literal(s) ((char *)(s "")) // use al_str_cr for runtime.
-#define al_str_c(s) (&((str){ (u32)((sizeof(s) / sizeof(char)) - 1), 0, al_string_if_literal(s) }))
-#define al_str_cr(s) (&((str){ (u32)al_strlen(s), 0, ((char *)(s)) })) // runtime
-#define al_str_w(s, i, n) (&((str){ ((u32)(n)), 0, &(s)[i] }))
+#define al_chars_if_literal(s) ((char *)(s "")) // use al_str_cs/cr for non-static arrays.
+#define al_str_c(c) ((str){ (u32)(sizeof(c) - 1), 0, al_chars_if_literal(c) })
+#define al_str_cs(c) ((str){ (u32)al_strnlen(c, sizeof(c)), 0, ((char *)(c)) }) // (s)ized
+#define al_str_cr(c) ((str){ (u32)al_strnlen(c, MAX_ALLOC_32), 0, ((char *)(c)) }) // (r)untime
+
+#define al_str_w(c, i, n) ((str){ ((u32)(n)), 0, &(c)[i] })
#define al_str_substr(s, start, end) al_str_w((s)->data, start, ((end) - (start)))
-#define AL_STR_FMT "%.*s"
-#define AL_STR_PRINTF(s) (s)->len, (s)->data
-#define AL_STR_PRINTF_MAXLEN(s, l) MIN((s)->len, (l)), (s)->data
+#define al_str_fmt(s) (s)->length, (s)->data
+#define al_str_fmt_maxlen(s, l) MIN((s)->length, (l)), (s)->data
AL_UNUSED_FUNCTION_PUSH
static inline bool al_str_is_empty(str *s)
{
- return s->len == 0;
+ return s->length == 0;
}
static inline void al_str_free(str *s)
@@ -39,43 +41,33 @@ static inline void al_str_free(str *s)
static inline u32 al_str_reserve(str *s, u32 size)
{
- 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));
- al_assert(s->data);
-
- return size;
+ return al_default_growing_allocation((void **)&s->data, s->alloc, size, al_malloc, al_realloc);
}
static inline void al_str_sized(str *s, u32 size)
{
- *s = al_str_zero();
+ *s = al_str_null();
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;
+ al_str_sized(dest, src->length);
+ al_memcpy(dest->data, src->data, src->length);
+ dest->length = src->length;
}
static inline void al_str_from(str *s, const char *c_str)
{
- size_t len = al_strlen(c_str);
- al_str_sized(s, (u32)len);
- al_memcpy(s->data, c_str, len);
- s->len = (u32)len;
+ size_t length = al_strlen(c_str);
+ al_str_sized(s, (u32)length);
+ al_memcpy(s->data, c_str, length);
+ s->length = (u32)length;
}
static inline void al_str_to_lower(str *s)
{
- for (u32 i = 0; i < s->len; i++) {
+ for (u32 i = 0; i < s->length; i++) {
al_str_at(s, i) = al_tolower(al_str_at(s, i));
}
}
@@ -83,26 +75,26 @@ static inline void al_str_to_lower(str *s)
// 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';
+ char *c = (char *)al_malloc(s->length + 1);
+ al_memcpy(c, s->data, s->length);
+ c[s->length] = '\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;
+ s->alloc = al_str_reserve(s, s->length + c->length);
+ al_memcpy(s->data + s->length, c->data, c->length);
+ s->length += c->length;
}
static inline void al_str_insert(str *s, u32 i, str *c)
{
- s->alloc = al_str_reserve(s, s->len + c->len);
+ s->alloc = al_str_reserve(s, s->length + c->length);
char *data = s->data + i;
- al_memmove(data + c->len, data, s->len - i);
- al_memcpy(data, c->data, c->len);
- s->len += c->len;
+ al_memmove(data + c->length, data, s->length - i);
+ al_memcpy(data, c->data, c->length);
+ s->length += c->length;
}
static inline void al_str_prepend(str *s, str *c)
@@ -110,65 +102,57 @@ 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 i, u32 len)
+static inline s32 al_str_cmp(str *s, str *c, u32 i, u32 length)
{
- if (i + len > s->len || len > c->len) {
- return -1;
- }
- return al_memcmp(&al_str_at(s, i), c->data, len);
+ if (length > c->length) return 1;
+ else if (length + i > s->length) return -1;
+ return al_memcmp(&al_str_at(s, i), c->data, length);
}
static inline bool al_str_eq(str *s, str *c)
{
- return al_str_cmp(s, c, 0, MAX(s->len, c->len)) == 0;
+ return al_str_cmp(s, c, 0, MAX(s->length, c->length)) == 0;
}
-static inline s32 al_str_find(str *s, char c)
+static inline u32 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);
+ char *loc = (char *)al_memchr(s->data, c, s->length);
+ return loc ? (u32)(loc - s->data) : al_str_npos;
}
-static inline s32 al_str_rfind(str *s, char c)
+static inline u32 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);
+ char *loc = (char *)al_memrchr(s->data, c, s->length);
+ return loc ? (u32)(loc - s->data) : al_str_npos;
}
// extremely slow.
-static inline s32 al_str_find_str(str *s, str *c)
+static inline u32 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 (al_str_at(s, i) == al_str_at(c, 0) && al_str_cmp(s, c, i, c->len) == 0) {
- return i;
+ if (c->length <= s->length) {
+ for (u32 i = 0; i < s->length - c->length; i++) {
+ if (al_str_at(s, i) == al_str_at(c, 0) &&
+ (al_str_cmp(s, c, i, c->length) == 0)) {
+ return i;
+ }
}
}
-
- return -1;
+ return al_str_npos;
}
static inline u32 al_str_hash(str *s)
{
u32 hash = 5381;
- for (u32 i = 0; i < s->len; i++) {
- hash = ((hash << 5) + hash) + al_str_at(s, i); /* hash * 33 + c */
+ for (u32 i = 0; i < s->length; i++) {
+ // hash * 33 + c
+ hash = ((hash << 5) + hash) + (uchar)al_str_at(s, i);
}
return hash;
}
AL_UNUSED_FUNCTION_POP
-s64 al_str_to_long(str *s, s32 base);
+s64 al_str_to_long(str *s, u32 base, bool *error);
bool al_str_get_line(str *buffer, char sep, str *line);
#endif // _AL_STR_H
diff --git a/include/al/test.h b/include/al/test.h
index da4f024..8fc37e3 100644
--- a/include/al/test.h
+++ b/include/al/test.h
@@ -14,7 +14,11 @@
if (!test()) return false;
#define AL_TEST_START(name) \
- al_printf(" "name"...")
+AL_MACRO_WRAP \
+{ \
+ al_printf(" "name"..."); \
+ al_fflush(stdout); \
+} AL_MACRO_END
#define AL_TEST_END() \
al_printf("OK\n"); \
@@ -22,7 +26,7 @@
#define AL_TEST_DEF(a, b, T, cmp, explain) \
AL_MACRO_WRAP \
-({ \
+{ \
AL_TEST_TYPE_##T _a = a; \
AL_TEST_TYPE_##T _b = b; \
if (cmp) { \
@@ -30,7 +34,7 @@ AL_MACRO_WRAP \
AL_TEST_PRINTF_##T(_a), AL_TEST_PRINTF_##T(_b)); \
return false; \
} \
-})
+} AL_MACRO_END
#define AL_TEST_EQ(a, b, T) \
AL_TEST_DEF(a, b, T, (AL_TEST_CMP_##T(_a, _b) != 0), \
@@ -64,6 +68,7 @@ AL_MACRO_WRAP \
AL_TEST_DEF(a, false, bool, (AL_TEST_CMP_bool(_a, _b) != 0), \
"is not")
+// bool
static inline s32 al_test_bool_cmp(bool a, bool b)
{
return (a == b) ? 0 : 1;
@@ -75,6 +80,21 @@ static inline s32 al_test_bool_cmp(bool a, bool b)
#define AL_TEST_FMT_bool "%s"
#define AL_TEST_PRINTF_bool(b) BOOLSTR(b)
+// u8
+static inline s32 al_test_u8_cmp(u8 a, u8 b)
+{
+ if (a == b) return 0;
+ else if (a < b) return -1;
+ else return 1;
+}
+
+#define AL_TEST_CMP_u8 al_test_u8_cmp
+#define AL_TEST_TYPE_u8 u8
+
+#define AL_TEST_FMT_u8 "%hhu"
+#define AL_TEST_PRINTF_u8(i) i
+
+// u16
static inline s32 al_test_u16_cmp(u16 a, u16 b)
{
if (a == b) return 0;
@@ -88,6 +108,7 @@ static inline s32 al_test_u16_cmp(u16 a, u16 b)
#define AL_TEST_FMT_u16 "%hu"
#define AL_TEST_PRINTF_u16(i) i
+// u32
static inline s32 al_test_u32_cmp(u32 a, u32 b)
{
if (a == b) return 0;
@@ -101,6 +122,7 @@ static inline s32 al_test_u32_cmp(u32 a, u32 b)
#define AL_TEST_FMT_u32 "%u"
#define AL_TEST_PRINTF_u32(i) i
+// s32
static inline s32 al_test_s32_cmp(s32 a, s32 b)
{
if (a == b) return 0;
@@ -114,7 +136,8 @@ static inline s32 al_test_s32_cmp(s32 a, s32 b)
#define AL_TEST_FMT_s32 "%d"
#define AL_TEST_PRINTF_s32(i) i
-static inline s32 al_test_size_t_cmp(size_t a, size_t b)
+// s64
+static inline s32 al_test_s64_cmp(s64 a, s64 b)
{
if (a == b) return 0;
else if (a < b) return -1;
@@ -127,7 +150,8 @@ static inline s32 al_test_size_t_cmp(size_t a, size_t b)
#define AL_TEST_FMT_s64 "%ld"
#define AL_TEST_PRINTF_s64(i) i
-static inline s32 al_test_s64_cmp(s64 a, s64 b)
+// size_t
+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;
@@ -140,6 +164,21 @@ static inline s32 al_test_s64_cmp(s64 a, s64 b)
#define AL_TEST_FMT_size_t "%zu"
#define AL_TEST_PRINTF_size_t(i) i
+// ptrdiff_t
+static inline s32 al_test_ptrdiff_t_cmp(ptrdiff_t a, ptrdiff_t b)
+{
+ if (a == b) return 0;
+ else if (a < b) return -1;
+ else return 1;
+}
+
+#define AL_TEST_CMP_ptrdiff_t al_test_ptrdiff_t_cmp
+#define AL_TEST_TYPE_ptrdiff_t ptrdiff_t
+
+#define AL_TEST_FMT_ptrdiff_t "%zd"
+#define AL_TEST_PRINTF_ptrdiff_t(i) i
+
+// pointer
static inline s32 al_test_ptr_cmp(void *a, void *b)
{
if (a == b) return 0;
diff --git a/include/al/types.h b/include/al/types.h
index 3398700..fc88077 100644
--- a/include/al/types.h
+++ b/include/al/types.h
@@ -1,6 +1,8 @@
#ifndef _AL_TYPES_H
#define _AL_TYPES_H
+// https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Integer-Const-Type.html
+
#ifdef _POSIX_C_SOURCE
#if _POSIX_C_SOURCE < 200112L
#error "libalabaster requires _POSIX_C_SOURCE >= 200112L"
@@ -39,6 +41,7 @@ typedef double f64;
// 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;
+typedef unsigned char uchar;
#ifdef _MSC_VER
#include <BaseTsd.h>
diff --git a/include/al/wstr.h b/include/al/wstr.h
index 561e236..c5734ba 100644
--- a/include/al/wstr.h
+++ b/include/al/wstr.h
@@ -7,27 +7,34 @@
#include <wchar.h>
typedef struct {
- u32 len;
+ u32 length;
u32 alloc;
wchar_t *__sized_by(alloc) data;
} wstr;
-#define al_wstr_zero() (wstr){ 0, 0, NULL }
+#define al_wstr_null() ((wstr){ 0, 0, NULL })
+#define al_wstr_npos ((u32)-1)
#define al_wstr_at(w, i) (w)->data[i]
-#define al_wstr_atr(w, i) (w)->data[(w)->len + i]
+#define al_wstr_atr(w, i) (w)->data[(w)->length - (i)]
-#define al_wide_string_if_literal(w) ((wchar_t *)(L"" w)) // use al_wstr_cr for runtime.
-#define al_wstr_c(w) (&((wstr){ (u32)((sizeof(w) / sizeof(wchar_t)) - 1), 0, al_wide_string_if_literal(w) }))
-#define al_wstr_cr(w) (&((wstr){ (u32)wcslen(w), 0, ((wchar_t *)(w)) })) // runtime
-#define al_wstr_w(w, i, n) (&((wstr){ ((u32)(n)), 0, &al_wstr_at(w, i) }))
-#define al_wstr_substr(w, start, end) al_wstr_w(w, start, ((end) - (start)))
+#define al_wide_chars_if_literal(wc) ((wchar_t *)(L"" wc)) // use al_wstr_cs/r for non-static arrays.
+#define al_wstr_c(wc) ((wstr){ (u32)((sizeof(wc) / sizeof(wchar_t)) - 1), 0, al_wide_chars_if_literal(wc) })
+#define al_wstr_cs(wc) ((wstr){ (u32)wcsnlen(wc, sizeof(wc)), 0, ((wchar_t *)(wc)) }) // (s)ized
+#define al_wstr_cr(wc) ((wstr){ (u32)wcsnlen(wc, MAX_ALLOC_32), 0, ((wchar_t *)(wc)) }) // (r)untime
-#define AL_WSTR_FMT "%ls"
-#define AL_WSTR_PRINTF(w) (w)->data
+#define al_wstr_w(wc, i, n) ((wstr){ ((u32)(n)), 0, &(wc)[i] })
+#define al_wstr_substr(w, start, end) al_wstr_w((w)->data, start, ((end) - (start)))
+
+#define al_wstr_fmt(w) (w)->data
AL_UNUSED_FUNCTION_PUSH
+static inline bool al_wstr_is_empty(wstr *w)
+{
+ return w->length == 0;
+}
+
static inline s32 al_wchar_width(wchar_t wc)
{
#ifdef AL_HAVE_WIDE_STRING_WIDTH
@@ -45,45 +52,37 @@ static inline void al_wstr_free(wstr *w)
static inline u32 al_wstr_reserve(wstr *w, u32 size)
{
- 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));
- al_assert(w->data);
-
- return size;
+ return al_default_growing_allocation((void **)&w->data, w->alloc, size, al_malloc, al_realloc);
}
static inline void al_wstr_sized(wstr *w, u32 size)
{
- *w = al_wstr_zero();
+ *w = al_wstr_null();
w->alloc = al_wstr_reserve(w, size * sizeof(wchar_t));
}
static inline void al_wstr_clone(wstr *dest, wstr *src)
{
- u32 len = src->len + 1;
- al_wstr_sized(dest, len);
- al_memcpy(dest->data, src->data, len * sizeof(wchar_t));
- dest->len = src->len;
+ u32 length = src->length;
+ al_wstr_sized(dest, length + 1);
+ al_memcpy(dest->data, src->data, length * sizeof(wchar_t));
+ dest->data[length] = L'\0';
+ dest->length = src->length;
}
static inline bool al_wstr_from_cstr(wstr *w, char *c)
{
#ifdef AL_HAVE_WIDE_STRING
mbstate_t mbstate = { 0 };
- size_t len = mbsrtowcs(NULL, (const char **)&c, 0, &mbstate);
- if (len == (size_t)-1) {
+ size_t length;
+ length = mbsrtowcs(NULL, (const char **)&c, 0, &mbstate);
+ if (length == (size_t)-1) {
return false;
}
- 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';
+ al_wstr_sized(w, (u32)(length + 1));
+ w->length = (u32)mbsrtowcs(w->data, (const char **)&c, length, &mbstate);
+ al_assert(w->length == (u32)length);
+ w->data[w->length] = L'\0';
return true;
#else
(void)c;
@@ -99,21 +98,26 @@ static inline void al_wstr_from_str(wstr *w, str *s)
al_free(c_str);
}
+// This is horrible.
static inline bool al_wstr_to_str(wstr *w, str *s)
{
// This is broken on windows. locale issue?
#ifdef AL_HAVE_WIDE_STRING
- wchar_t *data = w->data;
+ wstr copy;
+ // We have to make a copy here incase w->length is less than the
+ // full string pointed to by w->data.
+ al_wstr_clone(&copy, w);
+ wchar_t *copy_data = copy.data;
mbstate_t mbstate = { 0 };
- size_t len = wcsrtombs(NULL, (const wchar_t **)&w->data, 0, &mbstate);
- if (len == (size_t)-1) {
+ size_t length = wcsrtombs(NULL, (const wchar_t **)&copy_data, 0, &mbstate);
+ if (length == (size_t)-1) {
return false;
}
- al_str_sized(s, (u32)len);
+ al_str_sized(s, (u32)length);
// Excludes the null terminator.
- s->len = (u32)wcsrtombs(s->data, (const wchar_t **)&w->data, len, &mbstate);
- al_assert(s->len == (u32)len);
- w->data = data;
+ s->length = (u32)wcsrtombs(s->data, (const wchar_t **)&copy_data, length, &mbstate);
+ al_assert(s->length == (u32)length);
+ al_wstr_free(&copy);
return true;
#else
(void)s;
@@ -125,17 +129,17 @@ static inline bool al_wstr_to_str(wstr *w, str *s)
static inline s32 al_wstr_width(wstr *w)
{
#ifdef AL_HAVE_WIDE_STRING_WIDTH
- return wcswidth(w->data, w->len);
+ return wcswidth(w->data, w->length);
#else
(void)w;
al_assert_and_return(0);
#endif
}
-static inline s32 al_wstr_cmp(wstr *w, wstr *c, u32 start, u32 len)
+static inline s32 al_wstr_cmp(wstr *w, wstr *c, u32 start, u32 length)
{
#ifdef AL_HAVE_WIDE_STRING
- return wcsncmp(&al_wstr_at(w, start), c->data, len);
+ return wcsncmp(&al_wstr_at(w, start), c->data, length);
#else
(void)w;
(void)c;
@@ -145,24 +149,43 @@ static inline s32 al_wstr_cmp(wstr *w, wstr *c, u32 start, u32 len)
#endif
}
-static inline s32 al_wstr_find(wstr *w, wchar_t c)
+static inline u32 al_wstr_find(wstr *w, wchar_t c)
{
- for (s32 i = 0; i < (s32)w->len; i++) {
+ for (u32 i = 0; i < w->length; i++) {
if (al_wstr_at(w, i) == c) {
return i;
}
}
- return -1;
+ return al_wstr_npos;
}
-static inline s32 al_wstr_rfind(wstr *w, wchar_t c)
+static inline u32 al_wstr_rfind(wstr *w, wchar_t c)
{
- for (s32 i = (s32)w->len - 1; i >= 0; i--) {
+ for (u32 i = w->length; --i > 0;) {
if (al_wstr_at(w, i) == c) {
return i;
}
}
- return -1;
+ return al_wstr_npos;
+}
+
+static inline bool al_wstr_tok(wstr *result, wchar_t delim)
+{
+ u32 index = al_wstr_find(result, delim);
+ if (index == al_str_npos) {
+ return false;
+ }
+ *result = al_wstr_substr(result, index + 1, result->length);
+ return true;
+}
+
+static inline s64 al_wstr_to_long(wstr *w, u32 base, bool *error)
+{
+ str s;
+ al_wstr_to_str(w, &s);
+ s64 num = al_str_to_long(&s, base, error);
+ al_str_free(&s);
+ return num;
}
AL_UNUSED_FUNCTION_POP
diff --git a/meson.build b/meson.build
index 88247f8..75ee373 100644
--- a/meson.build
+++ b/meson.build
@@ -9,7 +9,10 @@ is_msvc_specifically = compiler.cmd_array()[0] == 'cl'
supports_needed_gnu_extensions = not is_msvc_specifically
have_builtin_expect = compiler.has_function('__builtin_expect')
-have_typeof = compiler.has_function('__typeof__')
+have_typeof = compiler.compiles('__typeof__(1) j;')
+if not have_typeof
+ error('Compiler support for \'__typeof__()\' is required.')
+endif
have_posix_memalign = compiler.has_function(
'posix_memalign', prefix: '#define _POSIX_C_SOURCE 200112L\n#include <stdlib.h>')
have_wide_string = compiler.has_function('wcsrtombs')
@@ -49,6 +52,7 @@ c89atomic = subproject('c89atomic').get_variable('c89atomic')
alabaster_src = [
'src/lib.c',
+ 'src/random.c',
'src/str.c',
'src/log.c',
'src/ring_buffer.c'
diff --git a/scripts/line_count.sh b/scripts/line_count.sh
index 9b46c9e..a6ac787 100755
--- a/scripts/line_count.sh
+++ b/scripts/line_count.sh
@@ -1,2 +1,3 @@
#! /usr/bin/env sh
-find ./src ./include -type f -exec wc -l {} +
+export LC_ALL="C"
+find ./src ./include -type f -exec sloccount {} +
diff --git a/src/array.c b/src/array.c
index 3236f67..6021a85 100644
--- a/src/array.c
+++ b/src/array.c
@@ -7,171 +7,159 @@
#define array(type) \
struct { \
- u32 size; \
+ u32 count; \
u32 alloc; \
type *__sized_by(alloc) data; \
}
-#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_init(array) ((array).count = 0, (array).alloc = 0, (array).data = NULL)
-#define al_array_is_empty(arr) ((arr).size == 0)
+#define al_array_offset(array, n) ((array).data + (n))
+#define al_array_at(array, i) ((array).data[i])
+#define al_array_last(array) al_array_at(array, (array).count - 1)
-#define al_array_offset(arr, i) ((arr).data + (i))
-
-#define al_array_at(arr, i) ((arr).data[i])
-#define al_array_last(arr) al_array_at(arr, (arr).size - 1)
-
-#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_item_size(array) sizeof(*(array).data) // NOLINT(bugprone-sizeof-expression)
+#define al_array_reserve(array, count) \
+ ((array).alloc = _al_array_reserve((void **)&(array).data, (array).alloc, ((count) * al_array_item_size(array))))
#define al_array_clone(dest, src) \
AL_MACRO_WRAP \
-({ \
+{ \
al_array_init(dest); \
- al_array_reserve(dest, (src).size); \
- (dest).size = (src).size; \
+ al_array_reserve(dest, (src).count); \
+ (dest).count = (src).count; \
al_memcpy(al_array_offset(dest, 0), al_array_offset(src, 0), \
- al_array_item_size(dest) * (dest).size); \
-})
+ al_array_item_size(dest) * (dest).count); \
+} AL_MACRO_END
#define al_array_copy(dest, src) \
AL_MACRO_WRAP \
-({ \
- al_array_reserve(dest, (src).size); \
- (dest).size = (src).size; \
+{ \
+ al_array_reserve(dest, (src).count); \
+ (dest).count = (src).count; \
al_memcpy(al_array_offset(dest, 0), al_array_offset(src, 0), \
- al_array_item_size(dest) * (dest).size); \
-})
+ al_array_item_size(dest) * (dest).count); \
+} AL_MACRO_END
-#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_push(array, item) \
+AL_MACRO_WRAP \
+{ \
+ al_array_reserve(array, (array).count + 1); \
+ __typeof__(item) v = item; \
+ (void)((array).data == &v); \
+ al_array_at(array, (array).count++) = v; \
+} AL_MACRO_END
-#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_offset(arr, i + 1), al_array_offset(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_insert(array, i, item) \
+AL_MACRO_WRAP \
+{ \
+ al_array_reserve(array, (array).count + 1); \
+ if (i != (array).count - 1) { \
+ al_memmove(al_array_offset(array, i + 1), al_array_offset(array, i), \
+ al_array_item_size(array) * ((array).count - i)); \
+ } \
+ (array).count++; \
+ __typeof__(item) v = item; \
+ (void)((array).data == &v); \
+ al_array_at(array, i) = v; \
+} AL_MACRO_END
-#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(array) al_array_at(array, --(array).count)
+#define al_array_pop_at(array, i, r) \
+AL_MACRO_WRAP \
+{ \
+ r = al_array_at(array, i); \
+ al_array_remove_at(array, i); \
+} AL_MACRO_END
-#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(array, elem) \
+AL_MACRO_WRAP \
+{ \
+ for (u32 i = 0; i < (array).count; i++) { \
+ if (al_array_at(array, i) == elem) { \
+ al_array_remove_at(array, i); \
+ break; \
+ } \
+ } \
+} AL_MACRO_END
-#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_check_remove(array, elem, removed) \
+AL_MACRO_WRAP \
+{ \
+ removed = false; \
+ for (u32 i = 0; i < (array).count; i++) { \
+ if (al_array_at(array, i) == elem) { \
+ al_array_remove_at(array, i); \
+ removed = true; \
+ break; \
+ } \
+ } \
+} AL_MACRO_END
-#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_all(array, elem) \
+AL_MACRO_WRAP \
+{ \
+ for (u32 i = (array).count; i-- > 0;) { \
+ if (al_array_at(array, i) == elem) { \
+ al_array_remove_at(array, i); \
+ } \
+ } \
+} AL_MACRO_END
-#define al_array_remove_at(arr, i) \
-AL_MACRO_WRAP \
-({ \
- if (i == (arr).size - 1) { \
- (arr).size--; \
- } else { \
- al_memmove(al_array_offset(arr, i), al_array_offset(arr, i + 1), \
- al_array_item_size(arr) * (--(arr).size - i)); \
- } \
-})
+#define al_array_remove_at(array, i) \
+AL_MACRO_WRAP \
+{ \
+ if (i == (array).count - 1) { \
+ (array).count--; \
+ } else { \
+ al_memmove(al_array_offset(array, i), al_array_offset(array, i + 1), \
+ al_array_item_size(array) * (--(array).count - i)); \
+ } \
+} AL_MACRO_END
-#define al_array_remove_range(arr, i, e) \
-AL_MACRO_WRAP \
-({ \
- if (e != (arr).size) { \
- al_memmove(al_array_offset(arr, i), al_array_offset(arr, e), \
- al_array_item_size(arr) * ((arr).size - e)); \
- } \
- (arr).size -= e - i; \
-})
+#define al_array_remove_range(array, start, end) \
+AL_MACRO_WRAP \
+{ \
+ if (end != (array).count) { \
+ al_memmove(al_array_offset(array, start), al_array_offset(array, end), \
+ al_array_item_size(array) * ((array).count - end)); \
+ } \
+ (array).count -= end - start; \
+} AL_MACRO_END
#ifdef AL_USE_STDLIB
-#define al_array_sort(arr, type, cmp) AL_STDLIB_QSORT((arr).data, type, (arr).size, cmp)
+#define al_array_sort(array, type, cmp) AL_STDLIB_QSORT((array).data, type, (array).count, cmp)
#else
-#define al_array_sort(arr, type, cmp) AL_INSERSION_SORT((arr).data, type, (arr).size, cmp)
+#define al_array_sort(array, type, cmp) AL_INSERSION_SORT((array).data, type, (array).count, cmp)
#endif
-#define al_array_free(arr) \
- if ((arr).alloc) AL_ARRAY_FREE((arr).data)
+#define al_array_free(array) \
+ if ((array).alloc) AL_ARRAY_FREE((array).data)
-#define al_array_foreach(arr, i, item) \
- for (u32 i = 0; (i < (arr).size && (item = al_array_at(arr, i), 1)); i++)
+#define al_array_foreach(array, i, item) \
+ for (u32 i = 0; (i < (array).count && (item = al_array_at(array, i), 1)); i++)
-#define al_array_foreach_rev(arr, i, item) \
- for (u32 i = (arr).size; (i-- > 0 && (item = al_array_at(arr, i), 1));)
+#define al_array_foreach_rev(array, i, item) \
+ for (u32 i = (array).count; (i-- > 0 && (item = al_array_at(array, i), 1));)
-#define al_array_foreach_ptr(arr, i, item) \
- for (u32 i = 0; (i < (arr).size && (item = al_array_offset(arr, i), 1)); i++)
+#define al_array_foreach_ptr(array, i, item) \
+ for (u32 i = 0; (i < (array).count && (item = al_array_offset(array, i), 1)); i++)
-#define al_array_foreach_ptr_rev(arr, i, item) \
- for (u32 i = (arr).size; (i-- > 0 && (item = al_array_offset(arr, i), 1));)
+#define al_array_foreach_ptr_rev(array, i, item) \
+ for (u32 i = (array).count; (i-- > 0 && (item = al_array_offset(array, i), 1));)
-#define al_array_remove_at_iter(arr, i) \
-AL_MACRO_WRAP \
-({ \
- al_array_remove_at(arr, i); \
- i--; \
-})
+#define al_array_remove_at_iter(array, i) \
+AL_MACRO_WRAP \
+{ \
+ al_array_remove_at(array, i); \
+ i--; \
+} AL_MACRO_END
AL_UNUSED_FUNCTION_PUSH
-static inline u32 _al_array_reserve(void **ptr, u32 item_size, u32 prev_size, u32 size)
+static inline u32 _al_array_reserve(void **ptr, u32 prev_size, u32 size)
{
- 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);
-
- return size;
+ return al_default_growing_allocation(ptr, prev_size, size, AL_ARRAY_MALLOC, AL_ARRAY_REALLOC);
}
AL_UNUSED_FUNCTION_POP
diff --git a/src/lib.c b/src/lib.c
index ca737e4..9641976 100644
--- a/src/lib.c
+++ b/src/lib.c
@@ -201,7 +201,24 @@ void al_set_alloc(void *(*malloc_func)(size_t), void *(*calloc_func)(size_t, siz
}
#endif
-u32 al_grow_step = 0xfff;
+u32 al_grow_step = 0x3fff; // 0b11111111111111
+
+u32 al_default_growing_allocation(void **ptr, u32 prev_size, u32 size,
+ void *(*malloc_func)(size_t), void *(*realloc_func)(void *, size_t))
+{
+ if (size <= prev_size) return prev_size;
+ al_assert(size > 0);
+
+ size = size < al_grow_step ? al_next_power_of_two(size) :
+ al_add_wrap(size, al_grow_step, MAX_ALLOC_32) & ~al_grow_step;
+ // This should only happen after wrapping around MAX_ALLOC_32 (zero all possible bits).
+ if (size == 0) size = MAX_ALLOC_32;
+
+ *ptr = (!*ptr) ? malloc_func(size) : realloc_func(*ptr, size);
+ al_assert(*ptr);
+
+ return size;
+}
size_t al_page_size = 0x1000;
void al_set_page_size(size_t size)
diff --git a/src/log.c b/src/log.c
index 748f0d5..ea39b98 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,14 +1,11 @@
#include "../include/al/log.h"
+#include "../include/al/macros.h"
//#define AL_LOG_SKIP
-#define AL_LOG_USE_SECTION
-#ifdef AL_LOG_USE_SECTION
-#define AL_LOG_TEMPLATE "%s:%d %s(): %s -> (%s) "
-#else
#define AL_LOG_TEMPLATE "%s:%d %s(): %s -> "
-#endif
+#define AL_LOG_TEMPLATE_SECTION AL_LOG_TEMPLATE"(%s) "
-#define AL_LOG_MESSAGE_MAX (AL_LOG_MESSAGE_SIZE - 1) // Space for newline.
+#define AL_LOG_MESSAGE_MAX ((size_t)(AL_LOG_MESSAGE_SIZE - 1u)) // Space for newline.
#ifndef AL_FORCE_DISABLE_OUTPUT
static s32 (*_al_print)(void *, u8, char *) = NULL;
@@ -23,39 +20,39 @@ void al_set_print(s32 (*print_func)(void *, u8, char *), void *userdata)
static const char *levels[] = { "info", "warn", "error", "debug" };
#ifndef 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)
+static __thread char messagebuf[AL_LOG_MESSAGE_SIZE];
+
+static char *get_message_buffer(u8 level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, va_list args)
{
- char *buffer = al_malloc(AL_LOG_MESSAGE_SIZE);
s32 prefix = 0;
-#ifdef AL_LOG_USE_SECTION
- prefix = al_snprintf(buffer, AL_LOG_MESSAGE_MAX, AL_LOG_TEMPLATE, name, line, func, levels[level], section);
-#else
- (void)section;
- 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;
+ if (!section) {
+ prefix = al_snprintf(messagebuf, AL_LOG_MESSAGE_MAX, AL_LOG_TEMPLATE, name, line, func, levels[level]);
+ } else {
+ prefix = al_snprintf(messagebuf, AL_LOG_MESSAGE_MAX, AL_LOG_TEMPLATE_SECTION, name, line, func, levels[level], section);
+ }
+ al_assert(prefix > 0);
+ al_vsnprintf(messagebuf + prefix, AL_LOG_MESSAGE_MAX - (size_t)prefix, fmt, args);
+ messagebuf[strcspn(messagebuf, "\r\n")] = '\0';
+ return messagebuf;
}
#endif
s32 _al_logv(u8 level, const char *section, const char *name, const s32 line, const char *func, const char *fmt, va_list args)
{
- if (!section) section = "";
#ifdef AL_LOG_SKIP
s32 ret = 0;
-#ifdef AL_LOG_USE_SECTION
- ret += al_printf(AL_LOG_TEMPLATE, name, line, func, levels[level], section);
-#else
- ret += al_printf(AL_LOG_TEMPLATE, name, line, func, levels[level]);
-#endif
+ if (!section) {
+ ret += al_printf(AL_LOG_TEMPLATE, name, line, func, levels[level]);
+ } else {
+ ret += al_printf(AL_LOG_TEMPLATE_SECTION, name, line, func, levels[level], section);
+ }
ret += al_vprintf(fmt, args);
if (strcspn(fmt, "\r\n") == al_strlen(fmt)) {
ret += al_printf("\n");
}
return ret;
#else
- return _al_print(_al_log_userdata, level, get_message_buffer(level, section, fmt, name, line, func, args));
+ return _al_print(_al_log_userdata, level, get_message_buffer(level, section, name, line, func, fmt, args));
#endif
}
diff --git a/src/random.c b/src/random.c
new file mode 100644
index 0000000..1bbf152
--- /dev/null
+++ b/src/random.c
@@ -0,0 +1,4 @@
+#include "../include/al/random.h"
+
+u32 al_rand_seed = 1738;
+__thread bool al_rand_set = false;
diff --git a/src/ring_buffer.c b/src/ring_buffer.c
index 1c39b7b..ded0138 100644
--- a/src/ring_buffer.c
+++ b/src/ring_buffer.c
@@ -3,9 +3,12 @@
#include "../include/al/macros.h"
// https://github.com/MusicPlayerDaemon/MPD/blob/master/src/util/RingBuffer.hxx
+//
+// This is no longer an implementation of a "contiguous" ring buffer but I used this as reference.
+// Wrapping is handled in read() and write().
// https://andrea.lattuada.me/blog/2019/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations.html
-void al_ring_buffer_init(struct al_ring_buffer *buf, u8 *data, size_t length)
+void al_ring_buffer_init(struct al_ring_buffer *buf, u8 *data, ptrdiff_t length)
{
buf->start = data;
buf->end = data + length;
@@ -20,7 +23,7 @@ static inline u8 *previous(struct al_ring_buffer *buf, u8 *ptr)
return --ptr;
}
-static inline void add(struct al_ring_buffer *buf, u8 **v, u8 *ptr, size_t n)
+static inline void add(struct al_ring_buffer *buf, u8 **v, u8 *ptr, ptrdiff_t n)
{
ptr += n;
al_assert(ptr <= buf->end);
@@ -28,14 +31,14 @@ static inline void add(struct al_ring_buffer *buf, u8 **v, u8 *ptr, size_t n)
al_atomic_store(void)(v, ptr, AL_ATOMIC_RELEASE);
}
-size_t al_ring_buffer_space(struct al_ring_buffer *buf)
+ptrdiff_t al_ring_buffer_space(struct al_ring_buffer *buf)
{
u8 *wp = al_atomic_load(void)(&buf->write, AL_ATOMIC_RELAXED);
u8 *rp = previous(buf, (u8 *)al_atomic_load(void)(&buf->read, AL_ATOMIC_RELAXED));
return (wp <= rp) ? rp - wp : (buf->end - wp) + (rp - buf->start);
}
-u8 *al_ring_buffer_write_chunk(struct al_ring_buffer *buf, size_t *size)
+u8 *al_ring_buffer_write_chunk(struct al_ring_buffer *buf, ptrdiff_t *size)
{
u8 *wp = al_atomic_load(void)(&buf->write, AL_ATOMIC_ACQUIRE);
u8 *rp = previous(buf, al_atomic_load(void)(&buf->read, AL_ATOMIC_RELAXED));
@@ -43,19 +46,19 @@ u8 *al_ring_buffer_write_chunk(struct al_ring_buffer *buf, size_t *size)
return wp;
}
-void al_ring_buffer_append(struct al_ring_buffer *buf, u8 *ptr, size_t n)
+void al_ring_buffer_append(struct al_ring_buffer *buf, u8 *ptr, ptrdiff_t n)
{
add(buf, &buf->write, ptr, n);
}
-size_t al_ring_buffer_occupied(struct al_ring_buffer *buf)
+ptrdiff_t al_ring_buffer_occupied(struct al_ring_buffer *buf)
{
u8 *rp = al_atomic_load(void)(&buf->read, AL_ATOMIC_RELAXED);
u8 *wp = al_atomic_load(void)(&buf->write, AL_ATOMIC_RELAXED);
return (rp <= wp) ? wp - rp : (buf->end - rp) + (wp - buf->start);
}
-u8 *al_ring_buffer_read_chunk(struct al_ring_buffer *buf, size_t *size)
+u8 *al_ring_buffer_read_chunk(struct al_ring_buffer *buf, ptrdiff_t *size)
{
u8 *rp = al_atomic_load(void)(&buf->read, AL_ATOMIC_ACQUIRE);
u8 *wp = al_atomic_load(void)(&buf->write, AL_ATOMIC_RELAXED);
@@ -63,24 +66,25 @@ u8 *al_ring_buffer_read_chunk(struct al_ring_buffer *buf, size_t *size)
return rp;
}
-void al_ring_buffer_consume(struct al_ring_buffer *buf, u8 *ptr, size_t n)
+void al_ring_buffer_consume(struct al_ring_buffer *buf, u8 *ptr, ptrdiff_t n)
{
add(buf, &buf->read, ptr, n);
}
-size_t al_ring_buffer_write(struct al_ring_buffer *buf, u8 *data, size_t n)
+ptrdiff_t al_ring_buffer_write(struct al_ring_buffer *buf, u8 *data, ptrdiff_t n)
{
u8 *wp = al_atomic_load(void)(&buf->write, AL_ATOMIC_ACQUIRE);
u8 *rp = previous(buf, al_atomic_load(void)(&buf->read, AL_ATOMIC_RELAXED));
- size_t size = MIN((wp <= rp ? rp : buf->end) - wp, (ptrdiff_t)n);
+ ptrdiff_t size, wrap;
- al_memcpy(wp, data, size);
+ size = MIN((wp <= rp ? rp : buf->end) - wp, n);
+ al_memcpy(wp, data, (size_t)size);
wp += size;
if (wp >= buf->end) {
- size_t wrap = MIN(rp - buf->start, (ptrdiff_t)(n - size));
- al_memcpy(buf->start, data + size, wrap);
+ wrap = MIN(rp - buf->start, n - size);
+ al_memcpy(buf->start, data + size, (size_t)wrap);
wp = buf->start + wrap;
size += wrap;
}
@@ -90,19 +94,20 @@ size_t al_ring_buffer_write(struct al_ring_buffer *buf, u8 *data, size_t n)
return size;
}
-size_t al_ring_buffer_read(struct al_ring_buffer *buf, u8 *ptr, size_t n)
+ptrdiff_t al_ring_buffer_read(struct al_ring_buffer *buf, u8 *ptr, ptrdiff_t n)
{
u8 *rp = al_atomic_load(void)(&buf->read, AL_ATOMIC_ACQUIRE);
u8 *wp = al_atomic_load(void)(&buf->write, AL_ATOMIC_RELAXED);
- size_t size = MIN((rp <= wp ? wp : buf->end) - rp, (ptrdiff_t)n);
+ ptrdiff_t size, wrap;
- al_memcpy(ptr, rp, size);
+ size = MIN((rp <= wp ? wp : buf->end) - rp, n);
+ al_memcpy(ptr, rp, (size_t)size);
rp += size;
if (rp >= buf->end) {
- size_t wrap = MIN(wp - buf->start, (ptrdiff_t)(n - size));
- al_memcpy(ptr + size, buf->start, wrap);
+ wrap = MIN(wp - buf->start, n - size);
+ al_memcpy(ptr + size, buf->start, (size_t)wrap);
rp = buf->start + wrap;
size += wrap;
}
@@ -112,27 +117,28 @@ size_t al_ring_buffer_read(struct al_ring_buffer *buf, u8 *ptr, size_t n)
return size;
}
-size_t al_ring_buffer_peek(struct al_ring_buffer *buf, u8 *ptr, size_t offset, size_t n)
+ptrdiff_t al_ring_buffer_peek(struct al_ring_buffer *buf, u8 *ptr, ptrdiff_t offset, ptrdiff_t n)
{
u8 *rp = al_atomic_load(void)(&buf->read, AL_ATOMIC_RELAXED);
u8 *wp = al_atomic_load(void)(&buf->write, AL_ATOMIC_RELAXED);
- ptrdiff_t size;
+ ptrdiff_t size, wrap;
if (rp <= wp) {
rp += offset;
- size = MIN(wp - rp, (ptrdiff_t)n);
- if (size < 0)
+ size = MIN(wp - rp, n);
+ if (size < 0) {
return 0;
+ }
- al_memcpy(ptr, rp, size);
+ al_memcpy(ptr, rp, (size_t)size);
} else {
rp += offset;
- size = MIN(buf->end - rp, (ptrdiff_t)n);
+ size = MIN(buf->end - rp, n);
if (size > 0) {
- al_memcpy(ptr, rp, size);
+ al_memcpy(ptr, rp, (size_t)size);
n -= size;
rp = buf->start;
} else {
@@ -140,9 +146,9 @@ size_t al_ring_buffer_peek(struct al_ring_buffer *buf, u8 *ptr, size_t offset, s
size = 0;
}
- ptrdiff_t wrap = MIN(wp - rp, (ptrdiff_t)n);
+ wrap = MIN(wp - rp, n);
if (wrap > 0) {
- al_memcpy(ptr + size, rp, wrap);
+ al_memcpy(ptr + size, rp, (size_t)wrap);
size += wrap;
}
}
@@ -150,16 +156,18 @@ size_t al_ring_buffer_peek(struct al_ring_buffer *buf, u8 *ptr, size_t offset, s
return size;
}
-size_t al_ring_buffer_discard(struct al_ring_buffer *buf, size_t n)
+ptrdiff_t al_ring_buffer_discard(struct al_ring_buffer *buf, ptrdiff_t n)
{
u8 *rp = al_atomic_load(void)(&buf->read, AL_ATOMIC_ACQUIRE);
u8 *wp = al_atomic_load(void)(&buf->write, AL_ATOMIC_RELAXED);
- size_t discard = MIN((rp <= wp ? wp : buf->end) - rp, (ptrdiff_t)n);
+ ptrdiff_t discard, wrap;
+
+ discard = MIN((rp <= wp ? wp : buf->end) - rp, n);
rp += discard;
if (rp >= buf->end) {
- size_t wrap = MIN(wp - buf->start, (ptrdiff_t)(n - discard));
+ wrap = MIN(wp - buf->start, n - discard);
rp = buf->start + wrap;
discard += wrap;
}
diff --git a/src/str.c b/src/str.c
index c955d51..2ad46aa 100644
--- a/src/str.c
+++ b/src/str.c
@@ -1,18 +1,18 @@
#include "../include/al/str.h"
// https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/stdlib/strtol.c;h=09d4333ed05f497ec00b7192204644349441e58d;hb=HEAD#l130
-s64 al_str_to_long(str *s, s32 base)
+s64 al_str_to_long(str *s, u32 base, bool *error)
{
u64 ret = 0;
u32 i = 0;
- s32 neg = 0;
+ bool neg = 0;
- while (al_isspace(al_str_at(s, i)) && i < s->len) {
+ while (al_isspace(al_str_at(s, i)) && i < s->length) {
i++;
}
if (al_str_at(s, i) == '-') {
- neg = 1;
+ neg = true;
i++;
} else if (al_str_at(s, i) == '+') {
i++;
@@ -24,41 +24,35 @@ s64 al_str_to_long(str *s, s32 base)
i += 2;
}
- u64 cutoff = neg ? -(u64)INT64_MIN : INT64_MAX;
- s32 add_limit = cutoff % (u64)base;
- cutoff /= (u64)base;
+ u64 cutoff = neg ? ((u64)INT64_MAX + 1) : (u64)INT64_MAX;
+ u64 add_limit = cutoff % base;
+ cutoff /= base;
- bool error = false;
+ *error = false;
- for (; i < s->len; i++) {
- char c = al_str_at(s, i);
+ for (; i < s->length; i++) {
+ uchar c = (uchar)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 for expressing a number.
- error = true;
+ *error = true;
break;
}
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;
+ *error = true;
break;
}
ret = ret * base + c;
}
- if (error) {
- ret = neg ? INT64_MIN : INT64_MAX;
- } else if (neg) {
- ret = -ret;
- }
-
- return ret;
+ return neg ? -(s64)ret : (s64)ret;
}
bool al_str_get_line(str *buffer, char sep, str *line)
@@ -70,17 +64,22 @@ bool al_str_get_line(str *buffer, char sep, str *line)
*line = *buffer;
} 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.
+ line->data += line->length + 1;
+ if ((bytes = (u32)(line->data - buffer->data)) >= buffer->length) {
+ // No more lines.
+ return false;
+ }
}
- bytes = buffer->len - bytes;
+ if ((bytes = buffer->length - bytes) == 0) {
+ // buffer is completely empty.
+ return false;
+ }
char *nl = (char *)al_memchr(line->data, sep, bytes);
// If we couldn't find a separator, move to the end of the buffer.
- line->len = !nl ? bytes : (u32)(nl - line->data);
+ line->length = !nl ? bytes : (u32)(nl - line->data);
return true;
}
diff --git a/tests/array.c b/tests/array.c
index 08d29eb..6cc88c6 100644
--- a/tests/array.c
+++ b/tests/array.c
@@ -3,23 +3,22 @@
#include <al/random.h>
#include "array.h"
-
-struct test_t {
- u32 i;
-};
+#include "common.h"
static bool array_test_init(void)
{
AL_TEST_START("array_init");
- array(u32) arr;
- al_array_init(arr);
+ array(u32) ints;
+ al_array_init(ints);
- AL_TEST_EQ((void *)arr.data, NULL, ptr);
- AL_TEST_EQ(arr.alloc, 0, u32);
- AL_TEST_EQ(arr.size, 0, u32);
+ AL_TEST_EQ(ints.count, 0, u32);
+ AL_TEST_EQ(ints.alloc, 0, u32);
+ AL_TEST_EQ(ints.data, NULL, ptr);
- al_array_free(arr);
+ al_array_free(ints);
+ // Not a double-free.
+ al_array_free(ints);
AL_TEST_END();
}
@@ -28,25 +27,22 @@ static bool array_test_reserve(void)
{
AL_TEST_START("array_reserve");
- array(u32) arr;
- al_array_init(arr);
-
- al_array_reserve(arr, 64);
-
- AL_TEST_NEQ((void *)arr.data, NULL, ptr);
- AL_TEST_EQ(arr.alloc, 64, u32);
+ array(u32) ints;
+ al_array_init(ints);
- al_array_reserve(arr, 128);
+ al_array_reserve(ints, 64);
+ AL_TEST_EQ(ints.alloc, 256, u32);
+ AL_TEST_NEQ(ints.data, NULL, ptr);
- AL_TEST_NEQ((void *)arr.data, NULL, ptr);
- AL_TEST_EQ(arr.alloc, 128, u32);
+ al_array_reserve(ints, 128);
+ AL_TEST_EQ(ints.alloc, 512, u32);
+ AL_TEST_NEQ(ints.data, NULL, ptr);
- al_array_reserve(arr, 129);
+ al_array_reserve(ints, 129);
+ AL_TEST_EQ(ints.alloc, 1024, u32);
+ AL_TEST_NEQ(ints.data, NULL, ptr);
- AL_TEST_NEQ((void *)arr.data, NULL, ptr);
- AL_TEST_EQ(arr.alloc, 256, u32);
-
- al_array_free(arr);
+ al_array_free(ints);
AL_TEST_END();
}
@@ -55,15 +51,19 @@ static bool array_test_at(void)
{
AL_TEST_START("array_at");
- array(u32) arr;
- al_array_init(arr);
+ array(u32) ints;
+ al_array_init(ints);
u32 x = 5;
- al_array_push(arr, x);
+ al_array_push(ints, x);
+ al_array_push(ints, (u32)4);
- AL_TEST_EQ(al_array_at(arr, 0), 5, u32);
+ AL_TEST_EQ(al_array_at(ints, 0), 5, u32);
+ AL_TEST_EQ(al_array_at(ints, 1), 4, u32);
+ AL_TEST_EQ(ints.count, 2, u32);
+ AL_TEST_EQ(ints.alloc, 8, u32);
- al_array_free(arr);
+ al_array_free(ints);
AL_TEST_END();
}
@@ -72,39 +72,69 @@ static bool array_test_last(void)
{
AL_TEST_START("array_last");
- array(u32) arr;
- al_array_init(arr);
+ array(u32) ints;
+ al_array_init(ints);
u32 x = 1, y = 2, z = 3;
+ al_array_push(ints, x);
+ al_array_push(ints, y);
+ al_array_push(ints, z);
- al_array_push(arr, x);
- al_array_push(arr, y);
- al_array_push(arr, z);
-
- AL_TEST_EQ(al_array_last(arr), 3, u32);
+ AL_TEST_EQ(al_array_last(ints), z, u32);
+ AL_TEST_EQ(ints.count, 3, u32);
+ AL_TEST_EQ(ints.alloc, 16, u32);
- al_array_free(arr);
+ al_array_free(ints);
AL_TEST_END();
}
+AL_UNUSED_FUNCTION_PUSH
+
+static s32 uint8_compare(const void *a, const void *b)
+{
+ if (*(u8 *)a < *(u8 *)b) return 1;
+ else if (*(u8 *)b < *(u8 *)a) return -1;
+ return 0;
+}
+
+AL_UNUSED_FUNCTION_POP
+
static bool array_test_push(void)
{
AL_TEST_START("array_push");
- array(u32) arr;
- al_array_init(arr);
+ array(u8) bytes;
+ al_array_init(bytes);
- u32 x = 4, y = 5;
+ u8 increment = 0;
+ for (u32 i = 0; i < MAX_ALLOC_32; i++) {
+ al_array_push(bytes, (increment = (u8)al_add_wrap(increment, 2, UINT8_MAX)));
+ }
+ AL_TEST_EQ(bytes.count, MAX_ALLOC_32, u32);
+ AL_TEST_EQ(bytes.alloc, MAX_ALLOC_32, u32);
+
+ AL_TEST_EQ(&al_array_at(bytes, MAX_ALLOC_32 - 1), &al_array_last(bytes), ptr);
- al_array_push(arr, x);
- al_array_push(arr, y);
+ AL_TEST_EQ(al_array_at(bytes, 3535), 187, u8);
+ AL_TEST_EQ(al_array_at(bytes, 2348151), 224, u8);
+ AL_TEST_EQ(al_array_at(bytes, 75134), 75, u8);
+ AL_TEST_EQ(al_array_at(bytes, 1735095), 152, u8);
+ AL_TEST_EQ(al_array_at(bytes, 191236099), 250, u8);
+ if (MAX_ALLOC_32 > INT32_MAX) {
+ AL_TEST_EQ(al_array_at(bytes, 3116282697), 236, u8);
+ AL_TEST_EQ(al_array_at(bytes, 2923789681), 199, u8);
+ }
- AL_TEST_EQ(arr.size, 2, u32);
- AL_TEST_EQ(al_array_at(arr, 0), x, u32);
- AL_TEST_EQ(al_array_at(arr, 1), y, u32);
+#if 0 // This is very slow.
+ al_array_sort(bytes, u8, uint8_compare);
+ AL_TEST_LTE(al_array_at(bytes, MAX_ALLOC_32 - 1), al_array_at(bytes, MAX_ALLOC_32 - 26000000), u8);
+ AL_TEST_LTE(al_array_at(bytes, MAX_ALLOC_32 - 27000000), al_array_at(bytes, MAX_ALLOC_32 - 52000000), u8);
+ AL_TEST_LTE(al_array_at(bytes, MAX_ALLOC_32 - 53000000), al_array_at(bytes, MAX_ALLOC_32 - 78000000), u8);
+ AL_TEST_LTE(al_array_at(bytes, MAX_ALLOC_32 - 79000000), al_array_at(bytes, MAX_ALLOC_32 - 104000000), u8);
+#endif
- al_array_free(arr);
+ al_array_free(bytes);
AL_TEST_END();
}
@@ -113,27 +143,23 @@ static bool array_test_pop(void)
{
AL_TEST_START("array_pop");
- array(u32) arr;
- al_array_init(arr);
+ array(u32) ints;
+ al_array_init(ints);
u32 x = 4, y = 5;
+ al_array_push(ints, x);
+ al_array_push(ints, y);
- al_array_push(arr, x);
- al_array_push(arr, y);
-
- u32 rx, ry;
-
- ry = al_array_pop(arr);
+ u32 ry = al_array_pop(ints);
+ AL_TEST_EQ(ints.count, 1, u32);
- AL_TEST_EQ(arr.size, 1, u32);
+ u32 rx = al_array_pop(ints);
+ AL_TEST_EQ(ints.count, 0, u32);
- rx = al_array_pop(arr);
-
- AL_TEST_EQ(arr.size, 0, u32);
AL_TEST_EQ(rx, x, u32);
AL_TEST_EQ(ry, y, u32);
- al_array_free(arr);
+ al_array_free(ints);
AL_TEST_END();
}
@@ -142,28 +168,28 @@ static bool array_test_remove_at(void)
{
AL_TEST_START("array_remove_at");
- array(u32) arr;
- al_array_init(arr);
- al_array_reserve(arr, 12);
+ array(u32) ints;
+ al_array_init(ints);
+ al_array_reserve(ints, 12);
u32 array_before[] = { 1, 2, 3, 4, 5, 6 };
u32 array_after[] = { 2, 3, 4 };
- for (u32 i = 0; i < sizeof(array_before) / sizeof(u32); i++) {
- al_array_push(arr, array_before[i]);
+ for (u32 i = 0; i < ARRAY_SIZE(array_before); i++) {
+ al_array_push(ints, array_before[i]);
}
- al_array_remove_at(arr, 0);
- al_array_remove_at(arr, 3);
- al_array_remove_at(arr, 3);
+ al_array_remove_at(ints, 0);
+ al_array_remove_at(ints, 3);
+ al_array_remove_at(ints, 3);
- AL_TEST_EQ(arr.size, (u32)(sizeof(array_after) / sizeof(u32)), u32);
+ AL_TEST_EQ(ints.count, ARRAY_SIZE(array_after), u32);
- for (u32 i = 0; i < sizeof(array_after) / sizeof(u32); i++) {
- AL_TEST_EQ(al_array_at(arr, i), array_after[i], u32);
+ for (u32 i = 0; i < ARRAY_SIZE(array_after); i++) {
+ AL_TEST_EQ(al_array_at(ints, i), array_after[i], u32);
}
- al_array_free(arr);
+ al_array_free(ints);
AL_TEST_END();
}
@@ -172,31 +198,33 @@ static bool array_test_remove_range(void)
{
AL_TEST_START("array_remove_range");
- array(u32) arr;
- al_array_init(arr);
- al_array_reserve(arr, 12);
+ array(u32) ints;
+ al_array_init(ints);
+ al_array_reserve(ints, 12);
u32 array_before[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
u32 array_after[] = { 1, 3, 4, 7, 8, 11 };
- for (u32 i = 0; i < sizeof(array_before) / sizeof(u32); i++) {
- al_array_push(arr, array_before[i]);
+ for (u32 i = 0; i < ARRAY_SIZE(array_before); i++) {
+ al_array_push(ints, array_before[i]);
}
- al_array_remove_range(arr, 1, 2);
- al_array_remove_range(arr, 3, 5);
- AL_TEST_EQ(arr.size, 9, u32);
- al_array_remove_range(arr, 5, 7);
- AL_TEST_EQ(arr.size, 7, u32);
- al_array_remove_range(arr, 6, 7);
+ al_array_remove_range(ints, 1, 2);
+ al_array_remove_range(ints, 3, 5);
+ AL_TEST_EQ(ints.count, 9, u32);
+
+ al_array_remove_range(ints, 5, 7);
+ AL_TEST_EQ(ints.count, 7, u32);
+
+ al_array_remove_range(ints, 6, 7);
- AL_TEST_EQ(arr.size, (u32)(sizeof(array_after) / sizeof(u32)), u32);
+ AL_TEST_EQ(ints.count, ARRAY_SIZE(array_after), u32);
- for (u32 i = 0; i < sizeof(array_after) / sizeof(u32); i++) {
- AL_TEST_EQ(al_array_at(arr, i), array_after[i], u32);
+ for (u32 i = 0; i < ARRAY_SIZE(array_after); i++) {
+ AL_TEST_EQ(al_array_at(ints, i), array_after[i], u32);
}
- al_array_free(arr);
+ al_array_free(ints);
AL_TEST_END();
}
@@ -205,33 +233,32 @@ static bool array_test_pop_at(void)
{
AL_TEST_START("array_pop_at");
- array(u32) arr;
- al_array_init(arr);
+ array(u32) ints;
+ al_array_init(ints);
u32 array_before[] = { 1, 2, 3, 4, 5, 6 };
u32 array_after[] = { 2, 3, 4 };
- for (u32 i = 0; i < sizeof(array_before) / sizeof(u32); i++) {
- al_array_push(arr, array_before[i]);
+ for (u32 i = 0; i < ARRAY_SIZE(array_before); i++) {
+ al_array_push(ints, array_before[i]);
}
u32 x, y, z;
-
- al_array_pop_at(arr, 0, x);
- al_array_pop_at(arr, 3, y);
- al_array_pop_at(arr, 3, z);
+ al_array_pop_at(ints, 0, x);
+ al_array_pop_at(ints, 3, y);
+ al_array_pop_at(ints, 3, z);
AL_TEST_EQ(x, array_before[0], u32);
AL_TEST_EQ(y, array_before[4], u32);
AL_TEST_EQ(z, array_before[5], u32);
- AL_TEST_EQ(arr.size, (u32)(sizeof(array_after) / sizeof(u32)), u32);
+ AL_TEST_EQ(ints.count, ARRAY_SIZE(array_after), u32);
- for (u32 i = 0; i < sizeof(array_after) / sizeof(u32); i++) {
- AL_TEST_EQ(al_array_at(arr, i), array_after[i], u32);
+ for (u32 i = 0; i < ARRAY_SIZE(array_after); i++) {
+ AL_TEST_EQ(al_array_at(ints, i), array_after[i], u32);
}
- al_array_free(arr);
+ al_array_free(ints);
AL_TEST_END();
}
@@ -240,39 +267,36 @@ static bool array_test_insert(void)
{
AL_TEST_START("array_insert");
- array(struct test_t) arr;
- al_array_init(arr);
-
- struct test_t x = {
- .i = 5
- };
+ array(struct test_t) objects;
+ al_array_init(objects);
- struct test_t y = {
- .i = 5
- };
+ struct test_t x = { .d = 5 };
+ struct test_t y = { .d = 2 };
+ struct test_t z = { .d = 6 };
- struct test_t z = {
- .i = 5
- };
+ al_array_push(objects, (struct test_t){ .d = 7 });
+ al_array_push(objects, (struct test_t){ .d = 9 });
+ al_array_push(objects, (struct test_t){ .d = 444 });
- al_array_insert(arr, 1, x);
- al_array_insert(arr, 0, y);
- al_array_insert(arr, 1, z);
+ al_array_insert(objects, 1, x);
+ al_array_insert(objects, 0, y);
+ al_array_insert(objects, 1, z);
- AL_TEST_EQ(al_array_at(arr, 3).i, x.i, u32);
- AL_TEST_EQ(al_array_at(arr, 0).i, y.i, u32);
- AL_TEST_EQ(al_array_at(arr, 1).i, z.i, u32);
+ AL_TEST_EQ(al_array_at(objects, 3).d, x.d, u32);
+ AL_TEST_EQ(al_array_at(objects, 0).d, y.d, u32);
+ AL_TEST_EQ(al_array_at(objects, 1).d, z.d, u32);
- AL_TEST_EQ(arr.size, 4, u32);
+ AL_TEST_EQ(objects.count, 6, u32);
- al_array_remove_at(arr, 3);
+ al_array_remove_at(objects, 3);
- AL_TEST_EQ(arr.size, 3, u32);
+ AL_TEST_EQ(objects.count, 5, u32);
- AL_TEST_EQ(al_array_at(arr, 0).i, y.i, u32);
- AL_TEST_EQ(al_array_at(arr, 1).i, z.i, u32);
+ AL_TEST_NEQ(al_array_at(objects, 3).d, x.d, u32);
+ AL_TEST_EQ(al_array_at(objects, 0).d, y.d, u32);
+ AL_TEST_EQ(al_array_at(objects, 1).d, z.d, u32);
- al_array_free(arr);
+ al_array_free(objects);
AL_TEST_END();
}
@@ -281,75 +305,75 @@ static bool array_test_foreach(void)
{
AL_TEST_START("array_foreach");
- array(u32) arr;
- al_array_init(arr);
+ array(u32) ints;
+ al_array_init(ints);
- al_array_push(arr, 0);
- al_array_push(arr, 1);
- al_array_push(arr, 2);
- al_array_push(arr, 3);
- al_array_push(arr, 4);
- al_array_push(arr, 5);
+ al_array_push(ints, (u32)0);
+ al_array_push(ints, (u32)1);
+ al_array_push(ints, (u32)2);
+ al_array_push(ints, (u32)3);
+ al_array_push(ints, (u32)4);
+ al_array_push(ints, (u32)5);
u32 iter0;
- al_array_foreach(arr, i, iter0) {
+ al_array_foreach(ints, i, iter0) {
AL_TEST_EQ(iter0, i, u32);
}
u32 iter1;
- al_array_foreach_rev(arr, i, iter1) {
+ al_array_foreach_rev(ints, i, iter1) {
AL_TEST_EQ(iter1, i, u32);
}
u32 *ptr0;
- al_array_foreach_ptr(arr, i, ptr0) {
+ al_array_foreach_ptr(ints, i, ptr0) {
AL_TEST_EQ(*ptr0, i, u32);
}
u32 iter2;
- al_array_foreach_rev(arr, i, iter2) {
+ al_array_foreach_rev(ints, i, iter2) {
AL_TEST_EQ(iter2, i, u32);
- al_array_remove_at(arr, i);
+ al_array_remove_at(ints, i);
}
- AL_TEST_EQ(arr.size, 0, u32);
+ AL_TEST_EQ(ints.count, 0, u32);
- al_array_push(arr, 0);
- al_array_push(arr, 1);
- al_array_push(arr, 2);
- al_array_push(arr, 3);
- al_array_push(arr, 4);
- al_array_push(arr, 5);
- al_array_push(arr, 6);
- al_array_push(arr, 7);
- al_array_push(arr, 8);
- al_array_push(arr, 9);
+ al_array_push(ints, (u32)0);
+ al_array_push(ints, (u32)1);
+ al_array_push(ints, (u32)2);
+ al_array_push(ints, (u32)3);
+ al_array_push(ints, (u32)4);
+ al_array_push(ints, (u32)5);
+ al_array_push(ints, (u32)6);
+ al_array_push(ints, (u32)7);
+ al_array_push(ints, (u32)8);
+ al_array_push(ints, (u32)9);
- u32 iter3, count0 = 0;
- al_array_foreach(arr, i, iter3) {
- AL_TEST_EQ(iter3, count0, u32);
- count0++;
- al_array_remove_at_iter(arr, i);
+ u32 iter3, count = 0;
+ al_array_foreach(ints, i, iter3) {
+ AL_TEST_EQ(iter3, count, u32);
+ count++;
+ al_array_remove_at_iter(ints, i);
}
- al_array_push(arr, 0);
- al_array_push(arr, 1);
- al_array_push(arr, 2);
- al_array_push(arr, 3);
- al_array_push(arr, 4);
- al_array_push(arr, 5);
- al_array_push(arr, 6);
- al_array_push(arr, 7);
- al_array_push(arr, 8);
- al_array_push(arr, 9);
+ al_array_push(ints, (u32)0);
+ al_array_push(ints, (u32)1);
+ al_array_push(ints, (u32)2);
+ al_array_push(ints, (u32)3);
+ al_array_push(ints, (u32)4);
+ al_array_push(ints, (u32)5);
+ al_array_push(ints, (u32)6);
+ al_array_push(ints, (u32)7);
+ al_array_push(ints, (u32)8);
+ al_array_push(ints, (u32)9);
u32 iter4;
- al_array_foreach(arr, i, iter4) {
+ al_array_foreach(ints, i, iter4) {
AL_TEST_EQ(iter4, i + i, u32);
- al_array_remove_at(arr, i);
+ al_array_remove_at(ints, i);
}
- al_array_free(arr);
+ al_array_free(ints);
AL_TEST_END();
}
@@ -361,28 +385,81 @@ static s32 int32_compare(const void *a, const void *b)
return 0;
}
+static s32 int32_compare_reverse(const void *a, const void *b)
+{
+ if (*(s32 *)a < *(s32 *)b) return -1;
+ else if (*(s32 *)b < *(s32 *)a) return 1;
+ return 0;
+}
+
+static inline s64 sum_of_array(s32 *data, u32 count)
+{
+ s64 sum = 0;
+ while (count-- > 0) {
+ sum += *data++;
+ }
+ return sum;
+}
+
static bool array_test_sort(void)
{
AL_TEST_START("array_sort");
- array(s32) arr;
- al_array_init(arr);
+ array(s32) ints;
+ al_array_init(ints);
+
+ al_array_push(ints, 0);
+ al_array_push(ints, 1);
+ al_array_push(ints, 2);
+ al_array_push(ints, 3);
+ al_array_push(ints, 4);
+ al_array_push(ints, 0);
+ al_array_push(ints, 99);
+ AL_TEST_EQ(sum_of_array(ints.data, ints.count), 109, s64);
+
+ s32 end = al_rand() % 4000;
+ for (s32 i = 0; i < end; i++) {
+ al_array_push(ints, (al_rand() % 9001) - 9000);
+ }
+
+ s64 before_sort_sum = sum_of_array(ints.data, ints.count);
+ al_array_sort(ints, s32, int32_compare);
+ AL_TEST_EQ(sum_of_array(ints.data, ints.count), before_sort_sum, s64);
+
+ for (u32 i = 1; i < ints.count; i++) {
+ AL_TEST_GTE(al_array_at(ints, i - 1), al_array_at(ints, i), s32);
+ }
- s32 end = al_rand() % 2000;
+ end = al_rand() % 4000;
for (s32 i = 0; i < end; i++) {
- al_array_push(arr, al_rand());
+ al_array_push(ints, (al_rand() % 90001) - 90000);
}
- al_array_sort(arr, s32, int32_compare);
+ before_sort_sum = sum_of_array(ints.data, ints.count);
+ al_array_sort(ints, s32, int32_compare_reverse);
+ AL_TEST_EQ(sum_of_array(ints.data, ints.count), before_sort_sum, s64);
- for (u32 i = 1; i < arr.size; i++) {
- AL_TEST_GTE(al_array_at(arr, i - 1), al_array_at(arr, i), s32);
+ for (u32 i = 1; i < ints.count; i++) {
+ AL_TEST_LTE(al_array_at(ints, i - 1), al_array_at(ints, i), s32);
+ }
+
+ end = al_rand() % 4000;
+ for (s32 i = 0; i < end; i++) {
+ al_array_push(ints, (al_rand() % 900001) - 900000);
+ }
+
+ before_sort_sum = sum_of_array(ints.data, ints.count);
+ al_array_sort(ints, s32, int32_compare);
+ AL_TEST_EQ(sum_of_array(ints.data, ints.count), before_sort_sum, s64);
+
+ for (u32 i = 1; i < ints.count; i++) {
+ AL_TEST_GTE(al_array_at(ints, i - 1), al_array_at(ints, i), s32);
}
AL_TEST_END();
}
-bool array_tests_run(void)
+bool array_tests_run(u32 skip_mask)
{
AL_TEST_START_GROUP("array");
@@ -390,7 +467,9 @@ bool array_tests_run(void)
AL_TEST_RUN(array_test_reserve);
AL_TEST_RUN(array_test_at);
AL_TEST_RUN(array_test_last);
- AL_TEST_RUN(array_test_push);
+ if (skip_mask & AL_TESTS_RUN_LIMITS) {
+ AL_TEST_RUN(array_test_push);
+ }
AL_TEST_RUN(array_test_pop);
AL_TEST_RUN(array_test_remove_at);
AL_TEST_RUN(array_test_remove_range);
diff --git a/tests/array.h b/tests/array.h
index 881f936..8416bf2 100644
--- a/tests/array.h
+++ b/tests/array.h
@@ -3,6 +3,6 @@
#include <al/types.h>
-bool array_tests_run(void);
+bool array_tests_run(u32 skip_mask);
#endif // _AL_ARRAY_TESTS_H
diff --git a/tests/array_typed.c b/tests/array_typed.c
index edaa52b..f61634d 100644
--- a/tests/array_typed.c
+++ b/tests/array_typed.c
@@ -2,28 +2,32 @@
#include <al/array_typed.h>
#include "array_typed.h"
+#include "common.h"
-struct test_t {
- u32 i;
-};
+AL_UNUSED_FUNCTION_PUSH
AL_ARRAY_INLINE_STORAGE_DEFINE(u32, u32, 64)
AL_ARRAY_DEFINE(u32, u32)
+AL_ARRAY_DEFINE(u8, u8)
AL_ARRAY_INLINE_STORAGE_DEFINE(test_t, struct test_t, 16)
+AL_UNUSED_FUNCTION_POP
+
static bool array_test_init(void)
{
AL_TEST_START("array_init");
- array(u32, 64) arr;
- al_array_init(u32, 64)(&arr);
+ array(u32, 64) ints;
+ al_array_init(u32, 64)(&ints);
- AL_TEST_EQ((void *)arr.data, NULL, ptr);
- AL_TEST_EQ(arr.alloc, 64, u32);
- AL_TEST_EQ(arr.size, 0, u32);
- AL_TEST_EQ(sizeof(arr.inline_data), 64 * sizeof(u32), size_t);
+ AL_TEST_EQ(ints.count, 0, u32);
+ AL_TEST_EQ(ints.alloc, 256, u32);
+ AL_TEST_EQ(ints.data, NULL, ptr);
+ AL_TEST_EQ(sizeof(ints.inline_data), 64 * sizeof(u32), size_t);
- al_array_free(u32, 64)(&arr);
+ al_array_free(u32, 64)(&ints);
+ // Not a double-free.
+ al_array_free(u32, 64)(&ints);
AL_TEST_END();
}
@@ -32,25 +36,22 @@ static bool array_test_reserve(void)
{
AL_TEST_START("array_reserve");
- array(u32, 64) arr;
- al_array_init(u32, 64)(&arr);
-
- al_array_reserve(u32, 64)(&arr, 64);
-
- AL_TEST_EQ((void *)arr.data, NULL, ptr);
- AL_TEST_EQ(arr.alloc, 64, u32);
-
- al_array_reserve(u32, 64)(&arr, 128);
+ array(u32, 64) ints;
+ al_array_init(u32, 64)(&ints);
- AL_TEST_NEQ((void *)arr.data, NULL, ptr);
- AL_TEST_EQ(arr.alloc, 128, u32);
+ al_array_reserve(u32, 64)(&ints, 64);
+ AL_TEST_EQ(ints.alloc, 256, u32);
+ AL_TEST_EQ(ints.data, NULL, ptr);
- al_array_reserve(u32, 64)(&arr, 129);
+ al_array_reserve(u32, 64)(&ints, 128);
+ AL_TEST_EQ(ints.alloc, 512, u32);
+ AL_TEST_NEQ(ints.data, NULL, ptr);
- AL_TEST_NEQ((void *)arr.data, NULL, ptr);
- AL_TEST_EQ(arr.alloc, 256, u32);
+ al_array_reserve(u32, 64)(&ints, 129);
+ AL_TEST_EQ(ints.alloc, 1024, u32);
+ AL_TEST_NEQ(ints.data, NULL, ptr);
- al_array_free(u32, 64)(&arr);
+ al_array_free(u32, 64)(&ints);
AL_TEST_END();
}
@@ -59,15 +60,19 @@ static bool array_test_at(void)
{
AL_TEST_START("array_at");
- array(u32, 64) arr;
- al_array_init(u32, 64)(&arr);
+ array(u32, 64) ints;
+ al_array_init(u32, 64)(&ints);
u32 x = 5;
- al_array_push(u32, 64)(&arr, &x);
+ al_array_push(u32, 64)(&ints, x);
+ al_array_push(u32, 64)(&ints, (u32)4);
- AL_TEST_EQ(*al_array_at(u32, 64)(&arr, 0), 5, u32);
+ AL_TEST_EQ(*al_array_at(u32, 64)(&ints, 0), 5, u32);
+ AL_TEST_EQ(*al_array_at(u32, 64)(&ints, 1), 4, u32);
+ AL_TEST_EQ(ints.count, 2, u32);
+ AL_TEST_EQ(ints.alloc, 256, u32);
- al_array_free(u32, 64)(&arr);
+ al_array_free(u32, 64)(&ints);
AL_TEST_END();
}
@@ -76,18 +81,19 @@ static bool array_test_last(void)
{
AL_TEST_START("array_last");
- array(u32, 64) arr;
- al_array_init(u32, 64)(&arr);
+ array(u32, 64) ints;
+ al_array_init(u32, 64)(&ints);
u32 x = 1, y = 2, z = 3;
+ al_array_push(u32, 64)(&ints, x);
+ al_array_push(u32, 64)(&ints, y);
+ al_array_push(u32, 64)(&ints, z);
- al_array_push(u32, 64)(&arr, &x);
- al_array_push(u32, 64)(&arr, &y);
- al_array_push(u32, 64)(&arr, &z);
+ AL_TEST_EQ(*al_array_last(u32, 64)(&ints), 3, u32);
+ AL_TEST_EQ(ints.count, 3, u32);
+ AL_TEST_EQ(ints.alloc, 256, u32);
- AL_TEST_EQ(*al_array_last(u32, 64)(&arr), 3, u32);
-
- al_array_free(u32, 64)(&arr);
+ al_array_free(u32, 64)(&ints);
AL_TEST_END();
}
@@ -96,19 +102,21 @@ static bool array_test_push(void)
{
AL_TEST_START("array_push");
- array(u32, 64) arr;
- al_array_init(u32, 64)(&arr);
-
- u32 x = 4, y = 5;
+ array(u8) bytes;
+ al_array_init(u8)(&bytes);
- al_array_push(u32, 64)(&arr, &x);
- al_array_push(u32, 64)(&arr, &y);
+ for (u32 i = 0; i < MAX_ALLOC_32; i++) {
+ al_array_push(u8)(&bytes, (u8)1);
+ }
+ AL_TEST_EQ(bytes.count, MAX_ALLOC_32, u32);
+ AL_TEST_EQ(bytes.alloc, MAX_ALLOC_32, u32);
- AL_TEST_EQ(arr.size, 2, u32);
- AL_TEST_EQ(*al_array_at(u32, 64)(&arr, 0), x, u32);
- AL_TEST_EQ(*al_array_at(u32, 64)(&arr, 1), y, u32);
+ AL_TEST_EQ(al_array_at(u8)(&bytes, MAX_ALLOC_32 - 1), al_array_last(u8)(&bytes), ptr);
+ AL_TEST_EQ(*al_array_at(u8)(&bytes, MAX_ALLOC_32 - 2), 1, u8);
+ AL_TEST_EQ(*al_array_at(u8)(&bytes, MAX_ALLOC_32 - 3), 1, u8);
+ AL_TEST_EQ(*al_array_at(u8)(&bytes, MAX_ALLOC_32 - 4), 1, u8);
- al_array_free(u32, 64)(&arr);
+ al_array_free(u8)(&bytes);
AL_TEST_END();
}
@@ -117,27 +125,25 @@ static bool array_test_pop(void)
{
AL_TEST_START("array_pop");
- array(u32, 64) arr;
- al_array_init(u32, 64)(&arr);
+ array(u32, 64) ints;
+ al_array_init(u32, 64)(&ints);
u32 x = 4, y = 5;
-
- al_array_push(u32, 64)(&arr, &x);
- al_array_push(u32, 64)(&arr, &y);
+ al_array_push(u32, 64)(&ints, x);
+ al_array_push(u32, 64)(&ints, y);
u32 rx, ry;
- al_array_pop(u32, 64)(&arr, &ry);
-
- AL_TEST_EQ(arr.size, 1, u32);
+ al_array_pop(u32, 64)(&ints, &ry);
+ AL_TEST_EQ(ints.count, 1, u32);
- al_array_pop(u32, 64)(&arr, &rx);
+ al_array_pop(u32, 64)(&ints, &rx);
+ AL_TEST_EQ(ints.count, 0, u32);
- AL_TEST_EQ(arr.size, 0, u32);
AL_TEST_EQ(rx, x, u32);
AL_TEST_EQ(ry, y, u32);
- al_array_free(u32, 64)(&arr);
+ al_array_free(u32, 64)(&ints);
AL_TEST_END();
}
@@ -146,28 +152,28 @@ static bool array_test_remove_at(void)
{
AL_TEST_START("array_remove_at");
- array(u32) arr;
- al_array_init(u32)(&arr);
- al_array_reserve(u32)(&arr, 12);
+ array(u32) ints;
+ al_array_init(u32)(&ints);
+ al_array_reserve(u32)(&ints, 12);
u32 array_before[] = { 1, 2, 3, 4, 5, 6 };
u32 array_after[] = { 2, 3, 4 };
- for (u32 i = 0; i < sizeof(array_before) / sizeof(u32); i++) {
- al_array_push(u32)(&arr, &array_before[i]);
+ for (u32 i = 0; i < ARRAY_SIZE(array_before); i++) {
+ al_array_push(u32)(&ints, array_before[i]);
}
- al_array_remove_at(u32)(&arr, 0);
- al_array_remove_at(u32)(&arr, 3);
- al_array_remove_at(u32)(&arr, 3);
+ al_array_remove_at(u32)(&ints, 0);
+ al_array_remove_at(u32)(&ints, 3);
+ al_array_remove_at(u32)(&ints, 3);
- AL_TEST_EQ(arr.size, (u32)(sizeof(array_after) / sizeof(u32)), u32);
+ AL_TEST_EQ(ints.count, ARRAY_SIZE(array_after), u32);
- for (u32 i = 0; i < sizeof(array_after) / sizeof(u32); i++) {
- AL_TEST_EQ(*al_array_at(u32)(&arr, i), array_after[i], u32);
+ for (u32 i = 0; i < ARRAY_SIZE(array_after); i++) {
+ AL_TEST_EQ(*al_array_at(u32)(&ints, i), array_after[i], u32);
}
- al_array_free(u32)(&arr);
+ al_array_free(u32)(&ints);
AL_TEST_END();
}
@@ -176,33 +182,31 @@ static bool array_test_pop_at(void)
{
AL_TEST_START("array_pop_at");
- array(u32, 64) arr;
- al_array_init(u32, 64)(&arr);
+ array(u32, 64) ints;
+ al_array_init(u32, 64)(&ints);
u32 array_before[] = { 1, 2, 3, 4, 5, 6 };
u32 array_after[] = { 2, 3, 4 };
- for (u32 i = 0; i < sizeof(array_before) / sizeof(u32); i++) {
- al_array_push(u32, 64)(&arr, &array_before[i]);
+ for (u32 i = 0; i < ARRAY_SIZE(array_before); i++) {
+ al_array_push(u32, 64)(&ints, array_before[i]);
}
- u32 x, y, z;
-
- al_array_pop_at(u32, 64)(&arr, 0, &x);
- al_array_pop_at(u32, 64)(&arr, 3, &y);
- al_array_pop_at(u32, 64)(&arr, 3, &z);
+ u32 x = al_array_pop_at(u32, 64)(&ints, 0);
+ u32 y = al_array_pop_at(u32, 64)(&ints, 3);
+ u32 z = al_array_pop_at(u32, 64)(&ints, 3);
AL_TEST_EQ(x, array_before[0], u32);
AL_TEST_EQ(y, array_before[4], u32);
AL_TEST_EQ(z, array_before[5], u32);
- AL_TEST_EQ(arr.size, (u32)(sizeof(array_after) / sizeof(u32)), u32);
+ AL_TEST_EQ(ints.count, ARRAY_SIZE(array_after), u32);
- for (u32 i = 0; i < sizeof(array_after) / sizeof(u32); i++) {
- AL_TEST_EQ(*al_array_at(u32, 64)(&arr, i), array_after[i], u32);
+ for (u32 i = 0; i < ARRAY_SIZE(array_after); i++) {
+ AL_TEST_EQ(*al_array_at(u32, 64)(&ints, i), array_after[i], u32);
}
- al_array_free(u32, 64)(&arr);
+ al_array_free(u32, 64)(&ints);
AL_TEST_END();
}
@@ -211,44 +215,41 @@ static bool array_test_insert(void)
{
AL_TEST_START("array_insert");
- array(test_t, 16) arr;
- al_array_init(test_t, 16)(&arr);
-
- struct test_t x = {
- .i = 5
- };
+ array(test_t, 16) objects;
+ al_array_init(test_t, 16)(&objects);
- struct test_t y = {
- .i = 5
- };
+ struct test_t x = { .d = 5 };
+ struct test_t y = { .d = 2 };
+ struct test_t z = { .d = 6 };
- struct test_t z = {
- .i = 5
- };
+ al_array_push(test_t, 16)(&objects, (struct test_t){ .d = 7 });
+ al_array_push(test_t, 16)(&objects, (struct test_t){ .d = 9 });
+ al_array_push(test_t, 16)(&objects, (struct test_t){ .d = 444 });
- al_array_insert(test_t, 16)(&arr, 1, &x);
- al_array_insert(test_t, 16)(&arr, 0, &y);
- al_array_insert(test_t, 16)(&arr, 1, &z);
+ al_array_insert(test_t, 16)(&objects, 1, x);
+ al_array_insert(test_t, 16)(&objects, 0, y);
+ al_array_insert(test_t, 16)(&objects, 1, z);
- AL_TEST_EQ(al_array_at(test_t, 16)(&arr, 3)->i, x.i, u32);
- AL_TEST_EQ(al_array_at(test_t, 16)(&arr, 0)->i, y.i, u32);
- AL_TEST_EQ(al_array_at(test_t, 16)(&arr, 1)->i, z.i, u32);
+ AL_TEST_EQ(al_array_at(test_t, 16)(&objects, 3)->d, x.d, u32);
+ AL_TEST_EQ(al_array_at(test_t, 16)(&objects, 0)->d, y.d, u32);
+ AL_TEST_EQ(al_array_at(test_t, 16)(&objects, 1)->d, z.d, u32);
- AL_TEST_EQ(arr.size, 4, u32);
+ AL_TEST_EQ(objects.count, 6, u32);
- al_array_remove_at(test_t, 16)(&arr, 3);
+ al_array_remove_at(test_t, 16)(&objects, 3);
- AL_TEST_EQ(arr.size, 3, u32);
+ AL_TEST_EQ(objects.count, 5, u32);
- AL_TEST_EQ(al_array_at(test_t, 16)(&arr, 0)->i, y.i, u32);
- AL_TEST_EQ(al_array_at(test_t, 16)(&arr, 1)->i, z.i, u32);
+ AL_TEST_NEQ(al_array_at(test_t, 16)(&objects, 0)->d, x.d, u32);
+ AL_TEST_EQ(al_array_at(test_t, 16)(&objects, 0)->d, y.d, u32);
+ AL_TEST_EQ(al_array_at(test_t, 16)(&objects, 1)->d, z.d, u32);
- al_array_free(test_t, 16)(&arr);
+ al_array_free(test_t, 16)(&objects);
AL_TEST_END();
}
-bool array_typed_tests_run(void)
+bool array_typed_tests_run(u32 skip_mask)
{
AL_TEST_START_GROUP("array_typed");
@@ -256,7 +257,9 @@ bool array_typed_tests_run(void)
AL_TEST_RUN(array_test_reserve);
AL_TEST_RUN(array_test_at);
AL_TEST_RUN(array_test_last);
- AL_TEST_RUN(array_test_push);
+ if (skip_mask & AL_TESTS_RUN_LIMITS) {
+ AL_TEST_RUN(array_test_push);
+ }
AL_TEST_RUN(array_test_pop);
AL_TEST_RUN(array_test_remove_at);
AL_TEST_RUN(array_test_pop_at);
diff --git a/tests/array_typed.h b/tests/array_typed.h
index 644cce6..2241ede 100644
--- a/tests/array_typed.h
+++ b/tests/array_typed.h
@@ -3,6 +3,6 @@
#include <al/types.h>
-bool array_typed_tests_run(void);
+bool array_typed_tests_run(u32 skip_mask);
#endif // _AL_ARRAY_TYPED_TESTS_H
diff --git a/tests/common.h b/tests/common.h
new file mode 100644
index 0000000..cd8e6ab
--- /dev/null
+++ b/tests/common.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <al/types.h>
+
+enum {
+ AL_TESTS_RUN_LIMITS = 1
+};
+
+struct test_t {
+ u32 d;
+ u32 j;
+};
diff --git a/tests/lib.c b/tests/lib.c
index 0923cf1..48b6c02 100644
--- a/tests/lib.c
+++ b/tests/lib.c
@@ -1,37 +1,62 @@
-#include <al/array.h>
#include <al/test.h>
+#include <al/array.h>
#include <al/lib.h>
-#include <al/random.h>
-struct test_t {
- u32 d;
-};
+#include "lib.h"
+#include "common.h"
static bool lib_test_add_wrap(void)
{
AL_TEST_START("lib_add_wrap");
- u32 x = UINT32_MAX - 5;
- x = al_u32_add_wrap(x, 15);
- AL_TEST_EQ(x, 10, u32);
+ // u32
+ u32 counter32 = UINT32_MAX - 5;
+ counter32 = al_u32_add_wrap(counter32, 15);
+ AL_TEST_EQ(counter32, 10, u32);
+
+ counter32 = UINT32_MAX;
+ counter32 = al_u32_add_wrap(counter32, 1);
+ AL_TEST_EQ(counter32, 1, u32);
+
+ counter32 = UINT32_MAX - 25;
+ counter32 = al_u32_add_wrap(counter32, 20);
+ AL_TEST_EQ(counter32, UINT32_MAX - 5, u32);
+ counter32 = al_u32_add_wrap(counter32, 6);
+ AL_TEST_EQ(counter32, 1, u32);
- x = UINT32_MAX;
- x = al_u32_add_wrap(x, 1);
- AL_TEST_EQ(x, 1, u32);
+ // u16
+ u16 counter16 = UINT16_MAX - 5;
+ counter16 = al_u16_add_wrap(counter16, 15);
+ AL_TEST_EQ(counter16, 10, u16);
- x = UINT32_MAX - 25;
- x = al_u32_add_wrap(x, 20);
- AL_TEST_EQ(x, UINT32_MAX - 5, u32);
- x = al_u32_add_wrap(x, 6);
- AL_TEST_EQ(x, 1, u32);
+ counter16 = UINT16_MAX;
+ counter16 = al_u16_add_wrap(counter16, 1);
+ AL_TEST_EQ(counter16, 1, u16);
- u16 y = UINT16_MAX - 5;
- y = al_u16_add_wrap(y, 15);
- AL_TEST_EQ(y, 10, u16);
+ counter16 = UINT16_MAX - 25;
+ counter16 = al_u16_add_wrap(counter16, 20);
+ AL_TEST_EQ(counter16, UINT16_MAX - 5, u16);
+ counter16 = al_u16_add_wrap(counter16, 6);
+ AL_TEST_EQ(counter16, 1, u16);
- y = UINT16_MAX;
- y = al_u16_add_wrap(y, 1);
- AL_TEST_EQ(y, 1, u16);
+ // inc_wrap
+ counter16 = UINT16_MAX - 4;
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), UINT16_MAX - 3, u16);
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), UINT16_MAX - 2, u16);
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), UINT16_MAX - 1, u16);
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), UINT16_MAX, u16);
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), 0, u16);
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), 1, u16);
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), 2, u16);
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), 3, u16);
+
+ // From 3 to UINT16_MAX.
+ for (u16 i = 0; i < UINT16_MAX - 3; i++) {
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), i + 4, u16);
+ }
+
+ // Wrap to 0.
+ AL_TEST_EQ((counter16 = al_u16_inc_wrap(counter16)), 0, u16);
AL_TEST_END();
}
@@ -40,62 +65,53 @@ static bool lib_test_offset_vs_at_and_ref(void)
{
AL_TEST_START("lib_offset_vs_at_and_ref");
- array(struct test_t *) ar;
- al_array_init(ar);
+ // Test that &al_array_at and al_array_offset are equivalent and that we can
+ // have NULL entires in an array of pointers.
+
+ array(struct test_t *) objects;
+ al_array_init(objects);
for (u32 i = 0; i < 10; i++) {
if (i == 4) {
- al_array_push(ar, NULL);
+ al_array_push(objects, (struct test_t *)NULL);
} else {
- al_array_push(ar, al_alloc_object(struct test_t));
+ al_array_push(objects, al_alloc_object(struct test_t));
}
}
- AL_TEST_EQ(&al_array_at(ar, 2), al_array_offset(ar, 2), ptr);
- AL_TEST_EQ(&al_array_at(ar, 3), al_array_offset(ar, 3), ptr);
- AL_TEST_NEQ(*&al_array_at(ar, 3), NULL, ptr);
- AL_TEST_EQ(&al_array_at(ar, 4), al_array_offset(ar, 4), ptr);
- AL_TEST_EQ(*&al_array_at(ar, 4), *al_array_offset(ar, 4), ptr);
- AL_TEST_NEQ(*&al_array_at(ar, 4), *al_array_offset(ar, 2), ptr);
- AL_TEST_EQ(*&al_array_at(ar, 4), NULL, ptr);
- AL_TEST_EQ(&al_array_at(ar, 5), al_array_offset(ar, 5), ptr);
+ AL_TEST_EQ(&al_array_at(objects, 2), al_array_offset(objects, 2), ptr);
+ AL_TEST_EQ(&al_array_at(objects, 3), al_array_offset(objects, 3), ptr);
+ AL_TEST_NEQ(*&al_array_at(objects, 3), NULL, ptr);
+
+ AL_TEST_EQ(&al_array_at(objects, 4), al_array_offset(objects, 4), ptr);
+ AL_TEST_EQ(*&al_array_at(objects, 4), *al_array_offset(objects, 4), ptr);
+
+ AL_TEST_NEQ(*&al_array_at(objects, 4), *al_array_offset(objects, 2), ptr);
+
+ AL_TEST_EQ(*&al_array_at(objects, 4), NULL, ptr);
+ AL_TEST_EQ(&al_array_at(objects, 5), al_array_offset(objects, 5), ptr);
for (u32 i = 0; i < 10; i++) {
if (i != 4) {
- al_free(al_array_at(ar, i));
+ al_free(al_array_at(objects, i));
}
}
AL_TEST_END();
}
-/*
-static bool lib_test_add_wrap_atomic(void)
+static bool lib_test_min_max(void)
{
- AL_TEST_START("lib_add_wrap_atomic");
-
- for (u32 i = 0; i < UINT16_MAX - 3; i++) {
- al_inc_u16();
- }
-
- AL_TEST_EQ(al_inc_u16(), UINT16_MAX - 3, u16);
- AL_TEST_EQ(al_inc_u16(), UINT16_MAX - 2, u16);
- AL_TEST_EQ(al_inc_u16(), UINT16_MAX - 1, u16);
- AL_TEST_EQ(al_inc_u16(), UINT16_MAX, u16);
- AL_TEST_EQ(al_inc_u16(), 0, u16);
- AL_TEST_EQ(al_inc_u16(), 1, u16);
- AL_TEST_EQ(al_inc_u16(), 2, u16);
- AL_TEST_EQ(al_inc_u16(), 3, u16);
-
- for (u32 i = 0; i < UINT16_MAX - 3; i++) {
- AL_TEST_EQ(al_inc_u16(), i + 4, u16);
- }
+ AL_TEST_START("lib_min_max");
- AL_TEST_EQ(al_inc_u16(), 0, u16);
+ AL_TEST_EQ(MAX((u32)4, (u32)3), 4, u32);
+ AL_TEST_EQ(MIN((u32)4, (u32)3), 3, u32);
+ // Compiler warnings.
+ //AL_TEST_EQ(MAX(4, (u32)3), 4, u32);
+ //AL_TEST_EQ(MIN(4, (u32)3), 3, u32);
AL_TEST_END();
}
-*/
bool lib_tests_run(void)
{
@@ -103,7 +119,7 @@ bool lib_tests_run(void)
AL_TEST_RUN(lib_test_add_wrap);
AL_TEST_RUN(lib_test_offset_vs_at_and_ref);
- //AL_TEST_RUN(lib_test_add_wrap_atomic);
+ AL_TEST_RUN(lib_test_min_max);
AL_TEST_END_GROUP();
}
diff --git a/tests/main.c b/tests/main.c
index 5964a04..672511a 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -1,5 +1,7 @@
#include <al/lib.h>
+#include <al/str.h>
#include <al/random.h>
+#include <time.h>
#include "lib.h"
#include "array.h"
@@ -8,18 +10,31 @@
#endif
#include "str.h"
#include "ring_buffer.h"
+#include "common.h"
-s32 main(void)
+s32 main(s32 argc, char *argv[])
{
- al_rand_init();
+ al_rand_init((u32)time(NULL));
- if (!lib_tests_run()) goto fail;
- if (!array_tests_run()) goto fail;
+ u32 skip_mask = 0;
+ if (argc > 1) {
+ for (s32 i = 1; i < argc; i++) {
+ if (al_str_eq(&al_str_cr(argv[i]), &al_str_c("run_limits"))) {
+ skip_mask |= AL_TESTS_RUN_LIMITS;
+ al_printf("MAX_ALLOC_32: %u, INT32_MAX: %u, UINT32_MAX: %u.\n",
+ MAX_ALLOC_32, INT32_MAX, UINT32_MAX);
+ }
+ }
+ }
+
+
+ if (!array_tests_run(skip_mask)) goto fail;
#ifdef AL_HAVE_GNU_EXTENSIONS
- if (!array_typed_tests_run()) goto fail;
+ if (!array_typed_tests_run(skip_mask)) goto fail;
#endif
- if (!str_tests_run()) goto fail;
+ if (!str_tests_run(skip_mask)) goto fail;
if (!ring_buffer_tests_run()) goto fail;
+ if (!lib_tests_run()) goto fail;
return EXIT_SUCCESS;
diff --git a/tests/ring_buffer.c b/tests/ring_buffer.c
index 30b583e..97286a3 100644
--- a/tests/ring_buffer.c
+++ b/tests/ring_buffer.c
@@ -2,22 +2,24 @@
#include <al/ring_buffer.h>
#include <al/atomic.h>
-#define TEST_BUFFER_SIZE 32
+#include "ring_buffer.h"
-static u8 buffer[TEST_BUFFER_SIZE];
-static u8 buffer_ret[TEST_BUFFER_SIZE];
-static u8 buffer_half[TEST_BUFFER_SIZE / 2] = {0};
-static u8 buffer_over[TEST_BUFFER_SIZE + 16] = {0};
+#define BUFFER_SIZE 32
+
+static u8 buffer[BUFFER_SIZE];
+static u8 output[BUFFER_SIZE];
+static u8 half_buffer[BUFFER_SIZE / 2] = { 0 };
+static u8 bigger_buffer[BUFFER_SIZE + 16] = { 0 };
static bool ring_buffer_test_init(void)
{
AL_TEST_START("ring_buffer_init");
struct al_ring_buffer buf;
- al_ring_buffer_init(&buf, buffer, TEST_BUFFER_SIZE);
+ al_ring_buffer_init(&buf, buffer, BUFFER_SIZE);
AL_TEST_EQ(buf.start, buffer, ptr);
- AL_TEST_EQ(buf.end, buffer + TEST_BUFFER_SIZE, ptr);
+ AL_TEST_EQ(buf.end, buffer + BUFFER_SIZE, ptr);
AL_TEST_EQ(al_atomic_load(void)(&buf.read, AL_ATOMIC_RELAXED), buffer, ptr);
AL_TEST_EQ(al_atomic_load(void)(&buf.write, AL_ATOMIC_RELAXED), buffer, ptr);
@@ -29,9 +31,9 @@ static bool ring_buffer_test_space(void)
AL_TEST_START("ring_buffer_space");
struct al_ring_buffer buf;
- al_ring_buffer_init(&buf, buffer, TEST_BUFFER_SIZE);
+ al_ring_buffer_init(&buf, buffer, BUFFER_SIZE);
- AL_TEST_EQ(al_ring_buffer_space(&buf), TEST_BUFFER_SIZE - 1, size_t);
+ AL_TEST_EQ(al_ring_buffer_space(&buf), BUFFER_SIZE - 1, ptrdiff_t);
AL_TEST_END();
}
@@ -41,9 +43,9 @@ static bool ring_buffer_test_occupied(void)
AL_TEST_START("ring_buffer_occupied");
struct al_ring_buffer buf;
- al_ring_buffer_init(&buf, buffer, TEST_BUFFER_SIZE);
+ al_ring_buffer_init(&buf, buffer, BUFFER_SIZE);
- AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, size_t);
+ AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, ptrdiff_t);
AL_TEST_END();
}
@@ -53,29 +55,28 @@ static bool ring_buffer_test_read_and_write_chunk(void)
AL_TEST_START("ring_buffer_read_and_write_chunk");
struct al_ring_buffer buf;
- al_ring_buffer_init(&buf, buffer, TEST_BUFFER_SIZE);
+ al_ring_buffer_init(&buf, buffer, BUFFER_SIZE);
char *data = "TestTEST";
- size_t data_size = al_strlen(data) + 1;
+ ptrdiff_t data_size = (ptrdiff_t)(al_strlen(data) + 1);
- size_t size;
+ ptrdiff_t size;
u8 *ptr = al_ring_buffer_write_chunk(&buf, &size);
+ AL_TEST_EQ(size, BUFFER_SIZE - 1, ptrdiff_t);
- AL_TEST_EQ(size, TEST_BUFFER_SIZE - 1, size_t);
+ al_memcpy(ptr, data, (size_t)data_size);
- al_memcpy(ptr, data, data_size);
al_ring_buffer_append(&buf, ptr, data_size);
-
- AL_TEST_EQ(al_ring_buffer_occupied(&buf), data_size, size_t);
- AL_TEST_EQ(al_ring_buffer_space(&buf), (TEST_BUFFER_SIZE - 1) - data_size, size_t);
+ AL_TEST_EQ(al_ring_buffer_occupied(&buf), data_size, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_space(&buf), (BUFFER_SIZE - 1) - data_size, ptrdiff_t);
ptr = al_ring_buffer_read_chunk(&buf, &size);
- AL_TEST_EQ(size, data_size, size_t);
- AL_TEST_TRUE((strcmp((char *)ptr, data) == 0));
- al_ring_buffer_consume(&buf, ptr, size);
+ AL_TEST_EQ(size, data_size, ptrdiff_t);
+ AL_TEST_TRUE(strcmp((char *)ptr, data) == 0);
- AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, size_t);
- AL_TEST_EQ(al_ring_buffer_space(&buf), TEST_BUFFER_SIZE - 1, size_t);
+ al_ring_buffer_consume(&buf, ptr, size);
+ AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_space(&buf), BUFFER_SIZE - 1, ptrdiff_t);
AL_TEST_END();
}
@@ -85,40 +86,45 @@ static bool ring_buffer_test_read_and_write(void)
AL_TEST_START("ring_buffer_read_and_write");
struct al_ring_buffer buf;
- al_ring_buffer_init(&buf, buffer, TEST_BUFFER_SIZE);
+ al_ring_buffer_init(&buf, buffer, BUFFER_SIZE);
char *data = "TestTEST";
- size_t data_size = al_strlen(data) + 1;
+ ptrdiff_t data_size = (ptrdiff_t)(al_strlen(data) + 1);
al_ring_buffer_write(&buf, (u8 *)data, data_size);
+ AL_TEST_EQ(al_ring_buffer_occupied(&buf), data_size, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_space(&buf), (BUFFER_SIZE - 1) - data_size, ptrdiff_t);
- AL_TEST_EQ(al_ring_buffer_occupied(&buf), data_size, size_t);
- AL_TEST_EQ(al_ring_buffer_space(&buf), (TEST_BUFFER_SIZE - 1) - data_size, size_t);
-
- al_ring_buffer_read(&buf, (u8 *)buffer_ret, data_size);
- AL_TEST_TRUE((strcmp((char *)buffer_ret, data) == 0));
+ al_ring_buffer_read(&buf, (u8 *)output, data_size);
+ AL_TEST_TRUE(strcmp((char *)output, data) == 0);
+ AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_space(&buf), BUFFER_SIZE - 1, ptrdiff_t);
- AL_TEST_EQ(al_ring_buffer_occupied(&buf), 0, size_t);
- AL_TEST_EQ(al_ring_buffer_space(&buf), TEST_BUFFER_SIZE - 1, size_t);
+ al_memset(half_buffer, 'd', sizeof(half_buffer));
+ AL_TEST_EQ(al_ring_buffer_write(&buf, half_buffer, sizeof(half_buffer)), sizeof(half_buffer), ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_occupied(&buf), sizeof(half_buffer), ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_space(&buf), (BUFFER_SIZE - 1) - sizeof(half_buffer), ptrdiff_t);
- al_memset(buffer_half, 'd', sizeof(buffer_half));
+ // Arbitrarily read data_size from what was written above.
+ AL_TEST_EQ(al_ring_buffer_read(&buf, (u8 *)output, data_size), data_size, ptrdiff_t);
+ AL_TEST_TRUE(al_memcmp(output, "ddddddddd", (size_t)data_size) == 0);
- AL_TEST_EQ(al_ring_buffer_write(&buf, buffer_half, sizeof(buffer_half)), sizeof(buffer_half), size_t);
- AL_TEST_EQ(al_ring_buffer_occupied(&buf), sizeof(buffer_half), size_t);
- AL_TEST_EQ(al_ring_buffer_space(&buf), (TEST_BUFFER_SIZE - 1) - sizeof(buffer_half), size_t);
-
- AL_TEST_EQ(al_ring_buffer_read(&buf, (u8 *)buffer_ret, data_size), data_size, size_t);
- AL_TEST_TRUE(al_memcmp(buffer_ret, "ddddddddd", data_size) == 0);
-
- AL_TEST_EQ(al_ring_buffer_write(&buf, buffer_half, sizeof(buffer_half)), sizeof(buffer_half), size_t);
- AL_TEST_EQ(al_ring_buffer_occupied(&buf), TEST_BUFFER_SIZE - data_size, size_t);
+ AL_TEST_EQ(al_ring_buffer_write(&buf, half_buffer, sizeof(half_buffer)), sizeof(half_buffer), ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_occupied(&buf), BUFFER_SIZE - data_size, ptrdiff_t);
+ // Test that we wrapped.
AL_TEST_LT(al_atomic_load(void)(&buf.write, AL_ATOMIC_RELAXED), al_atomic_load(void)(&buf.read, AL_ATOMIC_RELAXED), ptr);
- size_t space = al_ring_buffer_space(&buf);
- AL_TEST_EQ(space, data_size - 1, size_t);
- AL_TEST_EQ(al_ring_buffer_write(&buf, buffer_over, sizeof(buffer_over)), space, size_t);
+ ptrdiff_t space = al_ring_buffer_space(&buf);
+ // Maximum space is BUFFER_SIZE - 1.
+ AL_TEST_EQ(space, data_size - 1, ptrdiff_t);
+ al_memset(bigger_buffer, 'r', sizeof(bigger_buffer));
+ // Test impartial write because we're out of space.
+ AL_TEST_EQ(al_ring_buffer_write(&buf, bigger_buffer, sizeof(bigger_buffer)), space, ptrdiff_t);
- AL_TEST_EQ(al_ring_buffer_read(&buf, buffer_ret, sizeof(buffer_over)), TEST_BUFFER_SIZE - 1, size_t);
+ // Test we can read everything.
+ AL_TEST_EQ(al_ring_buffer_read(&buf, output, sizeof(bigger_buffer)), BUFFER_SIZE - 1, ptrdiff_t);
+ AL_TEST_TRUE(al_memcmp(output, half_buffer, sizeof(half_buffer)) == 0);
+ AL_TEST_TRUE(al_memcmp(output + ((BUFFER_SIZE - 1) - space), bigger_buffer, (size_t)space) == 0);
AL_TEST_END();
}
@@ -128,58 +134,63 @@ static bool ring_buffer_test_peek(void)
AL_TEST_START("ring_buffer_peek");
struct al_ring_buffer buf;
- al_ring_buffer_init(&buf, buffer, TEST_BUFFER_SIZE);
+ al_ring_buffer_init(&buf, buffer, BUFFER_SIZE);
- char *data = "abcabcabcabcabcabcabcabcabcabca";
- size_t data_size = al_strlen(data);
- AL_TEST_EQ(data_size, TEST_BUFFER_SIZE - 1, size_t);
+ char *data = "aBcDeFgHiJkLmNoPqRsTuVwXyZ12345";
+ ptrdiff_t data_size = (ptrdiff_t)al_strlen(data);
+ AL_TEST_EQ(data_size, BUFFER_SIZE - 1, ptrdiff_t);
al_ring_buffer_write(&buf, (u8 *)data, data_size);
- al_ring_buffer_peek(&buf, buffer_ret, 0, data_size);
- AL_TEST_TRUE(al_memcmp(buffer_ret, data, data_size) == 0);
+ // Peek everything.
+ al_ring_buffer_peek(&buf, output, 0, data_size);
+ AL_TEST_TRUE(al_memcmp(output, data, (size_t)data_size) == 0);
- al_ring_buffer_peek(&buf, buffer_ret, 3, data_size);
- AL_TEST_TRUE(al_memcmp(buffer_ret, data + 3, data_size - 3) == 0);
+ // Peek from an offset of 3.
+ al_ring_buffer_peek(&buf, output, 3, data_size);
+ AL_TEST_TRUE(al_memcmp(output, data + 3, (size_t)(data_size - 3)) == 0);
- al_ring_buffer_read(&buf, buffer_ret, 3);
- AL_TEST_TRUE(al_memcmp(buffer_ret, data, 3) == 0);
+ // Read 3 bytes and peek the remaining
+ al_ring_buffer_read(&buf, output, 3);
+ AL_TEST_TRUE(al_memcmp(output, data, 3) == 0);
al_ring_buffer_write(&buf, (u8 *)data, data_size);
- al_ring_buffer_peek(&buf, buffer_ret, 3, data_size);
- AL_TEST_TRUE(al_memcmp(buffer_ret, data + 6, data_size - 6) == 0);
-
- al_ring_buffer_peek(&buf, buffer_ret, 0, data_size);
- AL_TEST_TRUE(al_memcmp(buffer_ret, "abcabcabcabcabcabcabcabcabcaabc", data_size) == 0);
-
- al_ring_buffer_read(&buf, buffer_ret, (TEST_BUFFER_SIZE - 1) - 4);
-
- al_ring_buffer_peek(&buf, buffer_ret, 0, data_size);
- AL_TEST_TRUE(al_memcmp(buffer_ret, "aab", 3) == 0);
+ ptrdiff_t occupied = al_ring_buffer_occupied(&buf);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 3, data_size), occupied - 3, ptrdiff_t);
+ AL_TEST_TRUE(al_memcmp(output, data + 6, (size_t)(data_size - 6)) == 0);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 10, data_size), 0, size_t);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 3, data_size), 1, size_t);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 4, data_size), 0, size_t);
+ // Peek everything again.
+ al_ring_buffer_peek(&buf, output, 0, data_size);
+ AL_TEST_TRUE(al_memcmp(output, "DeFgHiJkLmNoPqRsTuVwXyZ12345aBc", (size_t)data_size) == 0);
- al_ring_buffer_peek(&buf, buffer_ret, 1, data_size);
- AL_TEST_TRUE(al_memcmp(buffer_ret, "abc", 3) == 0);
+ // Read up to the last 4 bytes.
+ al_ring_buffer_read(&buf, output, (BUFFER_SIZE - 1) - 4);
+ al_ring_buffer_peek(&buf, output, 0, data_size);
+ AL_TEST_TRUE(al_memcmp(output, "5aBc", 4) == 0);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 2, data_size), 2, size_t);
- AL_TEST_TRUE(al_memcmp(buffer_ret, "bc", 2) == 0);
+ // Test peek truncating the offset.
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 10, data_size), 0, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 3, data_size), 1, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 4, data_size), 0, ptrdiff_t);
- al_ring_buffer_read(&buf, buffer_ret, 1);
+ // Incrementally read the rest of the buffer.
+ al_ring_buffer_peek(&buf, output, 1, data_size);
+ AL_TEST_TRUE(al_memcmp(output, "aBc", 3) == 0);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 0, data_size), 3, size_t);
- AL_TEST_TRUE(al_memcmp(buffer_ret, "abc", 3) == 0);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 2, data_size), 2, ptrdiff_t);
+ AL_TEST_TRUE(al_memcmp(output, "Bc", 2) == 0);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 3, data_size), 0, size_t);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 4, data_size), 0, size_t);
+ al_ring_buffer_read(&buf, output, 1);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 0, data_size), 3, ptrdiff_t);
+ AL_TEST_TRUE(al_memcmp(output, "aBc", 3) == 0);
- AL_TEST_EQ(al_ring_buffer_read(&buf, buffer_ret, 4), 3, size_t);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 3, data_size), 0, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 4, data_size), 0, ptrdiff_t);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 0, data_size), 0, size_t);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 1, data_size), 0, size_t);
- AL_TEST_EQ(al_ring_buffer_peek(&buf, buffer_ret, 2, data_size), 0, size_t);
+ AL_TEST_EQ(al_ring_buffer_read(&buf, output, 4), 3, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 0, data_size), 0, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 1, data_size), 0, ptrdiff_t);
+ AL_TEST_EQ(al_ring_buffer_peek(&buf, output, 999, data_size), 0, ptrdiff_t);
AL_TEST_END();
}
diff --git a/tests/str.c b/tests/str.c
index 72ed81f..51b0bf1 100644
--- a/tests/str.c
+++ b/tests/str.c
@@ -2,30 +2,41 @@
#include <al/str.h>
#include <al/wstr.h>
+#include "str.h"
+#include "common.h"
+
static bool str_test_cmp(void)
{
AL_TEST_START("str_cmp");
- str *s0 = al_str_c("testtestasdf");
- str *s1 = al_str_c("testtestasdf");
- str *s2 = al_str_c("testtedfdfstasdf");
- str *s3 = al_str_c("dtesttedfdfstasdf");
+ str string0 = al_str_c("The Snake");
+ str string1 = al_str_c("The Rat");
+ str string2 = al_str_c("The Cat");
+ str string3 = al_str_c("The Dog");
+ str string4 = al_str_c("The Snake");
+
+ AL_TEST_FALSE(al_str_eq(&string0, &string1));
+ AL_TEST_FALSE(al_str_eq(&string0, &string2));
+ AL_TEST_FALSE(al_str_eq(&string0, &string3));
+ AL_TEST_FALSE(al_str_eq(&string2, &string3));
+ AL_TEST_TRUE(al_str_eq(&string3, &string3));
+ AL_TEST_TRUE(al_str_eq(&string4, &string0));
- AL_TEST_TRUE(al_str_eq(s0, s1));
- AL_TEST_FALSE(al_str_eq(s0, s2));
- AL_TEST_FALSE(al_str_eq(s0, s3));
- AL_TEST_FALSE(al_str_eq(s2, s3));
+ AL_TEST_EQ(al_str_cmp(&string0, &al_str_c("The "), 0, 4), 0, s32);
+ AL_TEST_EQ(al_str_cmp(&string0, &al_str_c(" S"), 3, 2), 0, s32);
+ // Sn[a]ke
+ AL_TEST_LT(al_str_cmp(&string0, &al_str_c("b"), 6, 1), 0, s32);
+ AL_TEST_GT(al_str_cmp(&string0, &al_str_cs(((char[]){ 'a' - 1 })), 6, 1), 0, s32);
- AL_TEST_EQ(al_str_cmp(s0, al_str_c("test"), 0, 4), 0, u32);
- AL_TEST_EQ(al_str_cmp(s0, al_str_c("tt"), 3, 2), 0, u32);
- AL_TEST_GT(al_str_cmp(s0, al_str_c("r"), 6, 1), 0, u32);
- AL_TEST_EQ(al_str_cmp(s0, al_str_c("ee"), 15, 2), -1, u32);
+ AL_TEST_EQ(al_str_cmp(&string0, &al_str_c("XX"), 15, 2), -1, s32);
+ AL_TEST_EQ(al_str_cmp(&al_str_c("YY"), &string2, string2.length, 1), -1, s32);
+ AL_TEST_EQ(al_str_cmp(&string2, &al_str_c("ZZ"), 0, string2.length), 1, s32);
- str *s4 = al_str_c("page");
- str *s5 = al_str_c("page.json");
+ str string5 = al_str_c("the_database");
+ str string6 = al_str_c("the_database.json");
- AL_TEST_FALSE(al_str_eq(s5, s4));
- AL_TEST_FALSE(al_str_eq(s4, s5));
+ AL_TEST_FALSE(al_str_eq(&string6, &string5));
+ AL_TEST_FALSE(al_str_eq(&string5, &string6));
AL_TEST_END();
}
@@ -34,18 +45,18 @@ static bool str_test_cat(void)
{
AL_TEST_START("str_cat");
- str *result = al_str_c("testtestasdf");
+ str result = al_str_c("hygshiylitf");
- str s0;
- al_str_from(&s0, "");
+ str string0;
+ al_str_from(&string0, "hyg");
- AL_TEST_EQ(s0.len, 0, u32);
+ AL_TEST_EQ(string0.length, 3, u32);
- al_str_cat(&s0, al_str_c("testtestasdf"));
+ al_str_cat(&string0, &al_str_c("shiylitf"));
- AL_TEST_TRUE(al_str_eq(result, &s0));
+ AL_TEST_TRUE(al_str_eq(&result, &string0));
- al_str_free(&s0);
+ al_str_free(&string0);
AL_TEST_END();
}
@@ -54,20 +65,18 @@ static bool str_test_insert(void)
{
AL_TEST_START("str_insert");
- str *insert_result = al_str_c("testtest[insert]asdf");
- str *prepend_result = al_str_c("[prepend]testtestasdf");
+ str insert_result = al_str_c("^_-^-^--__-^[insert]_-^--^___");
+ str prepend_result = al_str_c("[prepend]-^_^_^---^^-__");
str insert_str;
- str prepend_str;
-
- al_str_from(&insert_str, "testtestasdf");
- al_str_from(&prepend_str, "testtestasdf");
+ al_str_from(&insert_str, "^_-^-^--__-^_-^--^___");
+ al_str_insert(&insert_str, 12, &al_str_c("[insert]"));
+ AL_TEST_TRUE(al_str_eq(&insert_result, &insert_str));
- al_str_insert(&insert_str, 8, al_str_c("[insert]"));
- al_str_prepend(&prepend_str, al_str_c("[prepend]"));
-
- AL_TEST_TRUE(al_str_eq(insert_result, &insert_str));
- AL_TEST_TRUE(al_str_eq(prepend_result, &prepend_str));
+ str prepend_str;
+ al_str_from(&prepend_str, "-^_^_^---^^-__");
+ al_str_prepend(&prepend_str, &al_str_c("[prepend]"));
+ AL_TEST_TRUE(al_str_eq(&prepend_result, &prepend_str));
al_str_free(&insert_str);
al_str_free(&prepend_str);
@@ -79,12 +88,14 @@ static bool str_test_find_rfind(void)
{
AL_TEST_START("str_find_rfind");
- str *s0 = al_str_c("testtes\\ta\\sdf");
+ str string0 = al_str_c("wowowow\\$$\\wow");
- AL_TEST_EQ(al_str_find(s0, '\\'), 7, s32);
- AL_TEST_EQ(al_str_rfind(s0, '\\'), 10, s32);
+ AL_TEST_EQ(al_str_find(&string0, '\\'), 7, u32);
+ AL_TEST_EQ(al_str_rfind(&string0, '\\'), 10, u32);
+ AL_TEST_EQ(al_str_find(&string0, 'P'), al_str_npos, u32);
- AL_TEST_EQ(al_str_find_str(s0, al_str_c("tes\\")), 4, s32);
+ AL_TEST_EQ(al_str_find_str(&string0, &al_str_c("wow\\")), 4, u32);
+ AL_TEST_EQ(al_str_find_str(&string0, &al_str_c("John\\")), al_str_npos, u32);
AL_TEST_END();
}
@@ -93,25 +104,25 @@ static bool str_test_substr(void)
{
AL_TEST_START("str_substr");
- str *result0 = al_str_c("[cutout0]");
- str *result1 = al_str_c("[cutout1]");
+ str result0 = al_str_c("[cutout0]");
+ str result1 = al_str_c("[cutout1]");
str s;
- al_str_from(&s, "dfkdljfd[cutout0]dfd[cutout1]fd");
+ al_str_from(&s, "88888888[cutout0]999[cutout1]10");
- s32 start = al_str_find(&s, '[');
- s32 end = al_str_find(&s, ']') + 1;
+ u32 start = al_str_find(&s, '[');
+ u32 end = al_str_find(&s, ']') + 1;
- str *cutout0 = al_str_substr(&s, start, end);
- str *sub = al_str_substr(&s, end, s.len);
+ str cutout0 = al_str_substr(&s, start, end);
+ str sub = al_str_substr(&s, end, s.length);
- start = al_str_find(sub, '[');
- end = al_str_find(sub, ']') + 1;
+ start = al_str_find(&sub, '[');
+ end = al_str_find(&sub, ']') + 1;
- str *cutout1 = al_str_substr(sub, start, end);
+ str cutout1 = al_str_substr(&sub, start, end);
- AL_TEST_TRUE(al_str_eq(result0, cutout0));
- AL_TEST_TRUE(al_str_eq(result1, cutout1));
+ AL_TEST_TRUE(al_str_eq(&result0, &cutout0));
+ AL_TEST_TRUE(al_str_eq(&result1, &cutout1));
al_str_free(&s);
@@ -122,47 +133,38 @@ static bool str_test_get_line(void)
{
AL_TEST_START("str_get_line");
- 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 string0 = al_str_c("Yellow\nmellow\nhello,\nhello\n,\n");
+ str array0[] = { al_str_c("Yellow"), al_str_c("mellow"), al_str_c("hello,"), al_str_c("hello"), 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 string1 = al_str_c("Yellow\nmellow\nhello,\nhello\n,\n ");
+ str array1[] = { al_str_c("Yellow"), al_str_c("mellow"), al_str_c("hello,"), al_str_c("hello"), al_str_c(","), al_str_c(" ") };
- str *lines;
- str **lines_array;
- u32 lines_array_size;
+ str strings[] = { string0, string1 };
+ str *arrays[] = { array0, array1 };
+ u32 sizes[] = { ARRAY_SIZE(array0), ARRAY_SIZE(array1) };
- 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);
+ for (u32 i = 0; i < ARRAY_SIZE(strings); i++) {
+ u32 counter = 0;
+ str line = al_str_null();
+ for (; al_str_get_line(&strings[i], '\n', &line); ) {
+ AL_TEST_LT(counter, sizes[i], u32);
+ AL_TEST_TRUE(al_str_eq(&line, &arrays[i][counter++]));
}
- str line = al_str_zero();
- u32 c = 0;
+ AL_TEST_EQ(counter, sizes[i], u32);
- 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++]));
+ counter = 0;
+ line = al_str_null();
+ // One empty line.
+ for (; al_str_get_line(&al_str_c("\n"), '\n', &line); ) {
+ AL_TEST_LT(counter, 1, u32);
+ AL_TEST_EQ(line.length, 0, u32);
+ counter++;
}
- 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++;
- }
+ // No lines.
+ line = al_str_null();
+ AL_TEST_FALSE(al_str_get_line(&al_str_c(""), '\n', &line));
}
AL_TEST_END();
@@ -172,54 +174,155 @@ static bool str_test_to_long(void)
{
AL_TEST_START("str_to_long");
- str *s0 = al_str_c("10353");
- str *s1 = al_str_c("-3563");
- str *s2 = al_str_c("-2147483647"); // 1 away
- // This fails on MSVC for some reason.
- str *s2_1 = al_str_c("-2147483648"); // min
- str *s2_2 = al_str_c("-2147483649"); // underflow
- str *s3 = al_str_c("0xfff");
- str *s4 = al_str_c("0b01010");
- str *s5 = al_str_c("01010");
- str *s6 = al_str_c("99999999999999999999");
- str *s7 = al_str_c(" -99999999999999999999");
- str *s8 = al_str_c("---99999999999999999999");
- str *s9 = al_str_c("'p[afd'dfdfs[f");
- str *s10 = al_str_c("\n\t 01010");
- str *s11 = al_str_c("-9223372036854775809");
- str *s12 = al_str_c("6519749124957310923");
- str *s13 = al_str_c("-3519311901742109472");
+ str string0 = al_str_c("1738");
+ str string1 = al_str_c("-3563");
+ str string2 = al_str_c("-2147483647"); // 1 away (32 bit)
+ str string2_1 = al_str_c("-2147483648"); // min (32 bit)
+ str string2_2 = al_str_c("-2147483649"); // underflow (32 bit)
+ str string2_3 = al_str_c("9223372036854775807"); // int64_max
+ str string2_4 = al_str_c("9223372036854775806");
+ str string2_5 = al_str_c("9223372036854775808"); // overflow
+ str string2_6 = al_str_c("0x7fffffffffffffff"); // int64_max
+ str string2_7 = al_str_c("0x8000000000000000"); // overflow
+ str string2_8 = al_str_c("-0x8000000000000000"); // int64_min
+ str string2_9 = al_str_c("0b111111111111111111111111111111111111111111111111111111111111111"); // int64_max
+ str string2_10 = al_str_c("0b1000000000000000000000000000000000000000000000000000000000000000"); // overflow
+ str string2_11 = al_str_c("-0b1000000000000000000000000000000000000000000000000000000000000000"); // int64_min
+ str string3 = al_str_c("0xfff");
+ str string4 = al_str_c("0b01010");
+ str string5 = al_str_c("01010");
+ str string6 = al_str_c("9999999999999999999999999999999999");
+ str string7 = al_str_c(" -99999999999999999999");
+ str string8 = al_str_c("---99999999999999999999");
+ str string9 = al_str_c("'p[afd'dfdfs[f");
+ str string10 = al_str_c("\n\t 01010");
+ str string11 = al_str_c("-9223372036854775809");
+ str string12 = al_str_c("6519749124957310923");
+ str string13 = al_str_c("-3519311901742109472");
+ str string14 = al_str_c("18446744073709551614");
+ str string15 = al_str_c("-18446744073709551616");
+
+ bool error;
+
+ AL_TEST_EQ(al_str_to_long(&string0, 10, &error), 1738LL, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string1, 10, &error), -3563LL, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2, 10, &error), -2147483647LL, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2_1, 10, &error), -2147483648LL, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2_2, 10, &error), -2147483649LL, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2_3, 10, &error), INT64_MAX, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2_4, 10, &error), INT64_MAX - 1, s64);
+ AL_TEST_FALSE(error);
+
+ al_str_to_long(&string2_5, 10, &error);
+ AL_TEST_TRUE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2_6, 16, &error), INT64_MAX, s64);
+ AL_TEST_FALSE(error);
+
+ al_str_to_long(&string2_7, 16, &error);
+ AL_TEST_TRUE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2_8, 16, &error), INT64_MIN, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2_9, 2, &error), INT64_MAX, s64);
+ AL_TEST_FALSE(error);
+
+ al_str_to_long(&string2_10, 2, &error);
+ AL_TEST_TRUE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string2_11, 2, &error), INT64_MIN, s64);
+ AL_TEST_FALSE(error);
- AL_TEST_EQ(al_str_to_long(s0, 10), 10353L, s64);
- AL_TEST_EQ(al_str_to_long(s1, 10), -3563L, s64);
- AL_TEST_EQ(al_str_to_long(s2, 10), -2147483647L, s64);
- AL_TEST_EQ(al_str_to_long(s2_1, 10), -2147483648L, s64);
- AL_TEST_EQ(al_str_to_long(s2_2, 10), -2147483649L, s64);
- AL_TEST_EQ(al_str_to_long(s3, 16), 0xfff, s64);
- AL_TEST_EQ(al_str_to_long(s4, 2), 0b01010, s64);
- AL_TEST_EQ(al_str_to_long(s5, 2), 0b01010, s64);
- AL_TEST_EQ(al_str_to_long(s6, 10), INT64_MAX, s64);
- AL_TEST_EQ(al_str_to_long(s7, 10), INT64_MIN, s64);
- AL_TEST_EQ(al_str_to_long(s8, 10), INT64_MIN, s64);
- AL_TEST_EQ(al_str_to_long(s9, 10), INT64_MAX, s64);
- AL_TEST_EQ(al_str_to_long(s10, 2), 0b01010, s64);
- AL_TEST_EQ(al_str_to_long(s11, 10), INT64_MIN, s64);
- AL_TEST_EQ(al_str_to_long(s12, 10), 6519749124957310923L, s64);
- AL_TEST_EQ(al_str_to_long(s13, 10), -3519311901742109472, s64);
+ AL_TEST_EQ(al_str_to_long(&string3, 16, &error), 0xfff, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string4, 2, &error), 0b01010, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string5, 2, &error), 0b01010, s64);
+ AL_TEST_FALSE(error);
+
+ al_str_to_long(&string6, 10, &error);
+ AL_TEST_TRUE(error);
+
+ al_str_to_long(&string7, 10, &error);
+ AL_TEST_TRUE(error);
+
+ al_str_to_long(&string8, 10, &error);
+ AL_TEST_TRUE(error);
+
+ al_str_to_long(&string9, 10, &error);
+ AL_TEST_TRUE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string10, 2, &error), 0b01010, s64);
+ AL_TEST_FALSE(error);
+
+ al_str_to_long(&string11, 10, &error);
+ AL_TEST_TRUE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string12, 10, &error), 6519749124957310923LL, s64);
+ AL_TEST_FALSE(error);
+
+ AL_TEST_EQ(al_str_to_long(&string13, 10, &error), -3519311901742109472, s64);
+ AL_TEST_FALSE(error);
+
+ al_str_to_long(&string14, 10, &error);
+ AL_TEST_TRUE(error);
+
+ al_str_to_long(&string15, 10, &error);
+ AL_TEST_TRUE(error);
AL_TEST_END();
}
-static str *global __attribute__((unused)) = al_str_c("yeeee");
+// Very non-exhaustive.
+static bool str_test_limits(void)
+{
+ AL_TEST_START("str_limits");
+
+ str s = al_str_null();
+
+ for (u32 i = 0; i < MAX_ALLOC_32 - 1; i++) {
+ al_str_cat(&s, &al_str_c("y"));
+ }
+ al_str_cat(&s, &al_str_c("x"));
+
+ AL_TEST_TRUE(al_str_atr(&s, 1) == 'x');
+ AL_TEST_TRUE(al_str_at(&s, MAX_ALLOC_32 - 1) == 'x');
+ AL_TEST_TRUE(al_str_atr(&s, 2) == 'y');
+
+ AL_TEST_END();
+}
+
+#ifndef _MSC_VER
+static str global_string = al_str_c("yeeee");
+#endif
static bool str_test_error_prone_str_c(void)
{
AL_TEST_START("str_error_prone_str_c");
- str *n = al_str_c("yoyoyoyoyo");
- AL_TEST_EQ(n->len, al_strlen("yoyoyoyoyo"), u32);
- AL_TEST_EQ(n->alloc, 0, u32);
- AL_TEST_EQ(al_memcmp(n->data, "yoyoyoyoyo", al_strlen("yoyoyoyoyo") + 1), 0, u32);
+ str n = al_str_c("yoyoyoyoyo");
+ AL_TEST_EQ(n.length, al_strlen("yoyoyoyoyo"), u32);
+ AL_TEST_EQ(n.alloc, 0, u32);
+ AL_TEST_EQ(al_memcmp(n.data, "yoyoyoyoyo", al_strlen("yoyoyoyoyo") + 1), 0, s32);
+
+#ifndef _MSC_VER
+ AL_TEST_TRUE(al_str_eq(&global_string, &al_str_c("yeeee")));
+#endif
// This is expected to cause a compile error.
#if 0
@@ -229,8 +332,8 @@ static bool str_test_error_prone_str_c(void)
str ds = *al_str_c(d);
str ss = *al_str_cr(d);
- AL_TEST_EQ(ds.len, (u32)(sizeof(char *) - 1), u32);
- AL_TEST_EQ(ss.len, (u32)al_strlen(s), u32);
+ AL_TEST_EQ(ds.length, (u32)(sizeof(char *) - 1), u32);
+ AL_TEST_EQ(ss.length, (u32)al_strlen(s), u32);
al_free(d);
@@ -240,8 +343,8 @@ static bool str_test_error_prone_str_c(void)
wstr wds = *al_wstr_c(wd);
wstr wss = *al_wstr_cr(wd);
- AL_TEST_EQ(wds.len, (u32)((sizeof(wchar_t *) / sizeof(wchar_t)) - 1), u32);
- AL_TEST_EQ(wss.len, (u32)wcslen(ws), u32);
+ AL_TEST_EQ(wds.length, (u32)((sizeof(wchar_t *) / sizeof(wchar_t)) - 1), u32);
+ AL_TEST_EQ(wss.length, (u32)wcslen(ws), u32);
al_free(wd);
#endif
@@ -249,7 +352,7 @@ static bool str_test_error_prone_str_c(void)
AL_TEST_END();
}
-bool str_tests_run(void)
+bool str_tests_run(u32 skip_mask)
{
AL_TEST_START_GROUP("str");
@@ -260,6 +363,9 @@ bool str_tests_run(void)
AL_TEST_RUN(str_test_substr);
AL_TEST_RUN(str_test_get_line);
AL_TEST_RUN(str_test_to_long);
+ if (skip_mask & AL_TESTS_RUN_LIMITS) {
+ AL_TEST_RUN(str_test_limits);
+ }
AL_TEST_RUN(str_test_error_prone_str_c);
AL_TEST_END_GROUP();
diff --git a/tests/str.h b/tests/str.h
index 64eb0fa..044f8f6 100644
--- a/tests/str.h
+++ b/tests/str.h
@@ -3,6 +3,6 @@
#include <al/types.h>
-bool str_tests_run(void);
+bool str_tests_run(u32 skip_mask);
#endif // _AL_STR_TESTS_H