#pragma once /* Usage: Start with MAKE_MUT(name, itemAmount); MAKE_MUT allocates the object on the stack, so everything must happen within the scope of it. Optionally, call mut_init(name, el_something) with an appropriate ElType. End with mut_f(v|c|cd|p); There must be no allocations while a mut object is being built so GC doesn't do bad things. mut_pfree must be used to free a partially finished `mut` instance safely (e.g. before throwing an error). Methods ending with G expect that mut_init has been called with a type that can fit the elements that it'll set, and MUTG_INIT afterwards in the same scope. */ typedef struct Mut Mut; typedef struct MutFns MutFns; typedef void (*M_CopyF)(void*, usz, B, usz, usz); typedef void (*M_FillF)(void*, usz, B, usz); typedef void (*M_SetF)(void*, usz, B); typedef B (*M_GetF)(Mut*, usz); struct MutFns { u8 elType; u8 valType; M_CopyF m_copy, m_copyG; M_FillF m_fill, m_fillG; M_SetF m_set, m_setG; M_GetF m_getU; }; extern MutFns mutFns[el_MAX+1]; struct Mut { MutFns* fns; usz ia; Arr* val; union { void* a; B* aB; i8* ai8; i16* ai16; i32* ai32; u8* ac8; u16* ac16; u32* ac32; f64* af64; u64* abit; }; }; #define MAKE_MUT(N, IA) Mut N##_val; N##_val.fns = &mutFns[el_MAX]; N##_val.ia = (IA); Mut* N = &N##_val; static void mut_init(Mut* m, u8 n) { m->fns = &mutFns[n]; usz ia = m->ia; usz sz; // hack around inlining of the allocator too many times switch(n) { default: UD; case el_bit: sz = BITARR_SZ( ia); break; case el_i8: case el_c8: sz = TYARR_SZ(I8, ia); break; case el_i16: case el_c16: sz = TYARR_SZ(I16,ia); break; case el_i32: case el_c32: sz = TYARR_SZ(I32,ia); break; case el_f64: sz = TYARR_SZ(F64,ia); break; case el_B:; HArr_p t = m_harrUp(ia); m->val = (Arr*)t.c; m->aB = t.c->a; return; } Arr* a = m_arr(sz, m->fns->valType, ia); m->val = a; m->a = ((TyArr*)a)->a; } void mut_to(Mut* m, u8 n); static B mut_fv(Mut* m) { assert(m->fns->elType!=el_MAX); Arr* a = m->val; a->sh = &a->ia; sprnk(a, 1); return taga(a); } static B mut_fc(Mut* m, B x) { assert(m->fns->elType!=el_MAX); Arr* a = m->val; arr_shCopy(a, x); return taga(a); } static B mut_fcd(Mut* m, B x) { assert(m->fns->elType!=el_MAX); Arr* a = m->val; arr_shCopy(a, x); decG(x); return taga(a); } static Arr* mut_fp(Mut* m) { assert(m->fns->elType!=el_MAX); return m->val; } extern u8 el_orArr[]; static u8 el_or(u8 a, u8 b) { return el_orArr[a*16 + b]; } void mut_pfree(Mut* m, usz n); // consumes x; sets m[ms] to x static void mut_set(Mut* m, usz ms, B x) { m->fns->m_set(m, ms, x); } // clears the object (decrements its refcount) at position ms static void mut_rm(Mut* m, usz ms) { if (m->fns->elType == el_B) dec(m->aB[ms]); } // gets object at position ms, without increasing refcount static B mut_getU(Mut* m, usz ms) { return m->fns->m_getU(m, ms); } // doesn't consume; fills m[ms…ms+l] with x static void mut_fill(Mut* m, usz ms, B x, usz l) { m->fns->m_fill(m, ms, x, l); } // expects x to be an array, each position must be written to precisely once // doesn't consume static void mut_copy(Mut* m, usz ms, B x, usz xs, usz l) { assert(isArr(x)); m->fns->m_copy(m, ms, x, xs, l); } #define MUTG_INIT(N) MutFns N##_mutfns = *N->fns; void* N##_mutarr = N->a // // mut_set but assumes the type of x already fits in m #define mut_setG(N, ms, x) N##_mutfns.m_setG(N##_mutarr, ms, x) // // mut_fill but assumes the type of x already fits in m #define mut_fillG(N, ms, x, l) N##_mutfns.m_fillG(N##_mutarr, ms, x, l) // // mut_copy but assumes the type of x already fits in m #define mut_copyG(N, ms, x, xs, l) N##_mutfns.m_copyG(N##_mutarr, ms, x, xs, l) static void bit_cpy(u64* r, usz rs, u64* x, usz xs, usz l) { u64 re = rs+(u64)l; i64 d = (i64)xs-(i64)rs; u64 ti = rs>>6; u64 ei = re>>6; i64 dp = d>>6; u64 df = ((u64)d)&63u; #define RDF0 x[ti+dp] #define RDFp ((x[ti+dp] >> df) | (x[ti+dp+1] << (64-df))) #define READ (df==0? RDF0 : RDFp) if (ti!=ei) { if (rs&63) { u64 m = (1ULL << (rs&63))-1; r[ti] = (READ & ~m) | (r[ti] & m); ti++; } if (df==0) for (; tiia; usz xia = a(x)->ia; usz ria = wia+xia; if (reusable(w)) { u64 wsz = mm_size(v(w)); u8 wt = v(w)->type; // TODO f64∾i32, i32∾i8, c32∾c8 etc switch (wt) { case t_bitarr: if (BITARR_SZ( ria)ia=ria; bit_cpy(bitarr_ptr(w),wia,bitarr_ptr(x),0,xia); decG(x); return FL_KEEP(w,fl_squoze); } break; case t_i8arr: if (TYARR_SZ(I8, ria)ia=ria; memcpy(i8arr_ptr (w)+wia, i8any_ptr (x), xia*1); decG(x); return FL_KEEP(w,fl_squoze); } break; case t_i16arr: if (TYARR_SZ(I16,ria)ia=ria; memcpy(i16arr_ptr(w)+wia, i16any_ptr(x), xia*2); decG(x); return FL_KEEP(w,fl_squoze); } break; case t_i32arr: if (TYARR_SZ(I32,ria)ia=ria; memcpy(i32arr_ptr(w)+wia, i32any_ptr(x), xia*4); decG(x); return FL_KEEP(w,fl_squoze); } break; case t_c8arr: if (TYARR_SZ(C8, ria)ia=ria; memcpy(c8arr_ptr (w)+wia, c8any_ptr (x), xia*1); decG(x); return FL_KEEP(w,fl_squoze); } break; case t_c16arr: if (TYARR_SZ(C16,ria)ia=ria; memcpy(c16arr_ptr(w)+wia, c16any_ptr(x), xia*2); decG(x); return FL_KEEP(w,fl_squoze); } break; case t_c32arr: if (TYARR_SZ(C32,ria)ia=ria; memcpy(c32arr_ptr(w)+wia, c32any_ptr(x), xia*4); decG(x); return FL_KEEP(w,fl_squoze); } break; case t_f64arr: if (TYARR_SZ(F64,ria)ia=ria; memcpy(f64arr_ptr(w)+wia, f64any_ptr(x), xia*8); decG(x); return FL_KEEP(w,fl_squoze); } break; case t_harr: if (fsizeof(HArr,a,B,ria)ia = ria; B* rp = harr_ptr(w)+wia; B* xpB = arr_bptr(x); if (xpB!=NULL) { memcpy(rp, xpB, xia*sizeof(B)); for (usz i = 0; i < xia; i++) inc(rp[i]); } else { switch(TI(x,elType)) { case el_i8: { i8* xp=i8any_ptr (x); for (usz i=0; iia; usz ria = wia+1; if (reusable(w)) { u64 wsz = mm_size(v(w)); u8 wt = v(w)->type; switch (wt) { case t_bitarr: if (BITARR_SZ( ria)ia=ria; bitp_set(bitarr_ptr(w),wia,o2bu(x)); return true; } break; case t_i8arr: if (TYARR_SZ(I8, ria)ia=ria; i8arr_ptr (w)[wia]=o2iu(x); return true; } break; case t_i16arr: if (TYARR_SZ(I16,ria)ia=ria; i16arr_ptr(w)[wia]=o2iu(x); return true; } break; case t_i32arr: if (TYARR_SZ(I32,ria)ia=ria; i32arr_ptr(w)[wia]=o2iu(x); return true; } break; case t_c8arr: if (TYARR_SZ(C8, ria)ia=ria; c8arr_ptr (w)[wia]=o2cu(x); return true; } break; case t_c16arr: if (TYARR_SZ(C16,ria)ia=ria; c16arr_ptr(w)[wia]=o2cu(x); return true; } break; case t_c32arr: if (TYARR_SZ(C32,ria)ia=ria; c32arr_ptr(w)[wia]=o2cu(x); return true; } break; case t_f64arr: if (TYARR_SZ(F64,ria)ia=ria; f64arr_ptr(w)[wia]=o2fu(x); return true; } break; case t_harr: if (fsizeof(HArr,a,B,ria)ia = ria; harr_ptr(w)[wia] = x; return true; } break; } } return false; } B vec_addF(B w, B x); B vec_addN(B w, B x); // vec_add but not inlined static B vec_add(B w, B x) { // consumes both; fills may be wrong if (inplace_add(w, x)) return w; return vec_addF(w, x); }