Overview
Comment: | add generic routines from vesper |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
0894d03fbff624002b8ff1e608bd36b4 |
User & Date: | lexi on 2023-04-15 20:47:04 |
Other Links: | manifest | tags |
Context
2024-07-10
| ||
19:07 | periodic update check-in: f7c93df9f4 user: lexi tags: trunk | |
2023-04-15
| ||
20:47 | add generic routines from vesper check-in: 0894d03fbf user: lexi tags: trunk | |
2023-04-13
| ||
07:26 | relicense to EUPL check-in: 0f5a51907d user: lexi tags: trunk | |
Changes
Added clib/buffer.c version [a88ca60244].
1 +#include "buffer.h" 2 +#include <string.h> 3 +#include <stdlib.h> 4 + 5 +void buffer_init(buffer* b) { 6 + *b = (buffer) { 7 + .sz = 0, 8 + .run = 256, 9 + }; 10 + b -> ptr = malloc(b -> run); 11 +} 12 + 13 +buffer buffer_mk() { buffer b; buffer_init(&b); return b; } 14 + 15 +void buffer_push(buffer* b, strp const data) { 16 + size_t run = b->run; 17 + while (b -> sz + data.sz > run) run *= 2; 18 + if (run != b->run) { 19 + b->ptr = realloc(b->ptr, run); 20 + b->run = run; 21 + } 22 + memcpy(&b->ptr[b->sz], data.ptr, data.sz); 23 + b->sz += data.sz; 24 +} 25 + 26 +strp buffer_crush(buffer* b, size_t max) { 27 + if (b->run>max) { 28 + b->run = max; 29 + if (b->sz > max) { 30 + free(b->ptr); 31 + b->sz = 0; 32 + b->ptr = malloc(b->run); 33 + } else { 34 + b->ptr = realloc(b->ptr, b->run); 35 + } 36 + } 37 + return (strp){b->sz, b->ptr}; 38 +} 39 + 40 +size_t buffer_pushs(buffer* b, char const* data) { 41 + size_t len = strlen(data); 42 + buffer_push(b, (strp){len, .cptr = data}); 43 + return len; 44 +} 45 + 46 +void buffer_clear(buffer* b) { 47 + b -> sz = 0; 48 +}
Added clib/buffer.h version [97b258e329].
1 +#pragma once 2 +#include "type.h" 3 + 4 +typedef struct buffer { 5 + size_t sz, run; 6 + char* ptr; 7 +} buffer; 8 + 9 +void buffer_init(buffer* b); 10 +buffer buffer_mk(); 11 +void buffer_push(buffer* b, strp const data); 12 +strp buffer_crush(buffer* b, size_t max); 13 +size_t buffer_pushs(buffer* b, char const* data); 14 +#define buffer_pushl(b, d) (buffer_push(b, (strp){sizeof(d),(d)})) 15 +void buffer_clear(buffer* b);
Added clib/map.c version [f74e4bde0b].
1 +#include "map.h" 2 +#include <stdlib.h> 3 + 4 +map* mapNew(size_t init_sz) { 5 + map* m = malloc( 6 + sizeof(map) + 7 + sizeof(mapBox)*init_sz 8 + ); 9 + m -> sz = init_sz; 10 + m -> dtor = nullptr; 11 + for (size_t i = 0; i < init_sz; ++i) 12 + m -> boxes[i] = (mapBox) {}; 13 + //m -> weak = false; 14 + return m; 15 +} 16 + 17 +mapBox* mapBoxFor(map* m, strp key) { 18 + hash h = hashNew(key); 19 + return &m->boxes[h % (hash)m->sz]; 20 +} 21 + 22 +void mapBoxInsert(mapBox* b, mapLink* l) { 23 + l -> next = nullptr; 24 + l -> prev = b -> tail; 25 + 26 + if (b -> tail == nullptr) { 27 + b -> head = b -> tail = l; 28 + } else { 29 + b -> tail -> next = l; 30 + b -> tail = l; 31 + } 32 +} 33 + 34 +mapLink* mapEnter(map* m, strp key, mapValue val) { 35 + mapResult r = mapFind(m, key); 36 + if (r.link) { 37 + return r.link; 38 + } else { 39 + mapBox* b = r.box; 40 + mapLink* l = malloc(sizeof(mapLink) + key.sz); 41 + l -> ref = val; 42 + strMov(&l -> key, key); 43 + mapBoxInsert(b, l); 44 + //if(!m->weak) vspRef(val); 45 + return nullptr; 46 + } 47 +} 48 + 49 +bool mapClobber(map* m, strp key, mapValue val, void (*dtor)(mapValue)) { 50 + mapLink* link = mapEnter(m, key, val); 51 + if (link) { 52 + if (!dtor) dtor = m -> dtor; 53 + if (dtor) (*dtor)(link -> ref); 54 + link -> ref = val; 55 + return true; 56 + } 57 + return false; 58 +} 59 + 60 +mapResult mapFind(map* m, strp key) { 61 + mapBox* b = mapBoxFor(m, key); 62 + for(mapLink* l = b -> head; l != nullptr;) { 63 + if(strEq(strRef(&l->key), key)) { 64 + return (mapResult) { 65 + .map = m, 66 + .box = b, 67 + .link = l, 68 + }; 69 + } 70 + } 71 + return (mapResult){.map = m, .box = b}; 72 +} 73 +mapValue mapRef(map* m, strp key) { 74 + mapResult r = mapFind(m, key); 75 + if (r.link == nullptr) return mapValue_null; 76 + return r.link -> ref; 77 +} 78 +void mapErase(map* m, strp key) { 79 + mapResult r = mapFind(m, key); 80 + if (r.link -> prev) r.link -> prev -> next = r.link -> next; 81 + if (r.link -> next) r.link -> next -> prev = r.link -> prev; 82 + if (r.box -> head == r.link) r.box -> head = r.link -> next; 83 + if (r.box -> tail == r.link) r.box -> tail = r.link -> prev; 84 + //if (!m -> weak) vspUnref(r.link -> ref); 85 + free(r.link); 86 +} 87 +map* mapDel(map* m) { 88 + for (size_t i = 0; i < m -> sz; ++i) { 89 + mapBox* b = &m->boxes[i]; 90 + if (b -> head == nullptr) continue; 91 + for(mapLink* l = b -> head; l != nullptr;) { 92 + mapLink* next = l -> next; 93 + //if(!m->weak) vspUnref(l->ref); 94 + free(l); 95 + l = next; 96 + } 97 + } 98 + free(m); 99 +} 100 + 101 +map* mapResize(map* om, size_t newsz) { 102 + /* expensive!! */ 103 + map* nm = mapNew(newsz); 104 + //nm -> weak = om -> weak; 105 + for (size_t i = 0; i < om -> sz; ++i) { 106 + mapBox* b = &om->boxes[i]; 107 + if (b -> head == nullptr) continue; 108 + for(mapLink* l = b -> head; l != nullptr;) { 109 + mapBox* nb = mapBoxFor(nm, strRef(&l->key)); 110 + mapBoxInsert(nb, l); 111 + } 112 + } 113 + free(om); 114 + return nm; 115 +} 116 + 117 +static bool mapEqPredicate(mapValue a, void* b) { 118 + return a.ip = ((mapValue*)b) -> ip; /* real fucky */ 119 +} 120 + 121 +mapResult mapRFindPred(map* m, void* val, mapPredicate p) { 122 + for (size_t i = 0; i < m->sz; ++ i) { 123 + mapBox* b = &m -> boxes[i]; 124 + if (b -> head == nullptr) continue; 125 + for (mapLink* l = b -> head; l != nullptr; l = l -> next) { 126 + if ((*p)(l->ref, val)) return (mapResult) { 127 + .map = m, 128 + .box = b, 129 + .link = l, 130 + }; 131 + } 132 + } 133 + return (mapResult) {m}; 134 +} 135 + 136 +mapResult mapRFind(map* m, mapValue val) { 137 + return mapRFindPred(m, &val, mapEqPredicate); 138 +} 139 + 140 +strp mapRRefPred(map* m, void* val, mapPredicate p) { 141 + mapResult r = mapRFindPred(m, val, p); 142 + if (r.link == nullptr) return (strp){}; 143 + return strRef(&r.link -> key); 144 +} 145 + 146 +strp mapRRef(map* m, mapValue val) { 147 + return mapRRefPred(m, &val, mapEqPredicate); 148 +}
Added clib/map.h version [36b154fb5a].
1 +#pragma once 2 +#include "type.h" 3 +#define mapValue_null ((mapValue){.p=nullptr}) 4 + 5 +#ifndef _mapValue_size 6 +#define _mapValue_size ( \ 7 + sizeof(intmax_t) > sizeof(double) ? \ 8 + sizeof(intmax_t) : sizeof(double) \ 9 +) 10 +#endif 11 + 12 +typedef union mapValue { 13 + /* ensure proper alignment & offer convenience 14 + * handles for punning */ 15 + size_t sz; 16 + ptrdiff_t ofs; 17 + intptr_t ip; 18 + uintmax_t u; 19 + intmax_t s; 20 + double d; 21 + void * p; void const* p_ro; 22 + char * str; char const* str_ro; 23 + uint8_t* bytes; uint8_t const* bytes_ro; 24 + /* maps can pack very small structures directly into 25 + * the entry. if you use this feature, either define 26 + * _mapValue_size as a project global yourself, or 27 + * check to make sure your values fit into it on a 28 + * given architecture. i think this is guaranteed 29 + * to have at least 8 bytes of space (64-types are 30 + * mandated as of C11, possibly earleir?) but i'm 31 + * not 100% on that.*/ 32 + char str_pak [_mapValue_size]; 33 + uint8_t bytes_pak [_mapValue_size]; 34 +} mapValue; 35 + 36 +typedef struct mapLink { 37 + struct mapLink* next, * prev; 38 + mapValue ref; 39 + strv key; 40 +} mapLink; 41 + 42 +typedef struct mapBox { 43 + mapLink* head, * tail; 44 +} mapBox; 45 + 46 +typedef typeof(bool (*)(mapValue, void*)) mapPredicate; 47 +typedef typeof(void (*)(mapValue)) mapDTor; 48 + 49 +typedef struct map { 50 + size_t sz; 51 + //bool weak; 52 + mapDTor dtor; 53 + mapBox boxes []; 54 +} map; 55 + 56 +typedef struct mapResult { 57 + map* map; 58 + mapBox* box; 59 + mapLink* link; 60 +} mapResult; 61 + 62 + 63 +map* mapNew(size_t init_sz); 64 +mapBox* mapBoxFor(map* map, strp key); 65 +void mapBoxInsert(mapBox* b, mapLink* l); 66 +mapLink* mapEnter(map* m, strp key, mapValue val); 67 +bool mapClobber(map* m, strp key, mapValue val, mapDTor dtor); 68 +mapResult mapFind(map* map, strp key); 69 +mapValue mapRef(map* m, strp key); 70 +mapResult mapRFindPred(map* map, void* arg, mapPredicate match); 71 +mapResult mapRFind(map* m, mapValue val); 72 +strp mapRRefPred(map* m, void* val, mapPredicate p); 73 +strp mapRRef(map* m, mapValue val); 74 +void mapErase(map* map, strp key); 75 +map* mapDel(map* map); 76 +map* mapResize(map* map, size_t newsz);
Added clib/say.c version [84789a032f].
1 +#include "say.h" 2 + 3 +#ifdef __has_include 4 +# if __has_include(<unistd.h>) 5 +# define _say_use_ansi 6 +# define _say_use_fd 7 +# endif 8 +#elif defined(__unix__) || defined(__linux__) || defined(__unix) 9 +# define _say_use_ansi 10 +# define _say_use_fd 11 +#endif 12 + 13 +#ifdef _say_use_fd 14 +# include <unistd.h> 15 +#endif 16 + 17 +static void buffer_pushm 18 +( buffer* buf, 19 + uintmax_t val, 20 + bool neg, 21 + uint8_t base, 22 + bool ucase 23 +) { 24 + char nb [48] = {}; 25 + size_t digit = 48; 26 + do { 27 + uintmax_t v = val%base; 28 + if (v < 0xa) { 29 + nb[-- digit] = '0' + v; 30 + } else { 31 + if (base <= 36) { 32 + nb[-- digit] = (ucase?'A':'a') + v - 10; 33 + } else { 34 + if (v<36) nb[-- digit] = 'a' + v - 10; 35 + else nb[-- digit] = 'A' + v - 36; 36 + } 37 + } 38 + val /= base; 39 + } while(val > 0); 40 + if (neg) nb[-- digit] = '-'; 41 + buffer_push(buf, (strp){(sizeof nb) - digit, &nb[digit]}); 42 +} 43 + 44 +size_t saybuf(buffer* buf, FILE* dest, const char* fmt, say_arg* args) { 45 + say_arg const* arg = args; 46 +# ifdef _say_use_fd 47 + bool rich = dest == nullptr? true : isatty(fileno(dest)); 48 +# elif defined(_say_use_ansi) 49 + bool const rich = true; 50 +# endif 51 + 52 +# define pushraw(s) do{if(canPrint)buffer_pushl(buf, s);}while(0) 53 +# define pushcond(ch, won, woff) \ 54 + case ch: if (on) pushraw(won); else pushraw(woff); break 55 +# define ansisw(ch, num) pushcond(ch, "\x1b[" #num "m", "\x1b[2" #num "m") 56 +# define ansiclr(ch, num) \ 57 + case (ch) : pushraw("\x1b[3" #num "m"); break; \ 58 + case (ch)-0x20: pushraw("\x1b[4" #num "m"); break; \ 59 + 60 + uint8_t base = 10; 61 + enum {normal, only_when_rich, only_when_plain, silent} exclude = normal; 62 + for (size_t i = 0; fmt[i] != 0; ++i) { 63 + char m = fmt[i]; 64 + char n = fmt[i+1]; 65 + bool canPrint; 66 + switch (exclude) { 67 + case normal: canPrint = true; break; 68 + case silent: canPrint = false; break; 69 + case only_when_rich: 70 +# ifdef _say_use_ansi 71 + canPrint = rich; 72 +# else 73 + canPrint = false; 74 +# endif 75 + break; 76 + case only_when_plain: 77 +# ifdef _say_use_ansi 78 + canPrint = !rich; 79 +# else 80 + canPrint = true; 81 +# endif 82 + break; 83 + } 84 + if (n == 0) goto push; /* prevent bugs on broken seqs */ 85 + if (m == '[') { 86 + bool on = true; 87 + size_t param = 0; 88 + while((m=fmt[++i]) != ']') { 89 +# ifdef _say_use_ansi 90 + if (rich) { 91 + switch(m) { 92 + case '+': on = true; break; 93 + case '-': on = false; break; 94 + case '=': pushraw("\x1b[m"); break; 95 + 96 + ansisw('e', 1); ansisw('d', 2); 97 + ansisw('i', 3); ansisw('u', 4); 98 + ansisw('h', 7); 99 + 100 + ansiclr('k', 0); ansiclr('r', 1); 101 + ansiclr('g', 2); ansiclr('y', 3); 102 + ansiclr('b', 4); ansiclr('p', 5); 103 + ansiclr('c', 6); ansiclr('w', 7); 104 + ansiclr('x', 9); 105 + 106 + case 'L': pushraw("\x1b[2J"); 107 + default: goto fallback; 108 + } 109 + continue; 110 + } 111 +# endif 112 + 113 + fallback: switch (m) { 114 + case '^': exclude = only_when_rich; break; 115 + case '~': exclude = only_when_plain; break; 116 + case '|': exclude = normal; break; 117 + case '#': exclude = silent; break; 118 + case '?': exclude = *((bool*)*(arg++)) ? normal : silent; break; 119 + case '@': base = param; param = 0; break; 120 + case '$': arg = args[param]; param = 0; break; 121 + default: goto enter_param; 122 + } continue; 123 + 124 + enter_param: if (m >= '0' && m <= '9') { 125 + param *= 10; 126 + param += m - '0'; 127 + } 128 + } 129 + } else if (m == '%') { 130 + ++i; 131 + switch (n) { 132 + case '[': m = '['; 133 + case '%': goto push; 134 + case 'z': { 135 + char const* str = (char const*)*(arg++); 136 + if (canPrint) { 137 + if (str == nullptr) buffer_pushs(buf, "<null>"); 138 + else buffer_pushs(buf, str); 139 + } 140 + break; 141 + } 142 + case 's': { 143 + strp const* a = *(arg++); 144 + if (a -> ptr == nullptr) buffer_pushs(buf, "<null>"); 145 + else buffer_push(buf, *a); 146 + break; 147 + } 148 + case 'i': case 'I': 149 + case 'u': case 'U': { 150 + bool neg=false; uintmax_t mag; 151 + if (n=='i') { 152 + intmax_t s = *((intmax_t*)*(arg++)); 153 + if (s < 0) { mag = -s; neg = true; } 154 + else mag = s; 155 + } else mag = *((uintmax_t*)*(arg++)); 156 + buffer_pushm(buf, mag, neg, base, n < 'a'); 157 + break; 158 + } 159 + case 'f': case 'F': {// fraction 160 + fraction f = *((fraction*)*(arg++)); 161 + buffer_pushm(buf, fractionNum(f), fractionNeg(f), base, n<'a'); 162 + buffer_pushs(buf, "/"); 163 + buffer_pushm(buf, fractionDenom(f), false, base, n<'a'); 164 + } break; 165 + case 'x': case 'X': {// fixed 166 + fixed f = *((fixed*)*(arg++)); 167 + bool neg = fixedVal(f) < 0; 168 + f = fixedAbs(f); 169 + buffer_pushm(buf, fixedIntPart(f), neg, base, n<'a'); 170 + uint32_t fracpt = fixedFracPart(f); 171 + if (fracpt != 0) { 172 + intmax_t mul = base; 173 + /* find prec multiplicand */ 174 + while (mul < fixedPrec(f)) { 175 + if (mul * base < mul) { 176 + buffer_pushs(buf, "<fixed-point precision error>"); 177 + break; 178 + } 179 + mul *= base; 180 + } 181 + uintmax_t r = ((intmax_t)fracpt * mul*mul) / ((intmax_t)fixedPrec(f)*mul); 182 + buffer_pushs(buf, "."); 183 + buffer_pushm(buf, r, false, base, n<'a'); 184 + } 185 + } break; 186 + case 'n': case 'N': {// inexact 187 + } break; 188 + case '~': { 189 + char const* subfmt = (char const*)*(arg++); 190 + say_arg* subargs = (say_arg*)*(arg++); 191 + saybuf(buf, dest, subfmt, subargs); 192 + break; 193 + } 194 + } 195 + } else goto push; 196 + continue; 197 + 198 + push: if (canPrint) buffer_push(buf, (strp){1, &m}); 199 + } 200 + return arg - args; 201 +# undef ansiclr 202 +# undef ansisw 203 +# undef pushcond 204 +# undef pushraw 205 +} 206 + 207 +static inline void 208 +sayprep(FILE* dest) { 209 +# ifndef _say_use_fd 210 + setvbuf(dest, nullptr, _IONBF, 0); // hax 211 +# endif 212 +} 213 + 214 +void sayto(FILE* dest, char const* fmt, say_arg* args) { 215 + static _Thread_local buffer buf = {}; 216 + if (buf.run == 0) buffer_init(&buf); 217 + else buf.sz = 0; 218 + 219 + saybuf(&buf, dest, fmt, args); 220 + 221 +# ifdef _say_use_fd 222 + write(fileno(dest), buf.ptr, buf.sz); 223 +# else 224 + fprintf(dest, "%.*s", (int)buf.sz, buf.ptr); 225 +# endif 226 + buffer_crush(&buf, 2048); 227 +} 228 + 229 +void say(char const* fmt, say_arg* args) { 230 + static bool stprep = false; 231 + if (!stprep) { stprep=true; sayprep(stderr); }; 232 + sayto(stderr, fmt, args); 233 +}
Added clib/say.h version [229d1e6ce9].
1 +#pragma once 2 +#include <stdio.h> 3 +#include "type.h" 4 +#include "buffer.h" 5 +typedef void const* say_arg; 6 +typedef typeof(say_arg[]) saylist; 7 +size_t saybuf(buffer* buf, FILE* dest, const char* fmt, say_arg* args); 8 +void sayto(FILE* dest, char const* fmt, say_arg* args); 9 +void say(const char* fmt, say_arg* args);