All-inclusive Buffer for C
(Experiment - not yet stable or optimized)
๐ API
Buffet is a polymorphic string buffer type featuring :
- SSO (small string optimization) : short data is stored inline
- views : no-cost references to slices of data
- reference counting : secures the release of views and owned data
- cstr : obtain a null-terminated C string
- automated (re)allocations
In a mere register-fitting 16 bytes.
union Buffet {
// OWN, REF, VUE
struct {
char* data
uint32_t len
uint32_t aux:30, tag:2 // aux = {cap|off}
} ptr
// SSO
struct {
char data[15]
uint8_t len:6, tag:2
} sso
}
The tag sets how a Buffet is interpreted :
- SSO : as a char array
- OWN : as owning heap-allocated data
- REF : as a slice of owned data
- VUE : as a slice of other data
The ptr
sub-type covers :
- OWN : with
aux
as capacity - REF : with
aux
as offset - VUE : with
aux
as offset
Any proper data (SSO/OWN) is null-terminated.
make && make check
#include <stdio.h>
#include "buffet.h"
int main()
{
char text[] = "The train is fast";
Buffet vue;
buffet_strview (&vue, text+4, 5);
buffet_print(&vue);
text[4] = 'b';
buffet_print(&vue);
Buffet ref = buffet_view (&vue, 1, 4);
buffet_print(&ref);
char wet[] = " is wet";
buffet_append (&ref, wet, sizeof(wet));
buffet_print(&ref);
return 0;
}
$ gcc example.c buffet -o example && ./example
train
brain
rain
rain is wet
buffet_new
buffet_strcopy
buffet_strview
buffet_copy
buffet_view
buffet_append
buffet_free
buffet_cap
buffet_len
buffet_data
buffet_cstr
buffet_export
void buffet_new (Buffet *dst, size_t cap)
Create a Buffet of capacity at least cap
.
Buffet buf;
buffet_new(&buf, 20);
buffet_dbg(&buf);
// tag:OWN cap:32 len:0 data:''
void buffet_strcopy (Buffet *dst, const char *src, size_t len)
Copy len
bytes from string src
into new Buffet dst
.
Buffet copy;
buffet_strcopy(©, "Bonjour", 3);
buffet_dbg(©);
// tag:SSO cap:14 len:3 data:'Bon'
void buffet_strview (Buffet *dst, const char *src, size_t len)
View len
bytes from string src
into new Buffet dst
.
You get a window into src
. No copy or allocation is done.
char src[] = "Eat Buffet!";
Buffet view;
buffet_strview(&view, src+4, 3);
buffet_dbg(&view);
// tag:VUE cap:0 len:6 data:'Buffet!'
buffet_print(&view);
// Buf
Buffet buffet_copy (const Buffet *src, ptrdiff_t off, size_t len)
Create a new Buffet by copying len
bytes from Buffet src
, starting at offset off
.
Buffet buffet_view (const Buffet *src, ptrdiff_t off, size_t len)
Create a new Buffet by viewing len
bytes Buffet src
, starting at offset off
.
The return is internally either
- a REF if
src
is owning - a REF to the origin if
src
is itself a REF - a VUE on
src
data ifsrc
is SSO or VUE
src
now cannot be released before either
- the return is released
- the return is detached as owner (e.g. when you
append()
to it).
Buffet src;
buffet_strcopy(&src, "Bonjour", 7);
Buffet ref = buffet_view(&src, 0, 3);
buffet_dbg(&ref); // tag:VUE cap:0 len:3 data:'Bonjour'
buffet_print(&ref); // Bon
void buffet_free (Buffet *buf)
If buf
is SSO or VUE, it is simply zeroed, making it an empty SSO.
If buf
is REF, the refcount is decremented and buf zeroed.
If buf
owns data :
- with no references, the data is released and buf is zeroed
- with live references, buf is marked for release and waits for its last ref to be released.
char text[] = "Le grand orchestre de Patato Valdez";
Buffet own;
buffet_strcopy(&own, text, sizeof(text));
buffet_dbg(&own);
// tag:OWN data:'Le grand orchestre de Patato Valdez'
Buffet ref = buffet_view(&own, 22, 13);
buffet_dbg(&ref);
// tag:REF data:'Patato Valdez'
// Too soon but marked for release
buffet_free(&own);
buffet_dbg(&own);
// tag:OWN data:'Le grand orchestre de Patato Valdez'
// Release last ref, hence owner
buffet_free(&ref);
buffet_dbg(&own);
// tag:SSO data:''
size_t buffet_append (Buffet *dst, const char *src, size_t len)
Appends len
bytes from src
to dst
.
Returns new length or 0 on error.
If over capacity, dst
gets reallocated.
Buffet buf;
buffet_strcopy(&buf, "abc", 3);
size_t newlen = buffet_append(&buf, "def", 3); // newlen == 6
buffet_dbg(&buf);
// tag:SSO cap:14 len:6 data:'abcdef'
Get current capacity.
size_t buffet_cap (Buffet *buf)
Get current length.
size_t buffet_len (Buffet *buf)`
Get current data pointer.
const char* buffet_data (const Buffet *buf)`
If buf is a ref/view, strlen(buffet_data)
may be longer than buf.len
.
Get current data as a NUL-terminated C string.
const char* buffet_cstr (const Buffet *buf, bool *mustfree)
If REF/VUE, the slice is copied into a fresh C string that must be freed.
Copies data up to buf.len
into a fresh C string that must be freed.
char* buffet_export (const Buffet *buf)
Prints data up to buf.len
.
void buffet_print (const Buffet *buf)`
Prints buf state.
void buffet_dbg (Buffet *buf)
Buffet buf;
buffet_strcopy(&buf, "foo", 3);
buffet_dbg(&buf);
// tag:SSO cap:14 len:3 data:'foo'