From 88a97f393009fd2d9f4b873f834fd95d334def4b Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 28 Feb 2021 18:59:55 +0200 Subject: [PATCH 01/35] Conversions to c++ --- jsrc/CMakeLists.txt | 2 +- jsrc/{k.c => conversions.cpp} | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) rename jsrc/{k.c => conversions.cpp} (98%) diff --git a/jsrc/CMakeLists.txt b/jsrc/CMakeLists.txt index 7c91ae9f..01260abc 100644 --- a/jsrc/CMakeLists.txt +++ b/jsrc/CMakeLists.txt @@ -91,7 +91,7 @@ target_sources(j PRIVATE io.c j.c jdlllic.c - k.c + conversions.cpp m.c parsing/p.c parsing/pv.c diff --git a/jsrc/k.c b/jsrc/conversions.cpp similarity index 98% rename from jsrc/k.c rename to jsrc/conversions.cpp index 72f90692..af40b66d 100644 --- a/jsrc/k.c +++ b/jsrc/conversions.cpp @@ -3,8 +3,10 @@ /* */ /* Conversions Amongst Internal Types */ +extern "C" { #include "j.h" #include "verbs/vcomp.h" +} #define CVCASE(a, b) (((a) << 3) + (b)) // The main cases fit in low 8 bits of mask @@ -105,7 +107,7 @@ jtBfromD(J jt, A w, void *yv, D fuzz) { static B jtIfromD(J jt, A w, void *yv, D fuzz) { D p, q, *v; - I i, k = 0, n, *x; + I i, n, *x; n = AN(w); v = DAV(w); x = (I *)yv; @@ -315,7 +317,7 @@ jtQfromD(J jt, A w, void *yv, I mode) { for (i = 0; i < n; ++i) { t = wv[i]; ASSERT(!_isnan(t), EVNAN); - if (neg = 0 > t) t = -t; + if ((neg = 0 > t)) t = -t; q.d = iv1; if (t == inf) q.n = jtvci(jt, XPINF); @@ -328,7 +330,7 @@ jtQfromD(J jt, A w, void *yv, I mode) { q.d = jtxd1(jt, d, mode); q = jtqstd(jt, q); } else { - if (recip = 1 > t) t = 1.0 / t; + if ((recip = 1 > t)) t = 1.0 / t; e = (I)(0xfff0 & *tv); e >>= 4; e -= 1023; @@ -413,7 +415,7 @@ jtXfromQ(J jt, A w, void *yv) { static B jtZfromD(J jt, A w, void *yv) { D *wv = DAV(w); - Z *zv = yv; + Z *zv = static_cast(yv); DQ(AN(w), zv++->re = *wv++;) return 1; } @@ -478,7 +480,6 @@ jtccvt(J jt, I tflagged, A w, A *y) { if (inputn > 0) { // if converting the leading values, just update the counts n = inputn; // set the counts for local use, and in the block to be converted } else { // if converting trailing values... - I offset = (n + inputn) << bplg(t); // byte offset to start of data AK(w) += (n + inputn) << bplg(wt); yv = (I *)((C *)yv + ((n + inputn) << bplg(t))); // advance input and output pointers to new area n = -inputn; // get positive # atoms to convert @@ -512,7 +513,7 @@ jtccvt(J jt, I tflagged, A w, A *y) { } switch (CVCASE(CTTZ(t), CTTZ(wt))) { case CVCASE(INTX, B01X): { - I *x = yv; + I *x = static_cast(yv); B *v = (B *)wv; DQ(n, *x++ = *v++;); } @@ -536,13 +537,13 @@ jtccvt(J jt, I tflagged, A w, A *y) { case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return jtXfromI(jt, w, AV(d)) && jtQfromX(jt, d, yv); case CVCASE(FLX, INTX): { D *x = (D *)yv; - I *v = wv; + I *v = static_cast(wv); DQ(n, *x++ = (D)*v++;); } return 1; case CVCASE(CMPXX, INTX): { Z *x = (Z *)yv; - I *v = wv; + I *v = static_cast(wv); DQ(n, x++->re = (D)*v++;); } return 1; @@ -710,8 +711,7 @@ jtxco1(J jt, A w) { A jtxco2(J jt, A a, A w) { A z; - B b; - I j, n, r, *s, t, *wv, *zu, *zv; + I j, n, r, t; n = AN(w); r = AR(w); t = AT(w); From 2ef23027827e603363633d0cf93ef80dfdf01372 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sat, 6 Mar 2021 18:44:11 +0200 Subject: [PATCH 02/35] Add templated functions for simple conversions --- jsrc/conversions.cpp | 78 ++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 47 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index af40b66d..b45cd466 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -3,8 +3,10 @@ /* */ /* Conversions Amongst Internal Types */ +#include + +#include "array.hpp" extern "C" { -#include "j.h" #include "verbs/vcomp.h" } @@ -26,13 +28,19 @@ jtC1fromC2(J jt, A w, void *yv) { return 1; } -static B -jtC2fromC1(J jt, A w, void *yv) { - UC *v; - US *x; - v = UAV(w); - x = (US *)yv; - DQ(AN(w), *x++ = *v++;); +template +[[nodiscard]] static auto +convert(J jt, array w, void *yv) -> bool { + From *v = reinterpret_cast(UAV(w)); + std::copy(v, v + AN(w), static_cast(yv)); + return 1; +} + +template +[[nodiscard]] static auto +convert(J jt, array w, void *yv, Transform t) -> bool { + From *v = reinterpret_cast(UAV(w)); + std::transform(v, v + AN(w), static_cast(yv), t); return 1; } @@ -56,26 +64,6 @@ jtC2fromC4(J jt, A w, void *yv) { return 1; } -static B -jtC4fromC1(J jt, A w, void *yv) { - UC *v; - C4 *x; - v = UAV(w); - x = (C4 *)yv; - DQ(AN(w), *x++ = *v++;); - return 1; -} - -static B -jtC4fromC2(J jt, A w, void *yv) { - US *v; - C4 *x; - v = USAV(w); - x = (C4 *)yv; - DQ(AN(w), *x++ = *v++;); - return 1; -} - static B jtBfromI(J jt, A w, void *yv) { B *x; @@ -155,14 +143,14 @@ jtDfromZ(J jt, A w, void *yv, D fuzz) { static B jtXfromB(J jt, A w, void *yv) { - B *v; - I n, u[1]; - X *x; - n = AN(w); - v = BAV(w); - x = (X *)yv; - DO(n, *u = v[i]; x[i] = jtvec(jt, INT, 1L, u);); - return !jt->jerr; + return convert(jt, + w, + yv, + [=](auto v) { + int64_t u[] = {v}; + return jtvec(jt, INT, 1L, u); + }) && + !jt->jerr; } static B @@ -230,10 +218,7 @@ jtxd1(J jt, D p, I mode) { static B jtXfromD(J jt, A w, void *yv, I mode) { - D *v = DAV(w); - X *x = (X *)yv; - DO(AN(w), x[i] = jtxd1(jt, v[i], mode);); - return !jt->jerr; + return convert(jt, w, yv, [=](auto v){ return jtxd1(jt, v, mode); }) && !jt->jerr; } static B @@ -297,9 +282,7 @@ jtDfromX(J jt, A w, void *yv) { static B jtQfromX(J jt, A w, void *yv) { - X *v = XAV(w), *x = (X *)yv; - DQ(AN(w), *x++ = *v++; *x++ = iv1;); - return 1; + return convert(jt, w, yv, [](auto v) -> Q { return {v, iv1}; }); } static B @@ -416,7 +399,8 @@ static B jtZfromD(J jt, A w, void *yv) { D *wv = DAV(w); Z *zv = static_cast(yv); - DQ(AN(w), zv++->re = *wv++;) return 1; + DQ(AN(w), zv++->re = *wv++;); + return 1; } // Convert the data in w to the type t. w and t must be noun types. A new buffer is always created (with a @@ -504,10 +488,10 @@ jtccvt(J jt, I tflagged, A w, A *y) { switch (CVCASE(CTTZ(t), CTTZ(wt))) { case CVCASE(LITX, C2TX): return jtC1fromC2(jt, w, yv); case CVCASE(LITX, C4TX): return jtC1fromC4(jt, w, yv); - case CVCASE(C2TX, LITX): return jtC2fromC1(jt, w, yv); + case CVCASE(C2TX, LITX): return convert(jt, w, yv); case CVCASE(C2TX, C4TX): return jtC2fromC4(jt, w, yv); - case CVCASE(C4TX, LITX): return jtC4fromC1(jt, w, yv); - case CVCASE(C4TX, C2TX): return jtC4fromC2(jt, w, yv); + case CVCASE(C4TX, LITX): return convert(jt, w, yv); + case CVCASE(C4TX, C2TX): return convert(jt, w, yv); default: ASSERT(0, EVDOMAIN); } } From 223413faf88954bd2376ec1f938e0cd16589ee5e Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sat, 6 Mar 2021 18:46:03 +0200 Subject: [PATCH 03/35] Remove tautologically true #ifdef --- jsrc/conversions.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index b45cd466..68274d78 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -600,7 +600,6 @@ jtbcvt(J jt, C mode, A w) { FPREFIP; A y, z = w; if (!w) return 0; -#ifdef NANFLAG // there may be values (especially b types) that were nominally CMPX but might actually be integers. Those were // stored with the real part being the actual integer value and the imaginary part as the special 'flag' value. We // handle those here. If all the imaginary parts were flags, we accept all the integer parts and change the type @@ -629,7 +628,6 @@ jtbcvt(J jt, C mode, A w) { w = z; // this result is now eligible for further demotion } } -#endif // for all numerics, try Boolean/int/float in order, stopping when we find one that holds the data if (mode & 1 || !(AT(w) & XNUM + RAT)) { // if we are not stopping at XNUM/RAT // To avoid a needless copy, suppress conversion to B01 if type is B01, to INT if type is INT, etc From 7558baf6484d46563f238e3e61ea95a6d6fcb08f Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sat, 6 Mar 2021 19:51:49 +0200 Subject: [PATCH 04/35] Add range check to `convert()` --- jsrc/conversions.cpp | 96 ++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 65 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 68274d78..0dd8a51f 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -18,21 +18,28 @@ extern "C" { fuzz * \ ABS(v)) // used when v is known to be exact integer. It's close enough, maybe ULP too small on the high end -static B -jtC1fromC2(J jt, A w, void *yv) { - UC *x; - US c, *v; - v = USAV(w); - x = (C *)yv; - DQ(AN(w), c = *v++; if (!(256 > c)) return 0; *x++ = (UC)c;); - return 1; +template +[[nodiscard]] static constexpr auto +in_range(V value) -> bool { + return std::numeric_limits::min() <= value && value <= std::numeric_limits::max(); +} + +template +[[nodiscard]] static constexpr auto +in_range() -> bool { + return in_range(std::numeric_limits::min()) && in_range(std::numeric_limits::max()); } template [[nodiscard]] static auto convert(J jt, array w, void *yv) -> bool { - From *v = reinterpret_cast(UAV(w)); - std::copy(v, v + AN(w), static_cast(yv)); + From *v = reinterpret_cast(UAV(w)); + if constexpr (!in_range()) { + // TODO: replace with short circuiting solution + auto out = static_cast(yv); + return out + AN(w) == std::copy_if(v, v + AN(w), out, [](auto v) { return in_range(v); }); + } + std::copy(v, v + AN(w), static_cast(yv)); return 1; } @@ -44,37 +51,6 @@ convert(J jt, array w, void *yv, Transform t) -> bool { return 1; } -static B -jtC1fromC4(J jt, A w, void *yv) { - UC *x; - C4 c, *v; - v = C4AV(w); - x = (C *)yv; - DQ(AN(w), c = *v++; if (!(256 > c)) return 0; *x++ = (UC)c;); - return 1; -} - -static B -jtC2fromC4(J jt, A w, void *yv) { - US *x; - C4 c, *v; - v = C4AV(w); - x = (US *)yv; - DQ(AN(w), c = *v++; if (!(65536 > c)) return 0; *x++ = (US)c;); - return 1; -} - -static B -jtBfromI(J jt, A w, void *yv) { - B *x; - I n, p, *v; - n = AN(w); - v = AV(w); - x = (B *)yv; - DQ(n, p = *v++; *x++ = (B)p; if (p & -2) return 0;); - return 1; -} - static B jtBfromD(J jt, A w, void *yv, D fuzz) { B *x; @@ -451,7 +427,6 @@ jtccvt(J jt, I tflagged, A w, A *y) { RZ(*y = jtca(jt, w)); return 1; } - // else if(n&&t&JCHAR){ASSERT(HOMO(t,wt),EVDOMAIN); RZ(*y=jtuco1(jt,w)); return 1;} // Kludge on behalf of result assembly: we want to be able to stop converting after the valid cells. If // NOUNCVTVALIDCT is set in the type, we use the input *y as as override on the # cells to convert. We use it to // replace n (for use here) and yv, and AK(w) and AN(w) for the subroutines. If NOUNCVTVALIDCT is set, w is @@ -480,35 +455,29 @@ jtccvt(J jt, I tflagged, A w, A *y) { // Perform the conversion based on data types // For branch-table efficiency, we split the C2T and C4T and BIT conversions into one block, and // the rest in another - if ((t | wt) & - (C2T + C4T + BIT + SBT)) { // there are no SBT conversions, but we have to show domain error - // we must account for all NOUN types. Low 8 bits have most of them, and we know type can't be sparse. This - // picks up the others + if ((t | wt) & (C2T + C4T + BIT + SBT)) { + // there are no SBT conversions, but we have to show domain error we + // must account for all NOUN types. Low 8 bits have most of them, and + // we know type can't be sparse. This picks up the others ASSERT(!((t | wt) & SBT), EVDOMAIN); // No conversions for these types switch (CVCASE(CTTZ(t), CTTZ(wt))) { - case CVCASE(LITX, C2TX): return jtC1fromC2(jt, w, yv); - case CVCASE(LITX, C4TX): return jtC1fromC4(jt, w, yv); + case CVCASE(LITX, C2TX): return convert(jt, w, yv); + case CVCASE(LITX, C4TX): return convert(jt, w, yv); case CVCASE(C2TX, LITX): return convert(jt, w, yv); - case CVCASE(C2TX, C4TX): return jtC2fromC4(jt, w, yv); + case CVCASE(C2TX, C4TX): return convert(jt, w, yv); case CVCASE(C4TX, LITX): return convert(jt, w, yv); case CVCASE(C4TX, C2TX): return convert(jt, w, yv); default: ASSERT(0, EVDOMAIN); } } switch (CVCASE(CTTZ(t), CTTZ(wt))) { - case CVCASE(INTX, B01X): { - I *x = static_cast(yv); - B *v = (B *)wv; - DQ(n, *x++ = *v++;); - } + case CVCASE(INTX, B01X): + std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; case CVCASE(XNUMX, B01X): return jtXfromB(jt, w, yv); case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); return jtXfromB(jt, w, AV(d)) && jtQfromX(jt, d, yv); - case CVCASE(FLX, B01X): { - D *x = (D *)yv; - B *v = (B *)wv; - DQ(n, *x++ = *v++;); - } + case CVCASE(FLX, B01X): + std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; case CVCASE(CMPXX, B01X): { Z *x = (Z *)yv; @@ -516,14 +485,11 @@ jtccvt(J jt, I tflagged, A w, A *y) { DQ(n, x++->re = *v++;); } return 1; - case CVCASE(B01X, INTX): return jtBfromI(jt, w, yv); + case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return jtXfromI(jt, w, yv); case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return jtXfromI(jt, w, AV(d)) && jtQfromX(jt, d, yv); - case CVCASE(FLX, INTX): { - D *x = (D *)yv; - I *v = static_cast(wv); - DQ(n, *x++ = (D)*v++;); - } + case CVCASE(FLX, INTX): + std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; case CVCASE(CMPXX, INTX): { Z *x = (Z *)yv; From d3187f73fa219f65e3ad12449c59429723ba7d2c Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sat, 6 Mar 2021 22:32:29 +0200 Subject: [PATCH 05/35] Refactor `jtDfromX()` --- jsrc/conversions.cpp | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 0dd8a51f..a3cd3263 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -4,6 +4,8 @@ /* Conversions Amongst Internal Types */ #include +#include +#include #include "array.hpp" extern "C" { @@ -232,27 +234,14 @@ jtIfromX(J jt, A w, void *yv) { static B jtDfromX(J jt, A w, void *yv) { - D d, *x = (D *)yv /*,dm,dp*/; - I c, i, n, *v, wn; - X p, *wv; - // dp=1.7976931348623157e308; dm=-dp; - wn = AN(w); - wv = XAV(w); - for (i = 0; i < wn; ++i) { - p = wv[i]; - n = AN(p); - v = AV(p) + n - 1; - c = *v; - if (c == XPINF) - d = inf; - else if (c == XNINF) - d = infm; - else { - d = 0.0; - DQ(n, d = *v-- + d * XBASE;); - } - x[i] = d; - } + auto const wv = XAV(w); + std::transform(wv, wv + AN(w), static_cast(yv), [](auto p) { + auto const n = AN(p); + auto const v = std::reverse_iterator(AV(p) + n); + if (*v == XPINF) return inf; + if (*v == XNINF) return infm; + return std::accumulate(v, v + n, 0.0, [](auto d, auto v) { return v + d * XBASE; }); + }); return 1; } From f8d612b139016ce73b71b1f59910fcd73d475d9e Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sat, 6 Mar 2021 23:12:17 +0200 Subject: [PATCH 06/35] Const refactor `jtDfromQ()` --- jsrc/conversions.cpp | 69 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index a3cd3263..6991b7db 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -301,49 +301,48 @@ jtQfromD(J jt, A w, void *yv, I mode) { static B jtDfromQ(J jt, A w, void *yv) { - D d, f, n, *x, xb = (D)XBASE; - I cn, i, k, m, nn, pn, qn, r, *v, wn; - Q *wv; - X c, p, q, x2 = 0; - wn = AN(w); - wv = QAV(w); - x = (D *)yv; - nn = 308 / XBASEN; - for (i = 0; i < wn; ++i) { - p = wv[i].n; - pn = AN(p); - k = 1 == pn ? AV(p)[0] : 0; - q = wv[i].d; - qn = AN(q); + auto const xb = (D)XBASE; + auto const wn = AN(w); + auto const wv = QAV(w); + auto const x = (D *)yv; + auto const nn = 308 / XBASEN; + + // TODO: figure out nice algorithm for this + auto const add_digits = [&](auto n, auto v) { + auto f = 1.0; + auto d = 0.0; + DO(n, d += f * v[i]; f *= xb;); + return d; + }; + + X x2 = 0; + for (int64_t i = 0; i < wn; ++i) { + auto const p = wv[i].n; + auto const pn = AN(p); + auto const k = 1 == pn ? AV(p)[0] : 0; + auto const q = wv[i].d; + auto const qn = AN(q); if (k == XPINF) x[i] = inf; else if (k == XNINF) x[i] = infm; else if (pn <= nn && qn <= nn) { - n = 0.0; - f = 1.0; - v = AV(p); - DO(pn, n += f * v[i]; f *= xb;); - d = 0.0; - f = 1.0; - v = AV(q); - DO(qn, d += f * v[i]; f *= xb;); - x[i] = n / d; + auto const n = add_digits(pn, AV(p)); + auto const d = add_digits(qn, AV(q)); + x[i] = n / d; } else { - k = 5 + qn; if (!x2) if (!(x2 = jtxc(jt, 2L))) return 0; - if (!(c = jtxdiv(jt, jttake(jt, jtsc(jt, -(k + pn)), p), q, XMFLR))) return 0; - cn = AN(c); - m = MIN(cn, 5); - r = cn - (m + k); - v = AV(c) + cn - m; - n = 0.0; - f = 1.0; - DO(m, n += f * v[i]; f *= xb;); - d = 1.0; - DQ(ABS(r), d *= xb;); - x[i] = 0 > r ? n / d : n * d; + auto const k = 5 + qn; + auto c = jtxdiv(jt, jttake(jt, jtsc(jt, -(k + pn)), p), q, XMFLR); + if (!c) return 0; + auto const cn = AN(c); + auto const m = MIN(cn, 5); + auto const r = cn - (m + k); + auto const v = AV(c) + cn - m; + auto const n = add_digits(m, v); + auto d = std::pow(xb, std::abs(r)); + x[i] = 0 > r ? n / d : n * d; } } return 1; From d308fbf137e814934fd4448757316bd5e0201ad9 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sat, 6 Mar 2021 23:43:54 +0200 Subject: [PATCH 07/35] Refactor `jtXfromI()` --- jsrc/conversions.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 6991b7db..3295cd29 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -133,23 +133,22 @@ jtXfromB(J jt, A w, void *yv) { static B jtXfromI(J jt, A w, void *yv) { - B b; - I c, d, i, j, n, r, u[XIDIG], *v; - X *x; - n = AN(w); - v = AV(w); - x = (X *)yv; - for (i = 0; i < n; ++i) { - c = v[i]; - b = c == IMIN; - d = b ? -(1 + c) : ABS(c); - j = 0; - DO(XIDIG, u[i] = r = d % XBASE; d = d / XBASE; if (r) j = i;); - ++j; + I u[XIDIG]; + auto const v = AV(w); + std::transform(v, v + AN(w), static_cast(yv), [&](auto c) { + auto const b = c == IMIN; + auto d = b ? -(1 + c) : std::abs(c); + int64_t length = 0; + for (int64_t i = 0; i < XIDIG; ++i) { + u[i] = d % XBASE; + d = d / XBASE; + if (u[i]) length = i; + } + ++length; *u += b; - if (0 > c) DO(XIDIG, u[i] = -u[i];); - x[i] = jtvec(jt, INT, j, u); - } + if (0 > c) std::transform(u, u + XIDIG, u, [](auto v) { return -v; }); + return jtvec(jt, INT, length, u); + }); return !jt->jerr; } From bd251961b6b4682726099365f897a8b4cd5ead49 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 00:20:34 +0200 Subject: [PATCH 08/35] Extract couple helper functions --- jsrc/conversions.cpp | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 3295cd29..ce61ed0a 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -131,6 +131,12 @@ jtXfromB(J jt, A w, void *yv) { !jt->jerr; } +template +static auto +inplace_negate(T& u, int64_t n) { + std::transform(u, u + n, u, [](auto v) { return -v; }); +} + static B jtXfromI(J jt, A w, void *yv) { I u[XIDIG]; @@ -146,7 +152,7 @@ jtXfromI(J jt, A w, void *yv) { } ++length; *u += b; - if (0 > c) std::transform(u, u + XIDIG, u, [](auto v) { return -v; }); + if (0 > c) inplace_negate(u, XIDIG); return jtvec(jt, INT, length, u); }); return !jt->jerr; @@ -187,8 +193,9 @@ jtxd1(J jt, D p, I mode) { if (!m) { u[0] = 0; ++m; - } else if (0 > p) - DO(m, u[i] = -u[i];); + } else if (0 > p) { + inplace_negate(u, m); + } A z = jtxstd(jt, jtvec(jt, INT, m, u)); EPILOG(z); } @@ -210,6 +217,14 @@ jtBfromX(J jt, A w, void *yv) { return 1; } +template +[[nodiscard]] static auto +value_from_X(X p) -> T { + auto const n = AN(p); + auto const v = std::reverse_iterator(AV(p) + n); + return std::accumulate(v, v + n, T{}, [](auto d, auto v) { return v + d * XBASE; }); +} + static B jtIfromX(J jt, A w, void *yv) { I a, i, m, n, *u, *x; @@ -222,11 +237,7 @@ jtIfromX(J jt, A w, void *yv) { for (i = 0; i < n; ++i) { c = v[i]; if (!(1 != jtxcompare(jt, q, c) && 1 != jtxcompare(jt, c, p))) return 0; - m = AN(c); - u = AV(c) + m - 1; - a = 0; - DO(m, a = *u-- + a * XBASE;); - x[i] = a; + x[i] = value_from_X(c); } return 1; } @@ -235,11 +246,10 @@ static B jtDfromX(J jt, A w, void *yv) { auto const wv = XAV(w); std::transform(wv, wv + AN(w), static_cast(yv), [](auto p) { - auto const n = AN(p); - auto const v = std::reverse_iterator(AV(p) + n); - if (*v == XPINF) return inf; - if (*v == XNINF) return infm; - return std::accumulate(v, v + n, 0.0, [](auto d, auto v) { return v + d * XBASE; }); + auto const c = AV(p)[AN(p)-1]; + if (c == XPINF) return inf; + if (c == XNINF) return infm; + return value_from_X(p); }); return 1; } From 12fc5b9910c600bd192b1ab6cc2c0aacc8c1c4f9 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 00:47:49 +0200 Subject: [PATCH 09/35] Refactor couple transforms --- jsrc/conversions.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index ce61ed0a..c1e3d926 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -561,48 +561,48 @@ jtcvt(J jt, I t, A w) { A jtbcvt(J jt, C mode, A w) { FPREFIP; - A y, z = w; if (!w) return 0; + + auto const as_integer = [](auto const &v) { return *(I *)&v; }; + auto const isflag = [&](auto const &z) { return as_integer(z.im) == NANFLAG; }; + // there may be values (especially b types) that were nominally CMPX but might actually be integers. Those were // stored with the real part being the actual integer value and the imaginary part as the special 'flag' value. We // handle those here. If all the imaginary parts were flags, we accept all the integer parts and change the type // to integer. If none of the imaginary parts were flags, we leave the input unchanged. If some were flags, we // convert the flagged values to float and keep the result as complex + array result = w; if ((((AN(w) - 1) | (AT(w) & CMPX) - 1)) >= 0) { // not empty AND complex - I allflag = 1, anyflag = 0; - Z *wv = ZAV(w); - DO(AN(w), I isflag = *(I *)&wv[i].im == NANFLAG; allflag &= isflag; anyflag |= isflag;) - if (anyflag) { + Z *wv = ZAV(w); + auto flags = std::transform_reduce(wv, wv + AN(w), int64_t{}, std::plus{}, isflag); + if (flags) { I ipok = SGNIF(jtinplace, JTINPLACEWX) & AC(w); // both sign bits set (<0) if inplaceable - if (allflag) { - if (ipok >= 0) GATV(z, INT, AN(w), AR(w), AS(w)); - I *zv = IAV(z); // output area - DO(AN(w), zv[i] = *(I *)&wv[i].re;) // copy the results as integers + if (flags == AN(w)) { + if (ipok >= 0) GATV(result, INT, AN(w), AR(w), AS(w)); + std::transform(wv, wv + AN(w), IAV(result), [&](auto const &z) { return as_integer(z.re); }); } else { - if (ipok >= 0) GATV(z, CMPX, AN(w), AR(w), AS(w)); - Z *zv = ZAV(z); // output area - DO( - AN(w), - if (*(I *)&wv[i].im == NANFLAG) { - zv[i].re = (D) * (I *)&wv[i].re; - zv[i].im = 0.0; - } else { zv[i] = wv[i]; }) // copy floats, and converts any integers back to float + if (ipok >= 0) GATV(result, CMPX, AN(w), AR(w), AS(w)); + std::transform(wv, wv + AN(w), ZAV(result), [&](auto const &z) -> Z { + if (isflag(z)) return {.re = (D)as_integer(z.re), .im = 0.0}; + return z; // copy floats, and converts any integers back to float + }); } - w = z; // this result is now eligible for further demotion + w = result; // this result is now eligible for further demotion } } // for all numerics, try Boolean/int/float in order, stopping when we find one that holds the data if (mode & 1 || !(AT(w) & XNUM + RAT)) { // if we are not stopping at XNUM/RAT // To avoid a needless copy, suppress conversion to B01 if type is B01, to INT if type is INT, etc // set the NOFUZZ flag in jt to insist on an exact match so we won't lose precision + array y; jtinplace = (J)((I)jt + JTNOFUZZ); // demand exact match - z = !(mode & 14) && jtccvt(jtinplace, B01, w, &y) ? y + result = !(mode & 14) && jtccvt(jtinplace, B01, w, &y) ? y : (y = w, AT(w) & INT || (!(mode & 12) && jtccvt(jtinplace, INT, w, &y))) ? y : (y = w, AT(w) & FL || (!(mode & 8) && jtccvt(jtinplace, FL, w, &y))) ? y : w; // convert to enabled modes one by one, stopping when one works } - RNE(z); + RNE(result); } /* convert to lowest type. 0=mode: don't convert XNUM/RAT to other types */ A From 7372afb5f8c9cbc28c3485bc695eb482c20ee44a Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 01:15:55 +0200 Subject: [PATCH 10/35] Remove some decl-init split --- jsrc/conversions.cpp | 130 ++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 75 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index c1e3d926..19188b17 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -55,13 +55,10 @@ convert(J jt, array w, void *yv, Transform t) -> bool { static B jtBfromD(J jt, A w, void *yv, D fuzz) { - B *x; - D p, *v; - I n; - n = AN(w); - v = DAV(w); - x = (B *)yv; - DQ(n, p = *v++; if (p < -2 || 2 < p) return 0; // handle infinities + auto n = AN(w); + auto v = DAV(w); + auto x = (B *)yv; + DQ(n, auto p = *v++; if (p < -2 || 2 < p) return 0; // handle infinities I val = 2; val = (p == 0) ? 0 : val; val = FIEQ(p, 1.0, fuzz) ? 1 : val; @@ -72,15 +69,13 @@ jtBfromD(J jt, A w, void *yv, D fuzz) { static B jtIfromD(J jt, A w, void *yv, D fuzz) { - D p, q, *v; - I i, n, *x; - n = AN(w); - v = DAV(w); - x = (I *)yv; - for (i = 0; i < n; ++i) { - p = v[i]; - q = jround(p); - I rq = (I)q; + auto n = AN(w); + auto v = DAV(w); + auto x = (I *)yv; + for (int64_t i = 0; i < n; ++i) { + auto const p = v[i]; + auto const q = jround(p); + I rq = (I)q; if (!(p == q || FIEQ(p, q, fuzz))) return 0; // must equal int, possibly out of range // out-of-range values don't convert, handle separately if (p < (D)IMIN) { @@ -98,21 +93,18 @@ jtIfromD(J jt, A w, void *yv, D fuzz) { static B jtDfromZ(J jt, A w, void *yv, D fuzz) { - D d, *x; - I n; - Z *v; - n = AN(w); - v = ZAV(w); - x = (D *)yv; + auto const n = AN(w); + auto const *v = ZAV(w); + auto x = (D *)yv; if (fuzz) DQ( - n, d = ABS(v->im); if (d != inf && d <= fuzz * ABS(v->re)) { + n, auto d = std::abs(v->im); if (d != inf && d <= fuzz * std::abs(v->re)) { *x++ = v->re; v++; } else return 0;) else DQ( - n, d = v->im; if (!d) { + n, if (!v->im) { *x++ = v->re; v++; } else return 0;); @@ -161,9 +153,7 @@ jtXfromI(J jt, A w, void *yv) { static X jtxd1(J jt, D p, I mode) { PROLOG(0052); - A t; - D d, e = jttfloor(jt, p), q, r; - I m, *u; + D e = jttfloor(jt, p); switch (mode) { case XMFLR: p = e; break; case XMCEIL: p = ceil(p); break; @@ -176,15 +166,16 @@ jtxd1(J jt, D p, I mode) { } if (p == inf) return jtvci(jt, XPINF); if (p == -inf) return jtvci(jt, XNINF); + A t; GAT0(t, INT, 30, 1); - u = AV(t); - m = 0; - d = ABS(p); + auto u = AV(t); + int64_t m = 0; + auto d = std::abs(p); while (0 < d) { - q = floor(d / XBASE); - r = d - q * XBASE; - u[m++] = (I)r; - d = q; + auto const q = floor(d / XBASE); + auto const r = d - q * XBASE; + u[m++] = (I)r; + d = q; if (m == AN(t)) { RZ(t = jtext(jt, 0, t)); u = AV(t); @@ -207,13 +198,9 @@ jtXfromD(J jt, A w, void *yv, I mode) { static B jtBfromX(J jt, A w, void *yv) { - A q; - B *x; - I e; - X *v; - v = XAV(w); - x = (B *)yv; - DO(AN(w), q = v[i]; e = AV(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return 0; x[i] = (B)e;); + auto v = XAV(w); + auto x = (B *)yv; + DO(AN(w), A q = v[i]; I e = AV(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return 0; x[i] = (B)e;); return 1; } @@ -227,15 +214,14 @@ value_from_X(X p) -> T { static B jtIfromX(J jt, A w, void *yv) { - I a, i, m, n, *u, *x; - X c, p, q, *v; - v = XAV(w); - x = (I *)yv; - n = AN(w); + auto v = XAV(w); + auto x = (I *)yv; + auto n = AN(w); + X p, q; if (!(p = jtxc(jt, IMAX))) return 0; if (!(q = jtxminus(jt, jtnegate(jt, p), jtxc(jt, 1L)))) return 0; - for (i = 0; i < n; ++i) { - c = v[i]; + for (int64_t i = 0; i < n; ++i) { + auto c = v[i]; if (!(1 != jtxcompare(jt, q, c) && 1 != jtxcompare(jt, c, p))) return 0; x[i] = value_from_X(c); } @@ -359,10 +345,8 @@ jtDfromQ(J jt, A w, void *yv) { static B jtXfromQ(J jt, A w, void *yv) { - Q *v; - X *x; - v = QAV(w); - x = (X *)yv; + auto v = QAV(w); + auto x = (X *)yv; DQ(AN(w), if (!(jtequ(jt, iv1, v->d))) return 0; *x++ = v->n; ++v;); return !jt->jerr; } @@ -548,9 +532,8 @@ jtccvt(J jt, I tflagged, A w, A *y) { A jtcvt(J jt, I t, A w) { A y; - B b; - b = jtccvt(jt, t, w, &y); - ASSERT(b != 0, EVDOMAIN); + bool const b = jtccvt(jt, t, w, &y); + ASSERT(b, EVDOMAIN); return y; } @@ -635,14 +618,11 @@ jtpcvt(J jt, I t, A w) { A jtcvt0(J jt, A w) { - I n, t; - D *u; - t = AT(w); - n = AN(w); + auto const t = AT(w); + auto const n = (t & CMPX) ? 2 * AN(w) : AN(w); if (n && t & FL + CMPX) { - if (t & CMPX) n += n; - u = DAV(w); - DQ(n, if (*u == 0.0) *u = 0.0; ++u;); + auto u = DAV(w); + std::transform(u, u + n, u, [](auto v) { return v == 0.0 ? 0.0 : v; }); } return w; } /* convert -0 to 0 in place */ @@ -655,24 +635,24 @@ jtxco1(J jt, A w) { A jtxco2(J jt, A a, A w) { - A z; - I j, n, r, t; - n = AN(w); - r = AR(w); - t = AT(w); - ASSERT(t & DENSE, EVNONCE); + ASSERT(AT(w) & DENSE, EVNONCE); + I j; RE(j = jti0(jt, a)); switch (j) { case -2: return jtaslash1(jt, CDIV, w); case -1: return jtbcvt(jt, 1, w); case 1: return jtxco1(jt, w); case 2: - if (!(t & RAT)) RZ(w = jtcvt(jt, RAT, w)); - GATV(z, XNUM, 2 * n, r + 1, AS(w)); - AS(z)[r] = 2; - memcpy(AV(z), AV(w), 2 * n * SZI); - return z; - default: - ASSERT(0, EVDOMAIN); + if (!(AT(w) & RAT)) RZ(w = jtcvt(jt, RAT, w)); + { + auto const n = AN(w); + auto const r = AR(w); + A z; + GATV(z, XNUM, 2 * n, r + 1, AS(w)); + AS(z)[r] = 2; + memcpy(AV(z), AV(w), 2 * n * SZI); + return z; + } + default: ASSERT(0, EVDOMAIN); } } From 463b02fdc4295d8d197d60904bddecead6d40346 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 01:34:22 +0200 Subject: [PATCH 11/35] Add specialisations for `convert()` --- jsrc/conversions.cpp | 142 ++++++++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 64 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 19188b17..e4313548 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -21,19 +21,19 @@ extern "C" { ABS(v)) // used when v is known to be exact integer. It's close enough, maybe ULP too small on the high end template -[[nodiscard]] static constexpr auto +[[nodiscard]] constexpr auto in_range(V value) -> bool { return std::numeric_limits::min() <= value && value <= std::numeric_limits::max(); } template -[[nodiscard]] static constexpr auto +[[nodiscard]] constexpr auto in_range() -> bool { return in_range(std::numeric_limits::min()) && in_range(std::numeric_limits::max()); } template -[[nodiscard]] static auto +[[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { From *v = reinterpret_cast(UAV(w)); if constexpr (!in_range()) { @@ -46,15 +46,16 @@ convert(J jt, array w, void *yv) -> bool { } template -[[nodiscard]] static auto +[[nodiscard]] auto convert(J jt, array w, void *yv, Transform t) -> bool { From *v = reinterpret_cast(UAV(w)); std::transform(v, v + AN(w), static_cast(yv), t); return 1; } -static B -jtBfromD(J jt, A w, void *yv, D fuzz) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv, D fuzz) -> bool { auto n = AN(w); auto v = DAV(w); auto x = (B *)yv; @@ -67,8 +68,9 @@ jtBfromD(J jt, A w, void *yv, D fuzz) { return 1; } -static B -jtIfromD(J jt, A w, void *yv, D fuzz) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv, D fuzz) -> bool { auto n = AN(w); auto v = DAV(w); auto x = (I *)yv; @@ -91,8 +93,9 @@ jtIfromD(J jt, A w, void *yv, D fuzz) { return 1; } -static B -jtDfromZ(J jt, A w, void *yv, D fuzz) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv, D fuzz) -> bool { auto const n = AN(w); auto const *v = ZAV(w); auto x = (D *)yv; @@ -111,8 +114,9 @@ jtDfromZ(J jt, A w, void *yv, D fuzz) { return 1; } -static B -jtXfromB(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { return convert(jt, w, yv, @@ -129,8 +133,9 @@ inplace_negate(T& u, int64_t n) { std::transform(u, u + n, u, [](auto v) { return -v; }); } -static B -jtXfromI(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { I u[XIDIG]; auto const v = AV(w); std::transform(v, v + AN(w), static_cast(yv), [&](auto c) { @@ -191,13 +196,15 @@ jtxd1(J jt, D p, I mode) { EPILOG(z); } -static B -jtXfromD(J jt, A w, void *yv, I mode) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv, I mode) -> bool { return convert(jt, w, yv, [=](auto v){ return jtxd1(jt, v, mode); }) && !jt->jerr; } -static B -jtBfromX(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { auto v = XAV(w); auto x = (B *)yv; DO(AN(w), A q = v[i]; I e = AV(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return 0; x[i] = (B)e;); @@ -212,8 +219,9 @@ value_from_X(X p) -> T { return std::accumulate(v, v + n, T{}, [](auto d, auto v) { return v + d * XBASE; }); } -static B -jtIfromX(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { auto v = XAV(w); auto x = (I *)yv; auto n = AN(w); @@ -228,8 +236,9 @@ jtIfromX(J jt, A w, void *yv) { return 1; } -static B -jtDfromX(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { auto const wv = XAV(w); std::transform(wv, wv + AN(w), static_cast(yv), [](auto p) { auto const c = AV(p)[AN(p)-1]; @@ -240,13 +249,15 @@ jtDfromX(J jt, A w, void *yv) { return 1; } -static B -jtQfromX(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { return convert(jt, w, yv, [](auto v) -> Q { return {v, iv1}; }); } -static B -jtQfromD(J jt, A w, void *yv, I mode) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv, I mode) -> bool { B neg, recip; D c, d, t, *wv; I e, i, n, *v; @@ -294,8 +305,9 @@ jtQfromD(J jt, A w, void *yv, I mode) { return !jt->jerr; } -static B -jtDfromQ(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { auto const xb = (D)XBASE; auto const wn = AN(w); auto const wv = QAV(w); @@ -343,8 +355,9 @@ jtDfromQ(J jt, A w, void *yv) { return 1; } -static B -jtXfromQ(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { auto v = QAV(w); auto x = (X *)yv; DQ(AN(w), if (!(jtequ(jt, iv1, v->d))) return 0; *x++ = v->n; ++v;); @@ -352,8 +365,9 @@ jtXfromQ(J jt, A w, void *yv) { } // Imaginary parts have already been cleared -static B -jtZfromD(J jt, A w, void *yv) { +template <> +[[nodiscard]] auto +convert(J jt, A w, void *yv) -> bool { D *wv = DAV(w); Z *zv = static_cast(yv); DQ(AN(w), zv++->re = *wv++;); @@ -455,8 +469,8 @@ jtccvt(J jt, I tflagged, A w, A *y) { case CVCASE(INTX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; - case CVCASE(XNUMX, B01X): return jtXfromB(jt, w, yv); - case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); return jtXfromB(jt, w, AV(d)) && jtQfromX(jt, d, yv); + case CVCASE(XNUMX, B01X): return convert(jt, w, yv); + case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); return convert(jt, w, AV(d)) && convert(jt, d, yv); case CVCASE(FLX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; @@ -467,8 +481,8 @@ jtccvt(J jt, I tflagged, A w, A *y) { } return 1; case CVCASE(B01X, INTX): return convert(jt, w, yv); - case CVCASE(XNUMX, INTX): return jtXfromI(jt, w, yv); - case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return jtXfromI(jt, w, AV(d)) && jtQfromX(jt, d, yv); + case CVCASE(XNUMX, INTX): return convert(jt, w, yv); + case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, AV(d)) && convert(jt, d, yv); case CVCASE(FLX, INTX): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; @@ -478,52 +492,52 @@ jtccvt(J jt, I tflagged, A w, A *y) { DQ(n, x++->re = (D)*v++;); } return 1; - case CVCASE(B01X, FLX): return jtBfromD(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); - case CVCASE(INTX, FLX): return jtIfromD(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + case CVCASE(B01X, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + case CVCASE(INTX, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(XNUMX, FLX): - return jtXfromD(jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + return convert(jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(RATX, FLX): - return jtQfromD(jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); - case CVCASE(CMPXX, FLX): return jtZfromD(jt, w, yv); + return convert(jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + case CVCASE(CMPXX, FLX): return convert(jt, w, yv); case CVCASE(B01X, CMPXX): GATV(d, FL, n, r, s); - if (!(jtDfromZ(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; - return jtBfromD(jt, d, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + return convert(jt, d, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(INTX, CMPXX): GATV(d, FL, n, r, s); - if (!(jtDfromZ(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; - return jtIfromD(jt, d, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + return convert(jt, d, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(XNUMX, CMPXX): GATV(d, FL, n, r, s); - if (!(jtDfromZ(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; - return jtXfromD(jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + return convert(jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(RATX, CMPXX): GATV(d, FL, n, r, s); - if (!(jtDfromZ(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; - return jtQfromD(jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); - case CVCASE(FLX, CMPXX): return jtDfromZ(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); - case CVCASE(B01X, XNUMX): return jtBfromX(jt, w, yv); - case CVCASE(INTX, XNUMX): return jtIfromX(jt, w, yv); - case CVCASE(RATX, XNUMX): return jtQfromX(jt, w, yv); - case CVCASE(FLX, XNUMX): return jtDfromX(jt, w, yv); + if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + return convert(jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + case CVCASE(FLX, CMPXX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + case CVCASE(B01X, XNUMX): return convert(jt, w, yv); + case CVCASE(INTX, XNUMX): return convert(jt, w, yv); + case CVCASE(RATX, XNUMX): return convert(jt, w, yv); + case CVCASE(FLX, XNUMX): return convert(jt, w, yv); case CVCASE(CMPXX, XNUMX): GATV(d, FL, n, r, s); - if (!(jtDfromX(jt, w, AV(d)))) return 0; - return jtZfromD(jt, d, yv); + if (!(convert(jt, w, AV(d)))) return 0; + return convert(jt, d, yv); case CVCASE(B01X, RATX): GATV(d, XNUM, n, r, s); - if (!(jtXfromQ(jt, w, AV(d)))) return 0; - return jtBfromX(jt, d, yv); + if (!(convert(jt, w, AV(d)))) return 0; + return convert(jt, d, yv); case CVCASE(INTX, RATX): GATV(d, XNUM, n, r, s); - if (!(jtXfromQ(jt, w, AV(d)))) return 0; - return jtIfromX(jt, d, yv); - case CVCASE(XNUMX, RATX): return jtXfromQ(jt, w, yv); - case CVCASE(FLX, RATX): return jtDfromQ(jt, w, yv); + if (!(convert(jt, w, AV(d)))) return 0; + return convert(jt, d, yv); + case CVCASE(XNUMX, RATX): return convert(jt, w, yv); + case CVCASE(FLX, RATX): return convert(jt, w, yv); case CVCASE(CMPXX, RATX): GATV(d, FL, n, r, s); - if (!(jtDfromQ(jt, w, AV(d)))) return 0; - return jtZfromD(jt, d, yv); + if (!(convert(jt, w, AV(d)))) return 0; + return convert(jt, d, yv); default: ASSERT(0, EVDOMAIN); } } From 77c010562bcf4191ad4d8e74b369f0e209f9265e Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 01:56:00 +0200 Subject: [PATCH 12/35] Remove more decl-init split --- jsrc/conversions.cpp | 116 +++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index e4313548..f05bad61 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -258,34 +258,35 @@ convert(J jt, A w, void *yv) -> bool { template <> [[nodiscard]] auto convert(J jt, A w, void *yv, I mode) -> bool { - B neg, recip; - D c, d, t, *wv; - I e, i, n, *v; - Q q, *x; - S *tv; if (!(w)) return 0; - n = AN(w); - wv = DAV(w); - x = (Q *)yv; - tv = 3 + (S *)&t; - for (i = 0; i < n; ++i) { + auto const n = AN(w); + auto const wv = DAV(w); + auto x = (Q *)yv; + D t; + auto tv = 3 + (S *)&t; + Q q; + for (int64_t i = 0; i < n; ++i) { t = wv[i]; ASSERT(!_isnan(t), EVNAN); - if ((neg = 0 > t)) t = -t; + bool const neg = 0 > t; + if (neg) t = -t; q.d = iv1; if (t == inf) q.n = jtvci(jt, XPINF); else if (t == 0.0) q.n = iv0; else if (1.1102230246251565e-16 < t && t < 9.007199254740992e15) { - d = jround(1 / jtdgcd(jt, 1.0, t)); - c = jround(d * t); - q.n = jtxd1(jt, c, mode); - q.d = jtxd1(jt, d, mode); - q = jtqstd(jt, q); + auto const d = jround(1 / jtdgcd(jt, 1.0, t)); + auto const c = jround(d * t); + q = jtqstd(jt, + { + .n = jtxd1(jt, c, mode), + .d = jtxd1(jt, d, mode), + }); } else { - if ((recip = 1 > t)) t = 1.0 / t; - e = (I)(0xfff0 & *tv); + bool const recip = 1 > t; + if (recip) t = 1.0 / t; + auto e = (I)(0xfff0 & *tv); e >>= 4; e -= 1023; if (recip) { @@ -297,7 +298,7 @@ convert(J jt, A w, void *yv, I mode) -> bool { } } if (neg) { - v = AV(q.n); + auto v = AV(q.n); DQ(AN(q.n), *v = -*v; ++v;); } *x++ = q; @@ -381,13 +382,10 @@ convert(J jt, A w, void *yv) -> bool { B jtccvt(J jt, I tflagged, A w, A *y) { FPREFIP; - A d; - I n, r, *s, wt; - void *wv, *yv; - I t = tflagged & NOUN; + I const t = tflagged & NOUN; if (!w) return 0; - r = AR(w); - s = AS(w); + auto const r = AR(w); + auto const s = AS(w); if (((t | AT(w)) & SPARSE) != 0) { // Handle sparse RANK2T oqr = jt->ranks; @@ -415,8 +413,7 @@ jtccvt(J jt, I tflagged, A w, A *y) { jt->ranks = oqr; } // Now known to be non-sparse - n = AN(w); - wt = AT(w); + auto const wt = AT(w); // If type is already correct, return a clone - used to force a copy. Should get rid of this kludge if (TYPESEQ(t, wt)) { RZ(*y = jtca(jt, w)); @@ -427,13 +424,15 @@ jtccvt(J jt, I tflagged, A w, A *y) { // replace n (for use here) and yv, and AK(w) and AN(w) for the subroutines. If NOUNCVTVALIDCT is set, w is // modified: the caller must restore AN(w) and AK(w) if it needs it // TODO: same-length conversion could be done in place + auto n = AN(w); + A d; GA(d, t, n, r, s); - yv = voidAV(d); // allocate the same # atoms, even if we will convert fewer + auto yv = voidAV(d); // allocate the same # atoms, even if we will convert fewer if (tflagged & NOUNCVTVALIDCT) { - I inputn = *(I *)y; // fetch input, in case it is called for - if (inputn > 0) { // if converting the leading values, just update the counts - n = inputn; // set the counts for local use, and in the block to be converted - } else { // if converting trailing values... + I inputn = *(I *)y; // fetch input, in case it is called for + if (inputn > 0) { // if converting the leading values, just update the counts + n = inputn; // set the counts for local use, and in the block to be converted + } else { // if converting trailing values... AK(w) += (n + inputn) << bplg(wt); yv = (I *)((C *)yv + ((n + inputn) << bplg(t))); // advance input and output pointers to new area n = -inputn; // get positive # atoms to convert @@ -443,8 +442,8 @@ jtccvt(J jt, I tflagged, A w, A *y) { // If n and AN have been modified, it doesn't matter for rank-1 arguments whether the shape of the result is listed // as n or s[0] since only n atoms will be used. For higher ranks, we need the shape from s. So it's just as well // that we take the shape from s now - *y = d; - wv = voidAV(w); // return the address of the new block + *y = d; + auto wv = voidAV(w); // return the address of the new block if (t & CMPX) jtfillv(jt, t, n, (C *)yv); // why?? just fill in imaginary parts as we need to if (!n) return 1; // Perform the conversion based on data types @@ -466,14 +465,12 @@ jtccvt(J jt, I tflagged, A w, A *y) { } } switch (CVCASE(CTTZ(t), CTTZ(wt))) { - case CVCASE(INTX, B01X): - std::copy_n(static_cast(wv), n, static_cast(yv)); - return 1; + case CVCASE(INTX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; case CVCASE(XNUMX, B01X): return convert(jt, w, yv); - case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); return convert(jt, w, AV(d)) && convert(jt, d, yv); - case CVCASE(FLX, B01X): - std::copy_n(static_cast(wv), n, static_cast(yv)); - return 1; + case CVCASE(RATX, B01X): + GATV(d, XNUM, n, r, s); + return convert(jt, w, AV(d)) && convert(jt, d, yv); + case CVCASE(FLX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; case CVCASE(CMPXX, B01X): { Z *x = (Z *)yv; B *v = (B *)wv; @@ -483,21 +480,21 @@ jtccvt(J jt, I tflagged, A w, A *y) { case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return convert(jt, w, yv); case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, AV(d)) && convert(jt, d, yv); - case CVCASE(FLX, INTX): - std::copy_n(static_cast(wv), n, static_cast(yv)); - return 1; + case CVCASE(FLX, INTX): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; case CVCASE(CMPXX, INTX): { Z *x = (Z *)yv; - I *v = static_cast(wv); + I *v = static_cast(wv); DQ(n, x++->re = (D)*v++;); } return 1; case CVCASE(B01X, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(INTX, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(XNUMX, FLX): - return convert(jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + return convert( + jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(RATX, FLX): - return convert(jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + return convert( + jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(CMPXX, FLX): return convert(jt, w, yv); case CVCASE(B01X, CMPXX): GATV(d, FL, n, r, s); @@ -510,11 +507,13 @@ jtccvt(J jt, I tflagged, A w, A *y) { case CVCASE(XNUMX, CMPXX): GATV(d, FL, n, r, s); if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; - return convert(jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + return convert( + jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(RATX, CMPXX): GATV(d, FL, n, r, s); if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; - return convert(jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + return convert( + jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(FLX, CMPXX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(B01X, XNUMX): return convert(jt, w, yv); case CVCASE(INTX, XNUMX): return convert(jt, w, yv); @@ -604,15 +603,13 @@ jtbcvt(J jt, C mode, A w) { A jticvt(J jt, A w) { + auto const n = AN(w); + auto const* v = DAV(w); A z; - D *v, x; - I i, n, *u; - n = AN(w); - v = DAV(w); GATV(z, INT, n, AR(w), AS(w)); - u = AV(z); - for (i = 0; i < n; ++i) { - x = *v++; + auto u = AV(z); + for (int64_t i = 0; i < n; ++i) { + auto x = *v++; if (x < IMIN || FLIMAX <= x) return w; // if conversion will fail, skip it *u++ = (I)x; } @@ -621,12 +618,11 @@ jticvt(J jt, A w) { A jtpcvt(J jt, I t, A w) { - A y; - B b; RANK2T oqr = jt->ranks; RESETRANK; - b = jtccvt(jt, t, w, &y); - jt->ranks = oqr; + A y; + bool const b = jtccvt(jt, t, w, &y); + jt->ranks = oqr; return b ? y : w; } /* convert w to type t, if possible, otherwise just return w */ From bda0f83819216bb1b254ed3d5a4cb78ea994b271 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 02:18:59 +0200 Subject: [PATCH 13/35] Add helper function --- jsrc/conversions.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index f05bad61..5fb800ca 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -365,13 +365,17 @@ convert(J jt, A w, void *yv) -> bool { return !jt->jerr; } +template +auto +set_real_part(Z *z, int64_t n, T *t) { + for (int64_t i = 0; i < n; ++i) z[i].re = t[i]; +} + // Imaginary parts have already been cleared template <> [[nodiscard]] auto convert(J jt, A w, void *yv) -> bool { - D *wv = DAV(w); - Z *zv = static_cast(yv); - DQ(AN(w), zv++->re = *wv++;); + set_real_part(static_cast(yv), AN(w), DAV(w)); return 1; } @@ -471,22 +475,12 @@ jtccvt(J jt, I tflagged, A w, A *y) { GATV(d, XNUM, n, r, s); return convert(jt, w, AV(d)) && convert(jt, d, yv); case CVCASE(FLX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; - case CVCASE(CMPXX, B01X): { - Z *x = (Z *)yv; - B *v = (B *)wv; - DQ(n, x++->re = *v++;); - } - return 1; + case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, static_cast(wv)); return 1; case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return convert(jt, w, yv); case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, AV(d)) && convert(jt, d, yv); case CVCASE(FLX, INTX): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; - case CVCASE(CMPXX, INTX): { - Z *x = (Z *)yv; - I *v = static_cast(wv); - DQ(n, x++->re = (D)*v++;); - } - return 1; + case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, static_cast(wv)); return 1; case CVCASE(B01X, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(INTX, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(XNUMX, FLX): From 34a427da5bba8513350a2d32d0ab7e257073189e Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 02:39:43 +0200 Subject: [PATCH 14/35] Use helper functions more --- jsrc/conversions.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 5fb800ca..9d923bf6 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -129,16 +129,15 @@ convert(J jt, A w, void *yv) -> bool { template static auto -inplace_negate(T& u, int64_t n) { - std::transform(u, u + n, u, [](auto v) { return -v; }); +inplace_negate(T *u, int64_t n) { + std::transform(u, u + n, u, [](auto v) { return -v; }); } template <> [[nodiscard]] auto convert(J jt, A w, void *yv) -> bool { I u[XIDIG]; - auto const v = AV(w); - std::transform(v, v + AN(w), static_cast(yv), [&](auto c) { + auto const convert_one = [&](auto c) { auto const b = c == IMIN; auto d = b ? -(1 + c) : std::abs(c); int64_t length = 0; @@ -151,8 +150,8 @@ convert(J jt, A w, void *yv) -> bool { *u += b; if (0 > c) inplace_negate(u, XIDIG); return jtvec(jt, INT, length, u); - }); - return !jt->jerr; + }; + return convert(jt, w, yv, convert_one) && !jt->jerr; } static X @@ -239,14 +238,12 @@ convert(J jt, A w, void *yv) -> bool { template <> [[nodiscard]] auto convert(J jt, A w, void *yv) -> bool { - auto const wv = XAV(w); - std::transform(wv, wv + AN(w), static_cast(yv), [](auto p) { - auto const c = AV(p)[AN(p)-1]; + return convert(jt, w, yv, [](auto p) { + auto const c = AV(p)[AN(p) - 1]; if (c == XPINF) return inf; if (c == XNINF) return infm; return value_from_X(p); }); - return 1; } template <> @@ -297,10 +294,7 @@ convert(J jt, A w, void *yv, I mode) -> bool { q.d = jtca(jt, iv1); } } - if (neg) { - auto v = AV(q.n); - DQ(AN(q.n), *v = -*v; ++v;); - } + if (neg) inplace_negate(AV(q.n), AN(q.n)); *x++ = q; } return !jt->jerr; From ab99794b4e78f23288bd6b5115c5bcd96e180eb5 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 02:52:11 +0200 Subject: [PATCH 15/35] Parametrise `pointer_to_values()` return type --- jsrc/array.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jsrc/array.hpp b/jsrc/array.hpp index 7499a49d..b4787816 100644 --- a/jsrc/array.hpp +++ b/jsrc/array.hpp @@ -35,9 +35,10 @@ num(int64_t n) { return reinterpret_cast(Bnum[n - NUMMIN]); } +template [[nodiscard]] inline auto -pointer_to_values(array x) -> int64_t* { - return reinterpret_cast(reinterpret_cast(x) + x->kchain.k); +pointer_to_values(array x) -> Value* { + return reinterpret_cast(reinterpret_cast(x) + x->kchain.k); } [[nodiscard]] constexpr auto From fe73293a4436b30975a841c4e6aae84506e51139 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 02:53:02 +0200 Subject: [PATCH 16/35] Replace `*AV()` macros with `pointer_to_values()` --- jsrc/conversions.cpp | 84 ++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 9d923bf6..ace30e0f 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -35,7 +35,7 @@ in_range() -> bool { template [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - From *v = reinterpret_cast(UAV(w)); + auto *v = pointer_to_values(w); if constexpr (!in_range()) { // TODO: replace with short circuiting solution auto out = static_cast(yv); @@ -48,7 +48,7 @@ convert(J jt, array w, void *yv) -> bool { template [[nodiscard]] auto convert(J jt, array w, void *yv, Transform t) -> bool { - From *v = reinterpret_cast(UAV(w)); + auto *v = pointer_to_values(w); std::transform(v, v + AN(w), static_cast(yv), t); return 1; } @@ -57,7 +57,7 @@ template <> [[nodiscard]] auto convert(J jt, A w, void *yv, D fuzz) -> bool { auto n = AN(w); - auto v = DAV(w); + auto v = pointer_to_values(w); auto x = (B *)yv; DQ(n, auto p = *v++; if (p < -2 || 2 < p) return 0; // handle infinities I val = 2; @@ -72,7 +72,7 @@ template <> [[nodiscard]] auto convert(J jt, A w, void *yv, D fuzz) -> bool { auto n = AN(w); - auto v = DAV(w); + auto v = pointer_to_values(w); auto x = (I *)yv; for (int64_t i = 0; i < n; ++i) { auto const p = v[i]; @@ -97,7 +97,7 @@ template <> [[nodiscard]] auto convert(J jt, A w, void *yv, D fuzz) -> bool { auto const n = AN(w); - auto const *v = ZAV(w); + auto const *v = pointer_to_values(w); auto x = (D *)yv; if (fuzz) DQ( @@ -172,7 +172,7 @@ jtxd1(J jt, D p, I mode) { if (p == -inf) return jtvci(jt, XNINF); A t; GAT0(t, INT, 30, 1); - auto u = AV(t); + auto u = pointer_to_values(t); int64_t m = 0; auto d = std::abs(p); while (0 < d) { @@ -182,7 +182,7 @@ jtxd1(J jt, D p, I mode) { d = q; if (m == AN(t)) { RZ(t = jtext(jt, 0, t)); - u = AV(t); + u = pointer_to_values(t); } } if (!m) { @@ -204,9 +204,9 @@ convert(J jt, A w, void *yv, I mode) -> bool { template <> [[nodiscard]] auto convert(J jt, A w, void *yv) -> bool { - auto v = XAV(w); + auto v = pointer_to_values(w); auto x = (B *)yv; - DO(AN(w), A q = v[i]; I e = AV(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return 0; x[i] = (B)e;); + DO(AN(w), A q = v[i]; I e = pointer_to_values(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return 0; x[i] = (B)e;); return 1; } @@ -214,14 +214,14 @@ template [[nodiscard]] static auto value_from_X(X p) -> T { auto const n = AN(p); - auto const v = std::reverse_iterator(AV(p) + n); + auto const v = std::reverse_iterator(pointer_to_values(p) + n); return std::accumulate(v, v + n, T{}, [](auto d, auto v) { return v + d * XBASE; }); } template <> [[nodiscard]] auto convert(J jt, A w, void *yv) -> bool { - auto v = XAV(w); + auto v = pointer_to_values(w); auto x = (I *)yv; auto n = AN(w); X p, q; @@ -239,7 +239,7 @@ template <> [[nodiscard]] auto convert(J jt, A w, void *yv) -> bool { return convert(jt, w, yv, [](auto p) { - auto const c = AV(p)[AN(p) - 1]; + auto const c = pointer_to_values(p)[AN(p) - 1]; if (c == XPINF) return inf; if (c == XNINF) return infm; return value_from_X(p); @@ -257,7 +257,7 @@ template <> convert(J jt, A w, void *yv, I mode) -> bool { if (!(w)) return 0; auto const n = AN(w); - auto const wv = DAV(w); + auto const wv = pointer_to_values(w); auto x = (Q *)yv; D t; auto tv = 3 + (S *)&t; @@ -294,7 +294,7 @@ convert(J jt, A w, void *yv, I mode) -> bool { q.d = jtca(jt, iv1); } } - if (neg) inplace_negate(AV(q.n), AN(q.n)); + if (neg) inplace_negate(pointer_to_values(q.n), AN(q.n)); *x++ = q; } return !jt->jerr; @@ -305,7 +305,7 @@ template <> convert(J jt, A w, void *yv) -> bool { auto const xb = (D)XBASE; auto const wn = AN(w); - auto const wv = QAV(w); + auto const wv = pointer_to_values(w); auto const x = (D *)yv; auto const nn = 308 / XBASEN; @@ -321,7 +321,7 @@ convert(J jt, A w, void *yv) -> bool { for (int64_t i = 0; i < wn; ++i) { auto const p = wv[i].n; auto const pn = AN(p); - auto const k = 1 == pn ? AV(p)[0] : 0; + auto const k = 1 == pn ? pointer_to_values(p)[0] : 0; auto const q = wv[i].d; auto const qn = AN(q); if (k == XPINF) @@ -329,8 +329,8 @@ convert(J jt, A w, void *yv) -> bool { else if (k == XNINF) x[i] = infm; else if (pn <= nn && qn <= nn) { - auto const n = add_digits(pn, AV(p)); - auto const d = add_digits(qn, AV(q)); + auto const n = add_digits(pn, pointer_to_values(p)); + auto const d = add_digits(qn, pointer_to_values(q)); x[i] = n / d; } else { if (!x2) @@ -341,7 +341,7 @@ convert(J jt, A w, void *yv) -> bool { auto const cn = AN(c); auto const m = MIN(cn, 5); auto const r = cn - (m + k); - auto const v = AV(c) + cn - m; + auto const v = pointer_to_values(c) + cn - m; auto const n = add_digits(m, v); auto d = std::pow(xb, std::abs(r)); x[i] = 0 > r ? n / d : n * d; @@ -353,7 +353,7 @@ convert(J jt, A w, void *yv) -> bool { template <> [[nodiscard]] auto convert(J jt, A w, void *yv) -> bool { - auto v = QAV(w); + auto v = pointer_to_values(w); auto x = (X *)yv; DQ(AN(w), if (!(jtequ(jt, iv1, v->d))) return 0; *x++ = v->n; ++v;); return !jt->jerr; @@ -369,7 +369,7 @@ set_real_part(Z *z, int64_t n, T *t) { template <> [[nodiscard]] auto convert(J jt, A w, void *yv) -> bool { - set_real_part(static_cast(yv), AN(w), DAV(w)); + set_real_part(static_cast(yv), AN(w), pointer_to_values(w)); return 1; } @@ -399,8 +399,8 @@ jtccvt(J jt, I tflagged, A w, A *y) { case 3: // sparse to sparse t1 = DTYPE(t); GASPARSE(*y, t, 1, r, s); - yp = PAV(*y); - wp = PAV(w); + yp = pointer_to_values

(*y); + wp = pointer_to_values

(w); SPB(yp, a, jtca(jt, SPA(wp, a))); SPB(yp, i, jtca(jt, SPA(wp, i))); SPB(yp, e, jtcvt(jt, t1, SPA(wp, e))); @@ -425,7 +425,7 @@ jtccvt(J jt, I tflagged, A w, A *y) { auto n = AN(w); A d; GA(d, t, n, r, s); - auto yv = voidAV(d); // allocate the same # atoms, even if we will convert fewer + auto yv = pointer_to_values(d); // allocate the same # atoms, even if we will convert fewer if (tflagged & NOUNCVTVALIDCT) { I inputn = *(I *)y; // fetch input, in case it is called for if (inputn > 0) { // if converting the leading values, just update the counts @@ -441,7 +441,7 @@ jtccvt(J jt, I tflagged, A w, A *y) { // as n or s[0] since only n atoms will be used. For higher ranks, we need the shape from s. So it's just as well // that we take the shape from s now *y = d; - auto wv = voidAV(w); // return the address of the new block + auto wv = pointer_to_values(w); // return the address of the new block if (t & CMPX) jtfillv(jt, t, n, (C *)yv); // why?? just fill in imaginary parts as we need to if (!n) return 1; // Perform the conversion based on data types @@ -467,12 +467,12 @@ jtccvt(J jt, I tflagged, A w, A *y) { case CVCASE(XNUMX, B01X): return convert(jt, w, yv); case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); - return convert(jt, w, AV(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, static_cast(wv)); return 1; case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return convert(jt, w, yv); - case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, AV(d)) && convert(jt, d, yv); + case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, INTX): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, static_cast(wv)); return 1; case CVCASE(B01X, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); @@ -486,20 +486,20 @@ jtccvt(J jt, I tflagged, A w, A *y) { case CVCASE(CMPXX, FLX): return convert(jt, w, yv); case CVCASE(B01X, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + if (!(convert(jt, w, pointer_to_values(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; return convert(jt, d, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(INTX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + if (!(convert(jt, w, pointer_to_values(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; return convert(jt, d, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); case CVCASE(XNUMX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + if (!(convert(jt, w, pointer_to_values(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; return convert( jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(RATX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, AV(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + if (!(convert(jt, w, pointer_to_values(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; return convert( jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(FLX, CMPXX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); @@ -509,21 +509,21 @@ jtccvt(J jt, I tflagged, A w, A *y) { case CVCASE(FLX, XNUMX): return convert(jt, w, yv); case CVCASE(CMPXX, XNUMX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, AV(d)))) return 0; + if (!(convert(jt, w, pointer_to_values(d)))) return 0; return convert(jt, d, yv); case CVCASE(B01X, RATX): GATV(d, XNUM, n, r, s); - if (!(convert(jt, w, AV(d)))) return 0; + if (!(convert(jt, w, pointer_to_values(d)))) return 0; return convert(jt, d, yv); case CVCASE(INTX, RATX): GATV(d, XNUM, n, r, s); - if (!(convert(jt, w, AV(d)))) return 0; + if (!(convert(jt, w, pointer_to_values(d)))) return 0; return convert(jt, d, yv); case CVCASE(XNUMX, RATX): return convert(jt, w, yv); case CVCASE(FLX, RATX): return convert(jt, w, yv); case CVCASE(CMPXX, RATX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, AV(d)))) return 0; + if (!(convert(jt, w, pointer_to_values(d)))) return 0; return convert(jt, d, yv); default: ASSERT(0, EVDOMAIN); } @@ -557,16 +557,16 @@ jtbcvt(J jt, C mode, A w) { // convert the flagged values to float and keep the result as complex array result = w; if ((((AN(w) - 1) | (AT(w) & CMPX) - 1)) >= 0) { // not empty AND complex - Z *wv = ZAV(w); + Z *wv = pointer_to_values(w); auto flags = std::transform_reduce(wv, wv + AN(w), int64_t{}, std::plus{}, isflag); if (flags) { I ipok = SGNIF(jtinplace, JTINPLACEWX) & AC(w); // both sign bits set (<0) if inplaceable if (flags == AN(w)) { if (ipok >= 0) GATV(result, INT, AN(w), AR(w), AS(w)); - std::transform(wv, wv + AN(w), IAV(result), [&](auto const &z) { return as_integer(z.re); }); + std::transform(wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) { return as_integer(z.re); }); } else { if (ipok >= 0) GATV(result, CMPX, AN(w), AR(w), AS(w)); - std::transform(wv, wv + AN(w), ZAV(result), [&](auto const &z) -> Z { + std::transform(wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) -> Z { if (isflag(z)) return {.re = (D)as_integer(z.re), .im = 0.0}; return z; // copy floats, and converts any integers back to float }); @@ -592,10 +592,10 @@ jtbcvt(J jt, C mode, A w) { A jticvt(J jt, A w) { auto const n = AN(w); - auto const* v = DAV(w); + auto const* v = pointer_to_values(w); A z; GATV(z, INT, n, AR(w), AS(w)); - auto u = AV(z); + auto u = pointer_to_values(z); for (int64_t i = 0; i < n; ++i) { auto x = *v++; if (x < IMIN || FLIMAX <= x) return w; // if conversion will fail, skip it @@ -619,7 +619,7 @@ jtcvt0(J jt, A w) { auto const t = AT(w); auto const n = (t & CMPX) ? 2 * AN(w) : AN(w); if (n && t & FL + CMPX) { - auto u = DAV(w); + auto u = pointer_to_values(w); std::transform(u, u + n, u, [](auto v) { return v == 0.0 ? 0.0 : v; }); } return w; @@ -648,7 +648,7 @@ jtxco2(J jt, A a, A w) { A z; GATV(z, XNUM, 2 * n, r + 1, AS(w)); AS(z)[r] = 2; - memcpy(AV(z), AV(w), 2 * n * SZI); + memcpy(pointer_to_values(z), pointer_to_values(w), 2 * n * SZI); return z; } default: ASSERT(0, EVDOMAIN); From 300efec33467b3b636a54d4a29bc0247d32108a5 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 03:04:41 +0200 Subject: [PATCH 17/35] Use `array` instead of `A` --- jsrc/conversions.cpp | 76 ++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index ace30e0f..6d20f4bf 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -55,7 +55,7 @@ convert(J jt, array w, void *yv, Transform t) -> bool { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv, D fuzz) -> bool { +convert(J jt, array w, void *yv, D fuzz) -> bool { auto n = AN(w); auto v = pointer_to_values(w); auto x = (B *)yv; @@ -70,7 +70,7 @@ convert(J jt, A w, void *yv, D fuzz) -> bool { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv, D fuzz) -> bool { +convert(J jt, array w, void *yv, D fuzz) -> bool { auto n = AN(w); auto v = pointer_to_values(w); auto x = (I *)yv; @@ -95,7 +95,7 @@ convert(J jt, A w, void *yv, D fuzz) -> bool { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv, D fuzz) -> bool { +convert(J jt, array w, void *yv, D fuzz) -> bool { auto const n = AN(w); auto const *v = pointer_to_values(w); auto x = (D *)yv; @@ -116,7 +116,7 @@ convert(J jt, A w, void *yv, D fuzz) -> bool { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { return convert(jt, w, yv, @@ -135,7 +135,7 @@ inplace_negate(T *u, int64_t n) { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { I u[XIDIG]; auto const convert_one = [&](auto c) { auto const b = c == IMIN; @@ -170,7 +170,7 @@ jtxd1(J jt, D p, I mode) { } if (p == inf) return jtvci(jt, XPINF); if (p == -inf) return jtvci(jt, XNINF); - A t; + array t; GAT0(t, INT, 30, 1); auto u = pointer_to_values(t); int64_t m = 0; @@ -191,22 +191,22 @@ jtxd1(J jt, D p, I mode) { } else if (0 > p) { inplace_negate(u, m); } - A z = jtxstd(jt, jtvec(jt, INT, m, u)); + array z = jtxstd(jt, jtvec(jt, INT, m, u)); EPILOG(z); } template <> [[nodiscard]] auto -convert(J jt, A w, void *yv, I mode) -> bool { +convert(J jt, array w, void *yv, I mode) -> bool { return convert(jt, w, yv, [=](auto v){ return jtxd1(jt, v, mode); }) && !jt->jerr; } template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { auto v = pointer_to_values(w); auto x = (B *)yv; - DO(AN(w), A q = v[i]; I e = pointer_to_values(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return 0; x[i] = (B)e;); + DO(AN(w), array q = v[i]; I e = pointer_to_values(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return 0; x[i] = (B)e;); return 1; } @@ -220,7 +220,7 @@ value_from_X(X p) -> T { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { auto v = pointer_to_values(w); auto x = (I *)yv; auto n = AN(w); @@ -237,7 +237,7 @@ convert(J jt, A w, void *yv) -> bool { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { return convert(jt, w, yv, [](auto p) { auto const c = pointer_to_values(p)[AN(p) - 1]; if (c == XPINF) return inf; @@ -248,13 +248,13 @@ convert(J jt, A w, void *yv) -> bool { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { return convert(jt, w, yv, [](auto v) -> Q { return {v, iv1}; }); } template <> [[nodiscard]] auto -convert(J jt, A w, void *yv, I mode) -> bool { +convert(J jt, array w, void *yv, I mode) -> bool { if (!(w)) return 0; auto const n = AN(w); auto const wv = pointer_to_values(w); @@ -302,7 +302,7 @@ convert(J jt, A w, void *yv, I mode) -> bool { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { auto const xb = (D)XBASE; auto const wn = AN(w); auto const wv = pointer_to_values(w); @@ -352,7 +352,7 @@ convert(J jt, A w, void *yv) -> bool { template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { auto v = pointer_to_values(w); auto x = (X *)yv; DQ(AN(w), if (!(jtequ(jt, iv1, v->d))) return 0; *x++ = v->n; ++v;); @@ -368,7 +368,7 @@ set_real_part(Z *z, int64_t n, T *t) { // Imaginary parts have already been cleared template <> [[nodiscard]] auto -convert(J jt, A w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { set_real_part(static_cast(yv), AN(w), pointer_to_values(w)); return 1; } @@ -378,7 +378,7 @@ convert(J jt, A w, void *yv) -> bool { // 0 if error, 1 if success. If the conversion loses precision, error is returned // Calls through bcvt are tagged with a flag in jt, indicating to set fuzz=0 B -jtccvt(J jt, I tflagged, A w, A *y) { +jtccvt(J jt, I tflagged, array w, array *y) { FPREFIP; I const t = tflagged & NOUN; if (!w) return 0; @@ -423,7 +423,7 @@ jtccvt(J jt, I tflagged, A w, A *y) { // modified: the caller must restore AN(w) and AK(w) if it needs it // TODO: same-length conversion could be done in place auto n = AN(w); - A d; + array d; GA(d, t, n, r, s); auto yv = pointer_to_values(d); // allocate the same # atoms, even if we will convert fewer if (tflagged & NOUNCVTVALIDCT) { @@ -530,9 +530,9 @@ jtccvt(J jt, I tflagged, A w, A *y) { } // clear rank before calling ccvt - needed for sparse arrays only but returns the block as the result -A -jtcvt(J jt, I t, A w) { - A y; +auto +jtcvt(J jt, I t, array w) -> array { + array y; bool const b = jtccvt(jt, t, w, &y); ASSERT(b, EVDOMAIN); return y; @@ -542,8 +542,8 @@ jtcvt(J jt, I t, A w) { // and use 'exact' and 'no rank' for them. If mode=0, do not promote XNUM/RAT to fixed-length types. // If mode bit 1 is set, minimum precision is INT; if mode bit 2 is set, minimum precision is FL; if mode bit 3 is set, // minimum precision is CMPX Result is a new buffer, always -A -jtbcvt(J jt, C mode, A w) { +auto +jtbcvt(J jt, C mode, array w) -> array { FPREFIP; if (!w) return 0; @@ -556,7 +556,7 @@ jtbcvt(J jt, C mode, A w) { // to integer. If none of the imaginary parts were flags, we leave the input unchanged. If some were flags, we // convert the flagged values to float and keep the result as complex array result = w; - if ((((AN(w) - 1) | (AT(w) & CMPX) - 1)) >= 0) { // not empty AND complex + if ((((AN(w) - 1) | ((AT(w) & CMPX) - 1))) >= 0) { // not empty AND complex Z *wv = pointer_to_values(w); auto flags = std::transform_reduce(wv, wv + AN(w), int64_t{}, std::plus{}, isflag); if (flags) { @@ -589,11 +589,11 @@ jtbcvt(J jt, C mode, A w) { RNE(result); } /* convert to lowest type. 0=mode: don't convert XNUM/RAT to other types */ -A -jticvt(J jt, A w) { +auto +jticvt(J jt, array w) -> array { auto const n = AN(w); auto const* v = pointer_to_values(w); - A z; + array z; GATV(z, INT, n, AR(w), AS(w)); auto u = pointer_to_values(z); for (int64_t i = 0; i < n; ++i) { @@ -604,18 +604,18 @@ jticvt(J jt, A w) { return z; } -A -jtpcvt(J jt, I t, A w) { +auto +jtpcvt(J jt, I t, array w) -> array { RANK2T oqr = jt->ranks; RESETRANK; - A y; + array y; bool const b = jtccvt(jt, t, w, &y); jt->ranks = oqr; return b ? y : w; } /* convert w to type t, if possible, otherwise just return w */ -A -jtcvt0(J jt, A w) { +auto +jtcvt0(J jt, array w) -> array { auto const t = AT(w); auto const n = (t & CMPX) ? 2 * AN(w) : AN(w); if (n && t & FL + CMPX) { @@ -625,14 +625,14 @@ jtcvt0(J jt, A w) { return w; } /* convert -0 to 0 in place */ -A -jtxco1(J jt, A w) { +auto +jtxco1(J jt, array w) -> array { ASSERT(AT(w) & DENSE, EVNONCE); return jtcvt(jt, AT(w) & B01 + INT + XNUM ? XNUM : RAT, w); } -A -jtxco2(J jt, A a, A w) { +auto +jtxco2(J jt, array a, array w) -> array { ASSERT(AT(w) & DENSE, EVNONCE); I j; RE(j = jti0(jt, a)); @@ -645,7 +645,7 @@ jtxco2(J jt, A a, A w) { { auto const n = AN(w); auto const r = AR(w); - A z; + array z; GATV(z, XNUM, 2 * n, r + 1, AS(w)); AS(z)[r] = 2; memcpy(pointer_to_values(z), pointer_to_values(w), 2 * n * SZI); From b0069a628e0e6aac19da21ac971c23be047184e2 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 03:09:47 +0200 Subject: [PATCH 18/35] Until c++17 --- jsrc/conversions.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 6d20f4bf..8a2eee93 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -558,7 +558,9 @@ jtbcvt(J jt, C mode, array w) -> array { array result = w; if ((((AN(w) - 1) | ((AT(w) & CMPX) - 1))) >= 0) { // not empty AND complex Z *wv = pointer_to_values(w); - auto flags = std::transform_reduce(wv, wv + AN(w), int64_t{}, std::plus{}, isflag); + // FIXME: get proper c++17 support + // auto flags = std::transform_reduce(wv, wv + AN(w), int64_t{}, std::plus{}, isflag); + auto flags = std::accumulate(wv, wv + AN(w), int64_t{}, [&](auto sum, auto v) { return sum + isflag(v); }); if (flags) { I ipok = SGNIF(jtinplace, JTINPLACEWX) & AC(w); // both sign bits set (<0) if inplaceable if (flags == AN(w)) { From 5935520e51199d8f648820612e4864512e964f98 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 03:26:01 +0200 Subject: [PATCH 19/35] Use true/false for booleans, replace C-style casts --- jsrc/conversions.cpp | 351 +++++++++++++++++++++++-------------------- 1 file changed, 186 insertions(+), 165 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 8a2eee93..0531d1f3 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -38,59 +38,61 @@ convert(J jt, array w, void *yv) -> bool { auto *v = pointer_to_values(w); if constexpr (!in_range()) { // TODO: replace with short circuiting solution - auto out = static_cast(yv); + auto *out = static_cast(yv); return out + AN(w) == std::copy_if(v, v + AN(w), out, [](auto v) { return in_range(v); }); } std::copy(v, v + AN(w), static_cast(yv)); - return 1; + return true; } template [[nodiscard]] auto convert(J jt, array w, void *yv, Transform t) -> bool { auto *v = pointer_to_values(w); - std::transform(v, v + AN(w), static_cast(yv), t); - return 1; + std::transform(v, v + AN(w), static_cast(yv), t); + return true; } template <> [[nodiscard]] auto convert(J jt, array w, void *yv, D fuzz) -> bool { - auto n = AN(w); - auto v = pointer_to_values(w); - auto x = (B *)yv; - DQ(n, auto p = *v++; if (p < -2 || 2 < p) return 0; // handle infinities + auto n = AN(w); + auto *v = pointer_to_values(w); + auto *x = static_cast(yv); + DQ(n, auto p = *v++; if (p < -2 || 2 < p) return false; // handle infinities I val = 2; val = (p == 0) ? 0 : val; val = FIEQ(p, 1.0, fuzz) ? 1 : val; - if (val == 2) return 0; + if (val == 2) return false; *x++ = (B)val;) - return 1; + return true; } template <> [[nodiscard]] auto convert(J jt, array w, void *yv, D fuzz) -> bool { - auto n = AN(w); - auto v = pointer_to_values(w); - auto x = (I *)yv; + auto n = AN(w); + auto *v = pointer_to_values(w); + auto *x = static_cast(yv); for (int64_t i = 0; i < n; ++i) { auto const p = v[i]; auto const q = jround(p); - I rq = (I)q; - if (!(p == q || FIEQ(p, q, fuzz))) return 0; // must equal int, possibly out of range + I rq = static_cast(q); + if (!(p == q || FIEQ(p, q, fuzz))) { + return 0; // must equal int, possibly out of range + } // out-of-range values don't convert, handle separately - if (p < (D)IMIN) { - if (!(p >= IMIN * (1 + fuzz))) return 0; + if (p < static_cast IMIN) { + if (!(p >= IMIN * (1 + fuzz))) return false; rq = IMIN; } // if tolerantly < IMIN, error; else take IMIN else if (p >= FLIMAX) { - if (!(p <= -(D)IMIN * (1 + fuzz))) return 0; + if (!(p <= -static_cast IMIN * (1 + fuzz))) return false; rq = IMAX; } // if tolerantly > IMAX, error; else take IMAX *x++ = rq; } - return 1; + return true; } template <> @@ -98,20 +100,20 @@ template <> convert(J jt, array w, void *yv, D fuzz) -> bool { auto const n = AN(w); auto const *v = pointer_to_values(w); - auto x = (D *)yv; - if (fuzz) + auto *x = static_cast(yv); + if (fuzz != 0.0) DQ( n, auto d = std::abs(v->im); if (d != inf && d <= fuzz * std::abs(v->re)) { *x++ = v->re; v++; - } else return 0;) + } else return false;) else DQ( n, if (!v->im) { *x++ = v->re; v++; - } else return 0;); - return 1; + } else return false;); + return true; } template <> @@ -148,14 +150,14 @@ convert(J jt, array w, void *yv) -> bool { } ++length; *u += b; - if (0 > c) inplace_negate(u, XIDIG); + if (0 > c) { inplace_negate(u, XIDIG); } return jtvec(jt, INT, length, u); }; return convert(jt, w, yv, convert_one) && !jt->jerr; } -static X -jtxd1(J jt, D p, I mode) { +static auto +jtxd1(J jt, D p, I mode) -> X { PROLOG(0052); D e = jttfloor(jt, p); switch (mode) { @@ -166,26 +168,26 @@ jtxd1(J jt, D p, I mode) { p = e; break; case XMEXMT: - if (!TEQ(p, e)) return jtvec(jt, INT, 0L, &iotavec[-IOTAVECBEGIN]); + if (!TEQ(p, e)) { return jtvec(jt, INT, 0L, &iotavec[-IOTAVECBEGIN]); } } - if (p == inf) return jtvci(jt, XPINF); - if (p == -inf) return jtvci(jt, XNINF); - array t; - GAT0(t, INT, 30, 1); - auto u = pointer_to_values(t); + if (p == inf) { return jtvci(jt, XPINF); } + if (p == -inf) { return jtvci(jt, XNINF); } + array t = make_array(jt, 30, 1); + if (!t) return 0; + auto *u = pointer_to_values(t); int64_t m = 0; - auto d = std::abs(p); + auto d = std::abs(p); while (0 < d) { auto const q = floor(d / XBASE); auto const r = d - q * XBASE; - u[m++] = (I)r; + u[m++] = static_cast(r); d = q; if (m == AN(t)) { RZ(t = jtext(jt, 0, t)); u = pointer_to_values(t); } } - if (!m) { + if (m == 0) { u[0] = 0; ++m; } else if (0 > p) { @@ -198,38 +200,39 @@ jtxd1(J jt, D p, I mode) { template <> [[nodiscard]] auto convert(J jt, array w, void *yv, I mode) -> bool { - return convert(jt, w, yv, [=](auto v){ return jtxd1(jt, v, mode); }) && !jt->jerr; + return convert(jt, w, yv, [=](auto v) { return jtxd1(jt, v, mode); }) && !jt->jerr; } template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - auto v = pointer_to_values(w); - auto x = (B *)yv; - DO(AN(w), array q = v[i]; I e = pointer_to_values(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return 0; x[i] = (B)e;); - return 1; + auto *v = pointer_to_values(w); + auto *x = static_cast(yv); + DO(AN(w), array q = v[i]; I e = pointer_to_values(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return false; x[i] = (B)e;); + return true; } template [[nodiscard]] static auto value_from_X(X p) -> T { - auto const n = AN(p); - auto const v = std::reverse_iterator(pointer_to_values(p) + n); - return std::accumulate(v, v + n, T{}, [](auto d, auto v) { return v + d * XBASE; }); + auto const n = AN(p); + auto const v = std::reverse_iterator(pointer_to_values(p) + n); + return std::accumulate(v, v + n, T{}, [](auto d, auto v) { return v + d * XBASE; }); } template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - auto v = pointer_to_values(w); - auto x = (I *)yv; - auto n = AN(w); - X p, q; - if (!(p = jtxc(jt, IMAX))) return 0; - if (!(q = jtxminus(jt, jtnegate(jt, p), jtxc(jt, 1L)))) return 0; + auto *v = pointer_to_values(w); + auto *x = static_cast(yv); + auto n = AN(w); + X p = nullptr; + X q; + if ((p = jtxc(jt, IMAX)) == nullptr) return false; + if ((q = jtxminus(jt, jtnegate(jt, p), jtxc(jt, 1L))) == nullptr) return false; for (int64_t i = 0; i < n; ++i) { - auto c = v[i]; - if (!(1 != jtxcompare(jt, q, c) && 1 != jtxcompare(jt, c, p))) return 0; + auto *c = v[i]; + if (!(1 != jtxcompare(jt, q, c) && 1 != jtxcompare(jt, c, p))) return false; x[i] = value_from_X(c); } return 1; @@ -240,8 +243,8 @@ template <> convert(J jt, array w, void *yv) -> bool { return convert(jt, w, yv, [](auto p) { auto const c = pointer_to_values(p)[AN(p) - 1]; - if (c == XPINF) return inf; - if (c == XNINF) return infm; + if (c == XPINF) { return inf; } + if (c == XNINF) { return infm; } return value_from_X(p); }); } @@ -255,24 +258,24 @@ convert(J jt, array w, void *yv) -> bool { template <> [[nodiscard]] auto convert(J jt, array w, void *yv, I mode) -> bool { - if (!(w)) return 0; - auto const n = AN(w); - auto const wv = pointer_to_values(w); - auto x = (Q *)yv; - D t; - auto tv = 3 + (S *)&t; + if ((w) == nullptr) return false; + auto const n = AN(w); + auto *const wv = pointer_to_values(w); + auto *x = static_cast(yv); + D t = NAN; + auto *tv = 3 + reinterpret_cast(&t); Q q; for (int64_t i = 0; i < n; ++i) { t = wv[i]; ASSERT(!_isnan(t), EVNAN); bool const neg = 0 > t; - if (neg) t = -t; + if (neg) { t = -t; } q.d = iv1; - if (t == inf) + if (t == inf) { q.n = jtvci(jt, XPINF); - else if (t == 0.0) + } else if (t == 0.0) { q.n = iv0; - else if (1.1102230246251565e-16 < t && t < 9.007199254740992e15) { + } else if (1.1102230246251565e-16 < t && t < 9.007199254740992e15) { auto const d = jround(1 / jtdgcd(jt, 1.0, t)); auto const c = jround(d * t); q = jtqstd(jt, @@ -282,8 +285,8 @@ convert(J jt, array w, void *yv, I mode) -> bool { }); } else { bool const recip = 1 > t; - if (recip) t = 1.0 / t; - auto e = (I)(0xfff0 & *tv); + if (recip) { t = 1.0 / t; } + auto e = static_cast(0xfff0 & *tv); e >>= 4; e -= 1023; if (recip) { @@ -294,7 +297,7 @@ convert(J jt, array w, void *yv, I mode) -> bool { q.d = jtca(jt, iv1); } } - if (neg) inplace_negate(pointer_to_values(q.n), AN(q.n)); + if (neg) { inplace_negate(pointer_to_values(q.n), AN(q.n)); } *x++ = q; } return !jt->jerr; @@ -303,11 +306,11 @@ convert(J jt, array w, void *yv, I mode) -> bool { template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - auto const xb = (D)XBASE; - auto const wn = AN(w); - auto const wv = pointer_to_values(w); - auto const x = (D *)yv; - auto const nn = 308 / XBASEN; + auto const xb = static_cast(XBASE); + auto const wn = AN(w); + auto *const wv = pointer_to_values(w); + auto *const x = static_cast(yv); + auto const nn = 308 / XBASEN; // TODO: figure out nice algorithm for this auto const add_digits = [&](auto n, auto v) { @@ -317,44 +320,45 @@ convert(J jt, array w, void *yv) -> bool { return d; }; - X x2 = 0; + X x2 = nullptr; for (int64_t i = 0; i < wn; ++i) { - auto const p = wv[i].n; + auto *const p = wv[i].n; auto const pn = AN(p); auto const k = 1 == pn ? pointer_to_values(p)[0] : 0; - auto const q = wv[i].d; + auto *const q = wv[i].d; auto const qn = AN(q); - if (k == XPINF) + if (k == XPINF) { x[i] = inf; - else if (k == XNINF) + } else if (k == XNINF) { x[i] = infm; - else if (pn <= nn && qn <= nn) { + } else if (pn <= nn && qn <= nn) { auto const n = add_digits(pn, pointer_to_values(p)); auto const d = add_digits(qn, pointer_to_values(q)); x[i] = n / d; } else { - if (!x2) - if (!(x2 = jtxc(jt, 2L))) return 0; + if (x2 == nullptr) { + if ((x2 = jtxc(jt, 2L)) == nullptr) return false; + } auto const k = 5 + qn; - auto c = jtxdiv(jt, jttake(jt, jtsc(jt, -(k + pn)), p), q, XMFLR); - if (!c) return 0; + auto *c = jtxdiv(jt, jttake(jt, jtsc(jt, -(k + pn)), p), q, XMFLR); + if (c == nullptr) return false; auto const cn = AN(c); auto const m = MIN(cn, 5); auto const r = cn - (m + k); - auto const v = pointer_to_values(c) + cn - m; + auto *const v = pointer_to_values(c) + cn - m; auto const n = add_digits(m, v); auto d = std::pow(xb, std::abs(r)); x[i] = 0 > r ? n / d : n * d; } } - return 1; + return true; } template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - auto v = pointer_to_values(w); - auto x = (X *)yv; + auto *v = pointer_to_values(w); + auto *x = static_cast(yv); DQ(AN(w), if (!(jtequ(jt, iv1, v->d))) return 0; *x++ = v->n; ++v;); return !jt->jerr; } @@ -362,51 +366,49 @@ convert(J jt, array w, void *yv) -> bool { template auto set_real_part(Z *z, int64_t n, T *t) { - for (int64_t i = 0; i < n; ++i) z[i].re = t[i]; + for (int64_t i = 0; i < n; ++i) { z[i].re = t[i]; } } // Imaginary parts have already been cleared template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - set_real_part(static_cast(yv), AN(w), pointer_to_values(w)); - return 1; + set_real_part(static_cast(yv), AN(w), pointer_to_values(w)); + return true; } // Convert the data in w to the type t. w and t must be noun types. A new buffer is always created (with a // copy of the data if w is already of the right type), and returned in *y. Result is // 0 if error, 1 if success. If the conversion loses precision, error is returned // Calls through bcvt are tagged with a flag in jt, indicating to set fuzz=0 -B -jtccvt(J jt, I tflagged, array w, array *y) { +auto +jtccvt(J jt, I tflagged, array w, array *y) -> bool { FPREFIP; I const t = tflagged & NOUN; - if (!w) return 0; - auto const r = AR(w); - auto const s = AS(w); + if (w == nullptr) return false; + auto const r = AR(w); + auto *const s = AS(w); if (((t | AT(w)) & SPARSE) != 0) { // Handle sparse RANK2T oqr = jt->ranks; RESETRANK; - switch ((t & SPARSE ? 2 : 0) + (AT(w) & SPARSE ? 1 : 0)) { - I t1; - P *wp, *yp; + switch (((t & SPARSE) != 0 ? 2 : 0) + (AT(w) & SPARSE ? 1 : 0)) { case 1: RZ(w = jtdenseit(jt, w)); break; // sparse to dense case 2: RZ(*y = jtsparseit(jt, jtcvt(jt, DTYPE(t), w), IX(r), jtcvt(jt, DTYPE(t), jfalse))); jt->ranks = oqr; - return 1; // dense to sparse; convert type first (even if same dtype) + return true; // dense to sparse; convert type first (even if same dtype) case 3: // sparse to sparse - t1 = DTYPE(t); + I t1 = DTYPE(t); GASPARSE(*y, t, 1, r, s); - yp = pointer_to_values

(*y); - wp = pointer_to_values

(w); + P *yp = pointer_to_values

(*y); + P *wp = pointer_to_values

(w); SPB(yp, a, jtca(jt, SPA(wp, a))); SPB(yp, i, jtca(jt, SPA(wp, i))); SPB(yp, e, jtcvt(jt, t1, SPA(wp, e))); SPB(yp, x, jtcvt(jt, t1, SPA(wp, x))); jt->ranks = oqr; - return 1; + return true; } jt->ranks = oqr; } @@ -414,40 +416,43 @@ jtccvt(J jt, I tflagged, array w, array *y) { auto const wt = AT(w); // If type is already correct, return a clone - used to force a copy. Should get rid of this kludge if (TYPESEQ(t, wt)) { - RZ(*y = jtca(jt, w)); - return 1; + *y = jtca(jt, w); + return *y != nullptr; } // Kludge on behalf of result assembly: we want to be able to stop converting after the valid cells. If // NOUNCVTVALIDCT is set in the type, we use the input *y as as override on the # cells to convert. We use it to // replace n (for use here) and yv, and AK(w) and AN(w) for the subroutines. If NOUNCVTVALIDCT is set, w is // modified: the caller must restore AN(w) and AK(w) if it needs it // TODO: same-length conversion could be done in place - auto n = AN(w); - array d; - GA(d, t, n, r, s); - auto yv = pointer_to_values(d); // allocate the same # atoms, even if we will convert fewer - if (tflagged & NOUNCVTVALIDCT) { - I inputn = *(I *)y; // fetch input, in case it is called for - if (inputn > 0) { // if converting the leading values, just update the counts - n = inputn; // set the counts for local use, and in the block to be converted - } else { // if converting trailing values... + auto n = AN(w); + array d = jtga(jt, t, n, r, s); + if (!d) return false; + auto *yv = pointer_to_values(d); // allocate the same # atoms, even if we will convert fewer + if ((tflagged & NOUNCVTVALIDCT) != 0) { + I inputn = *reinterpret_cast(y); // fetch input, in case it is called for + if (inputn > 0) { // if converting the leading values, just update the counts + n = inputn; // set the counts for local use, and in the block to be converted + } else { // if converting trailing values... AK(w) += (n + inputn) << bplg(wt); - yv = (I *)((C *)yv + ((n + inputn) << bplg(t))); // advance input and output pointers to new area - n = -inputn; // get positive # atoms to convert + yv = reinterpret_cast(static_cast(yv) + + ((n + inputn) << bplg(t))); // advance input and output pointers to new area + n = -inputn; // get positive # atoms to convert } AN(w) = n; // change atomct of w to # atoms to convert } // If n and AN have been modified, it doesn't matter for rank-1 arguments whether the shape of the result is listed // as n or s[0] since only n atoms will be used. For higher ranks, we need the shape from s. So it's just as well // that we take the shape from s now - *y = d; - auto wv = pointer_to_values(w); // return the address of the new block - if (t & CMPX) jtfillv(jt, t, n, (C *)yv); // why?? just fill in imaginary parts as we need to - if (!n) return 1; + *y = d; + auto *wv = pointer_to_values(w); // return the address of the new block + if ((t & CMPX) != 0) { + jtfillv(jt, t, n, static_cast(yv)); // why?? just fill in imaginary parts as we need to + } + if (n == 0) return true; // Perform the conversion based on data types // For branch-table efficiency, we split the C2T and C4T and BIT conversions into one block, and // the rest in another - if ((t | wt) & (C2T + C4T + BIT + SBT)) { + if (((t | wt) & (C2T + C4T + BIT + SBT)) != 0) { // there are no SBT conversions, but we have to show domain error we // must account for all NOUN types. Low 8 bits have most of them, and // we know type can't be sparse. This picks up the others @@ -463,20 +468,24 @@ jtccvt(J jt, I tflagged, array w, array *y) { } } switch (CVCASE(CTTZ(t), CTTZ(wt))) { - case CVCASE(INTX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; + case CVCASE(INTX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return true; case CVCASE(XNUMX, B01X): return convert(jt, w, yv); case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); - case CVCASE(FLX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; - case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, static_cast(wv)); return 1; + case CVCASE(FLX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return true; + case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, static_cast(wv)); return true; case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return convert(jt, w, yv); - case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); - case CVCASE(FLX, INTX): std::copy_n(static_cast(wv), n, static_cast(yv)); return 1; - case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, static_cast(wv)); return 1; - case CVCASE(B01X, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); - case CVCASE(INTX, FLX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + case CVCASE(RATX, INTX): + GATV(d, XNUM, n, r, s); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + case CVCASE(FLX, INTX): std::copy_n(static_cast(wv), n, static_cast(yv)); return true; + case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, static_cast(wv)); return true; + case CVCASE(B01X, FLX): + return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + case CVCASE(INTX, FLX): + return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, FLX): return convert( jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); @@ -486,44 +495,53 @@ jtccvt(J jt, I tflagged, array w, array *y) { case CVCASE(CMPXX, FLX): return convert(jt, w, yv); case CVCASE(B01X, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; - return convert(jt, d, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + if (!(convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ))) { + return false; + } + return convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(INTX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; - return convert(jt, d, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + if (!(convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ))) { + return false; + } + return convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + if (!(convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ))) { + return false; + } return convert( jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(RATX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d), (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ))) return 0; + if (!(convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ))) { + return false; + } return convert( jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); - case CVCASE(FLX, CMPXX): return convert(jt, w, yv, (I)jtinplace & JTNOFUZZ ? 0.0 : FUZZ); + case CVCASE(FLX, CMPXX): + return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(B01X, XNUMX): return convert(jt, w, yv); case CVCASE(INTX, XNUMX): return convert(jt, w, yv); case CVCASE(RATX, XNUMX): return convert(jt, w, yv); case CVCASE(FLX, XNUMX): return convert(jt, w, yv); case CVCASE(CMPXX, XNUMX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d)))) return 0; + if (!(convert(jt, w, pointer_to_values(d)))) return false; return convert(jt, d, yv); case CVCASE(B01X, RATX): GATV(d, XNUM, n, r, s); - if (!(convert(jt, w, pointer_to_values(d)))) return 0; + if (!(convert(jt, w, pointer_to_values(d)))) return false; return convert(jt, d, yv); case CVCASE(INTX, RATX): GATV(d, XNUM, n, r, s); - if (!(convert(jt, w, pointer_to_values(d)))) return 0; + if (!(convert(jt, w, pointer_to_values(d)))) return false; return convert(jt, d, yv); case CVCASE(XNUMX, RATX): return convert(jt, w, yv); case CVCASE(FLX, RATX): return convert(jt, w, yv); case CVCASE(CMPXX, RATX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d)))) return 0; + if (!(convert(jt, w, pointer_to_values(d)))) return false; return convert(jt, d, yv); default: ASSERT(0, EVDOMAIN); } @@ -532,8 +550,8 @@ jtccvt(J jt, I tflagged, array w, array *y) { // clear rank before calling ccvt - needed for sparse arrays only but returns the block as the result auto jtcvt(J jt, I t, array w) -> array { - array y; - bool const b = jtccvt(jt, t, w, &y); + array y = nullptr; + bool const b = jtccvt(jt, t, w, &y);; ASSERT(b, EVDOMAIN); return y; } @@ -545,7 +563,7 @@ jtcvt(J jt, I t, array w) -> array { auto jtbcvt(J jt, C mode, array w) -> array { FPREFIP; - if (!w) return 0; + if (w == nullptr) { return nullptr; } auto const as_integer = [](auto const &v) { return *(I *)&v; }; auto const isflag = [&](auto const &z) { return as_integer(z.im) == NANFLAG; }; @@ -557,19 +575,20 @@ jtbcvt(J jt, C mode, array w) -> array { // convert the flagged values to float and keep the result as complex array result = w; if ((((AN(w) - 1) | ((AT(w) & CMPX) - 1))) >= 0) { // not empty AND complex - Z *wv = pointer_to_values(w); + Z *wv = pointer_to_values(w); // FIXME: get proper c++17 support // auto flags = std::transform_reduce(wv, wv + AN(w), int64_t{}, std::plus{}, isflag); auto flags = std::accumulate(wv, wv + AN(w), int64_t{}, [&](auto sum, auto v) { return sum + isflag(v); }); - if (flags) { + if (flags != 0) { I ipok = SGNIF(jtinplace, JTINPLACEWX) & AC(w); // both sign bits set (<0) if inplaceable if (flags == AN(w)) { if (ipok >= 0) GATV(result, INT, AN(w), AR(w), AS(w)); - std::transform(wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) { return as_integer(z.re); }); + std::transform( + wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) { return as_integer(z.re); }); } else { if (ipok >= 0) GATV(result, CMPX, AN(w), AR(w), AS(w)); std::transform(wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) -> Z { - if (isflag(z)) return {.re = (D)as_integer(z.re), .im = 0.0}; + if (isflag(z)) { return {.re = (D)as_integer(z.re), .im = 0.0}; }; return z; // copy floats, and converts any integers back to float }); } @@ -577,14 +596,14 @@ jtbcvt(J jt, C mode, array w) -> array { } } // for all numerics, try Boolean/int/float in order, stopping when we find one that holds the data - if (mode & 1 || !(AT(w) & XNUM + RAT)) { // if we are not stopping at XNUM/RAT + if (((mode & 1) != 0) || ((AT(w) & (XNUM + RAT)) == 0)) { // if we are not stopping at XNUM/RAT // To avoid a needless copy, suppress conversion to B01 if type is B01, to INT if type is INT, etc // set the NOFUZZ flag in jt to insist on an exact match so we won't lose precision - array y; + array y = nullptr; jtinplace = (J)((I)jt + JTNOFUZZ); // demand exact match - result = !(mode & 14) && jtccvt(jtinplace, B01, w, &y) ? y - : (y = w, AT(w) & INT || (!(mode & 12) && jtccvt(jtinplace, INT, w, &y))) ? y - : (y = w, AT(w) & FL || (!(mode & 8) && jtccvt(jtinplace, FL, w, &y))) + result = ((mode & 14) == 0) && jtccvt(jtinplace, B01, w, &y) ? y + : (y = w, AT(w) & INT || (((mode & 12) == 0) && jtccvt(jtinplace, INT, w, &y))) ? y + : (y = w, AT(w) & FL || (((mode & 8) == 0) && jtccvt(jtinplace, FL, w, &y))) ? y : w; // convert to enabled modes one by one, stopping when one works } @@ -593,15 +612,17 @@ jtbcvt(J jt, C mode, array w) -> array { auto jticvt(J jt, array w) -> array { - auto const n = AN(w); - auto const* v = pointer_to_values(w); - array z; + auto const n = AN(w); + auto const *v = pointer_to_values(w); + array z = nullptr; GATV(z, INT, n, AR(w), AS(w)); - auto u = pointer_to_values(z); + auto *u = pointer_to_values(z); for (int64_t i = 0; i < n; ++i) { auto x = *v++; - if (x < IMIN || FLIMAX <= x) return w; // if conversion will fail, skip it - *u++ = (I)x; + if (x < IMIN || FLIMAX <= x) { + return w; // if conversion will fail, skip it + } + *u++ = static_cast(x); } return z; } @@ -610,7 +631,7 @@ auto jtpcvt(J jt, I t, array w) -> array { RANK2T oqr = jt->ranks; RESETRANK; - array y; + array y = nullptr; bool const b = jtccvt(jt, t, w, &y); jt->ranks = oqr; return b ? y : w; @@ -619,9 +640,9 @@ jtpcvt(J jt, I t, array w) -> array { auto jtcvt0(J jt, array w) -> array { auto const t = AT(w); - auto const n = (t & CMPX) ? 2 * AN(w) : AN(w); - if (n && t & FL + CMPX) { - auto u = pointer_to_values(w); + auto const n = (t & CMPX) != 0 ? 2 * AN(w) : AN(w); + if ((n != 0) && ((t & (FL + CMPX)) != 0)) { + auto *u = pointer_to_values(w); std::transform(u, u + n, u, [](auto v) { return v == 0.0 ? 0.0 : v; }); } return w; @@ -630,24 +651,24 @@ jtcvt0(J jt, array w) -> array { auto jtxco1(J jt, array w) -> array { ASSERT(AT(w) & DENSE, EVNONCE); - return jtcvt(jt, AT(w) & B01 + INT + XNUM ? XNUM : RAT, w); + return jtcvt(jt, AT(w) & (B01 + INT + XNUM) ? XNUM : RAT, w); } auto jtxco2(J jt, array a, array w) -> array { ASSERT(AT(w) & DENSE, EVNONCE); - I j; + I j = 0; RE(j = jti0(jt, a)); switch (j) { case -2: return jtaslash1(jt, CDIV, w); case -1: return jtbcvt(jt, 1, w); case 1: return jtxco1(jt, w); case 2: - if (!(AT(w) & RAT)) RZ(w = jtcvt(jt, RAT, w)); + if ((AT(w) & RAT) == 0) RZ(w = jtcvt(jt, RAT, w)); { auto const n = AN(w); auto const r = AR(w); - array z; + array z = nullptr; GATV(z, XNUM, 2 * n, r + 1, AS(w)); AS(z)[r] = 2; memcpy(pointer_to_values(z), pointer_to_values(w), 2 * n * SZI); From b528de242d933359830195de16c6f4b66c50075a Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 13:48:31 +0200 Subject: [PATCH 20/35] Add stdbool.h and extern "C" guards in j.h --- jsrc/j.h | 10 ++++++++++ jsrc/je.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/jsrc/j.h b/jsrc/j.h index 7a3a6dfa..95244680 100644 --- a/jsrc/j.h +++ b/jsrc/j.h @@ -3,6 +3,12 @@ /* */ /* Global Definitions */ +#ifdef __cplusplus +extern "C" { +#else +#include +#endif + #if defined(__clang_major__) && !defined(__clang__) #error need workaround by define __clang__ in preprocessor macro #endif @@ -1135,3 +1141,7 @@ _clearfp(void) { // Create (x&y) where x and y are signed, so we can test for overflow. #define XANDY(x, y) ((I)((UI)(x) & (UI)(y))) + +#ifdef __cplusplus +} +#endif diff --git a/jsrc/je.h b/jsrc/je.h index 080705df..344fa04e 100644 --- a/jsrc/je.h +++ b/jsrc/je.h @@ -551,7 +551,7 @@ extern A jtcreatecycliciterator(J, A, A); extern A jtcrelocalsyms(J, A, A, I, I, I); extern A jtcstr(J, C*); extern A jtcvt(J, I, A); -extern B jtccvt(J, I, A, A*); +extern bool jtccvt(J, I, A, A*); extern A jtcvz(J, I, A); extern A jtdaxis(J, I, A); extern A jtddtokens(J, A, I); From 079d17173c16e8b16fc6b9079471905611068753 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 15:12:36 +0200 Subject: [PATCH 21/35] Chain conversion pairs with && --- jsrc/conversions.cpp | 53 ++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 0531d1f3..45eaaa35 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -398,7 +398,7 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { RZ(*y = jtsparseit(jt, jtcvt(jt, DTYPE(t), w), IX(r), jtcvt(jt, DTYPE(t), jfalse))); jt->ranks = oqr; return true; // dense to sparse; convert type first (even if same dtype) - case 3: // sparse to sparse + case 3: // sparse to sparse I t1 = DTYPE(t); GASPARSE(*y, t, 1, r, s); P *yp = pointer_to_values

(*y); @@ -482,10 +482,8 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, INTX): std::copy_n(static_cast(wv), n, static_cast(yv)); return true; case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, static_cast(wv)); return true; - case CVCASE(B01X, FLX): - return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); - case CVCASE(INTX, FLX): - return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + case CVCASE(B01X, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + case CVCASE(INTX, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, FLX): return convert( jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); @@ -495,54 +493,41 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { case CVCASE(CMPXX, FLX): return convert(jt, w, yv); case CVCASE(B01X, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ))) { - return false; - } - return convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(INTX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ))) { - return false; - } - return convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ))) { - return false; - } - return convert( - jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + convert( + jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(RATX, CMPXX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ))) { - return false; - } - return convert( - jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); - case CVCASE(FLX, CMPXX): - return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + convert( + jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + case CVCASE(FLX, CMPXX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(B01X, XNUMX): return convert(jt, w, yv); case CVCASE(INTX, XNUMX): return convert(jt, w, yv); case CVCASE(RATX, XNUMX): return convert(jt, w, yv); case CVCASE(FLX, XNUMX): return convert(jt, w, yv); case CVCASE(CMPXX, XNUMX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d)))) return false; - return convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(B01X, RATX): GATV(d, XNUM, n, r, s); - if (!(convert(jt, w, pointer_to_values(d)))) return false; - return convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(INTX, RATX): GATV(d, XNUM, n, r, s); - if (!(convert(jt, w, pointer_to_values(d)))) return false; - return convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(XNUMX, RATX): return convert(jt, w, yv); case CVCASE(FLX, RATX): return convert(jt, w, yv); case CVCASE(CMPXX, RATX): GATV(d, FL, n, r, s); - if (!(convert(jt, w, pointer_to_values(d)))) return false; - return convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); default: ASSERT(0, EVDOMAIN); } } @@ -551,7 +536,7 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { auto jtcvt(J jt, I t, array w) -> array { array y = nullptr; - bool const b = jtccvt(jt, t, w, &y);; + bool const b = jtccvt(jt, t, w, &y); ASSERT(b, EVDOMAIN); return y; } From acc08bad173e2c302d7a664e0c95f9803ee61a38 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 15:24:36 +0200 Subject: [PATCH 22/35] Inline `pointer_to_values()` with correct types --- jsrc/conversions.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 45eaaa35..0b9c07cb 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -444,7 +444,6 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { // as n or s[0] since only n atoms will be used. For higher ranks, we need the shape from s. So it's just as well // that we take the shape from s now *y = d; - auto *wv = pointer_to_values(w); // return the address of the new block if ((t & CMPX) != 0) { jtfillv(jt, t, n, static_cast(yv)); // why?? just fill in imaginary parts as we need to } @@ -468,20 +467,20 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { } } switch (CVCASE(CTTZ(t), CTTZ(wt))) { - case CVCASE(INTX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return true; + case CVCASE(INTX, B01X): std::copy_n(pointer_to_values(w), n, static_cast(yv)); return true; case CVCASE(XNUMX, B01X): return convert(jt, w, yv); case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); - case CVCASE(FLX, B01X): std::copy_n(static_cast(wv), n, static_cast(yv)); return true; - case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, static_cast(wv)); return true; + case CVCASE(FLX, B01X): std::copy_n(pointer_to_values(w), n, static_cast(yv)); return true; + case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, pointer_to_values(w)); return true; case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return convert(jt, w, yv); case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); - case CVCASE(FLX, INTX): std::copy_n(static_cast(wv), n, static_cast(yv)); return true; - case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, static_cast(wv)); return true; + case CVCASE(FLX, INTX): std::copy_n(pointer_to_values(w), n, static_cast(yv)); return true; + case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, pointer_to_values(w)); return true; case CVCASE(B01X, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(INTX, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, FLX): From 3b340f7726bee237db29601984122f2d722e9b4f Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Sun, 7 Mar 2021 15:57:43 +0200 Subject: [PATCH 23/35] Remove pointer_to_values() type parameter default --- jsrc/array.hpp | 4 ++-- jsrc/conversions.cpp | 46 ++++++++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/jsrc/array.hpp b/jsrc/array.hpp index b4787816..f7e5d46d 100644 --- a/jsrc/array.hpp +++ b/jsrc/array.hpp @@ -35,7 +35,7 @@ num(int64_t n) { return reinterpret_cast(Bnum[n - NUMMIN]); } -template +template [[nodiscard]] inline auto pointer_to_values(array x) -> Value* { return reinterpret_cast(reinterpret_cast(x) + x->kchain.k); @@ -50,7 +50,7 @@ is_sparse(array x) noexcept -> bool { template auto set_value_at(array x, int32_t index, T const& value) -> void { - pointer_to_values(x)[index] = value; + pointer_to_values(x)[index] = value; } // TODO: remove eventually, temporary while c_types exist diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 0b9c07cb..8f63436e 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -174,7 +174,7 @@ jtxd1(J jt, D p, I mode) -> X { if (p == -inf) { return jtvci(jt, XNINF); } array t = make_array(jt, 30, 1); if (!t) return 0; - auto *u = pointer_to_values(t); + auto *u = pointer_to_values(t); int64_t m = 0; auto d = std::abs(p); while (0 < d) { @@ -184,7 +184,7 @@ jtxd1(J jt, D p, I mode) -> X { d = q; if (m == AN(t)) { RZ(t = jtext(jt, 0, t)); - u = pointer_to_values(t); + u = pointer_to_values(t); } } if (m == 0) { @@ -208,7 +208,7 @@ template <> convert(J jt, array w, void *yv) -> bool { auto *v = pointer_to_values(w); auto *x = static_cast(yv); - DO(AN(w), array q = v[i]; I e = pointer_to_values(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return false; x[i] = (B)e;); + DO(AN(w), array q = v[i]; I e = pointer_to_values(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return false; x[i] = (B)e;); return true; } @@ -216,7 +216,7 @@ template [[nodiscard]] static auto value_from_X(X p) -> T { auto const n = AN(p); - auto const v = std::reverse_iterator(pointer_to_values(p) + n); + auto const v = std::reverse_iterator(pointer_to_values(p) + n); return std::accumulate(v, v + n, T{}, [](auto d, auto v) { return v + d * XBASE; }); } @@ -242,7 +242,7 @@ template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { return convert(jt, w, yv, [](auto p) { - auto const c = pointer_to_values(p)[AN(p) - 1]; + auto const c = pointer_to_values(p)[AN(p) - 1]; if (c == XPINF) { return inf; } if (c == XNINF) { return infm; } return value_from_X(p); @@ -297,7 +297,7 @@ convert(J jt, array w, void *yv, I mode) -> bool { q.d = jtca(jt, iv1); } } - if (neg) { inplace_negate(pointer_to_values(q.n), AN(q.n)); } + if (neg) { inplace_negate(pointer_to_values(q.n), AN(q.n)); } *x++ = q; } return !jt->jerr; @@ -324,7 +324,7 @@ convert(J jt, array w, void *yv) -> bool { for (int64_t i = 0; i < wn; ++i) { auto *const p = wv[i].n; auto const pn = AN(p); - auto const k = 1 == pn ? pointer_to_values(p)[0] : 0; + auto const k = 1 == pn ? pointer_to_values(p)[0] : 0; auto *const q = wv[i].d; auto const qn = AN(q); if (k == XPINF) { @@ -332,8 +332,8 @@ convert(J jt, array w, void *yv) -> bool { } else if (k == XNINF) { x[i] = infm; } else if (pn <= nn && qn <= nn) { - auto const n = add_digits(pn, pointer_to_values(p)); - auto const d = add_digits(qn, pointer_to_values(q)); + auto const n = add_digits(pn, pointer_to_values(p)); + auto const d = add_digits(qn, pointer_to_values(q)); x[i] = n / d; } else { if (x2 == nullptr) { @@ -345,7 +345,7 @@ convert(J jt, array w, void *yv) -> bool { auto const cn = AN(c); auto const m = MIN(cn, 5); auto const r = cn - (m + k); - auto *const v = pointer_to_values(c) + cn - m; + auto *const v = pointer_to_values(c) + cn - m; auto const n = add_digits(m, v); auto d = std::pow(xb, std::abs(r)); x[i] = 0 > r ? n / d : n * d; @@ -471,14 +471,14 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { case CVCASE(XNUMX, B01X): return convert(jt, w, yv); case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, B01X): std::copy_n(pointer_to_values(w), n, static_cast(yv)); return true; case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, pointer_to_values(w)); return true; case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return convert(jt, w, yv); case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, INTX): std::copy_n(pointer_to_values(w), n, static_cast(yv)); return true; case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, pointer_to_values(w)); return true; case CVCASE(B01X, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); @@ -492,20 +492,20 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { case CVCASE(CMPXX, FLX): return convert(jt, w, yv); case CVCASE(B01X, CMPXX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(INTX, CMPXX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, CMPXX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && convert( jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(RATX, CMPXX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && convert( jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); case CVCASE(FLX, CMPXX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); @@ -515,18 +515,18 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { case CVCASE(FLX, XNUMX): return convert(jt, w, yv); case CVCASE(CMPXX, XNUMX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(B01X, RATX): GATV(d, XNUM, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(INTX, RATX): GATV(d, XNUM, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(XNUMX, RATX): return convert(jt, w, yv); case CVCASE(FLX, RATX): return convert(jt, w, yv); case CVCASE(CMPXX, RATX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); default: ASSERT(0, EVDOMAIN); } } @@ -568,7 +568,7 @@ jtbcvt(J jt, C mode, array w) -> array { if (flags == AN(w)) { if (ipok >= 0) GATV(result, INT, AN(w), AR(w), AS(w)); std::transform( - wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) { return as_integer(z.re); }); + wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) { return as_integer(z.re); }); } else { if (ipok >= 0) GATV(result, CMPX, AN(w), AR(w), AS(w)); std::transform(wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) -> Z { @@ -600,7 +600,7 @@ jticvt(J jt, array w) -> array { auto const *v = pointer_to_values(w); array z = nullptr; GATV(z, INT, n, AR(w), AS(w)); - auto *u = pointer_to_values(z); + auto *u = pointer_to_values(z); for (int64_t i = 0; i < n; ++i) { auto x = *v++; if (x < IMIN || FLIMAX <= x) { @@ -655,7 +655,7 @@ jtxco2(J jt, array a, array w) -> array { array z = nullptr; GATV(z, XNUM, 2 * n, r + 1, AS(w)); AS(z)[r] = 2; - memcpy(pointer_to_values(z), pointer_to_values(w), 2 * n * SZI); + memcpy(pointer_to_values(z), pointer_to_values(w), 2 * n * SZI); return z; } default: ASSERT(0, EVDOMAIN); From a0379e4efff87fc968850e2ab3e6bca1117ce668 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Mon, 8 Mar 2021 01:31:53 +0200 Subject: [PATCH 24/35] Add checked transform variant of convert() --- jsrc/conversions.cpp | 137 ++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 68 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 8f63436e..4d97e46d 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "array.hpp" extern "C" { @@ -14,11 +15,12 @@ extern "C" { #define CVCASE(a, b) (((a) << 3) + (b)) // The main cases fit in low 8 bits of mask -// FIEQ are used in bcvt, where FUZZ may be set to 0 to ensure only exact values are demoted to lower precision -#define FIEQ(u, v, fuzz) \ - (ABS((u) - (v)) <= \ - fuzz * \ - ABS(v)) // used when v is known to be exact integer. It's close enough, maybe ULP too small on the high end +// fuzzy_equal() is used in bcvt, where FUZZ may be set to 0 to ensure only exact values are demoted to lower precision +// used when v is known to be exact integer. It's close enough, maybe ULP too small on the high end +[[nodiscard]] static auto +fuzzy_equal(double u, double v, double fuzz) -> bool { + return std::abs(u - v) <= fuzz * std::abs(v); +} template [[nodiscard]] constexpr auto @@ -32,88 +34,84 @@ in_range() -> bool { return in_range(std::numeric_limits::min()) && in_range(std::numeric_limits::max()); } -template +template +struct is_optional : std::false_type {}; + +template +struct is_optional> : std::true_type {}; + +template [[nodiscard]] auto -convert(J jt, array w, void *yv) -> bool { +value_if(bool cond, T value) -> std::optional { + return cond ? std::optional(value) : std::nullopt; +} + +template +[[nodiscard]] auto +convert(J jt, array w, void *yv, Transform t) -> bool { auto *v = pointer_to_values(w); - if constexpr (!in_range()) { - // TODO: replace with short circuiting solution - auto *out = static_cast(yv); - return out + AN(w) == std::copy_if(v, v + AN(w), out, [](auto v) { return in_range(v); }); + auto *result = static_cast(yv); + if constexpr (is_optional::value) { + for (int64_t i = 0; i < AN(w); ++i) { + auto opt = t(v[i]); + if (!opt) return false; + result[i] = opt.value(); + } + } else { + std::transform(v, v + AN(w), result, t); } - std::copy(v, v + AN(w), static_cast(yv)); return true; } -template +template [[nodiscard]] auto -convert(J jt, array w, void *yv, Transform t) -> bool { +convert(J jt, array w, void *yv) -> bool { + if constexpr (!in_range()) { + return convert(jt, w, yv, [](auto v) { return value_if(in_range(v), v); }); + } auto *v = pointer_to_values(w); - std::transform(v, v + AN(w), static_cast(yv), t); + std::copy(v, v + AN(w), static_cast(yv)); return true; } template <> [[nodiscard]] auto convert(J jt, array w, void *yv, D fuzz) -> bool { - auto n = AN(w); - auto *v = pointer_to_values(w); - auto *x = static_cast(yv); - DQ(n, auto p = *v++; if (p < -2 || 2 < p) return false; // handle infinities - I val = 2; - val = (p == 0) ? 0 : val; - val = FIEQ(p, 1.0, fuzz) ? 1 : val; - if (val == 2) return false; - *x++ = (B)val;) - return true; + auto const infinity = [](auto p) { return p < -2 || 2 < p; }; + return convert(jt, w, yv, [&](auto p) { + return value_if(!infinity(p) && (p == 0.0 || fuzzy_equal(p, 1.0, fuzz)), p != 0.0); + }); } template <> [[nodiscard]] auto convert(J jt, array w, void *yv, D fuzz) -> bool { - auto n = AN(w); - auto *v = pointer_to_values(w); - auto *x = static_cast(yv); - for (int64_t i = 0; i < n; ++i) { - auto const p = v[i]; + return convert(jt, w, yv, [&](auto p) -> std::optional { auto const q = jround(p); - I rq = static_cast(q); - if (!(p == q || FIEQ(p, q, fuzz))) { - return 0; // must equal int, possibly out of range + if (!(p == q || fuzzy_equal(p, q, fuzz))) { + return std::nullopt; // must equal int, possibly out of range } // out-of-range values don't convert, handle separately if (p < static_cast IMIN) { - if (!(p >= IMIN * (1 + fuzz))) return false; - rq = IMIN; + return value_if(p >= IMIN * (1 + fuzz), IMIN); } // if tolerantly < IMIN, error; else take IMIN else if (p >= FLIMAX) { - if (!(p <= -static_cast IMIN * (1 + fuzz))) return false; - rq = IMAX; + return value_if(p <= -static_cast IMIN * (1 + fuzz), IMAX); } // if tolerantly > IMAX, error; else take IMAX - *x++ = rq; - } - return true; + return q; + }); } template <> [[nodiscard]] auto convert(J jt, array w, void *yv, D fuzz) -> bool { - auto const n = AN(w); - auto const *v = pointer_to_values(w); - auto *x = static_cast(yv); - if (fuzz != 0.0) - DQ( - n, auto d = std::abs(v->im); if (d != inf && d <= fuzz * std::abs(v->re)) { - *x++ = v->re; - v++; - } else return false;) - else - DQ( - n, if (!v->im) { - *x++ = v->re; - v++; - } else return false;); - return true; + if (fuzz != 0.0) { + return convert(jt, w, yv, [&](auto const &v) { + auto const d = std::abs(v.im); + return value_if(d != inf && d <= fuzz * std::abs(v.re), v.re); + }); + } + return convert(jt, w, yv, [](auto v) { return value_if(!v.im, v.re); }); } template <> @@ -206,10 +204,10 @@ convert(J jt, array w, void *yv, I mode) -> bool { template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - auto *v = pointer_to_values(w); - auto *x = static_cast(yv); - DO(AN(w), array q = v[i]; I e = pointer_to_values(q)[0]; if ((AN(q) ^ 1) | (e & -2)) return false; x[i] = (B)e;); - return true; + return convert(jt, w, yv, [](auto q) { + auto const e = pointer_to_values(q)[0]; + return value_if(!((AN(q) ^ 1) | (e & -2)), e); + }); } template @@ -316,7 +314,10 @@ convert(J jt, array w, void *yv) -> bool { auto const add_digits = [&](auto n, auto v) { auto f = 1.0; auto d = 0.0; - DO(n, d += f * v[i]; f *= xb;); + std::for_each(v, v + n, [&](auto i) { + d += f * i; + f *= xb; + }); return d; }; @@ -357,10 +358,7 @@ convert(J jt, array w, void *yv) -> bool { template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - auto *v = pointer_to_values(w); - auto *x = static_cast(yv); - DQ(AN(w), if (!(jtequ(jt, iv1, v->d))) return 0; *x++ = v->n; ++v;); - return !jt->jerr; + return convert(jt, w, yv, [&](auto v) { return value_if(jtequ(jt, iv1, v.d), v.n); }) && !jt->jerr; } template @@ -641,14 +639,17 @@ jtxco1(J jt, array w) -> array { auto jtxco2(J jt, array a, array w) -> array { ASSERT(AT(w) & DENSE, EVNONCE); - I j = 0; - RE(j = jti0(jt, a)); + I j = jti0(jt, a); + if (jt->jerr != 0) return nullptr; switch (j) { case -2: return jtaslash1(jt, CDIV, w); case -1: return jtbcvt(jt, 1, w); case 1: return jtxco1(jt, w); case 2: - if ((AT(w) & RAT) == 0) RZ(w = jtcvt(jt, RAT, w)); + if ((AT(w) & RAT) == 0) { + w = jtcvt(jt, RAT, w); + if (!w) return nullptr; + } { auto const n = AN(w); auto const r = AR(w); From d860c288103f93bd9a5c1b4cc6f2949267f6aa60 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Mon, 8 Mar 2021 02:25:46 +0200 Subject: [PATCH 25/35] Use convert() instead of raw loops --- jsrc/conversions.cpp | 88 +++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 55 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 4d97e46d..785bb5fd 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -221,19 +221,14 @@ value_from_X(X p) -> T { template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - auto *v = pointer_to_values(w); - auto *x = static_cast(yv); - auto n = AN(w); - X p = nullptr; - X q; - if ((p = jtxc(jt, IMAX)) == nullptr) return false; - if ((q = jtxminus(jt, jtnegate(jt, p), jtxc(jt, 1L))) == nullptr) return false; - for (int64_t i = 0; i < n; ++i) { - auto *c = v[i]; - if (!(1 != jtxcompare(jt, q, c) && 1 != jtxcompare(jt, c, p))) return false; - x[i] = value_from_X(c); - } - return 1; + X p = jtxc(jt, IMAX); + if (!p) return false; + X q = jtxminus(jt, jtnegate(jt, p), jtxc(jt, 1L)); + if (!q) return false; + return convert(jt, w, yv, [&](auto c) -> std::optional { + if (!(1 != jtxcompare(jt, q, c) && 1 != jtxcompare(jt, c, p))) return std::nullopt; + return value_from_X(c); + }); } template <> @@ -305,9 +300,6 @@ template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { auto const xb = static_cast(XBASE); - auto const wn = AN(w); - auto *const wv = pointer_to_values(w); - auto *const x = static_cast(yv); auto const nn = 308 / XBASEN; // TODO: figure out nice algorithm for this @@ -322,37 +314,30 @@ convert(J jt, array w, void *yv) -> bool { }; X x2 = nullptr; - for (int64_t i = 0; i < wn; ++i) { - auto *const p = wv[i].n; + return convert(jt, w, yv, [&](auto nd) -> std::optional { + auto *const p = nd.n; auto const pn = AN(p); - auto const k = 1 == pn ? pointer_to_values(p)[0] : 0; - auto *const q = wv[i].d; + auto const kk = 1 == pn ? pointer_to_values(p)[0] : 0; + if (kk == XPINF) return inf; + if (kk == XNINF) return infm; + auto *const q = nd.d; auto const qn = AN(q); - if (k == XPINF) { - x[i] = inf; - } else if (k == XNINF) { - x[i] = infm; - } else if (pn <= nn && qn <= nn) { + if (pn <= nn && qn <= nn) { auto const n = add_digits(pn, pointer_to_values(p)); auto const d = add_digits(qn, pointer_to_values(q)); - x[i] = n / d; - } else { - if (x2 == nullptr) { - if ((x2 = jtxc(jt, 2L)) == nullptr) return false; - } - auto const k = 5 + qn; - auto *c = jtxdiv(jt, jttake(jt, jtsc(jt, -(k + pn)), p), q, XMFLR); - if (c == nullptr) return false; - auto const cn = AN(c); - auto const m = MIN(cn, 5); - auto const r = cn - (m + k); - auto *const v = pointer_to_values(c) + cn - m; - auto const n = add_digits(m, v); - auto d = std::pow(xb, std::abs(r)); - x[i] = 0 > r ? n / d : n * d; + return n / d; } - } - return true; + if (!x2 && !(x2 = jtxc(jt, 2L))) return std::nullopt; + auto const k = 5 + qn; + auto *c = jtxdiv(jt, jttake(jt, jtsc(jt, -(k + pn)), p), q, XMFLR); + if (!c) return std::nullopt; + auto const cn = AN(c); + auto const m = MIN(cn, 5); + auto const r = cn - (m + k); + auto const n = add_digits(m, pointer_to_values(c) + cn - m); + auto d = std::pow(xb, std::abs(r)); + return 0 > r ? n / d : n * d; + }); } template <> @@ -594,19 +579,12 @@ jtbcvt(J jt, C mode, array w) -> array { auto jticvt(J jt, array w) -> array { - auto const n = AN(w); - auto const *v = pointer_to_values(w); - array z = nullptr; - GATV(z, INT, n, AR(w), AS(w)); - auto *u = pointer_to_values(z); - for (int64_t i = 0; i < n; ++i) { - auto x = *v++; - if (x < IMIN || FLIMAX <= x) { - return w; // if conversion will fail, skip it - } - *u++ = static_cast(x); - } - return z; + array z = nullptr; + GATV(z, INT, AN(w), AR(w), AS(w)); + return convert( + jt, w, pointer_to_values(z), [](auto x) { return value_if(IMIN <= x && x < FLIMAX, x); }) + ? z + : w; // if conversion will fail, skip it } auto From 10504fcb820d219d240e07b1d5f37ac218ffb840 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Mon, 8 Mar 2021 03:40:59 +0200 Subject: [PATCH 26/35] Replace std::copy_n() with convert() Also use std::copy_n() instead of std::copy() in convert() Also also, I kind of understand, but wtf: std::numeric_limits::min() and std::numeric_limits::lowest() Now fixed behaviour with double (and bool) --- jsrc/conversions.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 785bb5fd..74d701d5 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -25,13 +25,16 @@ fuzzy_equal(double u, double v, double fuzz) -> bool { template [[nodiscard]] constexpr auto in_range(V value) -> bool { - return std::numeric_limits::min() <= value && value <= std::numeric_limits::max(); + if constexpr (std::is_same_v) + return true; + else + return std::numeric_limits::lowest() <= value && value <= std::numeric_limits::max(); } template [[nodiscard]] constexpr auto in_range() -> bool { - return in_range(std::numeric_limits::min()) && in_range(std::numeric_limits::max()); + return in_range(std::numeric_limits::lowest()) && in_range(std::numeric_limits::max()); } template @@ -450,19 +453,19 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { } } switch (CVCASE(CTTZ(t), CTTZ(wt))) { - case CVCASE(INTX, B01X): std::copy_n(pointer_to_values(w), n, static_cast(yv)); return true; + case CVCASE(INTX, B01X): return convert(jt, w, yv); case CVCASE(XNUMX, B01X): return convert(jt, w, yv); case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); - case CVCASE(FLX, B01X): std::copy_n(pointer_to_values(w), n, static_cast(yv)); return true; + case CVCASE(FLX, B01X): return convert(jt, w, yv); case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, pointer_to_values(w)); return true; case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return convert(jt, w, yv); case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); - case CVCASE(FLX, INTX): std::copy_n(pointer_to_values(w), n, static_cast(yv)); return true; + case CVCASE(FLX, INTX): return convert(jt, w, yv); case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, pointer_to_values(w)); return true; case CVCASE(B01X, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(INTX, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); From 194cbc44e70d179849154676317f355d862c9c29 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Mon, 8 Mar 2021 04:36:06 +0200 Subject: [PATCH 27/35] Refactor conversions to complex (Z) --- jsrc/conversions.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 74d701d5..e48afc61 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -69,12 +69,15 @@ convert(J jt, array w, void *yv, Transform t) -> bool { template [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - if constexpr (!in_range()) { + if constexpr (std::is_same_v) { + return convert(jt, w, yv, [](auto v) { return To{.re = static_cast(v), .im = {}}; }); + } else if constexpr (!in_range()) { return convert(jt, w, yv, [](auto v) { return value_if(in_range(v), v); }); + } else { + auto *v = pointer_to_values(w); + std::copy(v, v + AN(w), static_cast(yv)); + return true; } - auto *v = pointer_to_values(w); - std::copy(v, v + AN(w), static_cast(yv)); - return true; } template <> @@ -349,20 +352,6 @@ convert(J jt, array w, void *yv) -> bool { return convert(jt, w, yv, [&](auto v) { return value_if(jtequ(jt, iv1, v.d), v.n); }) && !jt->jerr; } -template -auto -set_real_part(Z *z, int64_t n, T *t) { - for (int64_t i = 0; i < n; ++i) { z[i].re = t[i]; } -} - -// Imaginary parts have already been cleared -template <> -[[nodiscard]] auto -convert(J jt, array w, void *yv) -> bool { - set_real_part(static_cast(yv), AN(w), pointer_to_values(w)); - return true; -} - // Convert the data in w to the type t. w and t must be noun types. A new buffer is always created (with a // copy of the data if w is already of the right type), and returned in *y. Result is // 0 if error, 1 if success. If the conversion loses precision, error is returned @@ -459,14 +448,14 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, B01X): return convert(jt, w, yv); - case CVCASE(CMPXX, B01X): set_real_part(static_cast(yv), n, pointer_to_values(w)); return true; + case CVCASE(CMPXX, B01X): return convert(jt, w, yv); case CVCASE(B01X, INTX): return convert(jt, w, yv); case CVCASE(XNUMX, INTX): return convert(jt, w, yv); case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, INTX): return convert(jt, w, yv); - case CVCASE(CMPXX, INTX): set_real_part(static_cast(yv), n, pointer_to_values(w)); return true; + case CVCASE(CMPXX, INTX): return convert(jt, w, yv); case CVCASE(B01X, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(INTX, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, FLX): From 4c39a04257d15bee6dc536bd65ec3c896217a4e4 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Mon, 8 Mar 2021 10:31:19 +0200 Subject: [PATCH 28/35] Make the CI compiler happy --- jsrc/conversions.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index e48afc61..0c841e73 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -25,10 +25,12 @@ fuzzy_equal(double u, double v, double fuzz) -> bool { template [[nodiscard]] constexpr auto in_range(V value) -> bool { - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { + (void)value; return true; - else + } else { return std::numeric_limits::lowest() <= value && value <= std::numeric_limits::max(); + } } template @@ -74,6 +76,7 @@ convert(J jt, array w, void *yv) -> bool { } else if constexpr (!in_range()) { return convert(jt, w, yv, [](auto v) { return value_if(in_range(v), v); }); } else { + (void)jt; auto *v = pointer_to_values(w); std::copy(v, v + AN(w), static_cast(yv)); return true; From 7229958d32d9fd8cdccb6c254fd7634286f4e298 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Wed, 17 Mar 2021 01:11:49 +0200 Subject: [PATCH 29/35] Add missing parentheses The macro definition had parentheses, which made it work --- jsrc/conversions.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 0c841e73..cf8007a2 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -54,7 +54,7 @@ value_if(bool cond, T value) -> std::optional { template [[nodiscard]] auto convert(J jt, array w, void *yv, Transform t) -> bool { - auto *v = pointer_to_values(w); + auto *v = pointer_to_values(w); auto *result = static_cast(yv); if constexpr (is_optional::value) { for (int64_t i = 0; i < AN(w); ++i) { @@ -87,9 +87,8 @@ template <> [[nodiscard]] auto convert(J jt, array w, void *yv, D fuzz) -> bool { auto const infinity = [](auto p) { return p < -2 || 2 < p; }; - return convert(jt, w, yv, [&](auto p) { - return value_if(!infinity(p) && (p == 0.0 || fuzzy_equal(p, 1.0, fuzz)), p != 0.0); - }); + return convert( + jt, w, yv, [&](auto p) { return value_if(!infinity(p) && (p == 0.0 || fuzzy_equal(p, 1.0, fuzz)), p != 0.0); }); } template <> @@ -101,11 +100,11 @@ convert(J jt, array w, void *yv, D fuzz) -> bool { return std::nullopt; // must equal int, possibly out of range } // out-of-range values don't convert, handle separately - if (p < static_cast IMIN) { + if (p < static_cast(IMIN)) { return value_if(p >= IMIN * (1 + fuzz), IMIN); } // if tolerantly < IMIN, error; else take IMIN else if (p >= FLIMAX) { - return value_if(p <= -static_cast IMIN * (1 + fuzz), IMAX); + return value_if(p <= -static_cast(IMIN) * (1 + fuzz), IMAX); } // if tolerantly > IMAX, error; else take IMAX return q; }); @@ -308,8 +307,8 @@ convert(J jt, array w, void *yv, I mode) -> bool { template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - auto const xb = static_cast(XBASE); - auto const nn = 308 / XBASEN; + auto const xb = static_cast(XBASE); + auto const nn = 308 / XBASEN; // TODO: figure out nice algorithm for this auto const add_digits = [&](auto n, auto v) { @@ -421,7 +420,7 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { // If n and AN have been modified, it doesn't matter for rank-1 arguments whether the shape of the result is listed // as n or s[0] since only n atoms will be used. For higher ranks, we need the shape from s. So it's just as well // that we take the shape from s now - *y = d; + *y = d; if ((t & CMPX) != 0) { jtfillv(jt, t, n, static_cast(yv)); // why?? just fill in imaginary parts as we need to } @@ -445,7 +444,7 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { } } switch (CVCASE(CTTZ(t), CTTZ(wt))) { - case CVCASE(INTX, B01X): return convert(jt, w, yv); + case CVCASE(INTX, B01X): return convert(jt, w, yv); case CVCASE(XNUMX, B01X): return convert(jt, w, yv); case CVCASE(RATX, B01X): GATV(d, XNUM, n, r, s); From c993b447179b9aeaf57c084331458f00e84ccd88 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Wed, 17 Mar 2021 01:19:40 +0200 Subject: [PATCH 30/35] Replace `I` and `D` with correct types --- jsrc/conversions.cpp | 151 ++++++++++++++++++++++--------------------- jsrc/je.h | 6 +- 2 files changed, 82 insertions(+), 75 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index cf8007a2..adf41b8f 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -72,7 +72,7 @@ template [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { if constexpr (std::is_same_v) { - return convert(jt, w, yv, [](auto v) { return To{.re = static_cast(v), .im = {}}; }); + return convert(jt, w, yv, [](auto v) { return To{.re = static_cast(v), .im = {}}; }); } else if constexpr (!in_range()) { return convert(jt, w, yv, [](auto v) { return value_if(in_range(v), v); }); } else { @@ -85,26 +85,26 @@ convert(J jt, array w, void *yv) -> bool { template <> [[nodiscard]] auto -convert(J jt, array w, void *yv, D fuzz) -> bool { +convert(J jt, array w, void *yv, double fuzz) -> bool { auto const infinity = [](auto p) { return p < -2 || 2 < p; }; - return convert( + return convert( jt, w, yv, [&](auto p) { return value_if(!infinity(p) && (p == 0.0 || fuzzy_equal(p, 1.0, fuzz)), p != 0.0); }); } template <> [[nodiscard]] auto -convert(J jt, array w, void *yv, D fuzz) -> bool { - return convert(jt, w, yv, [&](auto p) -> std::optional { +convert(J jt, array w, void *yv, double fuzz) -> bool { + return convert(jt, w, yv, [&](auto p) -> std::optional { auto const q = jround(p); if (!(p == q || fuzzy_equal(p, q, fuzz))) { return std::nullopt; // must equal int, possibly out of range } // out-of-range values don't convert, handle separately - if (p < static_cast(IMIN)) { + if (p < static_cast(IMIN)) { return value_if(p >= IMIN * (1 + fuzz), IMIN); } // if tolerantly < IMIN, error; else take IMIN else if (p >= FLIMAX) { - return value_if(p <= -static_cast(IMIN) * (1 + fuzz), IMAX); + return value_if(p <= -static_cast(IMIN) * (1 + fuzz), IMAX); } // if tolerantly > IMAX, error; else take IMAX return q; }); @@ -112,14 +112,14 @@ convert(J jt, array w, void *yv, D fuzz) -> bool { template <> [[nodiscard]] auto -convert(J jt, array w, void *yv, D fuzz) -> bool { +convert(J jt, array w, void *yv, double fuzz) -> bool { if (fuzz != 0.0) { - return convert(jt, w, yv, [&](auto const &v) { + return convert(jt, w, yv, [&](auto const &v) { auto const d = std::abs(v.im); return value_if(d != inf && d <= fuzz * std::abs(v.re), v.re); }); } - return convert(jt, w, yv, [](auto v) { return value_if(!v.im, v.re); }); + return convert(jt, w, yv, [](auto v) { return value_if(!v.im, v.re); }); } template <> @@ -143,8 +143,8 @@ inplace_negate(T *u, int64_t n) { template <> [[nodiscard]] auto -convert(J jt, array w, void *yv) -> bool { - I u[XIDIG]; +convert(J jt, array w, void *yv) -> bool { + int64_t u[XIDIG]; auto const convert_one = [&](auto c) { auto const b = c == IMIN; auto d = b ? -(1 + c) : std::abs(c); @@ -159,13 +159,13 @@ convert(J jt, array w, void *yv) -> bool { if (0 > c) { inplace_negate(u, XIDIG); } return jtvec(jt, INT, length, u); }; - return convert(jt, w, yv, convert_one) && !jt->jerr; + return convert(jt, w, yv, convert_one) && !jt->jerr; } static auto -jtxd1(J jt, D p, I mode) -> X { +jtxd1(J jt, double p, int64_t mode) -> X { PROLOG(0052); - D e = jttfloor(jt, p); + double e = jttfloor(jt, p); switch (mode) { case XMFLR: p = e; break; case XMCEIL: p = ceil(p); break; @@ -186,7 +186,7 @@ jtxd1(J jt, D p, I mode) -> X { while (0 < d) { auto const q = floor(d / XBASE); auto const r = d - q * XBASE; - u[m++] = static_cast(r); + u[m++] = static_cast(r); d = q; if (m == AN(t)) { RZ(t = jtext(jt, 0, t)); @@ -205,8 +205,8 @@ jtxd1(J jt, D p, I mode) -> X { template <> [[nodiscard]] auto -convert(J jt, array w, void *yv, I mode) -> bool { - return convert(jt, w, yv, [=](auto v) { return jtxd1(jt, v, mode); }) && !jt->jerr; +convert(J jt, array w, void *yv, int64_t mode) -> bool { + return convert(jt, w, yv, [=](auto v) { return jtxd1(jt, v, mode); }) && !jt->jerr; } template <> @@ -228,12 +228,12 @@ value_from_X(X p) -> T { template <> [[nodiscard]] auto -convert(J jt, array w, void *yv) -> bool { +convert(J jt, array w, void *yv) -> bool { X p = jtxc(jt, IMAX); if (!p) return false; X q = jtxminus(jt, jtnegate(jt, p), jtxc(jt, 1L)); if (!q) return false; - return convert(jt, w, yv, [&](auto c) -> std::optional { + return convert(jt, w, yv, [&](auto c) -> std::optional { if (!(1 != jtxcompare(jt, q, c) && 1 != jtxcompare(jt, c, p))) return std::nullopt; return value_from_X(c); }); @@ -241,8 +241,8 @@ convert(J jt, array w, void *yv) -> bool { template <> [[nodiscard]] auto -convert(J jt, array w, void *yv) -> bool { - return convert(jt, w, yv, [](auto p) { +convert(J jt, array w, void *yv) -> bool { + return convert(jt, w, yv, [](auto p) { auto const c = pointer_to_values(p)[AN(p) - 1]; if (c == XPINF) { return inf; } if (c == XNINF) { return infm; } @@ -258,12 +258,12 @@ convert(J jt, array w, void *yv) -> bool { template <> [[nodiscard]] auto -convert(J jt, array w, void *yv, I mode) -> bool { +convert(J jt, array w, void *yv, int64_t mode) -> bool { if ((w) == nullptr) return false; auto const n = AN(w); auto *const wv = pointer_to_values(w); auto *x = static_cast(yv); - D t = NAN; + double t = NAN; auto *tv = 3 + reinterpret_cast(&t); Q q; for (int64_t i = 0; i < n; ++i) { @@ -287,7 +287,7 @@ convert(J jt, array w, void *yv, I mode) -> bool { } else { bool const recip = 1 > t; if (recip) { t = 1.0 / t; } - auto e = static_cast(0xfff0 & *tv); + auto e = static_cast(0xfff0 & *tv); e >>= 4; e -= 1023; if (recip) { @@ -306,8 +306,8 @@ convert(J jt, array w, void *yv, I mode) -> bool { template <> [[nodiscard]] auto -convert(J jt, array w, void *yv) -> bool { - auto const xb = static_cast(XBASE); +convert(J jt, array w, void *yv) -> bool { + auto const xb = static_cast(XBASE); auto const nn = 308 / XBASEN; // TODO: figure out nice algorithm for this @@ -322,7 +322,7 @@ convert(J jt, array w, void *yv) -> bool { }; X x2 = nullptr; - return convert(jt, w, yv, [&](auto nd) -> std::optional { + return convert(jt, w, yv, [&](auto nd) -> std::optional { auto *const p = nd.n; auto const pn = AN(p); auto const kk = 1 == pn ? pointer_to_values(p)[0] : 0; @@ -359,9 +359,9 @@ convert(J jt, array w, void *yv) -> bool { // 0 if error, 1 if success. If the conversion loses precision, error is returned // Calls through bcvt are tagged with a flag in jt, indicating to set fuzz=0 auto -jtccvt(J jt, I tflagged, array w, array *y) -> bool { +jtccvt(J jt, int64_t tflagged, array w, array *y) -> bool { FPREFIP; - I const t = tflagged & NOUN; + int64_t const t = tflagged & NOUN; if (w == nullptr) return false; auto const r = AR(w); auto *const s = AS(w); @@ -376,7 +376,7 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { jt->ranks = oqr; return true; // dense to sparse; convert type first (even if same dtype) case 3: // sparse to sparse - I t1 = DTYPE(t); + int64_t t1 = DTYPE(t); GASPARSE(*y, t, 1, r, s); P *yp = pointer_to_values

(*y); P *wp = pointer_to_values

(w); @@ -406,14 +406,14 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { if (!d) return false; auto *yv = pointer_to_values(d); // allocate the same # atoms, even if we will convert fewer if ((tflagged & NOUNCVTVALIDCT) != 0) { - I inputn = *reinterpret_cast(y); // fetch input, in case it is called for - if (inputn > 0) { // if converting the leading values, just update the counts - n = inputn; // set the counts for local use, and in the block to be converted - } else { // if converting trailing values... + int64_t inputn = *reinterpret_cast(y); // fetch input, in case it is called for + if (inputn > 0) { // if converting the leading values, just update the counts + n = inputn; // set the counts for local use, and in the block to be converted + } else { // if converting trailing values... AK(w) += (n + inputn) << bplg(wt); - yv = reinterpret_cast(static_cast(yv) + - ((n + inputn) << bplg(t))); // advance input and output pointers to new area - n = -inputn; // get positive # atoms to convert + yv = reinterpret_cast( + static_cast(yv) + ((n + inputn) << bplg(t))); // advance input and output pointers to new area + n = -inputn; // get positive # atoms to convert } AN(w) = n; // change atomct of w to # atoms to convert } @@ -451,66 +451,73 @@ jtccvt(J jt, I tflagged, array w, array *y) -> bool { return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, B01X): return convert(jt, w, yv); case CVCASE(CMPXX, B01X): return convert(jt, w, yv); - case CVCASE(B01X, INTX): return convert(jt, w, yv); - case CVCASE(XNUMX, INTX): return convert(jt, w, yv); + case CVCASE(B01X, INTX): return convert(jt, w, yv); + case CVCASE(XNUMX, INTX): return convert(jt, w, yv); case CVCASE(RATX, INTX): GATV(d, XNUM, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(FLX, INTX): return convert(jt, w, yv); case CVCASE(CMPXX, INTX): return convert(jt, w, yv); - case CVCASE(B01X, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); - case CVCASE(INTX, FLX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + case CVCASE(B01X, FLX): + return convert(jt, w, yv, ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + case CVCASE(INTX, FLX): + return convert(jt, w, yv, ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, FLX): - return convert( - jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + return convert( + jt, w, yv, int64_t{(jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)}); case CVCASE(RATX, FLX): - return convert( - jt, w, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); - case CVCASE(CMPXX, FLX): return convert(jt, w, yv); + return convert( + jt, w, yv, int64_t{(jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)}); + case CVCASE(CMPXX, FLX): return convert(jt, w, yv); case CVCASE(B01X, CMPXX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && - convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + return convert( + jt, w, pointer_to_values(d), ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + convert(jt, d, yv, ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(INTX, CMPXX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && - convert(jt, d, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + return convert( + jt, w, pointer_to_values(d), ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + convert(jt, d, yv, ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(XNUMX, CMPXX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && - convert( - jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); + return convert( + jt, w, pointer_to_values(d), ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + convert( + jt, d, yv, int64_t{(jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)}); case CVCASE(RATX, CMPXX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d), ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && - convert( - jt, d, yv, (jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)); - case CVCASE(FLX, CMPXX): return convert(jt, w, yv, ((I)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); + return convert( + jt, w, pointer_to_values(d), ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ) && + convert( + jt, d, yv, int64_t{(jt->xmode & REPSGN(SGNIFNOT(tflagged, XCVTXNUMORIDEX))) | (tflagged >> XCVTXNUMCVX)}); + case CVCASE(FLX, CMPXX): + return convert(jt, w, yv, ((int64_t)jtinplace & JTNOFUZZ) != 0 ? 0.0 : FUZZ); case CVCASE(B01X, XNUMX): return convert(jt, w, yv); - case CVCASE(INTX, XNUMX): return convert(jt, w, yv); + case CVCASE(INTX, XNUMX): return convert(jt, w, yv); case CVCASE(RATX, XNUMX): return convert(jt, w, yv); - case CVCASE(FLX, XNUMX): return convert(jt, w, yv); + case CVCASE(FLX, XNUMX): return convert(jt, w, yv); case CVCASE(CMPXX, XNUMX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(B01X, RATX): GATV(d, XNUM, n, r, s); return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(INTX, RATX): GATV(d, XNUM, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); case CVCASE(XNUMX, RATX): return convert(jt, w, yv); - case CVCASE(FLX, RATX): return convert(jt, w, yv); + case CVCASE(FLX, RATX): return convert(jt, w, yv); case CVCASE(CMPXX, RATX): GATV(d, FL, n, r, s); - return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); + return convert(jt, w, pointer_to_values(d)) && convert(jt, d, yv); default: ASSERT(0, EVDOMAIN); } } // clear rank before calling ccvt - needed for sparse arrays only but returns the block as the result auto -jtcvt(J jt, I t, array w) -> array { +jtcvt(J jt, int64_t t, array w) -> array { array y = nullptr; bool const b = jtccvt(jt, t, w, &y); ASSERT(b, EVDOMAIN); @@ -526,7 +533,7 @@ jtbcvt(J jt, C mode, array w) -> array { FPREFIP; if (w == nullptr) { return nullptr; } - auto const as_integer = [](auto const &v) { return *(I *)&v; }; + auto const as_integer = [](auto const &v) { return *(int64_t *)&v; }; auto const isflag = [&](auto const &z) { return as_integer(z.im) == NANFLAG; }; // there may be values (especially b types) that were nominally CMPX but might actually be integers. Those were @@ -541,7 +548,7 @@ jtbcvt(J jt, C mode, array w) -> array { // auto flags = std::transform_reduce(wv, wv + AN(w), int64_t{}, std::plus{}, isflag); auto flags = std::accumulate(wv, wv + AN(w), int64_t{}, [&](auto sum, auto v) { return sum + isflag(v); }); if (flags != 0) { - I ipok = SGNIF(jtinplace, JTINPLACEWX) & AC(w); // both sign bits set (<0) if inplaceable + int64_t ipok = SGNIF(jtinplace, JTINPLACEWX) & AC(w); // both sign bits set (<0) if inplaceable if (flags == AN(w)) { if (ipok >= 0) GATV(result, INT, AN(w), AR(w), AS(w)); std::transform( @@ -549,7 +556,7 @@ jtbcvt(J jt, C mode, array w) -> array { } else { if (ipok >= 0) GATV(result, CMPX, AN(w), AR(w), AS(w)); std::transform(wv, wv + AN(w), pointer_to_values(result), [&](auto const &z) -> Z { - if (isflag(z)) { return {.re = (D)as_integer(z.re), .im = 0.0}; }; + if (isflag(z)) { return {.re = (double)as_integer(z.re), .im = 0.0}; }; return z; // copy floats, and converts any integers back to float }); } @@ -561,7 +568,7 @@ jtbcvt(J jt, C mode, array w) -> array { // To avoid a needless copy, suppress conversion to B01 if type is B01, to INT if type is INT, etc // set the NOFUZZ flag in jt to insist on an exact match so we won't lose precision array y = nullptr; - jtinplace = (J)((I)jt + JTNOFUZZ); // demand exact match + jtinplace = (J)((int64_t)jt + JTNOFUZZ); // demand exact match result = ((mode & 14) == 0) && jtccvt(jtinplace, B01, w, &y) ? y : (y = w, AT(w) & INT || (((mode & 12) == 0) && jtccvt(jtinplace, INT, w, &y))) ? y : (y = w, AT(w) & FL || (((mode & 8) == 0) && jtccvt(jtinplace, FL, w, &y))) @@ -582,7 +589,7 @@ jticvt(J jt, array w) -> array { } auto -jtpcvt(J jt, I t, array w) -> array { +jtpcvt(J jt, int64_t t, array w) -> array { RANK2T oqr = jt->ranks; RESETRANK; array y = nullptr; @@ -611,7 +618,7 @@ jtxco1(J jt, array w) -> array { auto jtxco2(J jt, array a, array w) -> array { ASSERT(AT(w) & DENSE, EVNONCE); - I j = jti0(jt, a); + int64_t j = jti0(jt, a); if (jt->jerr != 0) return nullptr; switch (j) { case -2: return jtaslash1(jt, CDIV, w); diff --git a/jsrc/je.h b/jsrc/je.h index 344fa04e..daac60a3 100644 --- a/jsrc/je.h +++ b/jsrc/je.h @@ -550,8 +550,8 @@ extern I jtcountnl(J); extern A jtcreatecycliciterator(J, A, A); extern A jtcrelocalsyms(J, A, A, I, I, I); extern A jtcstr(J, C*); -extern A jtcvt(J, I, A); -extern bool jtccvt(J, I, A, A*); +extern A jtcvt(J, int64_t, A); +extern bool jtccvt(J, int64_t, A, A*); extern A jtcvz(J, I, A); extern A jtdaxis(J, I, A); extern A jtddtokens(J, A, I); @@ -640,7 +640,7 @@ extern A jtparsea(J, A*, I); extern B jtparseinit(J); extern A jtparsex(J, A*, I, CW*, DC); extern A jtpaxis(J, I, A); -extern A jtpcvt(J, I, A); +extern A jtpcvt(J, int64_t, A); extern A jtpee(J, A*, CW*, I, I, DC); extern A jtpfill(J, I, A); extern A jtpind(J, I, A); From b71a0207a3a2bd9bc94dc91b7bd7c6d780b26069 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Wed, 17 Mar 2021 01:33:28 +0200 Subject: [PATCH 31/35] Extract transformation lambda to variable --- jsrc/conversions.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index adf41b8f..bf1f057c 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -125,14 +125,11 @@ convert(J jt, array w, void *yv, double fuzz) -> bool { template <> [[nodiscard]] auto convert(J jt, array w, void *yv) -> bool { - return convert(jt, - w, - yv, - [=](auto v) { - int64_t u[] = {v}; - return jtvec(jt, INT, 1L, u); - }) && - !jt->jerr; + auto const convert_one = [=](auto v) { + int64_t u[] = {v}; + return jtvec(jt, INT, 1L, u); + }; + return convert(jt, w, yv, convert_one) && !jt->jerr; } template From 05d91c69cfcde5a6bff8c02c46b5e2a4164d887b Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Wed, 17 Mar 2021 01:52:00 +0200 Subject: [PATCH 32/35] Remove unnecessary special case --- jsrc/conversions.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index bf1f057c..f2f05d38 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -25,12 +25,7 @@ fuzzy_equal(double u, double v, double fuzz) -> bool { template [[nodiscard]] constexpr auto in_range(V value) -> bool { - if constexpr (std::is_same_v) { - (void)value; - return true; - } else { - return std::numeric_limits::lowest() <= value && value <= std::numeric_limits::max(); - } + return std::numeric_limits::lowest() <= value && value <= std::numeric_limits::max(); } template From 2110d69d3e37ecdff35540f5468f8facd87d5b36 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Wed, 17 Mar 2021 01:58:57 +0200 Subject: [PATCH 33/35] Use std::negate{} --- jsrc/conversions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index f2f05d38..9af83df9 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -130,7 +130,7 @@ convert(J jt, array w, void *yv) -> bool { template static auto inplace_negate(T *u, int64_t n) { - std::transform(u, u + n, u, [](auto v) { return -v; }); + std::transform(u, u + n, u, std::negate{}); } template <> From 86ae356ea83b451f23ba93c0f55b7a8da2b7b419 Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Wed, 17 Mar 2021 02:44:05 +0200 Subject: [PATCH 34/35] Use std::div() --- jsrc/conversions.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/jsrc/conversions.cpp b/jsrc/conversions.cpp index 9af83df9..990f0933 100644 --- a/jsrc/conversions.cpp +++ b/jsrc/conversions.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "array.hpp" extern "C" { @@ -138,13 +139,14 @@ template <> convert(J jt, array w, void *yv) -> bool { int64_t u[XIDIG]; auto const convert_one = [&](auto c) { - auto const b = c == IMIN; - auto d = b ? -(1 + c) : std::abs(c); + bool const b = c == IMIN; + int64_t d = b ? -(1 + c) : std::abs(c); int64_t length = 0; for (int64_t i = 0; i < XIDIG; ++i) { - u[i] = d % XBASE; - d = d / XBASE; - if (u[i]) length = i; + auto const [q, r] = std::div(d, int64_t{XBASE}); + u[i] = r; + d = q; + if (r) length = i; } ++length; *u += b; @@ -174,11 +176,10 @@ jtxd1(J jt, double p, int64_t mode) -> X { if (!t) return 0; auto *u = pointer_to_values(t); int64_t m = 0; - auto d = std::abs(p); + int64_t d = std::abs(p); while (0 < d) { - auto const q = floor(d / XBASE); - auto const r = d - q * XBASE; - u[m++] = static_cast(r); + auto const [q, r] = std::div(d, int64_t{XBASE}); + u[m++] = r; d = q; if (m == AN(t)) { RZ(t = jtext(jt, 0, t)); From d5cc1b9944ac47c9190502cc53d0639ce9b9091c Mon Sep 17 00:00:00 2001 From: Juho Eerola Date: Wed, 17 Mar 2021 11:14:43 +0200 Subject: [PATCH 35/35] Disable bool-compare warning --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f24bd853..20109bf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,8 @@ add_compile_options($<$:-Wno-char-subscripts>) add_compile_options($<$:-Wno-string-plus-int>) add_compile_options($<$:-Wno-missing-braces>) add_compile_options($<$:-Wno-unknown-pragmas>) +add_compile_options($<$:-Wno-bool-compare>) + add_subdirectory(jsrc) add_subdirectory(base64)