kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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