3 ms·
Optimizing text is hard because you seldom up front know how much memory will be needed and allocations are slow. Another way to do it is to use: typedef stru
by quelsolaar 4y ago
Optimizing text is hard because you seldom up front know how much memory will be needed and allocations are slow.
Another way to do it is to use:
typedef struct{
size_t allocated;
size_t used;
char buffer[];
}String;
This lets the header and the string be the same allocation. Thats a huge saving. Its also useful to store the allocation and use size separatly so that you can reuse / modify buffers. The used field lets you use memcpy without looking for string termination.
You can make it even more complex by adding flags if the string is on the stack or on the heap. That way you can do things like:
String buffer = MACRO_TO_CREATE_STRING_BUFFER_ON_STACK(256), *b;
b = &buffer;
b = do_processing_with_buffer(&b); // allocates on heap a larger buffer if needed
string_free(b); // frees buffer if its on heap.
- jstimpfle 4y agoIn general it's hard to get more efficient than a simple struct String { const char *buffer; u32 size; }. Your method removes an indirection from the allocated storage, but you'd still need an external pointer to point to that struct in most cases. That, plus retrieving the size now costs an additional dereference. So I wouldn't use your method unless I knew that I'd have to reference the string from multiple locations. The best way to be efficient is often to make assumptions about the data. Most strings don't need any dynamic allocation after having been "built". So it makes a ton of sense to make a string builder API that returns a final string when it's finished. In this way, you save at least the "allocated" member. The advantage of the simpler string representation is that it works for any string (or substring) that is contiguous in memory, and is completely decoupled from allocation concerns. E.g. I can easily #define STRING(string_literal) \ ((String) { string_literal "", sizeof string_literal - 1 }) , to be able to statically declare such strings like this: String my_string = STRING("Foo bar"); If you have many strings that you know are small, then just the normal nul-terminated C string (without any size field) is as storage-efficient as it gets. In practice, I find string handling so easy that I rarely even define this struct String. I just pass around strings to functions as two arguments - pointer + size. It feels so light and data flows so easily between APIs, I love it.