cbuf.c (1821B)
1 /* Heap-backed growable byte buffer used by the C target for per-function 2 * declarations and body text. The TU writer is bytewise but CG hands us 3 * declarations and body emission interleaved; we accumulate both and flush 4 * at func_end. */ 5 6 #include "arch/c_target/c_emit.h" 7 #include "core/heap.h" 8 9 enum { CBUF_MIN_CAP = 256 }; 10 11 void cbuf_init(CBuf* b, Heap* h) { 12 b->heap = h; 13 b->data = NULL; 14 b->len = 0; 15 b->cap = 0; 16 } 17 18 void cbuf_fini(CBuf* b) { 19 if (b->data) b->heap->free(b->heap, b->data, b->cap); 20 b->data = NULL; 21 b->len = 0; 22 b->cap = 0; 23 } 24 25 void cbuf_reset(CBuf* b) { b->len = 0; } 26 27 static void cbuf_grow(CBuf* b, size_t want) { 28 size_t newcap = b->cap ? b->cap : CBUF_MIN_CAP; 29 while (newcap < want) newcap *= 2; 30 u8* nd = (u8*)b->heap->realloc(b->heap, b->data, b->cap, newcap, 1); 31 if (!nd) { 32 /* Out of memory; truncate silently. Caller writer will produce 33 * partial output but no UB. */ 34 return; 35 } 36 b->data = nd; 37 b->cap = newcap; 38 } 39 40 void cbuf_putc(CBuf* b, char c) { 41 if (b->len + 1 > b->cap) cbuf_grow(b, b->len + 1); 42 if (b->len < b->cap) b->data[b->len++] = (u8)c; 43 } 44 45 void cbuf_puts(CBuf* b, const char* s) { 46 while (*s) cbuf_putc(b, *s++); 47 } 48 49 void cbuf_putn(CBuf* b, const char* s, size_t n) { 50 if (b->len + n > b->cap) cbuf_grow(b, b->len + n); 51 for (size_t i = 0; i < n && b->len < b->cap; ++i) 52 b->data[b->len++] = (u8)s[i]; 53 } 54 55 void cbuf_put_u64(CBuf* b, u64 v) { 56 char tmp[24]; 57 size_t n = 0; 58 if (v == 0) { 59 cbuf_putc(b, '0'); 60 return; 61 } 62 while (v) { 63 tmp[n++] = (char)('0' + (v % 10)); 64 v /= 10; 65 } 66 while (n--) cbuf_putc(b, tmp[n]); 67 } 68 69 void cbuf_put_i64(CBuf* b, i64 v) { 70 u64 u; 71 if (v < 0) { 72 cbuf_putc(b, '-'); 73 /* careful with INT64_MIN */ 74 u = (u64)(-(v + 1)) + 1u; 75 } else { 76 u = (u64)v; 77 } 78 cbuf_put_u64(b, u); 79 }