new mut interface

This commit is contained in:
dzaima 2022-03-12 03:08:25 +02:00
parent 09fe162b73
commit 9d3067fa4b
3 changed files with 216 additions and 182 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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 (; i<re; i++) bitp_set(r, i, bitp_get(x, i+d));
}
// mut_copy but x is guaranteed to be a subtype of m
void mut_copyG(Mut* m, usz ms, B x, usz xs, usz 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));
u8 nmt = el_or(m->type, 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;