Skip to content

Commit 41abf29

Browse files
committed
Inplacing for i./i:/~.-./([-.-.)
1 parent d84142d commit 41abf29

File tree

11 files changed

+236
-161
lines changed

11 files changed

+236
-161
lines changed

jsrc/ar.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,10 +1013,10 @@ F1(jtslash){F1PREFIP;A h;AF f1;C c;V*v;
10131013
v=FAV(w);
10141014
I flag=v->flag&VASGSAFE; // if u is asgsafe, so is u/
10151015
switch(v->id){ // select the monadic case
1016-
case CCOMMA: f1=jtredcat; flag|=VJTFLGOK1; break;
1017-
case CCOMDOT: f1=jtredstitch; break;
1018-
case CSEMICO: f1=jtredsemi; break;
1019-
case CUNDER: f1=jtreduce; if(COPE==IDD(v->fgh[1])){c=FAV(v->fgh[0])->id; if(c==CCOMMA)f1=jtredcateach; else if(c==CCOMDOT)f1=jtredstiteach;} break;
1016+
case CCOMMA: f1=jtredcat; flag|=VJTFLGOK1; break; // ,/
1017+
case CCOMDOT: f1=jtredstitch; break; // ,./
1018+
case CSEMICO: f1=jtredsemi; break; // ;/
1019+
case CUNDER: f1=jtreduce; if(COPE==IDD(v->fgh[1])){c=FAV(v->fgh[0])->id; if(c==CCOMMA)f1=jtredcateach; else if(c==CCOMDOT)f1=jtredstiteach;} break; // ,&.>/
10201020
default: f1=jtreduce; flag|=(v->flag&VJTFLGOK2)>>(VJTFLGOK2X-VJTFLGOK1X); break; // monad is inplaceable if the dyad for u is
10211021
}
10221022
RZ(h=qq(w,v2(lr(w),RMAX))); // create the rank compound to use if dyad

jsrc/j.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -638,13 +638,13 @@ struct jtimespec jmtfclk(void); //'fast clock'; maybe less inaccurate; intended
638638
// modes for indexofsub()
639639
#define IIOPMSKX 5 // # bits of flags
640640
#define IIOPMSK (((I)1<<IIOPMSKX)-1) // operation bits. INTER also uses bit 3, which is included as a modifier in the switches
641-
#define IIOPMSKINIT 0xf //
641+
// obsolete #define IIOPMSKINIT 0xf // used to mask the op for initializing botmasks. Then the low-order 4 bits indicate the value to use
642642
#define IIDOT 0 // IIDOT and IICO must be 0-1
643643
#define IICO 1
644644
#define INUBSV 2 // BIT arrays INUBSV-INUBI init to 1 to that out-of-bounds in LESS keeps the value
645-
#define INUB 3
646-
#define ILESS 4
647-
#define INUBI 5
645+
#define ILESS 3 // -.
646+
#define INUB 4 // ~. NUB must be paired with NUBI
647+
#define INUBI 5 // I.@:~:
648648
#define IEPS 6 // BIT arrays IEPS and above init to 0 so out-of-bounds means not included
649649
// the I...EPS values below are wired into the function table at the end of vcompsc.c, where they are combined with a comparison
650650
#define II0EPS 7 // i.&0@:e. this must come first; others base on it
@@ -656,9 +656,10 @@ struct jtimespec jmtfclk(void); //'fast clock'; maybe less inaccurate; intended
656656
#define IALLEPS 13 // *./@:e.
657657
#define IIFBEPS 14 // I.@e.
658658
#define IFORKEY 15 // special key support: like i.~, but add # values mapped to the index, and return #unique values in AM
659-
#define IINTER 16 // ([ -. -.)
659+
#define IINTER 16 // ([ -. -.) LSBs cause BIT arrays to init to 0 meaning 'don't keep'
660+
#define INUBIP 0x14 // ~. inplace LSBs cause BIT arrays to init to 1
660661
#define IIMODFIELD ((I)7<<IIOPMSKX) // bits used to indicate processing options
661-
#define IIMODPACKX 5
662+
#define IIMODPACKX 5 // must not exceed 5 since used in a shift
662663
#define IIMODPACK (((I)1)<<IIMODPACKX) // modifier for type. (small-range search except i./i:) In IIDOT/IICO, indicates reflexive application. In others, indicates that the
663664
// bitmask should be stored as packed bits rather than bytes
664665
#define IIMODREFLEXX 5 // overlaps IIMODPACK; OK because reflexive i./i: needs to know where the match was & can't use bitmask

jsrc/t.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ PRIM primtab[256] = {
100100
/* *. */ PRIMATOMIC2(CSTARDOT,CSTARDOT,VERB, jtpolar, jtatomic2, 0, 0, 0 ,VISATOMIC1|VFUSEDOK2|VIRS2|VASGSAFE|VJTFLGOK2,VF2NONE|VF2PRIM),
101101
/* *: */ PRIMATOMIC2(CSTARCO,CSTARCO, VERB, jtsquare, jtatomic2, 0, 0, 0 ,VISATOMIC1|VFUSEDOK2|VIRS2|VASGSAFE|VJTFLGOK1|VJTFLGOK2,VF2NONE|VF2PRIM),
102102
/* - */ PRIMATOMIC2UV(CMINUS,CMINUS,VA1CNEG-VA1ORIGIN, VERB, jtnegate, jtatomic2, 0, 0, 0 ,VISATOMIC1|VFUSEDOK2|VIRS2|VASGSAFE|VJTFLGOK1|VJTFLGOK2,VF2NONE|VF2PRIM),
103-
/* -. */ PRIMACV(CNOT, VERB, jtnot, jtless, 0, RMAX,RMAX,VISATOMIC1|VASGSAFE|VJTFLGOK1|((7+(((ILESS-II0EPS)&0xf)<<3))&-SY_64),VF2NONE|VF2PRIM), // native compound allowing &n - 64-bit only
103+
/* -. */ PRIMACV(CNOT, VERB, jtnot, jtless, 0, RMAX,RMAX,VISATOMIC1|VASGSAFE|VJTFLGOK1|VJTFLGOK2|((7+(((ILESS-II0EPS)&0xf)<<3))&-SY_64),VF2NONE|VF2PRIM), // native compound allowing &n - 64-bit only
104104
/* -: */ PRIMACV(CHALVE, VERB, jthalve, jtmatch, 0, RMAX,RMAX,VISATOMIC1|VIRS2|VASGSAFE|VJTFLGOK1,VF2NONE|VF2PRIM), // alias CMATCH
105105
/* % */ PRIMATOMIC2UV(CDIV,CDIV,VA1CRECIP-VA1ORIGIN, VERB, jtrecip, jtatomic2, 0, 0, 0 ,VISATOMIC1|VFUSEDOK2|VIRS2|VASGSAFE|VJTFLGOK1|VJTFLGOK2,VF2NONE|VF2PRIM),
106106
/* %. */ PRIMACV(CDOMINO, VERB, jtminv, jtmdiv, 2, RMAX,2 ,VASGSAFE,VF2NONE|VF2PRIM),

jsrc/viavx.c

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ I hashallo(IH * RESTRICT hh,UI p,UI asct,I md){
3434
// ~. ~: I.@~. -. all prefer the table to be complemented and thus initialized to 1.
3535
// REVERSED types always initialize to 1, whether packed or not
3636
// this is a kludge - the initialization value should be passed in by the caller, in asct
37-
UI fillval = md&IREVERSED?(md&IIMODPACK?255:1):((md&(IIMODPACK+IIOPMSK))<=INUBI); fillval|=fillval<<8; fillval|=fillval<<16; // mvc overfetches, so need full UI
38-
mvc(p,hh->data.UI,4,&fillval); // fill with repeated copies of fillval
37+
UI fillval = (((1LL<<INUBSV)|(1LL<<ILESS)|(1LL<<INUB)|(1LL<<INUBI)|(1LL<<INUBIP))>>(md&(IIMODPACK+IIOPMSK)))&1; UI temp=md&IIMODPACK?255:1; fillval=md&IREVERSED?temp:fillval; // mvc overfetches, so need full UI. If PACK, always 0; otherwise look at bits 0-3 of opcode
38+
// obsolete UI fillval = md&IREVERSED?(md&IIMODPACK?255:1):((md&(IIMODPACK+IIOPMSKINIT))<=INUBI); // mvc overfetches, so need full UI. If PACK, always 0; otherwise look at bits 0-3 of opcode
39+
// obsolete fillval|=fillval<<8; fillval|=fillval<<16;
40+
mvc(p,hh->data.UI,1,&fillval); // fill with repeated copies of fillval
3941
// If the invalid area grows, update the invalid hwmk, and also the partition
4042
p >>= hh->hashelelgsize; // convert p to hash index
4143
if(p>hh->invalidhi){
@@ -767,7 +769,7 @@ A jtindexofsub(J jt,I mode,AD * RESTRICT a,AD * RESTRICT w){F2PREFIP;PROLOG(0079
767769
I zt; A z; // type of result to allocate; address of block
768770
if((mode&IIOPMSK)==IEPS)zt=B01;
769771
else{
770-
if(likely(a!=w)&&(at&INT+SY_64*FL)&-(SGNTO0(AC(w))&(I)jtinplace)){z=w; goto inplace;} // if inplaceable (not including assignment) and items have the right size
772+
if(likely(a!=w)&&(at&INT+SY_64*FL)&-(SGNTO0(AC(w))&((I)jtinplace>>JTINPLACEWX))){z=w; goto inplace;} // if inplaceable (not including assignment) and items have the right size
771773
zt=INT; // the result type depends on the operation.
772774
}
773775
GA(z,zt,wn,wr,AS(w)); // allocate result area
@@ -1064,22 +1066,33 @@ inplace:;
10641066
AF ifn=fntbl[FNTABLEPREFIX+fnx][bighash]; // get an early start fetching the function we will call
10651067

10661068
// Allocate the result area. NOTE that some of the routines, like small-range, always store at least one result; so we have to point z somewhere harmless before launching them. If we are prehashing we skip this.
1067-
// If the conditions are right, perform the operation inplace
1068-
A z;
1069+
// If the conditions are right, perform the operation inplace.
1070+
A z; // will hold result
10691071
switch(mode&(IPHCALC|IIOPMSK)){
10701072
default: fauxINT(z,zfaux,1,0) break; // if prehashed, we must create an area that can hold at least one stored result
1071-
case IIDOT: case IFORKEY:
1072-
case IICO: GATV0(z,INT,zn,f+f1); MCISH(AS(z),s,f) MCISH(f+AS(z),ws+wf,f1); break; // mustn't overfetch s
1073+
case IIDOT:
1074+
case IICO:
1075+
// i./i: can run inplace on w if w is abandoned, not the same block as a, rank matches rank needed, item size<=SZI, DIRECT, and (not UNINCORPABLE or same type as result)
1076+
if(likely(a!=w)&&likely(!(AFLAG(w)&AFUNINCORPABLE+AFRO))&&(-(AT(w)&(INT+SY_64*FL))&AC(w)&SGNIF(jtinplace,JTINPLACEWX)&((AR(w)^(f+f1))-1))<0){z=w; AT(z)=INT; break;} // inplace w if not disqualified
1077+
// if can't inplace fall through to...
1078+
case IFORKEY:
1079+
GATV0(z,INT,zn,f+f1); MCISH(AS(z),s,f) MCISH(f+AS(z),ws+wf,f1); break; // mustn't overfetch s
1080+
case ILESS: case IINTER:
1081+
// -./([-.-.) can run inplace if w is abandoned, not the same block as a, rank not 0, DIRECT, not UNINCORPABLE (since we don't want to change shape of an unincorpable)
1082+
if(likely(a!=w)&&likely(!(AFLAG(w)&AFUNINCORPABLE+AFRO))&&(((AT(w)&~DIRECT)-1)&AC(w)&SGNIF(jtinplace,JTINPLACEWX)&-(AR(w)))<0){z=w; break;} // inplace w if not disqualified
1083+
ws=wr==0?&AN(w):ws; GA(z,AT(w),AN(w),MAX(1,wr),ws); break; // if wr is an atom, use 1 for the shape
1084+
case INUB:
1085+
// ~. can run inplace if abandoned, rank>0, DIRECT
1086+
if(likely(!(AFLAG(w)&AFUNINCORPABLE+AFRO))&&(((AT(w)&~DIRECT)-1)&AC(w)&SGNIF(jtinplace,JTINPLACEWX)&-(AR(w)))<0){z=w; mode^=INUB^INUBIP; break;} // inplace w if not disqualified
1087+
{I q; PRODX(q,AR(a)-1,AS(a)+1,MIN(m,p+1)) GA(z,t,q,MAX(1,wr),ws); break;} // we speculatively overwrite, possibly 1 more than in a but no more than in w
1088+
case INUBI: GATV0(z,INT,MIN(m,p)+1,1); break; // we speculatively overwrite but never past a full buffer
10731089
case INUBSV: GATV0(z,B01,zn,f+f1+!acr); MCISH(AS(z),s,f) MCISH(f+AS(z),ws+wf,f1); if(!acr)AS(z)[AR(z)-1]=1; break; // mustn't overfetch s
1074-
case INUB: {I q; PRODX(q,AR(a)-1,AS(a)+1,MIN(m,p)+1) GA(z,t,q,MAX(1,wr),ws); break;} // +1 because we speculatively overwrite.
1075-
case ILESS: case IINTER: ws=wr==0?&AN(w):ws; GA(z,AT(w),AN(w),MAX(1,wr),ws); break; // if wr is an atom, use 1 for the shape
10761090
case IEPS: GATV0(z,B01,zn,f+f1); MCISH(AS(z),s,f) MCISH(f+AS(z),ws+wf,f1); break;
1077-
case INUBI: GATV0(z,INT,MIN(m,p)+1,1); break; // +1 because we speculatively overwrite
10781091
// (e. i. 0:) and friends don't do anything useful if e. produces rank > 1. The search for 0/1 always fails
10791092
case II0EPS: case II1EPS: case IJ0EPS: case IJ1EPS:
10801093
if(wr>MAX(ar,1))R sc(wr>r?ws[0]:1); GAT0(z,INT,1,0); break;
10811094
// ([: I. e.) ([: +/ e.) ([: +./ e.) ([: *./ e.) come here only if e. produces rank 0 or 1.
1082-
case IIFBEPS: GATV0(z,INT,c+1,1); break; // +1 because we speculatively overwrite
1095+
case IIFBEPS: GATV0(z,INT,c,1); break; // we speculatively overwrite but not past a full buffer
10831096
case IANYEPS: case IALLEPS:
10841097
GAT0(z,B01,1,0); break;
10851098
case ISUMEPS:
@@ -1099,7 +1112,7 @@ inplace:;
10991112
case IFORKEY: {z=reshape(shape(z),take(sc(m),sc(m))); RZ(z=mkwris(z)); AM(z)=!!m; R z;} // all 0 but the first has the total count. Must install # partitions=1 if #items>0
11001113
case IICO: R reshape(shape(z),sc(n?m:m-1));
11011114
case INUBSV: R reshape(shape(z),take(sc(m),num(1)));
1102-
case INUB: AN(z)=0; AS(z)[0]=m?1:0; R z;
1115+
case INUB: case INUBIP: AN(z)=0; AS(z)[0]=m?1:0; R z;
11031116
case ILESS: if(m&&fnx==-3)AN(z)=AS(z)[0]=0; else MC(AV(z),AV(w),AN(w)<<bplg(AT(w))); R z;
11041117
case IINTER: if(!(m&&fnx==-3))AN(z)=AS(z)[0]=0; R z; // y has atoms or something is empty, return all of w; otherwise empty
11051118
case IEPS: R reshape(shape(z),num(m&&(!n||(fnx&1)))); // fnx&1 is true if homo
@@ -1197,7 +1210,7 @@ A jtindexofprehashed(J jt,A a,A w,A hs,A self){A h,*hv,x,z;AF fn;I ar,*as,at,c,f
11971210
R z;
11981211
}
11991212

1200-
// x i. y, supports inplacing
1213+
// x i. y, supports inplacing (in subroutine)
12011214
F2(jtindexof){
12021215
if(unlikely(((UI)a^(UI)ds(CALP))<(UI)(AT(w)&LIT))&&likely(!ISSPARSE(AT(w)))){F2PREFIP; R jtadotidot(jt,w);}
12031216
R indexofsub(IIDOT,a,w);
@@ -1220,13 +1233,13 @@ F1(jtnubsieve){
12201233
F1(jtnub){
12211234
F1PREFIP;ARGCHK1(w);
12221235
if(unlikely((SGNIFSPARSE(AT(w))|SGNIF(AFLAG(w),AFNJAX))<0))R repeat(nubsieve(w),w); // sparse or NJA
1223-
A z; RZ(z=indexofsub(INUB,w,w));
1236+
A z; RZ(z=jtindexofsub(jtinplace,INUB,w,w));
12241237
// We extracted from w, so mark it (or its backer if virtual) non-pristine. If w was pristine and inplaceable, transfer its pristine status to the result. We overwrite w because it is no longer in use
12251238
PRISTXFERF(z,w)
12261239
RETF(z);
12271240
} /* ~.w */
12281241

1229-
// x -. y. does not have IRS
1242+
// x -. y. does not have IRS, support inplacing
12301243
F2(jtless){A x=w;I ar,at,k,r,*s,wr,*ws;
12311244
F2PREFIP;ARGCHK2(a,w);
12321245
at=AT(a); ar=AR(a);
@@ -1237,14 +1250,14 @@ F2(jtless){A x=w;I ar,at,k,r,*s,wr,*ws;
12371250
if(unlikely((-wr&-(r^wr))<0)){RZ(x=virtual(w,0,r)); AN(x)=wn; s=AS(x); ws=AS(w); k=ar>wr?0:1+wr-r; I s0; PRODX(s0,k,ws,1) s[0]=s0; MCISH(1+s,k+ws,r-1);} // use fauxvirtual here
12381251
// if nothing special (like sparse, or incompatible types, or x requires conversion) do the fast way; otherwise (-. x e. y) # x
12391252
// because LESS allocates a large array to hold all the values, we use the slower, less memory-intensive, version if a is mapped
1240-
RZ(x=(SGNIFSPARSE(at)|SGNIF(AFLAG(a),AFNJAX))>=0?indexofsub(ILESS,x,a):
1253+
RZ(x=(SGNIFSPARSE(at)|SGNIF(AFLAG(a),AFNJAX))>=0?jtindexofsub(jtinplace,ILESS,x,a):
12411254
repeat(not(eps(a,x)),a));
12421255
// We extracted from a, so mark it (or its backer if virtual) non-pristine. If a was pristine and inplaceable, transfer its pristine status to the result
12431256
PRISTXFERAF(x,a)
12441257
RETF(x);
12451258
} /* a-.w */
12461259

1247-
// x ([ -. -.[!.f]) y. does not have IRS
1260+
// x ([ -. -.[!.f]) y. does not have IRS, supports inplacing
12481261
DF2(jtintersect){A x=w;I ar,at,k,r,*s,wr,*ws;
12491262
F2PREFIP;ARGCHK2(a,w);
12501263
at=AT(a); ar=AR(a);
@@ -1259,7 +1272,7 @@ DF2(jtintersect){A x=w;I ar,at,k,r,*s,wr,*ws;
12591272
// if nothing special (like sparse, or incompatible types, or x requires conversion) do the fast way; otherwise (-. x e. y) # x
12601273
// because LESS allocates a large array to hold all the values, we use the slower, less memory-intensive, version if a is mapped
12611274
// Don't revert to fork! localuse.lu1.fork2hfn is not set
1262-
x=(SGNIFSPARSE(at)|SGNIF(AFLAG(a),AFNJAX))>=0?indexofsub(IINTER,x,a):
1275+
x=(SGNIFSPARSE(at)|SGNIF(AFLAG(a),AFNJAX))>=0?jtindexofsub(jtinplace,IINTER,x,a):
12631276
repeat(eps(a,x),a);
12641277
POPCCT
12651278
RZ(x);

jsrc/viavx.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@
6161
#define HASHSLOT(hash) j=((hash)*p)>>32;
6262

6363
// Misc code to set the shape once we see how many results there are, used for ~. y and x -. y
64-
#define ZISHAPE AS(z)[0]=AN(z)=zi-zv
64+
#define ZISHAPE AS(z)[0]=AN(z)=zi-zv // zi must point to a single atom (sc. an index)
6565
#define ZCSHAPE AS(z)[0]=(zc-(C*)zv)/k; AN(z)=n*AS(z)[0]
66+
#define ZCSHAPEI AN(z)=n*(AS(z)[0]=(zc-zv)) // I *zc points to a SZI-sized cell but might not be an atom
6667
#define ZUSHAPE(T) AS(z)[0]= zu-(T*)zv; AN(z)=n*AS(z)[0]
6768

6869
// Calculate the hash slot. The hash calculation (input parm) relies on the name v and produces the name j. We have moved v to an xmm register to reduce register pressure
@@ -78,11 +79,12 @@
7879
// If (store) is 1, the value of i (which is the loop index giving the position within a of the item being processed) is stored into the empty hash slot,
7980
// only if the hash search does not find a match. If (store) is 2, the entry that we found is cleared, by setting it to maxcount+1, when we find a match.
8081
// When (store)=2, we also ignore hash entries containing maxcount+1, treating them as failed compares
82+
// (store)=3 is ~. inplace:
8183
// Independent of (store), (fstmt) is executed if the item is found in the hash table, and (nfstmt) is executed if it is not found.
82-
#define FINDP(T,TH,hsrc,name,exp,fstmt,nfstmt,store) NOUNROLL do{if(hj==hsrc##sct){ \
83-
if(store==1)hv[name]=(TH)i; nfstmt break;} /* this is the not-found case */ \
84+
#define FINDP(T,TH,hsrc,name,exp,fstmt,nfstmt,store) NOUNROLL do{ \
85+
if(hj==hsrc##sct){if(store==1)hv[name]=(TH)i; if(store==3)hv[name]=wsct; nfstmt break;} /* this is the not-found case */ \
8486
if((store!=2||hj<hsrc##sct)&&(v=(T*)_mm_extract_epi64(vp,1),!(exp))){if(store==2)hv[name]=(TH)(hsrc##sct+1); fstmt break;} /* found */ \
85-
if(unlikely(--name<0))name+=p; hj=hv[name]; /* miscompare, nust continue search */ \
87+
if(unlikely(--name<0))name+=p; hj=hv[name]; /* miscompare, must continue search */ \
8688
}while(1);
8789

8890
// Traverse the hash table for one argument. (src) indicates which argument, a or w, we are looping through; (hsrc) indicates which argument provided the hash table.
@@ -92,6 +94,7 @@
9294
// q+2 is being calculated).
9395
// The (fstmt,nfstmt,store) arguments indicate what to do when a match/notmatch is resolved.
9496
// (loopctl) give the stride through the input array, the control for the main loop, and the index of the last value. These values differ for forward and reverse scans through the input.
97+
// in the loop i is the index of the item being looked up in the hash (if store is not 0 or 3, that will be the index stored into the hashtable on notfound)
9598
#define XSEARCH(T,TH,src,hsrc,hash,exp,stride,fstmt,nfstmt,store,vpofst,loopctl,finali) \
9699
{I i, j, hj; T *v; vp=_mm_insert_epi64(vp,(I)(src##v+vpofst),0); vpstride = _mm_insert_epi64(vp,(stride)*(I)sizeof(T),0); vp=_mm_shuffle_epi32(vp,0x44); vpstride=_mm_insert_epi64(vpstride,0LL,1); \
97100
HASHSLOTP(T,hash) if(src##sct>1){I j1,j2; vp=_mm_add_epi64(vp,vpstride); j1=j; HASHSLOTP(T,hash) hj=hv[j1]; vp=_mm_add_epi64(vp,vpstride); vpstride=_mm_shuffle_epi32(vpstride,0x44); \
@@ -100,8 +103,10 @@
100103

101104
// Traverse a in forward direction, adding values to the hash table
102105
#define XDOAP(T,TH,hash,exp,stride) XSEARCH(T,TH,a,a,hash,exp,stride,{},{},1,0, (i=0;i<asct-2;++i) ,asct-1)
103-
// Traverse w in forward direction, executing fstmt/nfstmt depending on found/notfound; and adding to the hash if (reflex) is 1, indicating a reflexive operation
106+
// Traverse w in forward direction, executing fstmt/nfstmt depending on found/notfound; and adding to the hash if (reflex) is 1, indicating a reflexive operation scaf could save a register if reflexive
104107
#define XDOP(T,TH,hash,exp,stride,fstmt,nfstmt,reflex) XSEARCH(T,TH,w,a,hash,exp,stride,fstmt,nfstmt,reflex,0, (i=0;i<wsct-2;++i) ,wsct-1)
108+
// version used for ~. inplace: reflex=3 (controls FINDP), only a is used. wsct is freed for use as stored-item count
109+
#define XDOPIP(T,TH,hash,exp,stride,fstmt,nfstmt,reflex) XSEARCH(T,TH,a,a,hash,exp,stride,fstmt,nfstmt,reflex,0, (i=0;i<asct-2;++i) ,asct-1)
105110
// same for traversing a/w in reverse
106111
#define XDQAP(T,TH,hash,exp,stride) XSEARCH(T,TH,a,a,hash,exp,(-(stride)),{},{},1,cn*(asct-1), (i=asct-1;i>1;--i) ,0)
107112
#define XDQP(T,TH,hash,exp,stride,fstmt,nfstmt,reflex) XSEARCH(T,TH,w,a,hash,exp,(-(stride)),fstmt,nfstmt,reflex,cn*(wsct-1), (i=wsct-1;i>1;--i) ,0)

0 commit comments

Comments
 (0)