String functions that return str8/16/32 allocated on an arena implicitly zero-terminate strings, so we can avoid one copy when passing to C stdlib APIs

This commit is contained in:
Martin Fouilleul 2023-06-26 16:06:26 +02:00
parent 4b491ee94a
commit ffb900d872
5 changed files with 41 additions and 21 deletions

View File

@ -23,8 +23,9 @@ str8 path_executable(mem_arena* arena)
u32 size = 0; u32 size = 0;
_NSGetExecutablePath(0, &size); _NSGetExecutablePath(0, &size);
result.len = size; result.len = size;
result.ptr = mem_arena_alloc_array(arena, char, result.len); result.ptr = mem_arena_alloc_array(arena, char, result.len+1);
_NSGetExecutablePath(result.ptr, &size); _NSGetExecutablePath(result.ptr, &size);
result.ptr[result.len] = '\0';
return(result); return(result);
}} }}

View File

@ -10,6 +10,12 @@
#include"util/strings.h" #include"util/strings.h"
/*NOTE:
by convention, functions that take an arena and return a path
allocated on that arena allocate 1 more character and null-terminate
the string.
*/
MP_API str8 path_slice_directory(str8 path); MP_API str8 path_slice_directory(str8 path);
MP_API str8 path_slice_filename(str8 path); MP_API str8 path_slice_filename(str8 path);

View File

@ -22,8 +22,11 @@ bool path_is_absolute(str8 path)
str8 path_executable(mem_arena* arena) str8 path_executable(mem_arena* arena)
{ {
///////////////////////////////////////////////////////////////////
//TODO use wide chars //TODO use wide chars
char* buffer = mem_arena_alloc_array(arena, char, MAX_PATH+1); ///////////////////////////////////////////////////////////////////
char* buffer = mem_arena_alloc_array(arena, char, MAX_PATH+2);
int size = GetModuleFileName(NULL, buffer, MAX_PATH+1); int size = GetModuleFileName(NULL, buffer, MAX_PATH+1);
//TODO: check for errors... //TODO: check for errors...
for(int i=0; i<size; i++) for(int i=0; i<size; i++)
@ -33,7 +36,6 @@ str8 path_executable(mem_arena* arena)
buffer[i] = '/'; buffer[i] = '/';
} }
} }
return(str8_from_buffer(size, buffer)); return(str8_from_buffer(size, buffer));
} }

View File

@ -28,21 +28,20 @@ str8 str8_push_buffer(mem_arena* arena, u64 len, char* buffer)
{ {
str8 str = {0}; str8 str = {0};
str.len = len; str.len = len;
str.ptr = mem_arena_alloc_array(arena, char, len); str.ptr = mem_arena_alloc_array(arena, char, len+1);
memcpy(str.ptr, buffer, len); memcpy(str.ptr, buffer, len);
str.ptr[str.len] = '\0';
return(str); return(str);
} }
str8 str8_push_cstring(mem_arena* arena, const char* str) str8 str8_push_cstring(mem_arena* arena, const char* str)
{ {
if(!str) int len = 0;
if(str)
{ {
return((str8){0}); len = strlen(str);
} }
else
{
return(str8_push_buffer(arena, strlen(str), (char*)str)); return(str8_push_buffer(arena, strlen(str), (char*)str));
}
} }
str8 str8_push_copy(mem_arena* arena, str8 s) str8 str8_push_copy(mem_arena* arena, str8 s)
@ -61,10 +60,7 @@ str8 str8_pushfv(mem_arena* arena, const char* format, va_list args)
//NOTE(martin): //NOTE(martin):
// We first compute the number of characters to write passing a size of 0. // We first compute the number of characters to write passing a size of 0.
// then we allocate len+1 (since vsnprint always terminates with a '\0'). // then we allocate len+1 (since vsnprint always terminates with a '\0').
// We could call vsprintf since we know the size, but I'm not sure there's a hard
// guarantee that vsprintf and vsnprintf write the same number of characters in all
// and every case, and that would be a difficult bug to spot, so it seems better to
// waste one byte and be safe.
char dummy; char dummy;
str8 str = {0}; str8 str = {0};
va_list argCopy; va_list argCopy;
@ -137,7 +133,7 @@ str8 str8_list_collate(mem_arena* arena, str8_list list, str8 prefix, str8 separ
{ {
str8 str = {0}; str8 str = {0};
str.len = prefix.len + list.len + list.eltCount*separator.len + postfix.len; str.len = prefix.len + list.len + list.eltCount*separator.len + postfix.len;
str.ptr = mem_arena_alloc_array(arena, char, str.len); str.ptr = mem_arena_alloc_array(arena, char, str.len + 1);
char* dst = str.ptr; char* dst = str.ptr;
memcpy(dst, prefix.ptr, prefix.len); memcpy(dst, prefix.ptr, prefix.len);
dst += prefix.len; dst += prefix.len;
@ -158,6 +154,7 @@ str8 str8_list_collate(mem_arena* arena, str8_list list, str8 prefix, str8 separ
dst += elt->string.len; dst += elt->string.len;
} }
memcpy(dst, postfix.ptr, postfix.len); memcpy(dst, postfix.ptr, postfix.len);
str.ptr[str.len] = '\0';
return(str); return(str);
} }
@ -239,8 +236,9 @@ str16 str16_push_buffer(mem_arena* arena, u64 len, u16* buffer)
{ {
str16 str = {0}; str16 str = {0};
str.len = len; str.len = len;
str.ptr = mem_arena_alloc_array(arena, u16, len); str.ptr = mem_arena_alloc_array(arena, u16, len+1);
memcpy(str.ptr, buffer, len*sizeof(u16)); memcpy(str.ptr, buffer, len*sizeof(u16));
str.ptr[str.len] = (u16)0;
return(str); return(str);
} }
@ -275,7 +273,7 @@ str16 str16_list_collate(mem_arena* arena, str16_list list, str16 prefix, str16
{ {
str16 str = {0}; str16 str = {0};
str.len = prefix.len + list.len + list.eltCount*separator.len + postfix.len; str.len = prefix.len + list.len + list.eltCount*separator.len + postfix.len;
str.ptr = mem_arena_alloc_array(arena, u16, str.len); str.ptr = mem_arena_alloc_array(arena, u16, str.len + 1);
char* dst = (char*)str.ptr; char* dst = (char*)str.ptr;
memcpy(dst, prefix.ptr, prefix.len*sizeof(u16)); memcpy(dst, prefix.ptr, prefix.len*sizeof(u16));
dst += prefix.len*sizeof(u16); dst += prefix.len*sizeof(u16);
@ -296,6 +294,7 @@ str16 str16_list_collate(mem_arena* arena, str16_list list, str16 prefix, str16
dst += elt->string.len*sizeof(u16); dst += elt->string.len*sizeof(u16);
} }
memcpy(dst, postfix.ptr, postfix.len*sizeof(u16)); memcpy(dst, postfix.ptr, postfix.len*sizeof(u16));
str.ptr[str.len] = (u16)0;
return(str); return(str);
} }
@ -323,8 +322,9 @@ str32 str32_push_buffer(mem_arena* arena, u64 len, u32* buffer)
{ {
str32 str = {0}; str32 str = {0};
str.len = len; str.len = len;
str.ptr = mem_arena_alloc_array(arena, u32, len); str.ptr = mem_arena_alloc_array(arena, u32, len+1);
memcpy(str.ptr, buffer, len*sizeof(u32)); memcpy(str.ptr, buffer, len*sizeof(u32));
str.ptr[str.len] = 0;
return(str); return(str);
} }
@ -359,7 +359,7 @@ str32 str32_list_collate(mem_arena* arena, str32_list list, str32 prefix, str32
{ {
str32 str = {0}; str32 str = {0};
str.len = prefix.len + list.len + list.eltCount*separator.len + postfix.len; str.len = prefix.len + list.len + list.eltCount*separator.len + postfix.len;
str.ptr = mem_arena_alloc_array(arena, u32, str.len); str.ptr = mem_arena_alloc_array(arena, u32, str.len+1);
char* dst = (char*)str.ptr; char* dst = (char*)str.ptr;
memcpy(dst, prefix.ptr, prefix.len*sizeof(u32)); memcpy(dst, prefix.ptr, prefix.len*sizeof(u32));
dst += prefix.len*sizeof(u32); dst += prefix.len*sizeof(u32);
@ -380,6 +380,7 @@ str32 str32_list_collate(mem_arena* arena, str32_list list, str32 prefix, str32
dst += elt->string.len*sizeof(u32); dst += elt->string.len*sizeof(u32);
} }
memcpy(dst, postfix.ptr, postfix.len*sizeof(u32)); memcpy(dst, postfix.ptr, postfix.len*sizeof(u32));
str.ptr[str.len] = 0;
return(str); return(str);
} }

View File

@ -19,8 +19,18 @@
extern "C" { extern "C" {
#endif #endif
/*NOTE:
By convention, functions that take an arena and return a string slice allocated on
this arena, always allocate one more element and null-terminate the string. This is
done so we can pass those strings directly to C APIs that requires C strings without
having to do a copy with str8_to_cstring().
This does _not_ applies to the string returned by str8_split(). Those are slices
into the original string. Only the _list nodes_ are allocated on the arena.
*/
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// string slices as values // u8 strings
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
typedef struct str8 typedef struct str8
{ {