#include "String.h" #include "GlobalArena.h" #include "Types.h" #include #include #include struct StringMeta { BumpArena b; usize length; }; static inline struct StringMeta* S_metadata(String s) { return (struct StringMeta*)(s - sizeof(struct StringMeta)); } String S_new(BumpArena b, const char* str) { if (NULL == b || NULL == str) return NULL; struct StringMeta sm = { .b = b, .length = strlen(str), }; void* start = B_alloc(b, sizeof(sm) + sm.length + 1); if (NULL == start) return NULL; memcpy(start, &sm, sizeof(sm)); start += sizeof(sm); memcpy(start, str, sm.length + 1); return start; } String S_newlen(BumpArena b, usize length) { if (NULL == b) return NULL; struct StringMeta sm = { .b = b, .length = length, }; void* start = B_alloc(b, sizeof(sm) + sm.length + 1); if (NULL == start) return NULL; memcpy(start, &sm, sizeof(sm)); start += sizeof(sm); memset(start, '\0', sm.length + 1); return start; } static inline usize S_allocated(String s) { return sizeof(struct StringMeta) + S_length(s) + 1; } String S_dup(BumpArena b, String s) { if (NULL == b || NULL == s) return NULL; usize allocated = S_allocated(s); void* start = B_alloc(b, allocated); if (NULL == start) return NULL; memcpy(start, s - sizeof(struct StringMeta), allocated); return start + sizeof(struct StringMeta); } usize S_length(String s) { if (NULL == s) return 0; return S_metadata(s)->length; } Result S_append(String s, const char* str) { if (NULL == s || NULL == str) return R_Uninitialized; struct StringMeta* sm = S_metadata(s); if (!B_resizeable(sm->b, s)) return R_OutOfBounds; usize strlength = strlen(str); RETURN_NOTOK(B_resize(sm->b, sizeof(*sm) + (sm->length + strlength) + 1)); strcat(s, str); sm->length += strlength; return R_Ok; } Result S_prepend(String s, const char* str) { if (NULL == s) return R_Uninitialized; struct StringMeta* sm = S_metadata(s); if (!B_resizeable(sm->b, s)) return R_OutOfBounds; usize strlength = strlen(str); RETURN_NOTOK(B_resize(sm->b, sizeof(*sm) + (sm->length + strlength) + 1)); for (usize i = sm->length; i > 0; --i) s[i - 1 + strlength] = s[i - 1]; for (usize i = 0; i < strlength; ++i) s[i] = str[i]; sm->length += strlength; return R_Ok; } usize S_find(String s, char c) { if (NULL == s) return -1; unsigned index = 0; while (s[index] != '\0' && s[index] != c) ++index; return index; } static String S_vconcat(BumpArena b, va_list args) { usize length = 0; va_list temp; va_copy(temp, args); for (const char* str = va_arg(temp, const char*); str != NULL; str = va_arg(temp, const char*)) { length += strlen(str); } va_end(temp); String result = S_newlen(b, length); if (NULL == result) return result; if (0 < length) { for (const char* str = va_arg(args, const char*); str != NULL; str = va_arg(args, const char*)) strncat(result, str, length); } return result; } String S_concat(BumpArena b, ...) { va_list args; usize length = 0; va_start(args, b); String result = S_vconcat(b, args); va_end(args); return result; } static String S_vprintf(BumpArena b, const char* fmt, va_list args) { va_list temp; va_copy(temp, args); usize length = vsnprintf(NULL, 0, fmt, temp); va_end(temp); String result = S_newlen(b, length); if (NULL == result) return NULL; vsnprintf(result, length + 1, fmt, args); return result; } String S_printf(BumpArena b, const char* fmt, ...) { va_list args; va_start(args, fmt); String result = S_vprintf(b, fmt, args); va_end(args); return result; } String SG_new(const char* str) { return S_new(g_arena, str); } String SG_newlen(usize length) { return S_newlen(g_arena, length); } String SG_dup(String s) { return S_dup(g_arena, s); } String SG_concat(const char* str, ...) { if (str == NULL) return NULL; va_list args; va_start(args, str); String result = S_vconcat(g_arena, args); va_end(args); S_prepend(result, str); return result; } String SG_printf(const char* fmt, ...) { va_list args; va_start(args, fmt); String result = S_vprintf(g_arena, fmt, args); va_end(args); return result; }