jrk

my own c stdlib to keep myself sane
git clone git://git.jakekoroman.com/jrk
Log | Files | Refs

commit f8e38ad61126db546feffb16dce3fb4c7781ffba
parent 28dfbe162b48059c1b3ad99b0c56fb2d9100e8cf
Author: Jake Koroman <jake@jakekoroman.com>
Date:   Fri, 12 Sep 2025 10:06:11 -0400

overhaul of jrk_Arena.

Diffstat:
Mjrk.h | 336+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 242 insertions(+), 94 deletions(-)

diff --git a/jrk.h b/jrk.h @@ -34,15 +34,17 @@ typedef double f64; do { result = value; goto defer; } while(0) #define JRK_KILOBYTES(x) ((u64)x*1024) -#define JRK_MEGABYTES(x) (JRK_KILOBYTES((u64)x*1024)) -#define JRK_GIGABYTES(x) (JRK_MEGABYTES((u64)x*1024)) +#define JRK_MEGABYTES(x) ((u64)JRK_KILOBYTES((u64)x*1024)) +#define JRK_GIGABYTES(x) ((u64)JRK_MEGABYTES((u64)x*1024)) +#define JRK_TERABYTES(x) ((u64)JRK_GIGABYTES((u64)x*1024)) #define JRK_TMPSTRINGS_ARR_CAPACITY 4 #define JRK_TMPSTRINGS_STR_CAPACITY JRK_KILOBYTES(1) typedef struct { u8 *data; - u64 count; + u64 offset; + u64 prev_offset; u64 capacity; } jrk_Arena; @@ -60,8 +62,13 @@ typedef struct { void *jrk_ecalloc(u64, u64); void *jrk_erealloc(void*, u64); -jrk_Arena jrk_arena_create(u64); -void *jrk__arena_push(jrk_Arena*, u64); +jrk_Arena jrk_arena_create(u8*, u64); +void *jrk_arena_push(jrk_Arena*, u64); +void jrk_arena_reset(jrk_Arena*); +void *jrk_arena_resize(jrk_Arena*, void*, u64, u64); + +i32 jrk_arena_sb_appendf(jrk_Arena*, jrk_StringBuilder*, const char*, ...); +void jrk_arena_sb_append_buf_at(jrk_Arena*, jrk_StringBuilder*, char *, u64, u64); i32 jrk_rand_num(i32); i32 jrk_rand_num_range(i32, i32); @@ -102,10 +109,6 @@ char *jrk_tmpstrings_pushf(char *, ...); #define jrk_emalloc(n) jrk_ecalloc(1, n) -#define jrk_arena_destroy(arena) ((arena.data) ? free(arena.data) : (void) 0) -#define jrk_arena_push_array(arena, type, n) (type *) jrk__arena_push(arena, sizeof(type) * n) -#define jrk_arena_push_struct(arena, type) (type *) jrk__arena_push(arena, sizeof(type)) - #define jrk_sb_to_sv(sb) jrk_sv_from_parts((sb).items, (sb).count) #define JRK_DA_DEFAULT_INIT_CAPACITY 16 @@ -122,6 +125,35 @@ char *jrk_tmpstrings_pushf(char *, ...); } \ } while (0) +#define jrk_arena_da_reserve(arena, da, expected_capacity) \ + do { \ + if ((da)->capacity == 0) { \ + (da)->capacity = JRK_DA_DEFAULT_INIT_CAPACITY; \ + (da)->items = jrk_arena_push(arena, (da)->capacity); \ + break; \ + } \ + if ((expected_capacity) > (da)->capacity) { \ + u64 old_cap = (da)->capacity; \ + while ((expected_capacity) > (da)->capacity) { \ + (da)->capacity *= 2; \ + } \ + (da)->items = jrk_arena_resize((arena), (da)->items, old_cap, (da)->capacity); \ + } \ + } while (0) + +#define jrk_arena_da_append(arena, da, item) \ + do { \ + jrk_arena_da_reserve((arena), (da), (da)->count + 1); \ + (da)->items[(da)->count++] = (item); \ + } while (0) + +#define jrk_arena_da_append_many(arena, da, new_items, new_items_count) \ + do { \ + jrk_arena_da_reserve((arena), (da), (da)->count + (new_items_count)); \ + memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \ + (da)->count += (new_items_count); \ + } while (0) + #define jrk_da_append(da, item) \ do { \ jrk_da_reserve((da), (da)->count + 1); \ @@ -151,79 +183,102 @@ char *jrk_tmpstrings_pushf(char *, ...); #define jrk_da_foreach(type,it,da) for (type *it = (da)->items; it < (da)->items + (da)->count; ++it) -#define jrk_sb_append_null(sb) jrk_da_append(sb, '\0') -#define jrk_sb_free(sb) jrk_da_free(sb) +#define jrk_sb_append_null(sb) jrk_da_append((sb), '\0') +#define jrk_sb_free(sb) jrk_da_free((sb)) + +#define jrk_arena_sb_append_null(arena, sb) jrk_arena_da_append((arena), (sb), '\0') + +#define jrk_arena_sb_append_cstr(arena, sb, cstr) \ + do { \ + const char *s = (cstr); \ + i64 n = strlen((cstr)); \ + jrk_arena_da_append_many((arena), (sb), s, n); \ + } while (0) -#define jrk_sb_append_cstr(sb, cstr) \ - do { \ - const char *s = (cstr); \ - i64 n = strlen(cstr); \ - jrk_da_append_many(sb, s, n); \ +#define jrk_sb_append_cstr(sb, cstr) \ + do { \ + const char *s = (cstr); \ + i64 n = strlen((cstr)); \ + jrk_da_append_many((sb), s, n); \ } while (0) -#define jrk_sb_append_buf(sb, buf, size) jrk_da_append_many(sb, buf, size) + +#define jrk_arena_sb_append_buf(arena, sb, buf, size) jrk_arena_da_append_many((arena), (sb), (buf), (size)) + +#define jrk_sb_append_buf(sb, buf, size) jrk_da_append_many((sb), (buf), (size)) #ifdef JRK_SHORTNAMES - #define UNUSED JRK_UNUSED - #define ARRSIZE JRK_ARRSIZE - #define KILOBYTES JRK_KILOBYTES - #define MEGABYTES JRK_MEGABYTES - #define GIGABYTES JRK_GIGABYTES - - #define return_defer jrk_return_defer - - #define Arena jrk_Arena - #define StringBuilder jrk_StringBuilder - #define StringView jrk_StringView - - #define tmpstrings_push jrk_tmpstrings_push - #define tmpstrings_pushf jrk_tmpstrings_pushf - - #define sb_appendf jrk_sb_appendf - #define sb_append_null jrk_sb_append_null - #define sb_append_buf jrk_sb_append_buf - #define sb_append_buf_at jrk_sb_append_buf_at - #define sb_append_cstr jrk_sb_append_cstr - #define sb_free jrk_sb_free - #define sb_fd_read_all jrk_sb_fd_read_all - #define sb_fd_write_all jrk_sb_fd_write_all - #define sb_to_sv jrk_sb_to_sv - #define sb_write_file jrk_sb_write_file - #define sb_read_entire_file jrk_sb_read_entire_file - - #define sv_trim_left jrk_sv_trim_left - #define sv_trim_right jrk_sv_trim_right - #define sv_trim jrk_sv_trim - #define sv_from_cstr jrk_sv_from_cstr - #define sv_from_parts jrk_sv_from_parts - #define sv_chop_delim jrk_sv_chop_delim - - #define ecalloc jrk_ecalloc - #define erealloc jrk_erealloc - #define emalloc jrk_emalloc - - #define da_reserve jrk_da_reserve - #define da_append jrk_da_append - #define da_append_many jrk_da_append_many - #define da_foreach jrk_da_foreach - #define da_create jrk_da_create - #define da_free jrk_da_free - - #define arena_create jrk_arena_create - #define arena_destroy jrk_arena_destroy - #define arena_push_struct jrk_arena_push_struct - #define arena_push_array jrk_arena_push_array - - #define rand_num jrk_rand_num - #define rand_num_range jrk_rand_num_range - - #define fd_close jrk_fd_close - #define fd_open_read jrk_fd_open_read - #define fd_open_write jrk_fd_open_write - #define fd_open_write_append jrk_fd_open_write_append - - #define shift jrk_shift - #define shift_loop jrk_shift_loop + #define UNUSED JRK_UNUSED + #define ARRSIZE JRK_ARRSIZE + #define KILOBYTES JRK_KILOBYTES + #define MEGABYTES JRK_MEGABYTES + #define GIGABYTES JRK_GIGABYTES + #define TERABYTES JRK_TERABYTES + + #define return_defer jrk_return_defer + + #define Arena jrk_Arena + #define StringBuilder jrk_StringBuilder + #define StringView jrk_StringView + + #define tmpstrings_push jrk_tmpstrings_push + #define tmpstrings_pushf jrk_tmpstrings_pushf + + #define sb_appendf jrk_sb_appendf + #define sb_append_null jrk_sb_append_null + #define sb_append_buf jrk_sb_append_buf + #define sb_append_buf_at jrk_sb_append_buf_at + #define sb_append_cstr jrk_sb_append_cstr + #define sb_free jrk_sb_free + #define sb_fd_read_all jrk_sb_fd_read_all + #define sb_fd_write_all jrk_sb_fd_write_all + #define sb_to_sv jrk_sb_to_sv + #define sb_write_file jrk_sb_write_file + #define sb_read_entire_file jrk_sb_read_entire_file + + #define sv_trim_left jrk_sv_trim_left + #define sv_trim_right jrk_sv_trim_right + #define sv_trim jrk_sv_trim + #define sv_from_cstr jrk_sv_from_cstr + #define sv_from_parts jrk_sv_from_parts + #define sv_chop_delim jrk_sv_chop_delim + + #define ecalloc jrk_ecalloc + #define erealloc jrk_erealloc + #define emalloc jrk_emalloc + + #define da_reserve jrk_da_reserve + #define da_append jrk_da_append + #define da_append_many jrk_da_append_many + #define da_foreach jrk_da_foreach + #define da_create jrk_da_create + #define da_free jrk_da_free + + #define arena_create jrk_arena_create + #define arena_push jrk_arena_push + #define arena_resize jrk_arena_resize + #define arena_reset jrk_arena_reset + + #define arena_da_reserve jrk_arena_da_reserve + #define arena_da_append jrk_arena_da_append + #define arena_da_append_many jrk_arena_da_append_many + + #define arena_sb_appendf jrk_arena_sb_appendf + #define arena_sb_append_buf_at jrk_arena_sb_append_buf_at + #define arena_sb_append_buf jrk_arena_sb_append_buf + #define arena_sb_append_cstr jrk_arena_sb_append_cstr + #define arena_sb_append_null jrk_arena_sb_append_null + + #define rand_num jrk_rand_num + #define rand_num_range jrk_rand_num_range + + #define fd_close jrk_fd_close + #define fd_open_read jrk_fd_open_read + #define fd_open_write jrk_fd_open_write + #define fd_open_write_append jrk_fd_open_write_append + + #define shift jrk_shift + #define shift_loop jrk_shift_loop #endif // JRK_SHORTNAMES #ifdef JRK_IMPLEMENTATION @@ -308,43 +363,136 @@ jrk_tmpstrings_pushf(char *fmt, ...) } jrk_Arena -jrk_arena_create(u64 n) +jrk_arena_create(u8 *buffer, u64 buffer_count) +{ + jrk_Arena result = {0}; + result.data = buffer; + result.capacity = buffer_count; + result.offset = 0; + result.prev_offset = 0; + return result; +} + +void * +jrk_arena_push(jrk_Arena *arena, u64 n) { - jrk_Arena result; - result.count = 0; - result.capacity = n; - result.data = jrk_ecalloc(result.capacity, 1); + jrk_assertv(arena->offset + n <= arena->capacity, + "jrk_arena_push(%p, %ld): arena push requires %ld bytes but has a capacity of %ld bytes", + arena, n, arena->offset + n, arena->capacity); + + void *result = &arena->data[arena->offset]; + arena->prev_offset = arena->offset; + arena->offset += n; + memset(result, 0, n); return result; } void * -jrk__arena_push(jrk_Arena *arena, u64 n) +jrk_arena_resize(jrk_Arena *arena, void *old, u64 old_size, u64 new_size) +{ + jrk_assertv(new_size > old_size, + "jrk_arena_resize(%p, %p, %ld, %ld): new_size is smaller than the old_size", + arena, old, old_size, new_size); + + jrk_assertv(arena->offset + (new_size - old_size) <= arena->capacity, + "jrk_arena_resize(%p, %p, %ld, %ld): arena resize requires %ld bytes but has a capacity of %ld bytes", + arena, old, old_size, new_size, arena->offset + (new_size - old_size), arena->capacity); + + void *result = NULL; + + if (old == &arena->data[arena->prev_offset]) { + result = old; + arena->offset = new_size; + } else { + result = &arena->data[arena->offset]; + arena->prev_offset = arena->offset; + arena->offset += new_size; + memset(result, 0, new_size); + memmove(result, old, old_size); + } + + return result; +} + +void +jrk_arena_reset(jrk_Arena *arena) +{ + arena->offset = 0; + arena->prev_offset = 0; + memset(arena->data, 0, arena->capacity); +} + +i32 +jrk_arena_sb_appendf(jrk_Arena *arena, jrk_StringBuilder *sb, const char *fmt, ...) { - jrk_assertv(arena->count + n <= arena->capacity, - "jrk__arena_push(%p, %ld): arena push requires %ld bytes but has a capacity of %ld bytes", - arena, n, arena->count + n, arena->capacity - ); + i32 result = -1; + + va_list args; + va_start(args, fmt); + result = vsnprintf(NULL, 0, fmt, args); + va_end(args); + + jrk_arena_da_reserve(arena, sb, sb->count + result + 1); + + va_start(args, fmt); + vsnprintf(sb->items + sb->count, result + 1, fmt, args); + va_end(args); + sb->count += result; - void *result = &arena->data[arena->count]; - arena->count += n; return result; } i32 jrk_sb_appendf(jrk_StringBuilder *sb, const char *fmt, ...) { + i32 result = -1; + va_list args; va_start(args, fmt); - i32 n = vsnprintf(NULL, 0, fmt, args); + result = vsnprintf(NULL, 0, fmt, args); va_end(args); - jrk_da_reserve(sb, sb->count + n + 1); + jrk_da_reserve(sb, sb->count + result + 1); + va_start(args, fmt); - vsnprintf(sb->items + sb->count, n + 1, fmt, args); + vsnprintf(sb->items + sb->count, result + 1, fmt, args); va_end(args); - sb->count += n; + sb->count += result; + + return result; +} + - return n; +void +jrk_arena_sb_append_buf_at(jrk_Arena *arena, jrk_StringBuilder *sb, char *buf, u64 size, u64 idx) +{ + jrk_assertv(idx < sb->count, "jrk_arena_sb_append_buf_at(%p, %p, %p, %ld, %ld): idx is greater than sb->count", + arena, sb, buf, size, idx); + + u64 new_size = sb->count + size; + char *old_items = sb->items; + + jrk_arena_da_reserve(arena, sb, new_size); + + if (old_items == sb->items) { // didn't move + jrk_StringBuilder temp_builder = {0}; + temp_builder.items = jrk_emalloc(sb->capacity); + temp_builder.count = sb->count; + temp_builder.capacity = sb->capacity; + memcpy(temp_builder.items, sb->items, sb->count); + + memcpy(sb->items, temp_builder.items, idx); + memcpy(sb->items + idx, buf, size); + memcpy(sb->items + idx + size, temp_builder.items + idx, temp_builder.count - idx); + + jrk_sb_free(temp_builder); + } else { // did move + memcpy(sb->items, old_items, idx); + memcpy(sb->items + idx, buf, size); + memcpy(sb->items + idx + size, old_items + idx, sb->count - idx); + } + + sb->count = new_size; } void