// Dyadic search functions: Member Of (∊), Index of (⊐), Progressive Index of (βŠ’) // π•¨βŠunit or unitβˆŠπ•©: scalar loop with early-exit // SHOULD use simd // SHOULD unify implementations // π•©βŠ’unit or π•¨βŠ’π•© where 1β‰₯≠𝕩: defer to π•¨βŠπ•© // Both arguments with rankβ‰₯1: // High-rank inputs: // Convert to a (lower-rank) typed integer array if cells are ≀62 bits // COULD have special hashing for equal type >64 bit cells, skipping squeezing // COULD try conditionally squeezing ahead-of-time, and not squeezing in bqn_hash // p⊐n & n∊p with short p & long n: n⊸=Β¨ p // bitarrβŠπ•©: more special arithmetic // SHOULD have impls for long p & short n // ≀16-bit elements: lookup tables // Character elements: reinterpret as integer elements // Otherwise, generic hashtable // SHOULD handle up to 64 bit cells via proper typed hash tables // SHOULD have fast path when cell sizes or element types doesn't match // SHOULD properly handle Β―0 #include "../core.h" #include "../utils/hash.h" #include "../utils/talloc.h" #include "../utils/calls.h" #define C2i(F, W, X) C2(F, m_i32(W), X) extern B eq_c2(B,B,B); extern B ne_c2(B,B,B); extern B or_c2(B,B,B); extern B add_c2(B,B,B); extern B sub_c2(B,B,B); extern B mul_c2(B,B,B); static u64 elRange(u8 eltype) { return 1ull<<(1<ft? it : ft; /* Table allocation width */ \ TALLOC(TY, tab0, t); TY* tab = tab0 + t/2; \ usz m=IN##ia, n=FOR##ia; \ void* ip = tyany_ptr(IN); \ void* fp = tyany_ptr(FOR); \ /* Initialize */ \ if (IN.u != FOR.u) { \ if (FOR##e==el_i16 && n1) { rsh=m_shArr(co); shcpy(rsh->a,SH(x),co); } B r0 = widenBitArr(x, co); usz csz = shProd(SH(r0),co,RNK(r0)) << elWidthLogBits(TI(r0,elType)); u8 t; if (csz==8) t = t_i8slice; else if (csz==16) t = t_i16slice; else if (csz==32) t = t_i32slice; else if (csz==64) t = t_f64slice; else UD; TySlice* r = m_arr(sizeof(TySlice), t, ria); r->p = a(r0); r->a = tyany_ptr(r0); if (co>=1) arr_shSetU((Arr*)r, co, rsh); else arr_shVec((Arr*)r); return taga(r); } static NOINLINE B cpyToElLog(B x, u8 xe, u8 lb) { switch(lb) { default: UD; case 0: return taga(cpyBitArr(x)); case 3: return taga(elNum(xe)? cpyI8Arr(x) : cpyC8Arr(x)); case 4: return taga(elNum(xe)? cpyI16Arr(x) : cpyC16Arr(x)); case 5: return taga(elNum(xe)? cpyI32Arr(x) : cpyC32Arr(x)); case 6: return taga(cpyF64Arr(x)); } } static NOINLINE B2 splitCells(B n, B p, u8 mode) { // 0:∊ 1:⊐ 2:βŠ’ #define SYMB (mode==0? "∊" : mode==1? "⊐" : "βŠ’") #define ARG_N (mode? "𝕩" : "𝕨") #define ARG_P (mode? "𝕨" : "𝕩") if (isAtm(p) || RNK(p)==0) thrF("%U: %U cannot have rank 0", SYMB, ARG_P); ur pr = RNK(p); if (isAtm(n)) n = m_atomUnit(n); ur nr = RNK(n); if (nr < pr-1) thrF("%U: Rank of %U must be at least the cell rank of %U (%H ≑ ≒𝕨, %H ≑ ≒𝕩)", SYMB, ARG_N, ARG_P, mode?p:n, mode?n:p); ur pcr = pr-1; ur nco = nr-pcr; if (nco>0 && eqShPart(SH(n)+nco, SH(p)+1, pcr)) { u8 ne = TI(n,elType); u8 pe = TI(p,elType); if (nepeb? neb : peb; ux rb = csz<16) { SGetU(w); #define XEQ(I) C2(ne, GetU(w,I), incG(x)) B r = XEQ(wia-1); for (usz i=wia-1; i--; ) r = C2(mul, XEQ(i), C2i(add, 1, r)); #undef XEQ decG(w); decG(x); return r; } if (xia+wia>20 && we<=el_i16 && xe<=el_i16) { B r; TABLE(w, x, i32, wia, i) return reduceI32Width(r, wia); } } else if (elChr(we) && elChr(xe)) { we-= el_c8-el_i8; xe-= el_c8-el_i8; goto tyEls; } i32* rp; B r = m_i32arrc(&rp, x); H_b2i* map = m_b2i(64); SGetU(x) SGetU(w) for (usz i = 0; i < wia; i++) { bool had; u64 p = mk_b2i(&map, GetU(w,i), &had); if (!had) map->a[p].val = i; } for (usz i = 0; i < xia; i++) rp[i] = getD_b2i(map, GetU(x,i), wia); free_b2i(map); decG(w); decG(x); return reduceI32Width(r, wia); } } B enclosed_0, enclosed_1; B memberOf_c2(B t, B w, B x) { if (isAtm(x) || RNK(x)!=1) { B2 t = splitCells(w, x, false); w = t.n; x = t.p; } if (isAtm(w)) goto single; ur wr = RNK(w); if (wr>0) goto many; B w0 = IGet(w, 0); dec(w); w = w0; goto single; B r; single: { usz xia = IA(x); SGetU(x) for (usz i = 0; i < xia; i++) if (equal(GetU(x, i), w)) { r = incG(enclosed_1); goto dec_wx; } r = incG(enclosed_0); dec_wx:; dec(w); goto dec_x; } many: { u8 we = TI(w,elType); usz wia = IA(w); u8 xe = TI(x,elType); usz xia = IA(x); if (xia == 0) { r=taga(arr_shCopy(allZeroes(wia), w)); decG(w); goto dec_x; } if (elNum(we) && elNum(xe)) { tyEls: #define WEQ(V) C2(eq, incG(w), V) if (xe==el_bit) { u64* xp = bitarr_ptr(x); u64 x0 = 1 & xp[0]; r = WEQ(m_usz(x0)); if (bit_has(xp, xia, !x0)) r = C2(or, r, WEQ(m_usz(!x0))); decG(w); goto dec_x; } if (xia<=(xe==el_i16?8:16) && wia>16) { SGetU(x); r = WEQ(GetU(x,0)); for (usz i=1; i20 && we<=el_i16 && xe<=el_i16) { B r; TABLE(x, w, i8, 0, 1) return taga(cpyBitArr(r)); } } else if (elChr(we) && elChr(xe)) { we-= el_c8-el_i8; xe-= el_c8-el_i8; goto tyEls; } H_Sb* set = m_Sb(64); SGetU(x) SGetU(w) bool had; for (usz i = 0; i < xia; i++) mk_Sb(&set, GetU(x,i), &had); u64* rp; r = m_bitarrc(&rp, w); for (usz i = 0; i < wia; i++) bitp_set(rp, i, has_Sb(set, GetU(w,i))); free_Sb(set); decG(w); goto dec_x; } dec_x:; decG(x); return r; } B count_c2(B t, B w, B x) { if (RARE(!isArr(w) || RNK(w)!=1)) { B2 t = splitCells(x, w, 2); w = t.p; x = t.n; } if (!isArr(x) || IA(x)<=1) return C2(indexOf, w, x); u8 we = TI(w,elType); usz wia = IA(w); u8 xe = TI(x,elType); usz xia = IA(x); i32* rp; B r = m_i32arrc(&rp, x); TALLOC(usz, wnext, wia+1); wnext[wia] = wia; if (we<=el_i16 && xe<=el_i16) { if (we==el_bit) { w = toI8Any(w); we = TI(w,elType); } if (xe==el_bit) { x = toI8Any(x); xe = TI(x,elType); } el8or16:; usz it = elRange(we); // Range of writes usz ft = elRange(xe); // Range of lookups usz t = it>ft? it : ft; // Table allocation width TALLOC(i32, tab0, t); i32* tab = tab0 + t/2; usz m=wia, n=xia; void* ip = tyany_ptr(w); void* fp = tyany_ptr(x); // Initialize if (xe==el_i16 && n=el_c8 && we<=el_c16 && xe>=el_c8 && xe<=el_c16) { we-= el_c8-el_i8; xe-= el_c8-el_i8; goto el8or16; } else { H_b2i* map = m_b2i(64); SGetU(x) SGetU(w) for (usz i = wia; i--; ) { bool had; u64 p = mk_b2i(&map, GetU(w,i), &had); wnext[i] = had ? map->a[p].val : wia; map->a[p].val = i; } for (usz i = 0; i < xia; i++) { bool had; u64 p = getQ_b2i(map, GetU(x,i), &had); usz j = wia; if (had) { j = map->a[p].val; map->a[p].val = wnext[j]; } rp[i] = j; } free_b2i(map); } TFREE(wnext); decG(w); decG(x); return reduceI32Width(r, wia); } void search_init(void) { { u64* p; Arr* a=m_bitarrp(&p, 1); arr_shAtm(a); *p= 0; gc_add(enclosed_0=taga(a)); } { u64* p; Arr* a=m_bitarrp(&p, 1); arr_shAtm(a); *p=~0ULL; gc_add(enclosed_1=taga(a)); } }