diff --git a/src/builtins/sfns.c b/src/builtins/sfns.c index 7b471d1d..7c6dfcad 100644 --- a/src/builtins/sfns.c +++ b/src/builtins/sfns.c @@ -12,7 +12,7 @@ static Arr* take_impl(usz ria, B x) { // consumes x; returns v↑⥊𝕩 without mut_copyG(r, 0, x, 0, xia); mut_fill(r, xia, xf, ria-xia); dec(x); - if (r->type!=el_B) { dec(xf); return mut_fp(r); } + if (r->fns->elType!=el_B) { dec(xf); return mut_fp(r); } return a(withFill(mut_fv(r), xf)); } else { return TI(x,slice)(x,0,ria); @@ -1296,7 +1296,7 @@ B slash_ucw(B t, B o, B w, B x) { if (a(w)->type == t_bitarr) { u64* d = bitarr_ptr(w); if (TI(x,elType)<=el_i32 && TI(rep,elType)<=el_i32) { - if (r->type!=el_i32) mut_to(r, el_i32); + if (r->fns->elType!=el_i32) mut_to(r, el_i32); i32* rp = r->ai32; x = toI32Any(x); i32* xp = i32any_ptr(x); rep = toI32Any(rep); i32* np = i32any_ptr(rep); diff --git a/src/utils/mut.c b/src/utils/mut.c index e80a0fa9..8fe3023b 100644 --- a/src/utils/mut.c +++ b/src/utils/mut.c @@ -1,78 +1,13 @@ #include "../core.h" #include "mut.h" -void mut_copyG(Mut* m, usz ms, B x, usz xs, usz l) { assert(isArr(x)); - // printf("mut_%d[%d…%d] ← %s[%d…%d]\n", m->type, ms, ms+l, type_repr(xt), xs, xs+l); fflush(stdout); - u8 xt = v(x)->type; - switch(m->type) { default: UD; - case el_bit: bit_cpy(m->abit, ms, bitarr_ptr(x), xs, l); return; - case el_i8: { i8* rp = m->ai8+ms; - switch (xt) { default: UD; - case t_bitarr: { u64* xp = bitarr_ptr(x); for (usz i = 0; i < l; i++) rp[i] = bitp_get(xp, xs+i); return; } - case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - } - } - case el_i16: { i16* rp = m->ai16+ms; - switch (xt) { default: UD; - case t_bitarr: { u64* xp = bitarr_ptr(x); for (usz i = 0; i < l; i++) rp[i] = bitp_get(xp, xs+i); return; } - case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - } - } - case el_i32: { i32* rp = m->ai32+ms; - switch (xt) { default: UD; - case t_bitarr: { u64* xp = bitarr_ptr(x); for (usz i = 0; i < l; i++) rp[i] = bitp_get(xp, xs+i); return; } - case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_i32arr: case t_i32slice: { i32* xp = i32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - } - } - case el_f64: { - f64* rp = m->af64+ms; - switch (xt) { default: UD; - case t_bitarr: { u64* xp = bitarr_ptr(x); for (usz i = 0; i < l; i++) rp[i] = bitp_get(xp, xs+i); return; } - case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_i32arr: case t_i32slice: { i32* xp = i32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_f64arr: case t_f64slice: { f64* xp = f64any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - } - } - case el_c8: { u8* rp = m->ac8+ms; u8* xp = c8any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case el_c16: { u16* rp = m->ac16+ms; - switch (xt) { default: UD; - case t_c8arr: case t_c8slice: { u8* xp = c8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_c16arr: case t_c16slice: { u16* xp = c16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - } - } - case el_c32: { u32* rp = m->ac32+ms; - switch (xt) { default: UD; - case t_c8arr: case t_c8slice: { u8* xp = c8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_c16arr: case t_c16slice: { u16* xp = c16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - case t_c32arr: case t_c32slice: { u32* xp = c32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } - } - } - case el_B: { - B* mpo = m->aB+ms; - B* xp = arr_bptr(x); - if (xp!=NULL) { - memcpy(mpo, xp+xs, l*sizeof(B)); - for (usz i = 0; i < l; i++) inc(mpo[i]); - return; - } - SGet(x) - for (usz i = 0; i < l; i++) mpo[i] = Get(x,i+xs); - return; - } - } -} - NOINLINE void mut_to(Mut* m, u8 n) { - u8 o = m->type; + u8 o = m->fns->elType; assert(o!=el_B); if (o==el_MAX) { mut_init(m, n); } else { - m->type = n; + m->fns = &mutFns[n]; sprnk(m->val, 1); m->val->sh = &m->val->ia; #ifdef USE_VALGRIND @@ -109,10 +44,139 @@ NOINLINE B vec_addR(B w, B x) { } NOINLINE void mut_pfree(Mut* m, usz n) { // free the first n elements - if (m->type==el_B) harr_pfree(taga(m->val), n); + if (m->fns->elType==el_B) harr_pfree(taga(m->val), n); else mm_free((Value*) m->val); } + +B vec_join(B w, B x) { + return vec_join_inline(w, x); +} + + + +#define CHK(REQ,NEL,N,...) if (!(REQ)) mut_to(m, NEL); m->fns->m_##N##G(m, __VA_ARGS__); +#define CHK_S(REQ,X,N,...) CHK(REQ, el_or(m->fns->elType, selfElType(X)), N, __VA_ARGS__) + + +#define DEF(RT, N, TY, INIT, CHK, EL, ARGS, ...) \ + static RT m_##N##G_##TY ARGS; \ + static RT m_##N##_##TY ARGS { INIT \ + if (RARE(!(CHK))) { \ + mut_to(m, EL); \ + m->fns->m_##N##G(m, __VA_ARGS__); \ + } else { \ + m_##N##G_##TY(m, __VA_ARGS__); \ + } \ + } \ + static RT m_##N##G_##TY ARGS + +#define DEF_S( RT, N, TY, CHK, X, ARGS, ...) DEF(RT, N, TY, , CHK, selfElType(X), ARGS, __VA_ARGS__) +#define DEF_E( RT, N, TY, CHK, X, ARGS, ...) DEF(RT, N, TY, , CHK, TI(X,elType), ARGS, __VA_ARGS__) +#define DEF_G( RT, N, TY, ARGS ) \ + static RT m_##N##G_##TY ARGS; \ + static RT (*m_##N##_##TY) ARGS = m_##N##G_##TY; \ + static RT m_##N##G_##TY ARGS + +DEF_S(void, set, MAX, false, x, (Mut* m, usz ms, B x), ms, x) { err("m_setG_MAX"); } +DEF_S(void, set, bit, q_bit(x), x, (Mut* m, usz ms, B x), ms, x) { bitp_set(m->abit, ms, o2bu(x)); } +DEF_S(void, set, i8, q_i8 (x), x, (Mut* m, usz ms, B x), ms, x) { m->ai8 [ms] = o2iu(x); } +DEF_S(void, set, i16, q_i16(x), x, (Mut* m, usz ms, B x), ms, x) { m->ai16[ms] = o2iu(x); } +DEF_S(void, set, i32, q_i32(x), x, (Mut* m, usz ms, B x), ms, x) { m->ai32[ms] = o2iu(x); } +DEF_S(void, set, c8, q_c8 (x), x, (Mut* m, usz ms, B x), ms, x) { m->ac8 [ms] = o2cu(x); } +DEF_S(void, set, c16, q_c16(x), x, (Mut* m, usz ms, B x), ms, x) { m->ac16[ms] = o2cu(x); } +DEF_S(void, set, c32, q_c32(x), x, (Mut* m, usz ms, B x), ms, x) { m->ac32[ms] = o2cu(x); } +DEF_S(void, set, f64, q_f64(x), x, (Mut* m, usz ms, B x), ms, x) { m->af64[ms] = o2fu(x); } +DEF_G(void, set, B, (Mut* m, usz ms, B x) ) { m->aB[ms] = x; } + +DEF_S(void, fill, MAX, false, x, (Mut* m, usz ms, B x, usz l), ms, x, l) { err("m_fillG_MAX"); } +DEF_S(void, fill, bit, q_bit(x), x, (Mut* m, usz ms, B x, usz l), ms, x, l) { u64* p = m->abit; bool v = o2bu(x); for (usz i = 0; i < l; i++) bitp_set(p, ms+i, v); } +DEF_S(void, fill, i8 , q_i8 (x), x, (Mut* m, usz ms, B x, usz l), ms, x, l) { i8* p = m->ai8 +ms; i8 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; } +DEF_S(void, fill, i16, q_i16(x), x, (Mut* m, usz ms, B x, usz l), ms, x, l) { i16* p = m->ai16+ms; i16 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; } +DEF_S(void, fill, i32, q_i32(x), x, (Mut* m, usz ms, B x, usz l), ms, x, l) { i32* p = m->ai32+ms; i32 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; } +DEF_S(void, fill, c8 , q_c8 (x), x, (Mut* m, usz ms, B x, usz l), ms, x, l) { u8* p = m->ac8 +ms; u8 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; } +DEF_S(void, fill, c16, q_c16(x), x, (Mut* m, usz ms, B x, usz l), ms, x, l) { u16* p = m->ac16+ms; u16 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; } +DEF_S(void, fill, c32, q_c32(x), x, (Mut* m, usz ms, B x, usz l), ms, x, l) { u32* p = m->ac32+ms; u32 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; } +DEF_S(void, fill, f64, isF64(x), x, (Mut* m, usz ms, B x, usz l), ms, x, l) { f64* p = m->af64+ms; f64 v = o2fu(x); for (usz i = 0; i < l; i++) p[i] = v; } +DEF_G(void, fill, B , (Mut* m, usz ms, B x, usz l) ) { + B* p = m->aB+ms; + for (usz i = 0; i < l; i++) p[i] = x; + if (isVal(x)) for (usz i = 0; i < l; i++) inc(x); + return; +} + +#define DEF_COPY(TY, BODY) DEF(void, copy, TY, u8 xe=TI(x,elType); u8 ne=el_or(xe,el_##TY);, ne==el_##TY, ne, (Mut* m, usz ms, B x, usz xs, usz l), ms, x, xs, l) { u8 xt=v(x)->type; (void)xt; BODY } +DEF_COPY(bit, { bit_cpy(m->abit, ms, bitarr_ptr(x), xs, l); return; }) +DEF_COPY(i8 , { i8* rp = m->ai8+ms; + switch (xt) { default: UD; + case t_bitarr: { u64* xp = bitarr_ptr(x); for (usz i = 0; i < l; i++) rp[i] = bitp_get(xp, xs+i); return; } + case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } +}) +DEF_COPY(i16, { i16* rp = m->ai16+ms; + switch (xt) { default: UD; + case t_bitarr: { u64* xp = bitarr_ptr(x); for (usz i = 0; i < l; i++) rp[i] = bitp_get(xp, xs+i); return; } + case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } +}) +DEF_COPY(i32, { i32* rp = m->ai32+ms; + switch (xt) { default: UD; + case t_bitarr: { u64* xp = bitarr_ptr(x); for (usz i = 0; i < l; i++) rp[i] = bitp_get(xp, xs+i); return; } + case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i32arr: case t_i32slice: { i32* xp = i32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } +}) +DEF_COPY(f64, { f64* rp = m->af64+ms; + switch (xt) { default: UD; + case t_bitarr: { u64* xp = bitarr_ptr(x); for (usz i = 0; i < l; i++) rp[i] = bitp_get(xp, xs+i); return; } + case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i32arr: case t_i32slice: { i32* xp = i32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_f64arr: case t_f64slice: { f64* xp = f64any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } +}) +DEF_COPY(c8 , { u8* rp = m->ac8+ms; u8* xp = c8any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; }) +DEF_COPY(c16, { u16* rp = m->ac16+ms; + switch (xt) { default: UD; + case t_c8arr: case t_c8slice: { u8* xp = c8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_c16arr: case t_c16slice: { u16* xp = c16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } +}) +DEF_COPY(c32, { u32* rp = m->ac32+ms; + switch (xt) { default: UD; + case t_c8arr: case t_c8slice: { u8* xp = c8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_c16arr: case t_c16slice: { u16* xp = c16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_c32arr: case t_c32slice: { u32* xp = c32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } +}) +DEF_E(void, copy, MAX, false, x, (Mut* m, usz ms, B x, usz xs, usz l), ms, x, xs, l) { err("m_copyG_MAX"); } +DEF_G(void, copy, B, (Mut* m, usz ms, B x, usz xs, usz l)) { + B* mpo = m->aB+ms; + B* xp = arr_bptr(x); + if (xp!=NULL) { + memcpy(mpo, xp+xs, l*sizeof(B)); + for (usz i = 0; i < l; i++) inc(mpo[i]); + return; + } + SGet(x) + for (usz i = 0; i < l; i++) mpo[i] = Get(x,i+xs); + return; +} + +static B m_getU_MAX(Mut* m, usz ms) { err("m_setG_MAX"); } +static B m_getU_bit(Mut* m, usz ms) { return m_i32(bitp_get(m->abit, ms)); } +static B m_getU_i8 (Mut* m, usz ms) { return m_i32(m->ai8 [ms]); } +static B m_getU_i16(Mut* m, usz ms) { return m_i32(m->ai16[ms]); } +static B m_getU_i32(Mut* m, usz ms) { return m_i32(m->ai32[ms]); } +static B m_getU_c8 (Mut* m, usz ms) { return m_c32(m->ac8 [ms]); } +static B m_getU_c16(Mut* m, usz ms) { return m_c32(m->ac16[ms]); } +static B m_getU_c32(Mut* m, usz ms) { return m_c32(m->ac32[ms]); } +static B m_getU_f64(Mut* m, usz ms) { return m_f64(m->af64[ms]); } +static B m_getU_B (Mut* m, usz ms) { return m->aB[ms]; } + +MutFns mutFns[el_MAX+1]; u8 el_orArr[el_MAX*16 + el_MAX+1]; void mutF_init() { for (u8 i = 0; i <= el_MAX; i++) { @@ -125,9 +189,20 @@ void mutF_init() { el_orArr[i*16 + j] = el; } } + #define FOR_TY(A) A(MAX) A(bit) A(i8) A(i16) A(i32) A(c8) A(c16) A(c32) A(f64) A(B) + #define F(T,N) mutFns[el_##T].m_##N = m_##N##_##T; + #define G(T) F(T,set) F(T,setG) F(T,getU) F(T,fill) F(T,fillG) F(T,copy) F(T,copyG) + FOR_TY(G) + #undef G + #undef F + mutFns[el_bit].elType = el_bit; mutFns[el_bit].valType = t_bitarr; + mutFns[el_i8 ].elType = el_i8 ; mutFns[el_i8 ].valType = t_i8arr; + mutFns[el_i16].elType = el_i16; mutFns[el_i16].valType = t_i16arr; + mutFns[el_i32].elType = el_i32; mutFns[el_i32].valType = t_i32arr; + mutFns[el_c8 ].elType = el_c8 ; mutFns[el_c8 ].valType = t_c8arr; + mutFns[el_c16].elType = el_c16; mutFns[el_c16].valType = t_c16arr; + mutFns[el_c32].elType = el_c32; mutFns[el_c32].valType = t_c32arr; + mutFns[el_f64].elType = el_f64; mutFns[el_f64].valType = t_f64arr; + mutFns[el_B ].elType = el_B ; mutFns[el_B ].valType = t_harr; + mutFns[el_MAX].elType = el_MAX; mutFns[el_MAX].valType = t_COUNT; } - - -B vec_join(B w, B x) { - return vec_join_inline(w, x); -} \ No newline at end of file diff --git a/src/utils/mut.h b/src/utils/mut.h index 04fa4ee7..3cde61b8 100644 --- a/src/utils/mut.h +++ b/src/utils/mut.h @@ -12,9 +12,27 @@ mut_pfree must be used to free a partially finished `mut` instance safely (e.g. methods ending with G expect that mut_init has been called with a type that can fit the elements that it'll set */ +typedef struct Mut Mut; +typedef struct MutFns MutFns; +typedef void (*MSB2v)(Mut*, usz, B); +typedef void (*MSBS2v)(Mut*, usz, B, usz); +typedef void (*MSBSS2v)(Mut*, usz, B, usz, usz); +typedef B (*MS2B)(Mut*, usz); +struct MutFns { + u8 elType; + u8 valType; + MSB2v m_set; + MSB2v m_setG; + MS2B m_getU; + MSBS2v m_fill; + MSBS2v m_fillG; + MSBSS2v m_copy; + MSBSS2v m_copyG; +}; +extern MutFns mutFns[el_MAX+1]; -typedef struct Mut { - u8 type; +struct Mut { + MutFns* fns; usz ia; Arr* val; union { @@ -23,54 +41,53 @@ typedef struct Mut { u8* ac8; u16* ac16; u32* ac32; f64* af64; u64* abit; }; -} Mut; -#define MAKE_MUT(N, IA) Mut N##_val; N##_val.type = el_MAX; N##_val.ia = (IA); Mut* N = &N##_val; +}; +#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->type = n; + m->fns = &mutFns[n]; usz ia = m->ia; - u8 ty; usz sz; // hack around inlining of the allocator too many times switch(n) { default: UD; - case el_bit: ty = t_bitarr; sz = BITARR_SZ( ia); break; - case el_i8: ty = t_i8arr ; sz = TYARR_SZ(I8, ia); break; - case el_i16: ty = t_i16arr; sz = TYARR_SZ(I16,ia); break; - case el_i32: ty = t_i32arr; sz = TYARR_SZ(I32,ia); break; - case el_c8: ty = t_c8arr ; sz = TYARR_SZ(C8, ia); break; - case el_c16: ty = t_c16arr; sz = TYARR_SZ(C16,ia); break; - case el_c32: ty = t_c32arr; sz = TYARR_SZ(C32,ia); break; - case el_f64: ty = t_f64arr; sz = TYARR_SZ(F64,ia); break; + case el_bit: sz = BITARR_SZ( ia); break; + case el_i8: sz = TYARR_SZ(I8, ia); break; + case el_i16: sz = TYARR_SZ(I16,ia); break; + case el_i32: sz = TYARR_SZ(I32,ia); break; + case el_c8: sz = TYARR_SZ(C8, ia); break; + case el_c16: sz = TYARR_SZ(C16,ia); break; + case el_c32: sz = TYARR_SZ(C32,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, ty, ia); + 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->type!=el_MAX); +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->type!=el_MAX); +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->type!=el_MAX); +static B mut_fcd(Mut* m, B x) { assert(m->fns->elType!=el_MAX); Arr* a = m->val; arr_shCopy(a, x); dec(x); return taga(a); } -static Arr* mut_fp(Mut* m) { assert(m->type!=el_MAX); +static Arr* mut_fp(Mut* m) { assert(m->fns->elType!=el_MAX); return m->val; } @@ -81,85 +98,39 @@ static u8 el_or(u8 a, u8 b) { void mut_pfree(Mut* m, usz n); -static void mut_set(Mut* m, usz ms, B x) { // consumes x; sets m[ms] to x - again:; - switch(m->type) { default: UD; - case el_MAX: goto change; - case el_bit: if (!q_bit(x)) goto change; bitp_set(m->abit, ms, o2bu(x)); return; - case el_i8: if (!q_i8 (x)) goto change; m->ai8 [ms] = o2iu(x); return; - case el_i16: if (!q_i16(x)) goto change; m->ai16[ms] = o2iu(x); return; - case el_i32: if (!q_i32(x)) goto change; m->ai32[ms] = o2iu(x); return; - case el_c8: if (!q_c8 (x)) goto change; m->ac8 [ms] = o2cu(x); return; - case el_c16: if (!q_c16(x)) goto change; m->ac16[ms] = o2cu(x); return; - case el_c32: if (!q_c32(x)) goto change; m->ac32[ms] = o2cu(x); return; - case el_f64: if (!q_f64(x)) goto change; m->af64[ms] = o2fu(x); return; - case el_B: { - m->aB[ms] = x; - return; - } - } - change: - mut_to(m, el_or(m->type, selfElType(x))); - goto again; -} -static void mut_setG(Mut* m, usz ms, B x) { // consumes; sets m[ms] to x, assumes the current type can store it - switch(m->type) { default: UD; - case el_bit: { assert(q_bit(x)); bitp_set(m->abit, ms, o2bu(x)); return; } - case el_i8 : { assert(q_i8 (x)); m->ai8 [ms] = o2iu(x); return; } - case el_i16: { assert(q_i16(x)); m->ai16[ms] = o2iu(x); return; } - case el_i32: { assert(q_i32(x)); m->ai32[ms] = o2iu(x); return; } - case el_c8 : { assert(q_c8 (x)); m->ac8 [ms] = o2cu(x); return; } - case el_c16: { assert(q_c16(x)); m->ac16[ms] = o2cu(x); return; } - case el_c32: { assert(q_c32(x)); m->ac32[ms] = o2cu(x); return; } - case el_f64: { assert(q_f64(x)); m->af64[ms] = o2fu(x); return; } - case el_B: { - m->aB[ms] = x; - return; - } - } -} -static void mut_rm(Mut* m, usz ms) { // clears the object at position ms - if (m->type == el_B) dec(m->aB[ms]); -} -static B mut_getU(Mut* m, usz ms) { - switch(m->type) { default: UD; - case el_bit: return m_i32(bitp_get(m->abit, ms)); - case el_i8: return m_i32(m->ai8 [ms]); - case el_i16: return m_i32(m->ai16[ms]); - case el_i32: return m_i32(m->ai32[ms]); - case el_c8: return m_c32(m->ac8 [ms]); - case el_c16: return m_c32(m->ac16[ms]); - case el_c32: return m_c32(m->ac32[ms]); - case el_f64: return m_f64(m->af64[ms]); - case el_B: return m->aB[ms]; - } -} +// do N = OBJ; F, while asserting that OBJ won't change during F +#define CONST_OP(N, OBJ, F) ({ \ + __auto_type N = OBJ; \ + F; \ + if (N!=OBJ) __builtin_unreachable(); \ +}) + +#define MUTG(NAME, ...) CONST_OP(f, m->fns->m_##NAME##G, f(__VA_ARGS__)) + +// 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); } -static void mut_fillG(Mut* m, usz ms, B x, usz l) { // doesn't consume x - switch(m->type) { default: UD; - case el_bit: { assert(q_bit(x)); u64* p = m->abit; bool v = o2bu(x); for (usz i = 0; i < l; i++) bitp_set(p, ms+i, v); return; } - case el_i8: { assert(q_i8 (x)); i8* p = m->ai8 +ms; i8 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } - case el_i16: { assert(q_i16(x)); i16* p = m->ai16+ms; i16 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } - case el_i32: { assert(q_i32(x)); i32* p = m->ai32+ms; i32 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } - case el_c8: { assert(q_c8 (x)); u8* p = m->ac8 +ms; u8 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } - case el_c16: { assert(q_c16(x)); u16* p = m->ac16+ms; u16 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } - case el_c32: { assert(q_c32(x)); u32* p = m->ac32+ms; u32 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } - case el_f64: { assert(isF64(x)); f64* p = m->af64+ms; f64 v = o2fu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } - case el_B: { - B* p = m->aB+ms; - for (usz i = 0; i < l; i++) p[i] = x; - if (isVal(x)) for (usz i = 0; i < l; i++) inc(x); - return; - } - } -} // doesn't consume; fills m[ms…ms+l] with x -static void mut_fill(Mut* m, usz ms, B x, usz l) { - u8 nmt = el_or(m->type, selfElType(x)); - if (nmt!=m->type) mut_to(m, nmt); - mut_fillG(m, ms, x, l); -} +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 x +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); } + +// mut_set but assumes the type of x already fits in m +static void mut_setG(Mut* m, usz ms, B x) { MUTG(set, m, ms, x); } +// mut_fill but assumes the type of x already fits in m +static void mut_fillG(Mut* m, usz ms, B x, usz l) { MUTG(fill, m, ms, x, l); } +// mut_copy but assumes the type of x already fits in m +static void mut_copyG(Mut* m, usz ms, B x, usz xs, usz l) { MUTG(copy, m, ms, x, xs, l); } static void bit_cpy(u64* r, usz rs, u64* x, usz xs, usz l) { // TODO rewrite this whole thing to be all fancy u64 i = rs; @@ -178,18 +149,6 @@ static void bit_cpy(u64* r, usz rs, u64* x, usz xs, usz l) { // TODO rewrite thi for (; itype, TI(x,elType)); - if (nmt!=m->type) mut_to(m, nmt); - mut_copyG(m, ms, x, xs, l); -} - - B vec_join(B w, B x); // consumes both FORCE_INLINE B vec_join_inline(B w, B x) { usz wia = a(w)->ia;