diff options
Diffstat (limited to 'archive/src/std')
-rw-r--r-- | archive/src/std/buf.h | 11 | ||||
-rw-r--r-- | archive/src/std/containers/container_utils.h | 17 | ||||
-rw-r--r-- | archive/src/std/containers/darray.h | 151 | ||||
-rw-r--r-- | archive/src/std/containers/graphs.h | 14 | ||||
-rw-r--r-- | archive/src/std/containers/hashmap.h | 27 | ||||
-rw-r--r-- | archive/src/std/containers/hashset.h | 29 | ||||
-rw-r--r-- | archive/src/std/containers/ring_queue.c | 68 | ||||
-rw-r--r-- | archive/src/std/containers/ring_queue.h | 35 | ||||
-rw-r--r-- | archive/src/std/containers/stack_array.h | 19 | ||||
-rw-r--r-- | archive/src/std/mem.c | 135 | ||||
-rw-r--r-- | archive/src/std/mem.h | 96 | ||||
-rw-r--r-- | archive/src/std/str.c | 74 | ||||
-rw-r--r-- | archive/src/std/str.h | 89 | ||||
-rw-r--r-- | archive/src/std/utils.h | 4 |
14 files changed, 769 insertions, 0 deletions
diff --git a/archive/src/std/buf.h b/archive/src/std/buf.h new file mode 100644 index 0000000..77fc7b9 --- /dev/null +++ b/archive/src/std/buf.h @@ -0,0 +1,11 @@ +/** + * @file buf.h + * @brief + */ +#pragma once +#include "defines.h" + +typedef struct bytebuffer { + u8* buf; + size_t size; +} bytebuffer; diff --git a/archive/src/std/containers/container_utils.h b/archive/src/std/containers/container_utils.h new file mode 100644 index 0000000..e1d164c --- /dev/null +++ b/archive/src/std/containers/container_utils.h @@ -0,0 +1,17 @@ +/** + * @file container_utils.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-06-19 + * + * @copyright Copyright (c) 2024 + * + */ + +#pragma once + +typedef struct generic_iterator { +} generic_iterator; + +typedef void* (*iterator_next_item)(void* iterator);
\ No newline at end of file diff --git a/archive/src/std/containers/darray.h b/archive/src/std/containers/darray.h new file mode 100644 index 0000000..080afb4 --- /dev/null +++ b/archive/src/std/containers/darray.h @@ -0,0 +1,151 @@ +/** + * @file darray.h + * @brief Typed dynamic array + * @copyright Copyright (c) 2023 + */ +// COPIED FROM KITC WITH SOME MINOR ADJUSTMENTS + +/* TODO: + - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a + new function?) +*/ + +#ifndef KITC_TYPED_ARRAY_H +#define KITC_TYPED_ARRAY_H + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define DARRAY_DEFAULT_CAPACITY 64 +#define DARRAY_RESIZE_FACTOR 3 + +/** @brief create a new darray type and functions with type `N` */ +#define typed_array(T) \ + struct { \ + /* @brief current number of items in the array */ \ + size_t len; \ + size_t capacity; \ + T* data; \ + } + +#define typed_array_iterator(T) \ + struct { \ + T##_darray* array; \ + size_t current_idx; \ + } + +#define PREFIX static + +#define KITC_DECL_TYPED_ARRAY(T) DECL_TYPED_ARRAY(T, T) + +#define DECL_TYPED_ARRAY(T, Type) \ + typedef typed_array(T) Type##_darray; \ + typedef typed_array_iterator(Type) Type##_darray_iter; \ + \ + /* Create a new one growable array */ \ + PREFIX Type##_darray* Type##_darray_new(size_t starting_capacity) { \ + Type##_darray* d; \ + T* data; \ + d = malloc(sizeof(Type##_darray)); \ + data = malloc(starting_capacity * sizeof(T)); \ + \ + d->len = 0; \ + d->capacity = starting_capacity; \ + d->data = data; \ + \ + return d; \ + } \ + \ + PREFIX void Type##_darray_free(Type##_darray* d) { \ + if (d != NULL) { \ + free(d->data); \ + free(d); \ + } \ + } \ + \ + PREFIX T* Type##_darray_resize(Type##_darray* d, size_t capacity) { \ + /* resize the internal data block */ \ + T* new_data = realloc(d->data, sizeof(T) * capacity); \ + /* TODO: handle OOM error */ \ + \ + d->capacity = capacity; \ + d->data = new_data; \ + return new_data; \ + } \ + \ + PREFIX void Type##_darray_push(Type##_darray* d, T value) { \ + if (d->len >= d->capacity) { \ + size_t new_capacity = \ + d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ + T* resized = Type##_darray_resize(d, new_capacity); \ + (void)resized; \ + } \ + \ + d->data[d->len] = value; \ + d->len += 1; \ + } \ + \ + PREFIX void Type##_darray_push_copy(Type##_darray* d, const T* value) { \ + if (d->len >= d->capacity) { \ + size_t new_capacity = \ + d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ + T* resized = Type##_darray_resize(d, new_capacity); \ + (void)resized; \ + } \ + \ + T* place = d->data + d->len; \ + d->len += 1; \ + memcpy(place, value, sizeof(T)); \ + } \ + \ + PREFIX void Type##_darray_pop(Type##_darray* d, T* dest) { \ + T* item = d->data + (d->len - 1); \ + d->len -= 1; \ + memcpy(dest, item, sizeof(T)); \ + } \ + \ + PREFIX void Type##_darray_ins(Type##_darray* d, const T* value, size_t index) { \ + /* check if requires resize */ \ + if (d->len + 1 > d->capacity) { \ + size_t new_capacity = \ + d->capacity > 0 ? d->capacity * DARRAY_RESIZE_FACTOR : DARRAY_DEFAULT_CAPACITY; \ + T* resized = Type##_darray_resize(d, new_capacity); \ + (void)resized; \ + } \ + \ + /* shift existing data after index */ \ + T* insert_dest = d->data + index; \ + T* shift_dest = insert_dest + 1; \ + \ + int num_items = d->len - index; \ + \ + d->len += 1; \ + memcpy(shift_dest, insert_dest, num_items * sizeof(T)); \ + memcpy(insert_dest, value, sizeof(T)); \ + } \ + \ + PREFIX void Type##_darray_clear(Type##_darray* d) { \ + d->len = 0; \ + memset(d->data, 0, d->capacity * sizeof(T)); \ + } \ + \ + PREFIX size_t Type##_darray_len(Type##_darray* d) { return d->len; } \ + \ + PREFIX Type##_darray_iter Type##_darray_iter_new(Type##_darray* d) { \ + Type##_darray_iter iterator; \ + iterator.array = d; \ + iterator.current_idx = 0; \ + return iterator; \ + } \ + \ + PREFIX void* Type##_darray_iter_next(Type##_darray_iter* iterator) { \ + if (iterator->current_idx < iterator->array->len) { \ + return &iterator->array->data[iterator->current_idx++]; \ + } else { \ + return NULL; \ + } \ + } + +#endif // KITC_TYPED_ARRAY_H diff --git a/archive/src/std/containers/graphs.h b/archive/src/std/containers/graphs.h new file mode 100644 index 0000000..5dbec97 --- /dev/null +++ b/archive/src/std/containers/graphs.h @@ -0,0 +1,14 @@ +/** + * @file graphs.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ + +// Adjacency list backed graphs + +// Matrix backed graphs (not as useful)
\ No newline at end of file diff --git a/archive/src/std/containers/hashmap.h b/archive/src/std/containers/hashmap.h new file mode 100644 index 0000000..95c1c6b --- /dev/null +++ b/archive/src/std/containers/hashmap.h @@ -0,0 +1,27 @@ +/** + * @file hashmap.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ + +typedef struct hashmap hashmap; + +/* +Example usage +------------- +init hashmap +insert (string, material) +get (string) -> material_opt or material* ? + +*/ + +void hashmap_init(hashmap* map); + +// ... + +void hashmap_free(hashmap* map);
\ No newline at end of file diff --git a/archive/src/std/containers/hashset.h b/archive/src/std/containers/hashset.h new file mode 100644 index 0000000..7f87213 --- /dev/null +++ b/archive/src/std/containers/hashset.h @@ -0,0 +1,29 @@ +/** + * @file hashset.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ + +#include "defines.h" + +typedef struct hashset hashset; + +/** @brief Describes a function that will take a pointer to a datatype (e.g. a u64 or a struct) + and return a hashed key. */ +typedef uint64_t (*hash_item)(void* item); + +void hashset_init(hashset* set, hash_item hash_func, size_t initial_capacity); +// TODO: void hashset_from_iterator(); +bool hashset_insert(hashset* set, void* item, uint64_t* out_key); +void hashset_batch_insert(hashset* set, void* items, u64 item_count); +bool hashset_contains(hashset* set, void* item); +bool hashset_remove_item(hashset* set, void* item); +bool hashset_remove_key(hashset* set, uint64_t key); +void hashset_merge(hashset* set_a, hashset* set_b); +hashset* hashset_merge_cloned(hashset* set_a, hashset* set_b); +void hashset_free(hashset* set);
\ No newline at end of file diff --git a/archive/src/std/containers/ring_queue.c b/archive/src/std/containers/ring_queue.c new file mode 100644 index 0000000..8bfc10b --- /dev/null +++ b/archive/src/std/containers/ring_queue.c @@ -0,0 +1,68 @@ +#include "ring_queue.h" + +#include <stdlib.h> +#include <string.h> +#include "defines.h" + +ring_queue* ring_queue_new(size_t type_size, size_t capacity, void* memory) { + ring_queue* q = malloc(sizeof(ring_queue)); + q->len = 0; + q->capacity = capacity; + q->type_size = type_size; + q->head = 0; + q->tail = -1; + + if (memory) { + // caller owns the memory + q->owns_memory = false; + q->data = memory; + } else { + // ring queue should own the memory + q->owns_memory = true; + q->data = malloc(capacity * type_size); + } + + return q; +} + +void ring_queue_free(ring_queue* queue) { + if (queue) { + if (queue->owns_memory) { + free(queue->data); + } + free(queue); + } +} + +bool ring_queue_enqueue(ring_queue* queue, const void* value) { + if (queue->len == queue->capacity) { + return false; + } + + queue->tail = (queue->tail + 1) % queue->capacity; + memcpy(queue->data + (queue->tail * queue->type_size), value, queue->type_size); + queue->len++; + return true; +} + +bool ring_queue_dequeue(ring_queue* queue, void* out_value) { + if (queue->len == 0) { + // queue is empty + return false; + } + + memcpy(out_value, queue->data + (queue->head * queue->type_size), queue->type_size); + queue->head = (queue->head + 1) % queue->capacity; + queue->len--; + return true; +} + +bool ring_queue_peek(const ring_queue* queue, void* out_value) { + if (queue->len == 0) { + // queue is empty + return false; + } + + memcpy(out_value, queue->data + (queue->head * queue->type_size), queue->type_size); + return true; +}
\ No newline at end of file diff --git a/archive/src/std/containers/ring_queue.h b/archive/src/std/containers/ring_queue.h new file mode 100644 index 0000000..15d5da4 --- /dev/null +++ b/archive/src/std/containers/ring_queue.h @@ -0,0 +1,35 @@ +/** + * @file ring_queue.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-02-24 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once +#include "defines.h" + +/** + * @brief a fixed-size ring queue + */ +typedef struct ring_queue { + size_t len; + size_t capacity; + size_t type_size; + void* data; + bool owns_memory; + int32_t head; + int32_t tail; +} ring_queue; + +ring_queue* ring_queue_new(size_t type_size, size_t capacity, void* memory_block); + +void ring_queue_free(ring_queue* queue); + +bool ring_queue_enqueue(ring_queue* queue, const void* value); + +bool ring_queue_dequeue(ring_queue* queue, void* out_value); + +bool ring_queue_peek(const ring_queue* queue, void* out_value);
\ No newline at end of file diff --git a/archive/src/std/containers/stack_array.h b/archive/src/std/containers/stack_array.h new file mode 100644 index 0000000..d2b6bdd --- /dev/null +++ b/archive/src/std/containers/stack_array.h @@ -0,0 +1,19 @@ +#pragma once +#include <stdbool.h> + +// Defines "_sarray" types + +#define TYPED_STACK_ARRAY(T, Name, Len) \ + typedef struct Name##_sarray { \ + T items[ Len ]; \ + size_t len; \ + } Name##_sarray; \ + Name##_sarray Name##_sarray_create() { \ + Name##_sarray arr = { .len = 0 }; \ + return arr; \ + } \ + bool Name##_sarray_push(Name##_sarray* arr, T item) { \ + if (arr->len == Len) { return false; }\ + arr->items[arr->len++] = item;\ + return true;\ + } diff --git a/archive/src/std/mem.c b/archive/src/std/mem.c new file mode 100644 index 0000000..1f9078b --- /dev/null +++ b/archive/src/std/mem.c @@ -0,0 +1,135 @@ +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "log.h" +#include "mem.h" + +#ifndef DEFAULT_ALIGNMENT +#define DEFAULT_ALIGNMENT (2 * sizeof(void*)) +#endif + +// --- Arena + +void* arena_alloc_align(arena* a, size_t size, size_t align) { + ptrdiff_t padding = -(uintptr_t)a->curr & (align - 1); + ptrdiff_t available = a->end - a->curr - padding; + // TRACE("Padding %td available %td", padding, available); + if (available < 0 || (ptrdiff_t)size > available) { + ERROR_EXIT("Arena ran out of memory\n"); + } + void* p = a->curr + padding; + a->curr += padding + size; + return memset(p, 0, size); +} +void* arena_alloc(arena* a, size_t size) { return arena_alloc_align(a, size, DEFAULT_ALIGNMENT); } + +arena arena_create(void* backing_buffer, size_t capacity) { + return (arena){ .begin = backing_buffer, + .curr = backing_buffer, + .end = backing_buffer + (ptrdiff_t)capacity }; +} + +void arena_free_all(arena* a) { + a->curr = a->begin; // pop everything at once and reset to the start. +} + +void arena_free_storage(arena* a) { free(a->begin); } + +arena_save arena_savepoint(arena* a) { + arena_save savept = { .arena = a, .savepoint = a->curr }; + return savept; +} + +void arena_rewind(arena_save savepoint) { savepoint.arena->curr = savepoint.savepoint; } + +// --- Pool + +void_pool void_pool_create(arena* a, const char* debug_label, u64 capacity, u64 entry_size) { + size_t memory_requirements = capacity * entry_size; + void* backing_buf = arena_alloc(a, memory_requirements); + + assert(entry_size >= sizeof(void_pool_header)); // TODO: create my own assert with error message + + void_pool pool = { .capacity = capacity, + .entry_size = entry_size, + .count = 0, + .backing_buffer = backing_buf, + .free_list_head = NULL, + .debug_label = debug_label }; + + void_pool_free_all(&pool); + + return pool; +} + +void void_pool_free_all(void_pool* pool) { + // set all entries to be free + for (u64 i = 0; i < pool->capacity; i++) { + void* ptr = &pool->backing_buffer[i * pool->entry_size]; + void_pool_header* free_node = + (void_pool_header*)ptr; // we reuse the actual entry itself to hold the header + if (i == (pool->capacity - 1)) { + // if the last one we make its next pointer NULL indicating its full + free_node->next = NULL; + } + free_node->next = pool->free_list_head; + // now the head points to this entry + pool->free_list_head = free_node; + } +} + +void* void_pool_get(void_pool* pool, u32 raw_handle) { + // An handle is an index into the array essentially + void* ptr = pool->backing_buffer + (raw_handle * pool->entry_size); + return ptr; +} + +void* void_pool_alloc(void_pool* pool, u32* out_raw_handle) { + // get the next free node + if (pool->count == pool->capacity) { + WARN("Pool is full!"); + return NULL; + } + if (pool->free_list_head == NULL) { + ERROR("%s Pool is full (head = null)", pool->debug_label); + return NULL; + } + void_pool_header* free_node = pool->free_list_head; + + // What index does this become? + uintptr_t start = (uintptr_t)pool->backing_buffer; + uintptr_t cur = (uintptr_t)free_node; + // TRACE("%ld %ld ", start, cur); + assert(cur > start); + u32 index = (u32)((cur - start) / pool->entry_size); + /* printf("Index %d\n", index); */ + if (out_raw_handle != NULL) { + *out_raw_handle = index; + } + + pool->free_list_head = free_node->next; + + memset(free_node, 0, pool->entry_size); + pool->count++; + return (void*)free_node; +} + +void void_pool_dealloc(void_pool* pool, u32 raw_handle) { + // push free node back onto the free list + void* ptr = void_pool_get(pool, raw_handle); + void_pool_header* freed_node = (void_pool_header*)ptr; + + freed_node->next = pool->free_list_head; + pool->free_list_head = freed_node; + + pool->count--; +} + +u32 void_pool_insert(void_pool* pool, void* item) { + u32 raw_handle; + void* item_dest = void_pool_alloc(pool, &raw_handle); + memcpy(item_dest, item, pool->entry_size); + return raw_handle; +} diff --git a/archive/src/std/mem.h b/archive/src/std/mem.h new file mode 100644 index 0000000..56c1230 --- /dev/null +++ b/archive/src/std/mem.h @@ -0,0 +1,96 @@ +/** + * @file mem.h + * @brief Allocators, memory tracking + * @version 0.1 + * @date 2024-02-24 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include <stddef.h> +#include "defines.h" + +typedef void* (*alloc_fn)(size_t size); +typedef void (*free_fn)(void* ptr); + +typedef struct allocator_t { + alloc_fn alloc; + free_fn free; +} allocator_t; + +// --- Arena + +// Inspired by https://nullprogram.com/blog/2023/09/27/ +typedef struct arena { + char* begin; + char* curr; + char* end; +} arena; + +typedef struct arena_save { + arena* arena; + char* savepoint; +} arena_save; + +arena arena_create(void* backing_buffer, size_t capacity); +void* arena_alloc(arena* a, size_t size); +void* arena_alloc_align(arena* a, size_t size, size_t align); +void arena_free_all(arena* a); +void arena_free_storage(arena* a); +arena_save arena_savepoint(arena* a); +void arena_rewind(arena_save savepoint); +// TODO: arena_resize + +// --- Pool + +typedef struct void_pool_header void_pool_header; +struct void_pool_header { + void_pool_header* next; +}; + +typedef struct void_pool { + u64 capacity; + u64 entry_size; + u64 count; + void* backing_buffer; + void_pool_header* free_list_head; + const char* debug_label; +} void_pool; + +void_pool void_pool_create(arena* a, const char* debug_label, u64 capacity, u64 entry_size); +void void_pool_free_all(void_pool* pool); +bool void_pool_is_empty(void_pool* pool); +bool void_pool_is_full(void_pool* pool); +void* void_pool_get(void_pool* pool, u32 raw_handle); +void* void_pool_alloc(void_pool* pool, u32* out_raw_handle); +void void_pool_dealloc(void_pool* pool, u32 raw_handle); +u32 void_pool_insert(void_pool* pool, void* item); +// TODO: fn to dealloc from the pointer that was handed out + +// TODO: macro that lets us specialise + +/* typedef struct Name##_handle Name##_handle; \ */ +#define TYPED_POOL(T, Name) \ + typedef struct Name##_pool { \ + void_pool inner; \ + } Name##_pool; \ + \ + static Name##_pool Name##_pool_create(arena* a, u64 cap, u64 entry_size) { \ + void_pool p = void_pool_create(a, "\"" #Name "\"", cap, entry_size); \ + return (Name##_pool){ .inner = p }; \ + } \ + static inline T* Name##_pool_get(Name##_pool* pool, Name##Handle handle) { \ + return (T*)void_pool_get(&pool->inner, handle.raw); \ + } \ + static inline T* Name##_pool_alloc(Name##_pool* pool, Name##Handle* out_handle) { \ + return (T*)void_pool_alloc(&pool->inner, &out_handle->raw); \ + } \ + static inline void Name##_pool_dealloc(Name##_pool* pool, Name##Handle handle) { \ + void_pool_dealloc(&pool->inner, handle.raw); \ + } \ + static Name##Handle Name##_pool_insert(Name##_pool* pool, T* item) { \ + u32 raw_handle = void_pool_insert(pool, item); \ + return (Name##Handle){ .raw = raw_handle }; \ + } diff --git a/archive/src/std/str.c b/archive/src/std/str.c new file mode 100644 index 0000000..89c76a0 --- /dev/null +++ b/archive/src/std/str.c @@ -0,0 +1,74 @@ +#include "str.h" +#include <assert.h> +#include <string.h> +#include "log.h" +#include "mem.h" + +Str8 Str8_create(u8* buf, size_t len) { return (Str8){ .buf = buf, .len = len }; } + +Str8 Str8_cstr_view(char* string) { return Str8_create((u8*)string, strlen(string)); } + +bool Str8_equals(Str8 a, Str8 b) { + if (a.len != b.len) { + return false; + } + + for (size_t i = 0; i < a.len; i++) { + if (a.buf[i] != b.buf[i]) { + return false; + } + } + return true; +} + +char* Str8_to_cstr(arena* a, Str8 s) { + bool is_null_terminated = s.buf[s.len - 1] == 0; + size_t n_bytes = is_null_terminated ? s.len : s.len + 1; + + u8* dest = arena_alloc(a, n_bytes); + + memcpy(dest, s.buf, s.len); + if (is_null_terminated) { + dest[s.len] = '\0'; + } + return (char*)dest; +} + +char* Clone_cstr(arena* a, const char* s) { + if (s == NULL) { + WARN("Tried to clone a NULL char*"); + return NULL; + } + Str8 st = Str8_cstr_view(s); + return Str8_to_cstr(a, st); +} + +Str8 Str8_concat(arena* a, Str8 left, Str8 right) { + size_t n_bytes = left.len + right.len + 1; + + u8* dest = arena_alloc(a, n_bytes); + memcpy(dest, left.buf, left.len); + memcpy(dest + right.len, right.buf, right.len); + + dest[n_bytes - 1] = '\0'; + + return Str8_create(dest, n_bytes); +} + +Str8 Str8_substr(Str8 s, u64 min, u64 max) { + assert(min >= 0); + assert(min < s.len); + assert(max >= 0); + assert(max <= s.len); + uint8_t* start = s.buf + (ptrdiff_t)min; + size_t new_len = max - min; + return (Str8){ .buf = start, .len = new_len }; +} + +Str8 Str8_take(Str8 s, u64 first_n) { return Str8_substr(s, 0, first_n); } + +Str8 Str8_drop(Str8 s, u64 last_n) { return Str8_substr(s, s.len - last_n, s.len); } + +Str8 Str8_skip(Str8 s, u64 n) { return Str8_substr(s, n, s.len); } + +Str8 Str8_chop(Str8 s, u64 n) { return Str8_substr(s, 0, s.len - n); } diff --git a/archive/src/std/str.h b/archive/src/std/str.h new file mode 100644 index 0000000..a29bf9a --- /dev/null +++ b/archive/src/std/str.h @@ -0,0 +1,89 @@ +/** + * @file str.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-02-25 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include <ctype.h> + +#include "defines.h" +#include "mem.h" + +/** + * @brief Fat pointer representing a UTF8 (TODO some APIs supporting utf8) encoded string + * @note when using `printf` you must use %s.*s length, string until our own modified + print routines are written. alternatively wrap in `cstr()` and pass to `%s`. + */ +typedef struct { + u8* buf; + size_t len; +} Str8; + +// --- Constructors + +/** @brief Take a string literal and turn it into a `str8` */ +#define str8(s) \ + (Str8) { (u8*)s, ((sizeof(s) / sizeof(*(s)) - 1)) } + +Str8 Str8_create(u8* buf, size_t len); + +// TODO: Str8_OntoArena(arena* a, Str8 s); + +/** @brief Return a null-terminated C string cloned onto an arena */ +char* Str8_to_cstr(arena* a, Str8 s); + +#define cstr(a, s) (Str8_to_cstr(a, s)) // Shorthand + +/** @brief Return a Str8 that references a statically allocated string. + `string` therefore must already be null-terminated. + @note The backing `string` cannot be modified. */ +Str8 Str8_cstr_view(char* string); + +char* Clone_cstr(arena* a, const char* s); + +// --- Comparisons + +/** @brief Compare two strings for exact equality */ +bool Str8_equals(Str8 a, Str8 b); + +/** + * @brief Compare the first `first_nchars` of each string for equality + * @details If either of the strings are shorter than the number only the characters up until the + end of the shorter string will be compared. + * @returns 0 if they are fully equal up until `first_nchars`, i.e they never differed, else it + returns the index at which the first string differed from the second string. +*/ +size_t Str8_nequals(Str8 a, Str8 b, size_t first_nchars); + +bool Str8_ends_with(Str8 input_str, Str8 suffix); + +/// --- Subviews + +Str8 Str8_substr(Str8 s, u64 min, u64 max); +/** @brief Keeps only the `first_n` chars of `s` */ +Str8 Str8_take(Str8 s, u64 first_n); +/** @brief Keeps only the `last_n` chars of `s` */ +Str8 Str8_drop(Str8 s, u64 last_n); +/** @brief Keeps everything after the first `n` chars of `s` */ +Str8 Str8_skip(Str8 s, u64 n); +/** @brief Keeps everything before the last `n` chars of `s` */ +Str8 Str8_chop(Str8 s, u64 n); + +Str8 Str8_concat(arena* a, Str8 left, Str8 right); + +/// --- Misc + +static inline bool Str8_is_null_term(Str8 a) { + return a.buf[a.len] == 0; // This doesn't seem safe. YOLO +} + +// TODO: move or delete this and replace with handling using our internal type +static void skip_space(char* p) { + while (isspace((unsigned char)*p)) ++p; +} diff --git a/archive/src/std/utils.h b/archive/src/std/utils.h new file mode 100644 index 0000000..c9827a3 --- /dev/null +++ b/archive/src/std/utils.h @@ -0,0 +1,4 @@ +#pragma once +#include <stdbool.h> + +const char* bool_str(bool input) { return input ? "True" : "False"; }
\ No newline at end of file |