kit

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

bytebuf.h (3251B)


      1 #ifndef KIT_OBJ_BYTEBUF_H
      2 #define KIT_OBJ_BYTEBUF_H
      3 
      4 /* Heap-backed growable byte buffer — the canonical staging buffer for object
      5  * writers that assemble a blob (a linkedit table, a .dynstr, a chained-fixups
      6  * stream) before handing it to a Writer. The ELF and Mach-O linkers both grew
      7  * their own near-identical copies; this is the shared one.
      8  *
      9  * Offsets returned by the append family are byte offsets into the buffer at
     10  * the time of the call, which callers patch up later via the data/len fields.
     11  * Allocation failure is fatal inside VEC_GROW (it panics), so callers do not
     12  * need to check append return values for OOM. */
     13 
     14 #include <string.h>
     15 
     16 #include "core/bytes.h"
     17 #include "core/core.h"
     18 #include "core/util.h"
     19 #include "core/vec.h"
     20 
     21 typedef struct ObjByteBuf {
     22   Heap* heap;
     23   u8* data;
     24   u32 len;
     25   u32 cap;
     26 } ObjByteBuf;
     27 
     28 static inline void objbb_init(ObjByteBuf* b, Heap* h) {
     29   b->heap = h;
     30   b->data = NULL;
     31   b->len = 0;
     32   b->cap = 0;
     33 }
     34 
     35 static inline void objbb_fini(ObjByteBuf* b) {
     36   if (b->data) b->heap->free(b->heap, b->data, b->cap);
     37   b->data = NULL;
     38   b->cap = b->len = 0;
     39 }
     40 
     41 static inline void objbb_reserve(ObjByteBuf* b, u32 need) {
     42   if (need <= b->cap) return;
     43   (void)VEC_GROW(b->heap, b->data, b->cap, need);
     44 }
     45 
     46 /* Zero-fill up to the next `a`-aligned length; returns the new (aligned)
     47  * length so callers can record an aligned offset in one step. */
     48 static inline u32 objbb_align(ObjByteBuf* b, u32 a) {
     49   u32 n = (u32)ALIGN_UP((u64)b->len, (u64)a);
     50   if (n > b->len) {
     51     objbb_reserve(b, n);
     52     memset(b->data + b->len, 0, n - b->len);
     53     b->len = n;
     54   }
     55   return b->len;
     56 }
     57 
     58 static inline u32 objbb_append(ObjByteBuf* b, const void* src, u32 n) {
     59   u32 off = b->len;
     60   objbb_reserve(b, b->len + n);
     61   if (n) memcpy(b->data + b->len, src, n);
     62   b->len += n;
     63   return off;
     64 }
     65 
     66 static inline u32 objbb_u8(ObjByteBuf* b, u8 v) {
     67   return objbb_append(b, &v, 1);
     68 }
     69 
     70 static inline u32 objbb_u16(ObjByteBuf* b, u16 v) {
     71   u8 t[2];
     72   wr_u16_le(t, v);
     73   return objbb_append(b, t, 2);
     74 }
     75 
     76 static inline u32 objbb_u32(ObjByteBuf* b, u32 v) {
     77   u8 t[4];
     78   wr_u32_le(t, v);
     79   return objbb_append(b, t, 4);
     80 }
     81 
     82 static inline u32 objbb_u64(ObjByteBuf* b, u64 v) {
     83   u8 t[8];
     84   wr_u64_le(t, v);
     85   return objbb_append(b, t, 8);
     86 }
     87 
     88 /* Append n bytes plus a NUL terminator (no dedup). */
     89 static inline u32 objbb_str(ObjByteBuf* b, const char* s, u32 n) {
     90   u32 off = b->len;
     91   objbb_reserve(b, b->len + n + 1u);
     92   if (n) memcpy(b->data + b->len, s, n);
     93   b->data[b->len + n] = 0;
     94   b->len += n + 1u;
     95   return off;
     96 }
     97 
     98 /* Append a NUL-terminated string with linear dedup over what we've appended
     99  * so far. Strtabs (.dynstr) are small, so the scan stays cheap. An empty
    100  * string maps to offset 0 (the leading NUL the caller is expected to have
    101  * placed). */
    102 static inline u32 objbb_append_str(ObjByteBuf* b, const char* s, u32 n) {
    103   if (n == 0) return 0;
    104   if (b->len > n) {
    105     u32 i;
    106     for (i = 0; i + n < b->len; ++i) {
    107       if (b->data[i + n] == 0 && memcmp(b->data + i, s, n) == 0) return i;
    108     }
    109   }
    110   return objbb_str(b, s, n);
    111 }
    112 
    113 /* objbb_append_str for a NUL-terminated C string. */
    114 static inline u32 objbb_append_cstr(ObjByteBuf* b, const char* s) {
    115   return objbb_append_str(b, s, (u32)strlen(s));
    116 }
    117 
    118 #endif