MAKE_MUT_INIT, move mut_init to mut.c

This commit is contained in:
dzaima 2023-03-06 22:22:33 +02:00
parent 3f0bc57503
commit 8194f51b30
10 changed files with 103 additions and 102 deletions

View File

@ -137,7 +137,7 @@ B ud_c2(B t, B w, B x) {
usz ria=cia;
for (usz i=0; i<fr; i++) if (mulOn(ria, rsh[i])) thrM("↕: result shape too large");
TALLOC(usz, ri, fr-1);
MAKE_MUT(r, ria); mut_init(r, TI(x,elType));
MAKE_MUT_INIT(r, ria, TI(x,elType));
MUTG_INIT(r);
usz k = cia*rsh[fr-1];
if (wr==1) {

View File

@ -256,7 +256,7 @@ static NOINLINE B select_cells(usz n, B x, ur xr) {
} else {
usz rs = shProd(xsh, 2, xr);
usz xs = rs*xsh[1]; // aka csz
MAKE_MUT(rm, cam*rs); mut_init(rm, TI(x,elType)); MUTG_INIT(rm);
MAKE_MUT_INIT(rm, cam*rs, TI(x,elType)); MUTG_INIT(rm);
usz xi = rs*n;
usz ri = 0;
for (usz i = 0; i < cam; i++) {
@ -276,7 +276,7 @@ static NOINLINE B select_cells(usz n, B x, ur xr) {
}
static NOINLINE B shift_cells(B f, B x, u8 e, u8 rtid) {
MAKE_MUT(r, IA(x)); mut_init(r, e); MUTG_INIT(r);
MAKE_MUT_INIT(r, IA(x), e); MUTG_INIT(r);
usz cam = SH(x)[0];
usz csz = SH(x)[1];
assert(cam!=0 && csz!=0);

View File

@ -64,7 +64,7 @@ B scan_add_bool(B x, u64 ia) { // consumes x
u8 re = xs<=I8_MAX? el_i8 : xs<=I16_MAX? el_i16 : xs<=I32_MAX? el_i32 : el_f64;
if (xs < ia/128) {
B ones = C1(slash, x);
MAKE_MUT(r0, ia) mut_init(r0, re); MUTG_INIT(r0);
MAKE_MUT_INIT(r0, ia, re); MUTG_INIT(r0);
SGetU(ones)
usz ri = 0;
for (usz i = 0; i < xs; i++) {

View File

@ -311,7 +311,7 @@ B select_c2(B t, B w, B x) {
usz csz = arr_csz(x);
CFRes f = cf_get(1, csz<<elWidthLogBits(xe));
MAKE_MUT(rm, ria); mut_init(rm, xe);
MAKE_MUT_INIT(rm, ria, xe);
usz i = 0; f64 badw;
if (xe<el_B && elInt(we)) {
void* wp = tyany_ptr(w);
@ -472,7 +472,7 @@ B select_ucw(B t, B o, B w, B x) {
return x;
}
}
MAKE_MUT(r, xia); mut_init(r, el_or(xe, re));
MAKE_MUT_INIT(r, xia, el_or(xe, re));
MUTG_INIT(r);
mut_copyG(r, 0, x, 0, xia);
SGet(rep)
@ -486,7 +486,7 @@ B select_ucw(B t, B o, B w, B x) {
decG(w); decG(rep); FREE_CHECK;
return mut_fcd(r, x);
}
MAKE_MUT(r, xia); mut_init(r, el_or(xe, re));
MAKE_MUT_INIT(r, xia, el_or(xe, re));
MUTG_INIT(r);
mut_copyG(r, 0, x, 0, xia);
SGet(rep)

View File

@ -24,8 +24,7 @@ static Arr* take_impl(usz ria, B x) { // consumes x; returns v↑⥊𝕩 without
usz xia = IA(x);
if (ria>xia) {
B xf = getFillE(x);
MAKE_MUT(r, ria); mut_init(r, el_or(TI(x,elType), selfElType(xf)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, ria, el_or(TI(x,elType), selfElType(xf))); MUTG_INIT(r);
mut_copyG(r, 0, x, 0, xia);
mut_fillG(r, xia, xf, ria-xia);
decG(x);
@ -273,8 +272,7 @@ B shape_c2(B t, B w, B x) {
} else {
if (TI(x,elType) == el_B) {
B xf = getFillQ(x);
MAKE_MUT(m, nia); mut_init(m, el_B);
MUTG_INIT(m);
MAKE_MUT_INIT(m, nia, el_B); MUTG_INIT(m);
i64 div = nia/xia;
i64 mod = nia%xia;
for (i64 i = 0; i < div; i++) mut_copyG(m, i*xia, x, 0, xia);
@ -526,7 +524,6 @@ NOINLINE B takedrop_highrank(bool take, B w, B x) {
} else if (ria==0) { // printf("empty result\n");
r = taga(arr_shSetU(emptyArr(x, rr), rr, rsh));
} else { // printf("generic\n");
MAKE_MUT(rm, ria); mut_init(rm, TI(x,elType));
B xf = getFillR(x);
if (anyFill && noFill(xf)) {
#if PROPER_FILLS
@ -536,7 +533,7 @@ NOINLINE B takedrop_highrank(bool take, B w, B x) {
#endif
}
MUTG_INIT(rm);
MAKE_MUT_INIT(rm, ria, TI(x,elType)); MUTG_INIT(rm);
if (IA(x)==0) {
mut_fillG(rm, 0, xf, ria);
} else { // actual generic copying code
@ -657,8 +654,7 @@ B take_c2(B t, B w, B x) {
usz xia = IA(x);
if (n>xia) {
B xf = getFillE(x);
MAKE_MUT(r, n); mut_init(r, el_or(TI(x,elType), selfElType(xf)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, n, el_or(TI(x,elType), selfElType(xf))); MUTG_INIT(r);
mut_fillG(r, 0, xf, n-xia);
mut_copyG(r, n-xia, x, 0, xia);
decG(x);
@ -997,8 +993,7 @@ B couple_c2(B t, B w, B x) {
if (!eqShape(w, x)) thrF("≍: 𝕨 and 𝕩 must have equal shapes (%H ≡ ≢𝕨, %H ≡ ≢𝕩)", w, x);
usz ia = IA(w);
ur wr = RNK(w);
MAKE_MUT(r, ia*2); mut_init(r, el_or(TI(w,elType), TI(x,elType)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, ia*2, el_or(TI(w,elType), TI(x,elType))); MUTG_INIT(r);
mut_copyG(r, 0, w, 0, ia);
mut_copyG(r, ia, x, 0, ia);
Arr* ra = mut_fp(r);
@ -1025,8 +1020,7 @@ B shiftb_c1(B t, B x) {
B xf = getFillE(x);
usz csz = arr_csz(x);
MAKE_MUT(r, ia); mut_init(r, el_or(TI(x,elType), selfElType(xf)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, ia, el_or(TI(x,elType), selfElType(xf))); MUTG_INIT(r);
mut_copyG(r, csz, x, 0, ia-csz);
mut_fillG(r, 0, xf, csz);
return qWithFill(mut_fcd(r, x), xf);
@ -1038,8 +1032,7 @@ B shiftb_c2(B t, B w, B x) {
B f = fill_both(w, x);
usz wia = IA(w);
usz xia = IA(x);
MAKE_MUT(r, xia); mut_init(r, el_or(TI(w,elType), TI(x,elType)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, xia, el_or(TI(w,elType), TI(x,elType))); MUTG_INIT(r);
int mid = wia<xia? wia : xia;
mut_copyG(r, 0 , w, 0, mid);
mut_copyG(r, mid, x, 0, xia-mid);
@ -1053,8 +1046,7 @@ B shifta_c1(B t, B x) {
if (ia==0) return x;
B xf = getFillE(x);
usz csz = arr_csz(x);
MAKE_MUT(r, ia); mut_init(r, el_or(TI(x,elType), selfElType(xf)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, ia, el_or(TI(x,elType), selfElType(xf))); MUTG_INIT(r);
mut_copyG(r, 0, x, csz, ia-csz);
mut_fillG(r, ia-csz, xf, csz);
return qWithFill(mut_fcd(r, x), xf);
@ -1066,8 +1058,7 @@ B shifta_c2(B t, B w, B x) {
B f = fill_both(w, x);
usz wia = IA(w);
usz xia = IA(x);
MAKE_MUT(r, xia); mut_init(r, el_or(TI(w,elType), TI(x,elType)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, xia, el_or(TI(w,elType), TI(x,elType))); MUTG_INIT(r);
if (wia < xia) {
usz m = xia-wia;
mut_copyG(r, 0, x, wia, m);
@ -1132,8 +1123,7 @@ B reverse_c1(B t, B x) {
usz cam = SH(x)[0];
usz rp = 0;
usz ip = IA(x);
MAKE_MUT(r, ip); mut_init(r, TI(x,elType));
MUTG_INIT(r);
MAKE_MUT_INIT(r, ip, TI(x,elType)); MUTG_INIT(r);
for (usz i = 0; i < cam; i++) {
ip-= csz;
mut_copyG(r, rp, x, ip, csz);
@ -1200,8 +1190,7 @@ static NOINLINE B rotate_highrank(bool inv, B w, B x) {
ccsz*= xshc;
}
MAKE_MUT(rm, IA(x)); mut_init(rm, TI(x,elType));
MUTG_INIT(rm);
MAKE_MUT_INIT(rm, IA(x), TI(x,elType)); MUTG_INIT(rm);
usz n0 = csz*rot0;
usz n1 = csz*(l0-rot0);
@ -1239,8 +1228,7 @@ B reverse_c2(B t, B w, B x) {
i64 am = WRAP_ROT(o2i64(w), cam);
if (am==0) return x;
am*= csz;
MAKE_MUT(r, xia); mut_init(r, TI(x,elType));
MUTG_INIT(r);
MAKE_MUT_INIT(r, xia, TI(x,elType)); MUTG_INIT(r);
mut_copyG(r, 0, x, am, xia-am);
mut_copyG(r, xia-am, x, 0, am);
B xf = getFillQ(x);
@ -1398,8 +1386,7 @@ B pick_uc1(B t, B o, B x) { // TODO do in-place like pick_ucw; maybe just call i
usz ia = IA(x);
B arg = IGet(x, 0);
B rep = c1(o, arg);
MAKE_MUT(r, ia); mut_init(r, el_or(TI(x,elType), selfElType(rep)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, ia, el_or(TI(x,elType), selfElType(rep))); MUTG_INIT(r);
mut_setG(r, 0, rep);
mut_copyG(r, 1, x, 1, ia-1);
return qWithFill(mut_fcd(r, x), xf);
@ -1442,8 +1429,7 @@ B pick_ucw(B t, B o, B w, B x) {
else if (xt==t_c16arr) { u16* xp = c16any_ptr(x); xp[wi] = o2cG(rep); return x; }
else if (xt==t_c32arr) { u32* xp = c32any_ptr(x); xp[wi] = o2cG(rep); return x; }
}
MAKE_MUT(r, xia); mut_init(r, el_or(TI(x,elType), selfElType(rep)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, xia, el_or(TI(x,elType), selfElType(rep))); MUTG_INIT(r);
mut_setG(r, wi, rep);
mut_copyG(r, 0, x, 0, wi);
mut_copyG(r, wi+1, x, wi+1, xia-wi-1);
@ -1466,8 +1452,7 @@ static B takedrop_ucw(i64 wi, B o, u64 am, B x, ux xr) {
usz* repsh = SH(rep);
if (RNK(rep)==0 || !eqShPart(repsh+1, SH(x)+1, xr-1) || repsh[0]!=am) thrM("𝔽⌾(n⊸↑)𝕩: 𝔽 returned an array with a different shape than n↑𝕩");
MAKE_MUT(r, xia);
mut_init(r, el_or(TI(x,elType), TI(rep,elType))); MUTG_INIT(r);
MAKE_MUT_INIT(r, xia, el_or(TI(x,elType), TI(rep,elType))); MUTG_INIT(r);
if (wi<0) {
mut_copyG(r, 0, x, 0, lv);
mut_copyG(r, lv, rep, 0, tk);

View File

@ -687,7 +687,7 @@ B slash_c2(B t, B w, B x) {
SLOW2("𝕨/𝕩", w, x);
B xf = getFillQ(x);
usz csz = arr_csz(x);
MAKE_MUT(r0, s*csz) mut_init(r0, TI(x,elType)); MUTG_INIT(r0);
MAKE_MUT_INIT(r0, s*csz, TI(x,elType)); MUTG_INIT(r0);
SGetU(w)
if (csz!=1) { usz ri=0; for (ux i=0; i<wia; i++) { usz c=o2s(GetU(w, i)); for(ux j=0;j<c;j++) { mut_copyG(r0, ri, x, i*csz, csz); ri+= csz; } } }
else { SGetU(x) usz ri=0; for (ux i=0; i<wia; i++) { usz c=o2s(GetU(w, i)); if (c) { mut_fillG(r0, ri, GetU(x, i), c); ri+= c; } } }
@ -768,7 +768,7 @@ B slash_c2(B t, B w, B x) {
if (xl>6 || (xl<3 && xl!=0) || TI(x,elType)==el_B) {
B xf = getFillQ(x);
if (xr!=1) {
MAKE_MUT(r0, IA(x) * wv) mut_init(r0, TI(x,elType)); MUTG_INIT(r0);
MAKE_MUT_INIT(r0, IA(x) * wv, TI(x,elType)); MUTG_INIT(r0);
usz csz = arr_csz(x);
ux ri = 0;
for (ux i = 0; i < xlen; i++) for (ux j = 0; j < wv; j++) {
@ -971,7 +971,7 @@ B slash_ucw(B t, B o, B w, B x) {
usz argIA = IA(arg);
B rep = c1(o, arg);
if (isAtm(rep) || RNK(rep)!=1 || IA(rep) != argIA) thrF("𝔽⌾(a⊸/)𝕩: Result of 𝔽 must have the same shape as a/𝕩 (expected ⟨%s⟩, got %H)", argIA, rep);
MAKE_MUT(r, ia); mut_init(r, el_or(TI(x,elType), TI(rep,elType)));
MAKE_MUT_INIT(r, ia, el_or(TI(x,elType), TI(rep,elType)));
SGet(x)
SGet(rep)
usz repI = 0;
@ -979,7 +979,7 @@ B slash_ucw(B t, B o, B w, B x) {
u64* d = bitarr_ptr(w);
if (elInt(TI(x,elType)) && elInt(TI(rep,elType))) {
if (r->fns->elType!=el_i32) mut_to(r, el_i32);
i32* rp = r->ai32;
i32* rp = r->a;
x = toI32Any(x); i32* xp = i32any_ptr(x);
rep = toI32Any(rep); i32* np = i32any_ptr(rep);
for (usz i = 0; i < ia; i++) {

View File

@ -408,10 +408,10 @@ BQNFFIEnt ffi_parseType(B arg, bool forRes) { // doesn't consume; parse argument
}
arg = chr_squeezeChk(inc(arg));
MAKE_MUT(tmp, ia+1); mut_init(tmp, el_c32); MUTG_INIT(tmp);
MAKE_MUT_INIT(tmp, ia+1, el_c32); MUTG_INIT(tmp);
mut_copyG(tmp, 0, arg, 0, ia);
mut_setG(tmp, ia, m_c32(0));
u32* xp = tmp->ac32;
u32* xp = tmp->a;
u32* xpN = xp + ia;
BQNFFIEnt t;

View File

@ -419,7 +419,7 @@ B nativeComp_c2(B t, B w, B x) {
B tokens = nc_tokenize(prims, sysvs, xBuf, xia, &fnBlock);
decG(xBufO);
// // parse
// parse
B objs = emptyHVec();
i32* bc0;
B bytecode = m_i32arrv(&bc0, fnBlock? 3 : 0);

View File

@ -1,6 +1,42 @@
#include "../core.h"
#include "mut.h"
FORCE_INLINE void mut_init(Mut* m, u8 n) {
m->fns = &mutFns[n];
usz ia = m->ia;
u64 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->a = t.c->a;
return;
}
Arr* a = m_arr(sz, m->fns->valType, ia);
m->val = a;
m->a = ((TyArr*)a)->a;
}
#if __clang__
NOINLINE void make_mut_init(Mut* rp, ux ia, u8 el) {
MAKE_MUT(r, ia)
mut_init(r, el);
*rp = r_val;
}
#else
NOINLINE Mut make_mut_init(ux ia, u8 el) {
MAKE_MUT(r, ia)
mut_init(r, el);
return r_val;
}
#endif
static Arr* (*cpyFns[])(B) = {
[el_bit] = cpyBitArr,
[el_i8] = cpyI8Arr, [el_c8] = cpyC8Arr,
@ -35,8 +71,7 @@ NOINLINE void mut_to(Mut* m, u8 n) {
NOINLINE B vec_addF(B w, B x) {
usz wia = IA(w);
MAKE_MUT(r, wia+1); mut_init(r, el_or(TI(w,elType), selfElType(x)));
MUTG_INIT(r);
MAKE_MUT_INIT(r, wia+1, el_or(TI(w,elType), selfElType(x))); MUTG_INIT(r);
mut_copyG(r, 0, w, 0, wia);
mut_setG(r, wia, x);
dec(w);
@ -383,16 +418,16 @@ MAKE_CCPY(C32, c32)
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]; }
static B m_getU_MAX(void* a, usz ms) { err("m_setG_MAX"); }
static B m_getU_bit(void* a, usz ms) { return m_i32(bitp_get(((u64*) a), ms)); }
static B m_getU_i8 (void* a, usz ms) { return m_i32(((i8* ) a)[ms]); }
static B m_getU_i16(void* a, usz ms) { return m_i32(((i16*) a)[ms]); }
static B m_getU_i32(void* a, usz ms) { return m_i32(((i32*) a)[ms]); }
static B m_getU_c8 (void* a, usz ms) { return m_c32(((u8* ) a)[ms]); }
static B m_getU_c16(void* a, usz ms) { return m_c32(((u16*) a)[ms]); }
static B m_getU_c32(void* a, usz ms) { return m_c32(((u32*) a)[ms]); }
static B m_getU_f64(void* a, usz ms) { return m_f64(((f64*) a)[ms]); }
static B m_getU_B (void* a, usz ms) { return ((B*) a)[ms]; }
M_CopyF copyFns[el_MAX];
M_FillF fillFns[el_MAX];

View File

@ -3,20 +3,21 @@
/* 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);
Start with MAKE_MUT(name, itemAmount) or MAKE_MUT_INIT(name, itemAmount, elType).
Those allocate the Mut instance on the stack, so it must be finished before the scope ends.
MAKE_MUT doesn't allocate any backing array, and will do so during mut_(set|fill|copy) (one of which must be the next operation on the Mut).
MAKE_MUT_INIT makes a backing array with the specified element type; mut_(set|fill|copy) can still widen it, but the primary use-case is for the G-postfixed functions.
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.
End with mut_f(v|c|cd|p);.
There must be no allocations while a mut object is being built so GC doesn't read the partially-initialized object.
mut_pfree must be used to free a partially filled `mut` instance safely (e.g. before throwing an error).
*/
typedef struct Mut Mut;
typedef struct MutFns MutFns;
typedef void (*M_SetF)(void*, usz, B);
typedef B (*M_GetF)(Mut*, usz);
typedef B (*M_GetF)(void*, usz);
struct MutFns {
u8 elType;
u8 valType;
@ -31,37 +32,18 @@ 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;
};
void* a;
};
#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 = PIA(m);
u64 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);
#if __clang__ && __has_attribute(noescape) // workaround for clang not realizing that stack-returned structs aren't captured
void make_mut_init(__attribute__((noescape)) Mut* rp, ux ia, u8 el);
#define MAKE_MUT_INIT(N, IA, EL) Mut N##_val; Mut* N = &N##_val; make_mut_init(N, IA, EL);
#else
Mut make_mut_init(ux ia, u8 el);
#define MAKE_MUT_INIT(N, IA, EL) Mut N##_val = make_mut_init(IA, EL); Mut* N = &N##_val;
#endif
#define MAKE_MUT(N, IA) Mut N##_val; N##_val.fns = &mutFns[el_MAX]; N##_val.ia = (IA); Mut* N = &N##_val;
static B mut_fv(Mut* m) { assert(m->fns->elType!=el_MAX);
NOGC_E;
@ -70,13 +52,13 @@ static B mut_fv(Mut* m) { assert(m->fns->elType!=el_MAX);
SPRNK(a, 1);
return taga(a);
}
static B mut_fc(Mut* m, B x) { assert(m->fns->elType!=el_MAX);
static B mut_fc(Mut* m, B x) { assert(m->fns->elType!=el_MAX); // doesn't consume x
NOGC_E;
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);
static B mut_fcd(Mut* m, B x) { assert(m->fns->elType!=el_MAX); // consumes x
NOGC_E;
Arr* a = m->val;
arr_shCopy(a, x);
@ -100,25 +82,24 @@ 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]); }
static void mut_rm(Mut* m, usz ms) { if (m->fns->elType == el_B) dec(((B*)m->a)[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 B mut_getU(Mut* m, usz ms) { return m->fns->m_getU(m->a, 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
// doesn't consume; expects x to be an array, each position must be written to precisely once
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
// these methods function as the non-G-postfixed ones, except that
// the MAKE_MUT_INIT must have been used, MUTG_INIT called, and x must fit into the array type initialized to
#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)
@ -187,7 +168,7 @@ FORCE_INLINE B arr_join_inline(B w, B x, bool consume, bool* reusedW) {
case t_harr: if (fsizeof(HArr,a,B,ria)<wsz) { rp = harr_ptr(w); goto yes; } break;
}
no:; // failed to reuse
MAKE_MUT(r, ria); mut_init(r, el_or(TI(w,elType), TI(x,elType)));
MAKE_MUT_INIT(r, ria, el_or(TI(w,elType), TI(x,elType)));
MUTG_INIT(r);
mut_copyG(r, 0, w, 0, wia);
mut_copyG(r, wia, x, 0, xia);