diff --git a/docs/ra-ra.texi b/docs/ra-ra.texi index e97629e..a4f82da 100644 --- a/docs/ra-ra.texi +++ b/docs/ra-ra.texi @@ -1595,7 +1595,7 @@ Error handling in @code{ra::} is controlled by two macros: @itemize @item @code{RA_DO_CHECK} -is a binary flag that controls runtime checks. The default is 1 which means to check for errors. 0 means not to check. The checks themselves are done with @code{RA_ASSERT}. +is a binary flag that controls runtime checks. The default is 1 which means to check for errors. 0 means not to check. The checks themselves are done with @code{RA_ASSERT}. After including @code{ra/ra.hh}, this flag will always be defined. @item @code{RA_ASSERT(cond, ...)} is a function-like macro. @code{cond} is an expression that evaluates to true (in the @code{ra::} namespace) if the assertion is satisfied. The other arguments are informative and do not need to be used. If the assertion fails, the default definition of @code{RA_ASSERT(cond, ...)} prints those arguments to @code{std::cerr} and aborts. @end itemize @@ -1697,6 +1697,10 @@ Item 1 Item 2 @end enumerate +@section The cost of @code{RA_DO_CHECK} + +FIXME + @c ------------------------------------------------ @node Internals @chapter Internals diff --git a/examples/throw.cc b/examples/throw.cc index 0551971..6277db7 100644 --- a/examples/throw.cc +++ b/examples/throw.cc @@ -1,7 +1,7 @@ // -*- mode: c++; coding: utf-8 -*- // ra-ra/examples - Customize ra:: reaction to errors. -// (c) Daniel Llorens - 2019-2023 +// (c) Daniel Llorens - 2019-2024 // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License as published by the Free // Software Foundation; either version 3 of the License, or (at your option) any @@ -30,7 +30,7 @@ struct ra_error: public std::exception }; #define RA_ASSERT( cond, ... ) \ - { if (!( cond )) throw ra_error("ra:: assert [" STRINGIZE(cond) "] " __VA_OPT__(,) __VA_ARGS__); } + { if (!( cond )) throw ra_error("ra::", std::source_location::current(), " (" STRINGIZE(cond) ") " __VA_OPT__(,) __VA_ARGS__); } // The override will be in effect for the rest of ra::. diff --git a/ra/base.hh b/ra/base.hh index afa4b6c..b30e609 100644 --- a/ra/base.hh +++ b/ra/base.hh @@ -281,8 +281,7 @@ struct shape_manip_t constexpr shape_manip_t operator<<(std::ostream & o, print_shape_t shape) { return shape_manip_t { o, shape }; } -// include is_fov bc shape() may be std::vector or std::array. -// exclude std::string_view so it is is_fov but still prints as a string [ra13]. +// exclude std::string_view so it still prints as a string [ra13]. template requires (is_ra || (is_fov && !std::is_convertible_v)) constexpr std::ostream & operator<<(std::ostream & o, A && a) { return o << format_array(a); } diff --git a/ra/big.hh b/ra/big.hh index 017dc08..ec28bb9 100644 --- a/ra/big.hh +++ b/ra/big.hh @@ -122,13 +122,13 @@ struct ViewBig constexpr dim_t select(Dim * dim, int k, dim_t i) const { - RA_CHECK(inside(i, len(k)), "Bad index in len[", k, "]=", len(k), ": ", i, "."); + RA_CHECK(inside(i, len(k)), "Bad index ", i, " for len[", k, "]=", len(k), "."); return step(k)*i; } constexpr dim_t select(Dim * dim, int k, is_iota auto i) const { - RA_CHECK(inside(i, len(k)), "Bad index in len[", k, "]=", len(k), ": iota [", i.n, " ", i.i, " ", i.s, "]."); + RA_CHECK(inside(i, len(k)), "Bad index iota [", i.n, " ", i.i, " ", i.s, "] for len[", k, "]=", len(k), "."); *dim = { .len = i.n, .step = step(k) * i.s }; return 0==i.n ? 0 : step(k)*i.i; } @@ -173,8 +173,7 @@ struct ViewBig constexpr rank_t extended = (0 + ... + beatable.add); ViewBig sub; rank_t subrank = rank()+extended; - if constexpr (RANK==ANY) { - RA_CHECK(subrank>=0, "Bad rank."); + if constexpr (ANY==RANK) { sub.dimv.resize(subrank); } sub.cp = cp + select_loop(sub.dimv.data(), 0, i ...); @@ -207,7 +206,7 @@ struct ViewBig operator T & () const { if constexpr (0!=RANK) { - RA_CHECK(1==size(), "Bad conversion to scalar from shape [", ra::noshape, ra::shape(this), "]."); + RA_CHECK(1==size(), "Bad conversion to scalar from shape [", ra::noshape, ra::shape(*this), "]."); } return cp[0]; } @@ -241,7 +240,7 @@ struct storage_traits { using T = V::value_type; static_assert(!std::is_same_v, bool>, "No pointers to bool in std::vector."); - constexpr static auto create(dim_t n) { RA_CHECK(n>=0); return V(n); } + constexpr static auto create(dim_t n) { RA_CHECK(0<=n, "Bad size ", n, "."); return V(n); } template constexpr static auto data(VV & v) { return v.data(); } }; @@ -250,7 +249,7 @@ struct storage_traits> { using V = std::unique_ptr

; using T = std::decay_t().get())>; - constexpr static auto create(dim_t n) { RA_CHECK(n>=0); return V(new T[n]); } + constexpr static auto create(dim_t n) { RA_CHECK(0<=n, "Bad size ", n, "."); return V(new T[n]); } template constexpr static auto data(VV & v) { return v.get(); } }; @@ -259,7 +258,7 @@ struct storage_traits> { using V = std::shared_ptr

; using T = std::decay_t().get())>; - constexpr static auto create(dim_t n) { RA_CHECK(n>=0); return V(new T[n], std::default_delete()); } + constexpr static auto create(dim_t n) { RA_CHECK(0<=n, "Bad size ", n, "."); return V(new T[n], std::default_delete()); } template constexpr static auto data(VV & v) { return v.get(); } }; @@ -310,7 +309,7 @@ struct Container: public ViewBig::T, RANK> // const/nonconst shims over View's methods. FIXME > gcc13 ? __cpp_explicit_this_parameter #define RA_CONST_OR_NOT(CONST) \ - constexpr T CONST & back() CONST { RA_CHECK(1==rank() && size()>0); return store[size()-1]; } \ + constexpr T CONST & back() CONST { RA_CHECK(1==rank() && size()>0, "Bad back()."); return store[size()-1]; } \ constexpr auto data() CONST { return view().data(); } \ constexpr decltype(auto) operator()(auto && ... a) CONST { return view()(RA_FWD(a) ...); } \ constexpr decltype(auto) operator[](auto && ... a) CONST { return view()(RA_FWD(a) ...); } \ @@ -400,14 +399,14 @@ struct Container: public ViewBig::T, RANK> // resize first axis or full shape. Only for some kinds of store. void resize(dim_t const s) { - static_assert(RANK==ANY || RANK>0); RA_CHECK(00); RA_CHECK(0::T, RANK> // lets us move. A template + RA_FWD wouldn't work for push_back(brace-enclosed-list). void push_back(T && t) { - static_assert(RANK==1 || RANK==ANY); RA_CHECK(1==rank()); + static_assert(ANY==RANK || 1==RANK); RA_CHECK(1==rank()); store.push_back(std::move(t)); ++View::dimv[0].len; View::cp = store.data(); } void push_back(T const & t) { - static_assert(RANK==1 || RANK==ANY); RA_CHECK(1==rank()); + static_assert(ANY==RANK || 1==RANK); RA_CHECK(1==rank()); store.push_back(t); ++View::dimv[0].len; View::cp = store.data(); } void emplace_back(auto && ... a) { - static_assert(RANK==1 || RANK==ANY); RA_CHECK(1==rank()); + static_assert(ANY==RANK || 1==RANK); RA_CHECK(1==rank()); store.emplace_back(RA_FWD(a) ...); ++View::dimv[0].len; View::cp = store.data(); } void pop_back() { - static_assert(RANK==1 || RANK==ANY); RA_CHECK(1==rank()); - RA_CHECK(View::dimv[0].len>0); - store.pop_back(); + static_assert(ANY==RANK || 1==RANK); RA_CHECK(1==rank()); + RA_CHECK(0 & a, Container & b) { if constexpr (ANY==RANKA) { - RA_CHECK(rank(a)==rank(b)); + RA_CHECK(rank(a)==rank(b), "Mismatched ranks ", rank(a), " and ", rank(b), "."); decltype(b.dimv) c = a.dimv; start(a.dimv) = b.dimv; std::swap(b.dimv, c); } else if constexpr (ANY==RANKB) { - RA_CHECK(rank(a)==rank(b)); + RA_CHECK(rank(a)==rank(b), "Mismatched ranks ", rank(a), " and ", rank(b), "."); decltype(a.dimv) c = b.dimv; start(b.dimv) = a.dimv; std::swap(a.dimv, c); @@ -590,7 +589,7 @@ template inline ViewBig reverse(ViewBig const & view, int k=0) { - RA_CHECK(inside(k, view.rank()), "Bad reverse axis ", k, " for view of rank ", view.rank(), "."); + RA_CHECK(inside(k, view.rank()), "Bad axis ", k, " for rank ", view.rank(), "."); ViewBig r = view; if (auto & dim=r.dimv[k]; dim.len!=0) { r.cp += dim.step*(dim.len-1); @@ -689,8 +688,7 @@ reshape_(ViewBig const & a, S && sb_) rank_t i = 0; for (; i=lb, "Reshape with copy not implemented."); + RA_CHECK(is_c_order(a, false) && la>=lb, "Reshape with copy not implemented."); // FIXME ViewBig(SS const & s, T * p). Cf [ra37]. filldim(b.dimv, sb); for (int j=0; j!=b.rank(); ++j) { @@ -703,7 +701,7 @@ reshape_(ViewBig const & a, S && sb_) } } if (i==a.rank()) { -// tile & return +// tile for (rank_t j=i; j) { - RA_CHECK(BAD==nn || inside(j[0], n), "Out of range for len[0]=", n, ": ", j[0], "."); + RA_CHECK(BAD==nn || inside(j[0], n), "Bad index ", j[0], " for len[0]=", n, "."); return i[j[0]*s]; } constexpr decltype(auto) operator*() const { return *i; } @@ -207,7 +207,7 @@ struct Iota constexpr static bool keep_step(dim_t st, int z, int j) { return st*step(z)==step(j); } constexpr auto at(auto && j) const { - RA_CHECK(BAD==nn || inside(j[0], n), "Out of range for len[0]=", n, ": ", j[0], "."); + RA_CHECK(BAD==nn || inside(j[0], n), "Bad index ", j[0], " for len[0]=", n, "."); return i + I(j[w])*I(s); } constexpr I operator*() const { return i; } @@ -297,7 +297,7 @@ template requires (is_iterator && !is_ra_scalar) constexpr auto start(T & t) { return t; } -// FIXME const Iterator would still be unusable after start() +// FIXME const Iterator would still be unusable after start(). constexpr decltype(auto) start(is_iterator auto && t) { return RA_FWD(t); } @@ -334,11 +334,10 @@ struct Match, mp::int_list> dim_t ls = len_s(k); if (((k() && ls!=choose_len(std::decay_t

::len_s(k), ls)) || ...)) { return 0; - } else { - int anyk = ((k() && (ANY==std::decay_t

::len_s(k))) + ...); - int fixk = ((k() && (0<=std::decay_t

::len_s(k))) + ...); - tbc = tbc || (anyk>0 && anyk+fixk>1); } + int anyk = ((k() && (ANY==std::decay_t

::len_s(k))) + ...); + int fixk = ((k() && (0<=std::decay_t

::len_s(k))) + ...); + tbc = tbc || (anyk>0 && anyk+fixk>1); } return tbc ? 1 : 2; } @@ -346,9 +345,9 @@ struct Match, mp::int_list> constexpr bool check() const { - if constexpr (sizeof...(P)<2) { + if constexpr (constexpr int c = check_s(); 2==c) { return true; - } else if constexpr (constexpr int c = check_s(); 0==c) { + } else if constexpr (0==c) { return false; } else if constexpr (1==c) { for (int k=0; k, mp::int_list> dim_t ls = len(k); #pragma GCC diagnostic pop if (((k(t)) && ls!=choose_len(std::get(t).len(k), ls)) || ...)) { - RA_CHECK(!checkp, "Mismatch on axis ", k, " [", (std::array { std::get(t).len(k) ... }), "]."); return false; } } @@ -368,10 +366,13 @@ struct Match, mp::int_list> constexpr Match(P ... p_): t(p_ ...) // [ra1] { -// TODO Maybe on ply, would make checkp unnecessary, make agree_xxx() unnecessary. +// TODO Maybe on ply would make checkp, agree_xxx() unnecessary. if constexpr (checkp && !(has_len

|| ...)) { - static_assert(check_s(), "Shape mismatch."); - RA_CHECK(check()); + constexpr int c = check_s(); + static_assert(0!=c, "Mismatched shapes."); // FIXME c++26 + if constexpr (1==c) { + RA_CHECK(check(), "Mismatched shapes", format_array(ra::shape(p_), {.shape=noshape, .open=" [", .close="]"}) ..., "."); + } } } diff --git a/ra/ra.hh b/ra/ra.hh index 9aaf609..bf36afd 100644 --- a/ra/ra.hh +++ b/ra/ra.hh @@ -443,7 +443,7 @@ template >> constexpr decltype(auto) refmin(A && a, Less && less = {}) { - RA_CHECK(a.size()>0); + RA_CHECK(a.size()>0, "refmin requires nonempty argument."); decltype(auto) s = ra::start(a); auto p = &(*s); for_each([&less, &p](auto & a) { if (less(a, *p)) { p = &a; } }, s); @@ -454,7 +454,7 @@ template >> constexpr decltype(auto) refmax(A && a, Less && less = {}) { - RA_CHECK(a.size()>0); + RA_CHECK(a.size()>0, "refmax requires nonempty argument."); decltype(auto) s = ra::start(a); auto p = &(*s); for_each([&less, &p](auto & a) { if (less(*p, a)) { p = &a; } }, s); diff --git a/ra/small.hh b/ra/small.hh index ecdf6bf..e62ccba 100644 --- a/ra/small.hh +++ b/ra/small.hh @@ -90,7 +90,7 @@ resize(A & a, dim_t s) RA_CHECK(s>=0, "Bad resize ", s, "."); a.resize(s); } else { - RA_CHECK(s==start(a).len(0) || BAD==s, "Bad resize ", s, " vs ", start(a).len(0), "."); + RA_CHECK(s==start(a).len(0) || BAD==s, "Bad resize ", s, " needing ", start(a).len(0), "."); } } @@ -461,7 +461,7 @@ struct ViewSmall: public SmallBase constexpr static dim_t select(dim_t i) { - RA_CHECK(inside(i, len(k)), "Bad index in len[", k, "]=", len(k), ": ", i, "."); + RA_CHECK(inside(i, len(k)), "Bad index ", i, " in len[", k, "]=", len(k), "."); return step(k)*i; } template @@ -471,7 +471,7 @@ struct ViewSmall: public SmallBase if constexpr ((1>=i.n ? 1 : (i.s<0 ? -i.s : i.s)*(i.n-1)+1) > len(k)) { // FIXME c++23 std::abs static_assert(always_false, "Bad index."); } else { - RA_CHECK(inside(i, len(k)), "Bad index in len[", k, "]=", len(k), ": iota [", i.n, " ", i.i, " ", i.s, "]"); + RA_CHECK(inside(i, len(k)), "Bad index iota [", i.n, " ", i.i, " ", i.s, "] in len[", k, "]=", len(k), "."); } return 0==i.n ? 0 : step(k)*i.i; } diff --git a/ra/test.hh b/ra/test.hh index 67b8f4d..6cff393 100644 --- a/ra/test.hh +++ b/ra/test.hh @@ -173,9 +173,9 @@ struct TestRecorder return c; } else { test(false, - RA_LAZYINFO("Mismatched args [", ra::noshape, ra::shape(a), "] [", ra::noshape, ra::shape(b), "]", + RA_LAZYINFO("Mismatched shapes [", ra::noshape, ra::shape(a), "] [", ra::noshape, ra::shape(b), "]", willstrictshape ? " (strict shape)" : ""), - RA_LAZYINFO("Shape mismatch", willstrictshape ? " (strict shape)" : ""), + RA_LAZYINFO("Mismatched shapes", willstrictshape ? " (strict shape)" : ""), loc); return false; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e833d5d..473b480 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,5 @@ # -*- coding: utf-8; mode: cmake -*- -# (c) Daniel Llorens - 2018, 2019 +# (c) Daniel Llorens - 2018-2024 cmake_minimum_required (VERSION 3.5) project (ra-test) @@ -8,8 +8,8 @@ include_directories ("..") SET (TARGETS at bench big-0 big-1 bug83 checks compatibility concrete const constexpr dual early explode-0 foreign frame-new frame-old fromb fromu headers io iota iterator-small len list9 macros mem-fn nested-0 old operators optimize owned ownership ply ra-0 ra-1 ra-10 ra-11 - ra-12 ra-13 ra-14 ra-2 ra-3 ra-4 ra-5 ra-6 ra-7 ra-8 ra-9 ra-dual reduction reexported - reshape return-expr self-assign sizeof small-0 small-1 stl-compat swap tensorindex + ra-12 ra-13 ra-14 ra-15 ra-16 ra-2 ra-3 ra-4 ra-5 ra-6 ra-7 ra-8 ra-9 ra-dual reduction + reexported reshape return-expr self-assign sizeof small-0 small-1 stl-compat swap tensorindex tuples types vector-array view-ops wedge where wrank) include ("../config/cc.cmake") diff --git a/test/SConstruct b/test/SConstruct index c601124..6c1ae4c 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,7 +1,7 @@ # -*- coding: utf-8; mode: Python -*- # SConstruct for ra/test -# (c) Daniel Llorens - 2015-2023 +# (c) Daniel Llorens - 2015-2024 # This library is free software; you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation; either version 3 of the License, or (at your option) any @@ -58,8 +58,8 @@ tester = ra.to_test_ra(env, variant_dir) 'frame-old', 'fromb', 'fromu', 'headers', 'io', 'iota', 'iterator-small', 'len', 'list9', 'macros', 'mem-fn', 'ndebug', 'nested-0', 'old', 'operators', 'optimize', 'owned', 'ownership', 'ply', 'ra-0', 'ra-1', 'ra-10', 'ra-11', 'ra-12', 'ra-13', - 'ra-14', 'ra-15', 'ra-2', 'ra-3', 'ra-4', 'ra-5', 'ra-6', 'ra-7', 'ra-8', 'ra-9', - 'ra-dual', 'reduction', 'reduction-1', 'reexported', 'reshape', 'return-expr', + 'ra-14', 'ra-15', 'ra-16', 'ra-2', 'ra-3', 'ra-4', 'ra-5', 'ra-6', 'ra-7', 'ra-8', + 'ra-9', 'ra-dual', 'reduction', 'reduction-1', 'reexported', 'reshape', 'return-expr', 'self-assign', 'sizeof', 'small-0', 'small-1', 'stl-compat', 'swap', 'tensorindex', 'test', 'tuples', 'types', 'vector-array', 'view-ops', 'wedge', 'where', 'wrank', # 'bug90745', # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90745 gcc 9-10.2 so far diff --git a/test/checks.cc b/test/checks.cc index 10f86c9..d2d53b1 100644 --- a/test/checks.cc +++ b/test/checks.cc @@ -1,13 +1,13 @@ // -*- mode: c++; coding: utf-8 -*- // ra-ra/test - Runtime checks. -// (c) Daniel Llorens - 2019-2023 +// (c) Daniel Llorens - 2019-2024 // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License as published by the Free // Software Foundation; either version 3 of the License, or (at your option) any // later version. -#ifdef RA_DO_CHECK +#if RA_DO_CHECK==0 #undef RA_DO_CHECK #define RA_DO_CHECK 1 // kind of the point here #endif @@ -31,7 +31,7 @@ struct ra_error: public std::exception }; #define RA_ASSERT( cond, ... ) \ - { if (!( cond )) throw ra_error("ra:: assert [" STRINGIZE(cond) "]", ##__VA_ARGS__); } + { if (!( cond )) throw ra_error("ra::", std::source_location::current(), " (" STRINGIZE(cond) ") " __VA_OPT__(,) __VA_ARGS__); } // ------------------------------------- #include "ra/test.hh" @@ -42,6 +42,7 @@ using ra::int_c, ra::mp::int_list; int main() { + cout << "******* " << RA_DO_CHECK << "******" << endl; TestRecorder tr(std::cout); tr.section("bad cell rank"); { @@ -222,7 +223,7 @@ int main() tr.info("uninitialized dynamic rank").test_eq(2, x); } tr.section("iffy conversions"); -// FIXME this fails at runtime bc val[0] might have size 1, but this is much more likely to be a coding error. +// won't fail until runtime bc val[0] might have size 1, but FIXME this is very likely a coding error. // FIXME shape doesn't show in the error message as it should. { ra::Big val = { { 7, 0, 0, 0.5, 1.5, 1, 1, 1 } }; diff --git a/test/ra-16.cc b/test/ra-16.cc new file mode 100644 index 0000000..fdc3491 --- /dev/null +++ b/test/ra-16.cc @@ -0,0 +1,64 @@ +// -*- mode: c++; coding: utf-8 -*- +// ra/test - Spurious out of range error with gcc11 -O3 I can't reproduce + +// (c) Daniel Llorens - 2024 +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) any +// later version. + +#include +#include "ra/test.hh" + +using real = float; +using real2 = ra::Small; +using real3 = ra::Small; +using real23 = ra::Small; +using real32 = ra::Small; +using complex = std::complex; + +template +constexpr void +sph22c_s_op(Tu const & u, TR & R) +{ + real ct = cos(u[0]), st = sin(u[0]), cp = cos(u[1]), sp = sin(u[1]); + R = { ct*cp, -sp, ct*sp, cp, -st, real(0) }; +} + +constexpr real2 +c2s2(real3 const c) +{ + real2 s; + real p2 = ra::sqr(c[0])+ra::sqr(c[1]); + s[0] = atan2(sqrt(p2), c[2]); + s[1] = atan2(c[1], c[0]); + return s; +} + +ra::Big rr = { { 0., 0., 1. } }; +ra::Big a({20, 1, 3}, 0.); +ra::Big dip({20, 2}, 1.); + +void +far(real const f, ra::ViewBig const & rr, ra::ViewBig & a) +{ + real A = 1., m = .5, n = .4; + for_each([&](auto && r, auto & a) { + a = real(0); + if (r[2]>0) { + real32 op; + sph22c_s_op(c2s2(r), op); + real pn = A*std::pow(r[2], n); + real23 opmn = transpose<1, 0>(op)*real2 { pn*std::pow(r[2], m-1), pn }; + gemm(dip, gemm(op, opmn), a); + } + }, iter<1>(rr), iter<2>(ra::transpose<1, 0, 2>(a))); +} + +int main() +{ + ra::TestRecorder tr(std::cout); + far(20e9, rr, a); + tr.test_eq(complex(40.), sum(a)); + return tr.summary(); +} diff --git a/test/types.cc b/test/types.cc index 0c1ab02..ab46f75 100644 --- a/test/types.cc +++ b/test/types.cc @@ -47,7 +47,7 @@ test_predicates(char const * type, TestRecorder & tr, struct Unreg { int x; }; // prefer decltype(declval(...)) to https://stackoverflow.com/a/13842784 the latter drops const -#define TESTPRED(A, ...) test_predicates (STRINGIZE(A), tr, ##__VA_ARGS__) +#define TESTPRED(A, ...) test_predicates (STRINGIZE(A), tr __VA_OPT__(,) __VA_ARGS__) int main() {