diff options
author | bonmas14 <bonmas14@gmail.com> | 2025-08-02 23:20:37 +0000 |
---|---|---|
committer | bonmas14 <bonmas14@gmail.com> | 2025-08-02 23:20:37 +0000 |
commit | 1cf89852f951b59b89f2a8bd7b54a0b0b74d439c (patch) | |
tree | 884af08903beba5f0e1e8435df4a1c7015270487 /src | |
download | ungrateful-1cf89852f951b59b89f2a8bd7b54a0b0b74d439c.tar.gz ungrateful-1cf89852f951b59b89f2a8bd7b54a0b0b74d439c.zip |
memory manipulation, strings, allocators list and logger.
Diffstat (limited to 'src')
-rw-r--r-- | src/un_list.c | 83 | ||||
-rw-r--r-- | src/un_log.c | 71 | ||||
-rw-r--r-- | src/un_memory.c | 229 | ||||
-rw-r--r-- | src/un_strings.c | 381 | ||||
-rw-r--r-- | src/ungrateful.c | 6 | ||||
-rw-r--r-- | src/ungrateful.h | 202 |
6 files changed, 972 insertions, 0 deletions
diff --git a/src/un_list.c b/src/un_list.c new file mode 100644 index 0000000..a670de0 --- /dev/null +++ b/src/un_list.c @@ -0,0 +1,83 @@ +List un_list_create(u64 start_capacity, u64 element_size, Allocator alloc) { + List list; + + list.count = 0; + list.capacity = start_capacity; + list.element_size = element_size; + list.alloc = alloc; + + list.data = un_memory_alloc(list.capacity * list.element_size, alloc); + + assert(list.data != NULL); + return list; +} + +void un_list_destroy(List *list) { + un_memory_destroy(&list->alloc); + UN_CLEAR(*list); +} + +List un_list_clone(List *list, Allocator alloc) { + List result; + + result = *list; + result.alloc = alloc; + result.data = un_memory_alloc(result.capacity * result.element_size, alloc); + assert(result.data != NULL); + + un_memory_copy(result.data, list->data, result.count * result.element_size); + + return result; +} + +static b32 list_grow_if_needed(List *list) { + if ((list->count + 1) <= list->capacity) { + return true; + } else { + void *mem = un_memory_realloc(list->data, list->element_size * list->capacity * 2, list->alloc); + + if (!mem) { + return false; + } + + list->data = mem; + list->capacity *= 2; + } + + return true; +} + +void un_list_append(List *list, void *data) { + void *addr; + + if (list_grow_if_needed(list)) { + addr = (u8*)list->data + list->count * list->element_size; + un_memory_copy(addr, data, list->element_size); + list->count++; + } else { + un_log_write_cstring(UN_LOG_ERROR, UN_CSTR "Failed to grow list"); + } +} + +void *un_list_get(List *list, u64 index) { + if (index >= list->count) return NULL; + + return (u8*)list->data + index * list->element_size; +} + +void un_list_remove(List *list, u64 index) { + void *addr; + u64 move_elements; + + if (index >= list->count) return; + + addr = (u8*)list->data + index * list->element_size; + + move_elements = list->count - (index + 1); + + if (move_elements) { + un_memory_move(addr, (u8*)addr + list->element_size, move_elements * list->element_size); + } + + list->count--; +} diff --git a/src/un_log.c b/src/un_log.c new file mode 100644 index 0000000..ef5bb02 --- /dev/null +++ b/src/un_log.c @@ -0,0 +1,71 @@ +#include <stdio.h> + +Log_Level un_current_log_level = UN_LOG_INFO; + +u8 log_buffer[UN_KB(4)]; + +void un_log_write_internal(Log_Level level, String format, va_list vaptr) { + if (level < un_current_log_level) return; + + switch (level) { + case UN_LOG_TRACE: + fprintf(stderr, "[TRACE] "); + break; + case UN_LOG_DEBUG: + fprintf(stderr, "[DEBUG] "); + break; + case UN_LOG_INFO: + fprintf(stderr, "[INFO] "); + break; + case UN_LOG_WARNING: + fprintf(stderr, "[WARNING] "); + break; + case UN_LOG_ERROR: + fprintf(stderr, "[ERROR] "); + break; + case UN_LOG_FATAL: + fprintf(stderr, "[FATAL] "); + break; + default: + break; + } + + sprintf(CSTR log_buffer, "%.*s", (int)format.size, format.data); + vfprintf(stderr, CSTR log_buffer, vaptr); + + switch (level) { + case UN_LOG_RAW: + break; + case UN_LOG_FATAL: + fprintf(stderr, "\n"); + assert(false); + break; + default: + fprintf(stderr, "\n"); + break; + } +} + +extern void un_log_write_cstring(Log_Level level, u8 *format, ...) { + va_list vaptr; + String temp; + + if (level < un_current_log_level) return; + + temp.size = un_string_get_length(format); + temp.data = format; + + va_start(vaptr, format); + un_log_write_internal(level, temp, vaptr); + va_end(vaptr); +} + +void un_log_write(Log_Level level, String format, ...) { + va_list vaptr; + + if (level < un_current_log_level) return; + + va_start(vaptr, format); + un_log_write_internal(level, format, vaptr); + va_end(vaptr); +} diff --git a/src/un_memory.c b/src/un_memory.c new file mode 100644 index 0000000..9ff316b --- /dev/null +++ b/src/un_memory.c @@ -0,0 +1,229 @@ +#include <stdlib.h> + +/// -------- Basic functions + +void un_memory_set(u8 *buffer, u8 value, u64 size) { + if (size == 0) return; + assert(buffer != NULL); + + while (size-- > 0) { + *buffer++ = value; + } +} + +void un_memory_copy(u8 *dest, u8 *source, u64 size) { + if (size == 0) return; + + assert(dest != NULL); + assert(source != NULL); + +#ifdef DEBUG + + if (dest < source) { + assert(((ptrdiff_t)source - (ptrdiff_t)dest) >= (ptrdiff_t)size); + } else { + assert(((ptrdiff_t)dest - (ptrdiff_t)source) >= (ptrdiff_t)size); + } +#endif // DEBUG + + while (size-- > 0) { + *dest++ = *source++; + } +} + +s32 un_memory_compare(u8 *left, u8 *right, u64 size) { + while (size-- > 0) { + if (*left++ == *right++) + continue; + + return left[-1] > right[-1] ? 1 : -1; + } + + return 0; +} + +void un_memory_move(u8 *dest, u8 *src, u64 size) { + Allocator talloc = un_allocator_get_temporary(); + + void *temp = un_memory_alloc(size, talloc); + + un_memory_copy(temp, src, size); + un_memory_copy(dest, temp, size); +} + +void *un_memory_alloc(u64 size, Allocator alloc) { + assert(alloc.proc != NULL); + return alloc.proc(NULL, size, UN_ALLOC_MSG_ALLOCATE, alloc.data); +} + +void *un_memory_realloc(void *ptr, u64 size, Allocator alloc) { + assert(alloc.proc != NULL); + return alloc.proc(ptr, size, UN_ALLOC_MSG_REALLOCATE, alloc.data); +} + +void *un_memory_free(void *ptr, Allocator alloc) { + assert(alloc.proc != NULL); + return alloc.proc(ptr, 0, UN_ALLOC_MSG_FREE, alloc.data); +} + +void un_memory_destroy(Allocator *alloc) { + assert(alloc != NULL); + assert(alloc->proc != NULL); + + alloc->proc(NULL, 0, UN_ALLOC_MSG_SELF_DELETE, alloc->data); + + UN_CLEAR(*alloc); +} + +/// -------- Stdlib allocator + +static ALLOCATOR_PROC_SIGNATURE(un_std_alloc_proc) { + UNUSED(data); + + switch (message) { + case UN_ALLOC_MSG_ALLOCATE: + return calloc(1, size); + case UN_ALLOC_MSG_REALLOCATE: + return realloc(p, size); + case UN_ALLOC_MSG_FREE: + free(p); + break; + case UN_ALLOC_MSG_SELF_DELETE: break; + } + + return NULL; +} + +Allocator un_allocator_get_standard(void) { + return CLITERAL(Allocator) { .proc = un_std_alloc_proc }; +} + +/// -------- Temp allocator + +static struct { + u64 index; + u8 data[UN_TEMP_SIZE]; +} temp; + +static void temp_reset(void) { + temp.index = 0; +} + +static void *temp_alloc(u64 size) { + if ((temp.index + size) > UN_TEMP_SIZE) { + un_log_write_cstring(UN_LOG_ERROR, UN_CSTR "Temp allocator wrapped!"); + temp_reset(); + } + + if ((temp.index + size) > UN_TEMP_SIZE) { + un_log_write_cstring(UN_LOG_ERROR, UN_CSTR "Too much space requested!"); + return NULL; + } + + void *ptr = (u8*)temp.data + temp.index; + temp.index += size; + un_memory_set(ptr, 0x00, size); + + return ptr; +} + +static ALLOCATOR_PROC_SIGNATURE(un_temp_alloc_proc) { + UNUSED(data); + UNUSED(p); + + switch (message) { + case UN_ALLOC_MSG_ALLOCATE: + return temp_alloc(size); + case UN_ALLOC_MSG_REALLOCATE: + case UN_ALLOC_MSG_FREE: + break; + case UN_ALLOC_MSG_SELF_DELETE: break; + } + + return NULL; +} + +Allocator un_allocator_get_temporary(void) { + return CLITERAL(Allocator) { .proc = un_temp_alloc_proc }; +} + +/// Arena allocator + +typedef struct Arena { + u64 size; + u64 occupied; + struct Arena *next; + u8 data[1]; +} Arena; + +static Arena *arena_create(u64 size) { + Allocator alloc; + Arena *arena; + + alloc = un_allocator_get_standard(); + arena = CLITERAL(Arena*)un_memory_alloc(size, alloc); + + if (!arena) { + un_log_write_cstring(UN_LOG_FATAL, UN_CSTR "Buy mem, failed to create arena!"); + return NULL; + } + + UN_CLEAR(*arena); + arena->size = size - sizeof(Arena); + return arena; +} + +static void arena_delete(Arena *arena) { + if (arena->next != NULL) { + arena_delete(arena->next); + } + + Allocator alloc = un_allocator_get_standard(); + un_memory_free(arena, alloc); +} + +static void *arena_allocate(u64 size, Arena *arena) { + u8* pos; + + if (size <= (arena->size - arena->occupied)) { + pos = arena->data + arena->occupied; + arena->occupied += size; + return (void*)pos; + } + + if (!arena->next) { + arena->next = arena_create((arena->size + sizeof(Arena)) * 2LL); + } + + return arena_allocate(size, arena->next); +} + +static ALLOCATOR_PROC_SIGNATURE(un_arena_alloc_proc) { + assert(data != NULL); + UNUSED(p); + + switch (message) { + case UN_ALLOC_MSG_ALLOCATE: + return arena_allocate(size, (Arena*)data); + case UN_ALLOC_MSG_REALLOCATE: + un_log_write_cstring(UN_LOG_ERROR, UN_CSTR "Arena doesn't reallocate."); + break; + case UN_ALLOC_MSG_FREE: + un_log_write_cstring(UN_LOG_ERROR, UN_CSTR "Arena doesn't free it's memory, please destroy arena itself."); + break; + case UN_ALLOC_MSG_SELF_DELETE: + arena_delete((Arena*)data); + break; + } + + return NULL; +} + +Allocator un_allocator_create_arena(u64 size) { + Allocator alloc = { 0 }; + + alloc.proc = un_arena_alloc_proc; + alloc.data = arena_create(size); + + return alloc; +} diff --git a/src/un_strings.c b/src/un_strings.c new file mode 100644 index 0000000..1499726 --- /dev/null +++ b/src/un_strings.c @@ -0,0 +1,381 @@ +u64 un_string_get_length(u8 *cstring) { + u8* start = cstring; + + while (*start != '\0') { + start++; + } + + return start - cstring; +} + +String un_string_from_cstring(u8* cstring) { + String result; + u64 length = un_string_get_length(cstring); + assert(length < LLONG_MAX); + result.size = length; + result.data = cstring; + return result; +} + +u8* un_string_to_cstring(String string, Allocator alloc) { + u8 *mem; + + assert(string.size > 0); + + mem = (u8*)un_memory_alloc(string.size + 1, alloc); + un_memory_copy(mem, string.data, (u64)string.size); + + return mem; +} + +String un_string_copy(String source, Allocator alloc) { + u8 *mem; + String result; + + assert(source.size >= 0); + + mem = (u8*)un_memory_alloc(source.size, alloc); + un_memory_copy(mem, source.data, (u64)source.size); + + result.size = source.size; + result.data = mem; + + return result; +} + +s32 un_string_compare(String left, String right) { + s32 result; + + if (left.size == right.size && left.size == 0) return 0; + if (left.size == 0) return -1; + if (right.size == 0) return 1; + + result = un_memory_compare(left.data, right.data, left.size); + + if (result == 0) { + if (left.size > right.size) return 1; + if (left.size < right.size) return -1; + return 0; + } else { + return result; + } +} + +String un_string_concat(String left, String right, Allocator alloc) { + String result = { 0 }; + + assert(left.size >= 0 && right.size >= 0); + + if (left.size == right.size && left.size == 0) { + return result; + } + + u8* data = (u8*)un_memory_alloc(left.size + right.size, alloc); + + if (left.size > 0) { + assert(left.data != NULL); + un_memory_copy(data, left.data, left.size); + } + + if (right.size > 0) { + assert(right.data != NULL); + un_memory_copy((data + left.size), right.data, right.size); + } + + result.size = left.size + right.size; + result.data = data; + + return result; +} + +String un_string_swap(String input, u8 from, u8 to, Allocator alloc) { + s64 i; + String output; + + output = un_string_copy(input, alloc); + + for (i = 0; i < input.size; i++) { + if (output.data[i] != from) + continue; + + output.data[i] = to; + } + + return output; +} + +List un_string_split(String input, String pattern, Allocator alloc) { + List splits; + String string; + s64 i, start; + u64 matches, size; + u8 *buffer; + + UN_CLEAR(splits); + + if (input.size <= pattern.size) { + return splits; + } + + if (pattern.size == 0) { + return splits; + } + + for (i = 0, matches = 1; i < (input.size - (pattern.size - 1)); i++) { + if (un_memory_compare(input.data + i, pattern.data, pattern.size) != 0) { + continue; + } + + matches++; + } + + splits = un_list_create(matches, sizeof(String), alloc); + + start = 0; + + for (i = 0; i < (input.size - (pattern.size - 1)); i++) { + if (un_memory_compare(input.data + i, pattern.data, pattern.size) != 0) { + continue; + } + + size = i - start; + + if (size == 0) { + start = i + pattern.size; + continue; + } + + buffer = (u8*)un_memory_alloc(size, alloc); + un_memory_copy(buffer, input.data + start, size); + string = CLITERAL(String) { .size = size, .data = buffer }; + un_list_append(&splits, &string); + start = i + pattern.size; + } + + if (start != input.size - pattern.size) { + if (un_memory_compare(input.data + start, pattern.data, pattern.size) == 0) { + return splits; + } + + size = input.size - start; + if (size == 0) { + return splits; + } + + buffer = (u8*)un_memory_alloc(size, alloc); + un_memory_copy(buffer, input.data + start, size); + string = CLITERAL(String) { .size = size, .data = buffer }; + un_list_append(&splits, &string); + } + + return splits; +} + +String un_string_join(List string_list, String separator, Allocator alloc) { + String cont, temp; + u64 i; + Allocator talloc; + + UN_CLEAR(cont); + + talloc = un_allocator_get_temporary(); + + assert(string_list.element_size == sizeof(String)); + + + for (i = 0; i < string_list.count; i++) { + temp = *(String *)un_list_get(&string_list, i); + + cont = un_string_concat(cont, temp, talloc); + + if (i != (string_list.count - 1)) { + cont = un_string_concat(cont, separator, talloc); + } + } + + return un_string_copy(cont, alloc); +} + +String un_string_substring(String input, s64 start, s64 max_size) { + String slice; + + assert(start >= 0); + assert(max_size > 0); + + slice.size = UN_MIN(max_size, (input.size - (s64)max_size)); + slice.data = input.data + start; + + + if (start > (input.size - max_size)) { + slice.size = UN_MIN(max_size, (input.size - (s64)max_size)); + } else { + slice.size = max_size; + } + + slice.data = input.data + start; + return slice; +} + +s64 un_string_index_of(String input, u8 value, u64 skip_count) { + s64 i; + + for (i = 0; i < input.size; i++) { + if (input.data[i] != value) { + continue; + } + + if (skip_count) { + skip_count--; + } else { + return i; + } + } + + return -1; +} +extern s64 un_string_index_of_last(String input, u8 value) { + s64 i, index; + + index = -1; + + for (i = 0; i < input.size; i++) { + if (input.data[i] == value) index = i; + } + + return index; +} + +static String format_u64(u64 value) { + String output; + u64 l, r, size; + u8 t; + u8 buffer[32]; + + size = 0; + + if (value == 0) { + return UN_STR("0"); + } + + while (value) { + buffer[size++] = '0' + (value % 10); + value /= 10; + } + + assert(size <= 20); + + for (l = 0, r = size - 1; l < r; l++, r--) { + t = buffer[l]; + buffer[l] = buffer[r]; + buffer[r] = t; + } + + output.size = size; + output.data = buffer; + return un_string_copy(output, un_allocator_get_temporary()); +} + +static String format_s64(s64 value) { + String output; + u64 l, r, size; + b32 negative; + u8 t; + u8 buffer[32]; + + size = 0; + + if (value == 0) { + return UN_STR("0"); + } + + negative = false; + + if (value < 0) { + value = -value; + negative = true; + } + + while (value) { + buffer[size++] = '0' + (value % 10); + value /= 10; + } + + if (negative) { + buffer[size++] = '-'; + } + + assert(size <= 20); + + for (l = 0, r = size - 1; l < r; l++, r--) { + t = buffer[l]; + buffer[l] = buffer[r]; + buffer[r] = t; + } + + output.size = size; + output.data = buffer; + return un_string_copy(output, un_allocator_get_temporary()); +} + +String un_string_format(Allocator alloc, String buffer, ...) { + va_list args; + String s; + List output; + s64 i, j; + + Allocator talloc = un_allocator_get_temporary(); + output = un_list_create(UN_KB(1), sizeof(u8), talloc); + + va_start(args, buffer); + + for (i = 0; i < buffer.size; i++) { + if (buffer.data[i] != '%') { + un_list_append(&output, buffer.data + i); + continue; + } + + switch (buffer.data[++i]) { + case '%': + { + un_list_append(&output, buffer.data + i); + } break; + case 'c': + { + u32 b = va_arg(args, u32); + un_list_append(&output, &b); + } break; + + case 'u': + { + s = format_u64(va_arg(args, u64)); + for (j = 0; j < s.size; j++) { + un_list_append(&output, s.data + j); + } + } break; + + case 'd': + { + s = format_s64(va_arg(args, u64)); + for (j = 0; j < s.size; j++) { + un_list_append(&output, s.data + j); + } + } break; + + case 's': + { + s = va_arg(args, String); + for (j = 0; j < s.size; j++) { + un_list_append(&output, s.data + j); + } + } break; + default: break; + } + } + + va_end(args); + + s.size = (s64)output.count; + s.data = output.data; + + return un_string_copy(s, alloc); +} diff --git a/src/ungrateful.c b/src/ungrateful.c new file mode 100644 index 0000000..1ceefd6 --- /dev/null +++ b/src/ungrateful.c @@ -0,0 +1,6 @@ +#include "ungrateful.h" + +#include "un_memory.c" +#include "un_strings.c" +#include "un_list.c" +#include "un_log.c" diff --git a/src/ungrateful.h b/src/ungrateful.h new file mode 100644 index 0000000..8d1e70e --- /dev/null +++ b/src/ungrateful.h @@ -0,0 +1,202 @@ +#if !defined(UNGRATEFUL_H) +# define UNGRATEFUL_H + +/* + Ungrateful - standard library for game development. + + LICENSE: + + Copyright (C) 2025 Bogdan Masyutin (bonmas14) + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Bogdan Masyutin - bonmas14@gmail.com +*/ + +#if defined(__clang__) || defined(__GNUC__) +# define CLANG_COMPILER +# define __TRAP() __builtin_trap() +#elif _MSC_VER >= 1939 +# define MSVC_COMPILER +# include <intrin.h> +# define __TRAP() __debugbreak() +#else +# error "Unknown compiler" +#endif + +#if defined(__cplusplus) +# define CLITERAL(type) type +#else +# define CLITERAL(type) (type) +#endif + +#if defined(_WIN32) +# define OS_WINDOWS +#elif defined(__linux__) +# define OS_LINUX +#else +# error "unknown platform!" +#endif + +#define UN_TEMP_SIZE UN_MB(50) + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdarg.h> +#include <limits.h> +#include <assert.h> + +#define UNUSED(x) (void)(x) + +#define UN_KB(s) ((u64)(s) * 1024LL) +#define UN_MB(s) (UN_KB(s) * 1024LL) +#define UN_GB(s) (UN_MB(s) * 1024LL) + +#define UN_MAX(a, b) (a) > (b) ? (a) : (b) +#define UN_MIN(a, b) (a) < (b) ? (a) : (b) + +#define UN_CSTR (u8*) +#define UN_STR(cstr) un_string_from_cstring(UN_CSTR cstr) +#define CSTR (char*) + +#define UN_CLEAR(var) un_memory_set((void*)&var, 0, sizeof(var)) + +#if defined(__cplusplus) +extern "C" { +#endif + + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; + +typedef int8_t b32; +typedef int8_t b8; + +typedef float f32; +typedef double f64; + +/* ---- Memory Allocators API ---- */ + +typedef enum { + UN_ALLOC_MSG_ALLOCATE, + UN_ALLOC_MSG_REALLOCATE, + UN_ALLOC_MSG_FREE, + UN_ALLOC_MSG_SELF_DELETE, +} Allocator_Message; + +#define ALLOCATOR_PROC_SIGNATURE(name)\ + void *name(void *p, u64 size, Allocator_Message message, void *data) + +typedef ALLOCATOR_PROC_SIGNATURE(Allocator_Proc); + +typedef struct { + Allocator_Proc *proc; + void *data; +} Allocator; + +// extern Allocator un_allocator_create_heap(s64 chunk_size); /* ... for large things */ +extern Allocator un_allocator_create_arena(u64 initial_size); /* Grouping allocator, that will recursively grow */ + +extern Allocator un_allocator_get_standard(void); +extern Allocator un_allocator_get_temporary(void); + +extern void *un_memory_alloc(u64 size, Allocator alloc); +extern void *un_memory_realloc(void *ptr, u64 size, Allocator alloc); +extern void *un_memory_free(void *ptr, Allocator alloc); +extern void un_memory_destroy(Allocator *alloc); + +extern void un_memory_set(u8 *dest, u8 value, u64 size); +extern void un_memory_copy(u8 *dest, u8 *src, u64 size); +extern void un_memory_move(u8 *dest, u8 *src, u64 size); +extern s32 un_memory_compare(u8 *left, u8 *right, u64 size); /* checks for every byte in arrays for condition: if left is bigger that right. */ + +/* ---- Generic list structure ---- */ + +typedef struct { + u64 count; + u64 capacity; + u64 element_size; + Allocator alloc; + void *data; +} List; + +extern List un_list_create(u64 start_capacity, u64 element_size, Allocator alloc); +extern void un_list_destroy(List *list); + +extern List un_list_clone(List *list, Allocator alloc); +extern void un_list_append(List *list, void *data); +extern void *un_list_get(List *list, u64 index); +extern void un_list_remove(List *list, u64 index); + +/* ---- no-wide string API ---- */ + +typedef struct { + s64 size; + u8 *data; +} String; + +extern u64 un_string_get_length(u8 *cstring); + +extern String un_string_from_cstring(u8* cstring); +extern u8* un_string_to_cstring(String string, Allocator alloc); + +extern String un_string_copy(String source, Allocator alloc); +extern s32 un_string_compare(String left, String right); +extern String un_string_concat(String left, String right, Allocator alloc); + +extern String un_string_swap(String input, u8 from, u8 to, Allocator alloc); +extern List un_string_split(String input, String pattern, Allocator alloc); +extern String un_string_join(List string_list, String separator, Allocator alloc); + +extern String un_string_substring(String input, s64 start, s64 max_size); + +extern s64 un_string_index_of(String input, u8 value, u64 skip_count); +extern s64 un_string_index_of_last(String input, u8 value); + +extern String un_string_format(Allocator alloc, String buffer, ...); +extern String un_string_tformat(String buffer, ...); + +/* ---- Logging API ---- */ + +typedef enum { + UN_LOG_TRACE, + UN_LOG_DEBUG, + UN_LOG_INFO, + UN_LOG_WARNING, + UN_LOG_ERROR, + UN_LOG_FATAL, + UN_LOG_RAW +} Log_Level; + +extern Log_Level un_current_log_level; + +extern void un_log_write(Log_Level level, String format, ...); +extern void un_log_write_cstring(Log_Level level, u8 *format, ...); + +#if defined(__cplusplus) +} +#endif + +#endif // UNGRATEFUL_H |