diff --git a/src/noh.h b/src/noh.h index d864aae..16359a0 100644 --- a/src/noh.h +++ b/src/noh.h @@ -187,6 +187,17 @@ do { (da)->elems[(da)->count++] = (elem); \ } while(0) +// The same as noh_da_append, but uses an arena to allocate more data. No data is freed. +#define noh_da_append_arena(arena, da, elem) \ +do { \ + if ((da)->count >= (da)->capacity) { \ + (da)->capacity = (da)->capacity == 0 ? NOH_DA_INIT_CAP : (da)->capacity * 2; \ + (da)->elems = noh_arena_alloc((arena), (da)->capacity * sizeof(*(da)->elems)); \ + } \ + \ + (da)->elems[(da)->count++] = (elem); \ +} while(0) + // Appends multiple elements to a dynamic array. Allocates more memory and moves all elements to newly allocated memory // if needed. #define noh_da_append_multiple(da, new_elems, new_elems_count) \ @@ -201,6 +212,19 @@ do { (da)->count += new_elems_count; \ } while (0) +// The same as noh_da_append_multiple, but uses an arena to allocate more data. No data is freed. +#define noh_da_append_multiple_arena(arena, da, new_elems, new_elems_count) \ +do { \ + if ((da)->count + new_elems_count > (da)->capacity) { \ + if ((da)->capacity == 0) (da)->capacity = NOH_DA_INIT_CAP; \ + while ((da)->count + new_elems_count > (da)->capacity) (da)->capacity *= 2; \ + (da)->elems = noh_arena_alloc((arena), (da)->capacity * sizeof(*(da)->elems)); \ + } \ + \ + memcpy((da)->elems + (da)->count, new_elems, new_elems_count * sizeof(*(da)->elems)); \ + (da)->count += new_elems_count; \ +} while (0) + // Removes the element at the specified location. #define noh_da_remove_at(da, index) \ do { \ @@ -335,6 +359,9 @@ typedef struct { char *elems; size_t count; size_t capacity; + // If set, memory will be allocated in this arena when adding to the string. + // if set or unset halfway through using a string, this will cause undefined behaviour. + Noh_Arena *arena; } Noh_String; // Copies a Noh_String to the arena, and frees the Noh_String @@ -343,6 +370,10 @@ char *noh_arena_consume_string(Noh_Arena *arena, Noh_String *string); // Creates a Noh_String from a c-string. Noh_String noh_string_from_cstr(const char *cstr); +// Creates a Noh_String from a c-string. +// Provide a Noh_Arena to allocate the string's data in. +Noh_String noh_string_from_cstr_arena(Noh_Arena *arena, const char *cstr); + // Appends a null-terminated string into a Noh_String. void noh_string_append_cstr(Noh_String *string, const char *cstr); @@ -353,7 +384,10 @@ void noh_string_append_null(Noh_String *string); void noh_string_replace(Noh_String *string, const char from, const char to); // Frees a Noh_String, freeing the memory used and settings the count and capacity to 0. -#define noh_string_free(string) noh_da_free(string) +#define noh_string_free(string) do { \ + noh_assert(!(string)->arena && "A string with an arena cannot be freed."); \ + noh_da_free(string); \ +} while(0) // Resets a Noh_String, setting the count to 0. #define noh_string_reset(string) noh_da_reset(string) @@ -857,31 +891,54 @@ char *noh_arena_consume_string(Noh_Arena *arena, Noh_String *string) { } Noh_String noh_string_from_cstr(const char *cstr) { + return noh_string_from_cstr_arena(cstr, NULL); +} + +Noh_String noh_string_from_cstr_arena(Noh_Arena *arena, const char *cstr) { Noh_String str = {0}; + if (arena) str.arena = arena; + noh_string_append_cstr(&str, cstr); return str; } void noh_string_append_cstr(Noh_String *string, const char *cstr) { size_t len = strlen(cstr); - noh_da_append_multiple(string, cstr, len); + + if (string->arena) { + noh_da_append_multiple_arena(string->arena, string, cstr, len); + } else { + noh_da_append_multiple(string, cstr, len); + } } void noh_string_append_null(Noh_String *string) { - noh_da_append(string, '\0'); + if (string->arena) { + noh_da_append_arena(string->arena, string, '\0'); + } else { + noh_da_append(string, '\0'); + } } void noh_string_replace(Noh_String *string, const char from, const char to) { Noh_String result = {0}; for (size_t i = 0; i < string->count; i++) { - if (string->elems[i] == from) { - noh_da_append(&result, to); + if (result.arena) { + if (string->elems[i] == from) { + noh_da_append_arena(result.arena, &result, to); + } else { + noh_da_append_arena(result.arena, &result, string->elems[i]); + } } else { - noh_da_append(&result, string->elems[i]); + if (string->elems[i] == from) { + noh_da_append(&result, to); + } else { + noh_da_append(&result, string->elems[i]); + } } } - noh_string_free(string); + if (!string->arena) noh_string_free(string); string->elems = result.elems; string->count = result.count; string->capacity = result.capacity; @@ -906,7 +963,11 @@ bool noh_string_read_file(Noh_String *string, const char *filename) { size_t n = fread(buf, 1, buf_size, f); while (n > 0) { - noh_da_append_multiple(string, buf, n); + if (string->arena) { + noh_da_append_multiple_arena(string->arena, string, buf, n); + } else { + noh_da_append_multiple(string, buf, n); + } n = fread(buf, 1, buf_size, f); } @@ -951,7 +1012,11 @@ Noh_String_View noh_sv_copy_cstr(Noh_Arena *arena, const char *cstr) { } void noh_string_append_sv(Noh_String *string, Noh_String_View sv) { - noh_da_append_multiple(string, sv.elems, sv.count); + if (string->arena) { + noh_da_append_multiple_arena(string->arena, string, sv.elems, sv.count); + } else { + noh_da_append_multiple(string, sv.elems, sv.count); + } } void noh_sv_increase_position(Noh_String_View *sv, size_t distance) { @@ -1293,9 +1358,15 @@ void noh_quote_if_needed(const char *value, Noh_String *string) { if (!strchr(value, ' ')) { noh_string_append_cstr(string, value); } else { - noh_da_append(string, '\''); - noh_string_append_cstr(string, value); - noh_da_append(string, '\''); + if (string->arena) { + noh_da_append_arena(string->arena, string, '\''); + noh_string_append_cstr(string, value); + noh_da_append_arena(string->arena, string, '\''); + } else { + noh_da_append(string, '\''); + noh_string_append_cstr(string, value); + noh_da_append(string, '\''); + } } }