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