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;
_NSGetExecutablePath(0, &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);
result.ptr[result.len] = '\0';
return(result);
}}

View File

@ -10,6 +10,12 @@
#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_filename(str8 path);

View File

@ -22,8 +22,11 @@ bool path_is_absolute(str8 path)
str8 path_executable(mem_arena* arena)
{
///////////////////////////////////////////////////////////////////
//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);
//TODO: check for errors...
for(int i=0; i<size; i++)
@ -33,7 +36,6 @@ str8 path_executable(mem_arena* arena)
buffer[i] = '/';
}
}
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};
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);
str.ptr[str.len] = '\0';
return(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));
}
}
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):
// 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').
// 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;
str8 str = {0};
va_list argCopy;
@ -137,7 +133,7 @@ str8 str8_list_collate(mem_arena* arena, str8_list list, str8 prefix, str8 separ
{
str8 str = {0};
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;
memcpy(dst, prefix.ptr, 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;
}
memcpy(dst, postfix.ptr, postfix.len);
str.ptr[str.len] = '\0';
return(str);
}
@ -239,8 +236,9 @@ str16 str16_push_buffer(mem_arena* arena, u64 len, u16* buffer)
{
str16 str = {0};
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));
str.ptr[str.len] = (u16)0;
return(str);
}
@ -275,7 +273,7 @@ str16 str16_list_collate(mem_arena* arena, str16_list list, str16 prefix, str16
{
str16 str = {0};
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;
memcpy(dst, prefix.ptr, 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);
}
memcpy(dst, postfix.ptr, postfix.len*sizeof(u16));
str.ptr[str.len] = (u16)0;
return(str);
}
@ -323,8 +322,9 @@ str32 str32_push_buffer(mem_arena* arena, u64 len, u32* buffer)
{
str32 str = {0};
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));
str.ptr[str.len] = 0;
return(str);
}
@ -359,7 +359,7 @@ str32 str32_list_collate(mem_arena* arena, str32_list list, str32 prefix, str32
{
str32 str = {0};
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;
memcpy(dst, prefix.ptr, 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);
}
memcpy(dst, postfix.ptr, postfix.len*sizeof(u32));
str.ptr[str.len] = 0;
return(str);
}

View File

@ -19,8 +19,18 @@
extern "C" {
#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
{