/* Generic buffer structure, both dynamic and static. Underlying implementation is very simplistic, but it's done so in assumption that we always bulk allocate, with no fragmentation. */ #ifndef COM_BUF_H #define COM_BUF_H #include "def.h" #include "str.h" #include #include #define COM_BUF_GROWABLE (1 << 0) /* Potentially growable. */ #define COM_BUF_STACK (1 << 1) /* Stack residing. */ #define COM_BUF_RING (1 << 2) /* Cycling memory. */ #define COM_BUF_SUB (1 << 3) /* Buffer inside of a buffer. */ typedef struct com_buf { uint32_t len; /* Length in typed number of elements. */ uint32_t cap; /* Capacity in typed number of elements. */ uint32_t flags; union { uint32_t needle; /* Present for ring type. */ } type; uint8_t typesz; char data[] __attribute__((aligned(COM_DEF_ALIGNMENT))); } com_buf; /* Creates a stack local buffer. It can grow if is set growable, one must still * free it. */ #define com_buf_make_on_stack(p_t, p_v, p_c, p_f) \ char p_v##_buf[sizeof(p_t) * (p_c)] \ __attribute__((aligned(COM_DEF_ALIGNMENT))); \ struct com_buf *p_v = (struct com_buf *)&p_v##_buf; \ p_v->cap = (p_c); \ p_v->flags = p_f | COM_BUF_STACK; \ p_v->typesz = sizeof(p_t); #define com_buf_index_as(p_t, p_v, p_i) \ (p_t *)(&(p_v)->data[sizeof(p_t) * (p_i)]) /* Dynamic allocation to persist no matter the function flow. */ struct com_buf *com_buf_make(uint32_t cap, uint32_t flags); /* Makes sure there's N elements of capacity at least. Returns false if it * cannot do so. */ bool com_buf_make_room(struct com_buf *b, uint32_t n); /* Drops the memory, not touching the cap. */ static inline void com_buf_clear(struct com_buf *b) { b->len = 0; } void com_buf_free(struct com_buf *b); #endif