buf.h (2344B)
1 #ifndef KIT_BUF_H 2 #define KIT_BUF_H 3 4 #include <string.h> 5 6 #include "core/core.h" 7 #include "core/heap.h" 8 9 #define BUF_CHUNK 65536 10 11 typedef struct BufChunk BufChunk; 12 struct BufChunk { 13 BufChunk* next; 14 u32 used; 15 u32 cap; /* usable size of data[] */ 16 u8 data[]; 17 }; 18 19 /* Directory entry: a chunk and the buffer offset of its first byte. Chunk 20 * starts increase monotonically, so the directory is a sorted index that lets 21 * buf_patch / buf_read binary-search to the owning chunk. */ 22 typedef struct BufChunkRef { 23 u32 start; 24 BufChunk* chunk; 25 } BufChunkRef; 26 27 typedef struct Buf { 28 Heap* heap; 29 BufChunk* head; 30 BufChunk* tail; 31 u32 total; /* sum of used across all chunks */ 32 /* Sorted index of chunk start offsets, appended to as chunks are created. 33 * Turns random-access patch/read from O(n_chunks) (walk from head) into 34 * O(log n_chunks). It is purely an accelerator: if a push ever fails, the 35 * forward `next` walk from the nearest indexed chunk still finds the byte. */ 36 BufChunkRef* dir; 37 u32 ndir; 38 u32 dir_cap; 39 } Buf; 40 41 void buf_init(Buf*, Heap*); 42 void buf_fini(Buf*); 43 44 /* Out-of-line body for the empty-tail / chunk-spanning case. */ 45 void buf_write_slow(Buf*, const void* data, size_t n); 46 47 /* Append n bytes. Inlined fast path: when the bytes fit the current tail chunk 48 * (the overwhelmingly common code-emit case — chunks hold 64KB), this is a bare 49 * memcpy + two field bumps with no call. Empty-tail / spanning writes fall to 50 * buf_write_slow. Behaviour is byte-for-byte identical to the old out-of-line 51 * loop; only the call/loop scaffolding is removed from the hot case. */ 52 static inline void buf_write(Buf* b, const void* data, size_t n) { 53 BufChunk* t = b->tail; 54 if (t && (size_t)(t->cap - t->used) >= n) { 55 memcpy(t->data + t->used, data, n); 56 t->used += (u32)n; 57 b->total += (u32)n; 58 return; 59 } 60 buf_write_slow(b, data, n); 61 } 62 63 u8* buf_reserve(Buf*, 64 size_t n); /* contiguous; spills to a fresh chunk if needed */ 65 u32 buf_pos(const Buf*); 66 void buf_patch(Buf*, u32 ofs, const void* data, 67 size_t n); /* must lie within written range */ 68 void buf_read(const Buf*, u32 ofs, void* dst, 69 size_t n); /* must lie within written range */ 70 71 void buf_flatten(const Buf*, 72 u8* dst); /* copy entire contents out, dst >= total bytes */ 73 74 #endif