From 3c0665636b547c3dbe5289061dea473f1572e9c0 Mon Sep 17 00:00:00 2001 From: lloda Date: Mon, 27 May 2024 13:38:08 +0200 Subject: [PATCH] Fix size_s / size for std:: ranges * ra/base.hh (size_s): Avoid tuple_size which doesn't do what we need. (from_ravel): Renamed from ravel_from_iterators, take range instead. * test/small-0.cc: More tests for from_ravel. This patch is backported from c++23 branch 8c4700927fff6e0ebe64f0ea054b09c9fde8a514. --- ra/base.hh | 7 ++++++- ra/small.hh | 8 +++++--- test/small-0.cc | 17 ++++++++++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/ra/base.hh b/ra/base.hh index ffcf594..5287490 100644 --- a/ra/base.hh +++ b/ra/base.hh @@ -125,6 +125,8 @@ RA_IS_DEF(is_iterator, IteratorConcept) template concept is_ra = is_iterator || SliceConcept; template concept is_builtin_array = std::is_array_v>; RA_IS_DEF(is_fov, (!is_scalar && !is_ra && !is_builtin_array && std::ranges::bidirectional_range)) +template constexpr bool is_std_array = false; // snowflake +template constexpr bool is_std_array> = true; template requires (!std::is_void_v) consteval rank_t @@ -177,8 +179,11 @@ size_s() return 1; } else if constexpr (is_builtin_array) { return std::apply([] (auto ... i) { return (std::extent_v * ... * 1); }, mp::iota {}); - } else if constexpr (is_fov && requires { std::tuple_size::value; }) { + } else if constexpr (is_std_array) { return std::tuple_size_v; + } else if constexpr (is_fov && requires { V::size(); }) { + return V::size(); +// FIXME no std::dynamic_extent in gcc 11 } else if constexpr (is_fov || rs==ANY) { return ANY; } else if constexpr (requires { V::size_s(); }) { diff --git a/ra/small.hh b/ra/small.hh index fef4c1e..a5430db 100644 --- a/ra/small.hh +++ b/ra/small.hh @@ -625,13 +625,15 @@ SmallArray> template SmallArray(A0, A ...) -> Small; -// FIXME tagged ravel constructor. Then we can pass any rank 1 thing not just iterator pairs. +// FIXME tagged ravel constructor template constexpr auto -ravel_from_iterators(auto && begin, auto && end) +from_ravel(auto && b) { A a; - std::copy(RA_FWD(begin), RA_FWD(end), a.begin()); + RA_CHECK(1==ra::rank(b) && ra::size(b)==ra::size(a), + "Bad ravel argument [", ra::noshape, ra::shape(b), "] expecting [", ra::size(a), "]."); + std::ranges::copy(RA_FWD(b), a.begin()); return a; } diff --git a/test/small-0.cc b/test/small-0.cc index c075ad5..05d6f52 100644 --- a/test/small-0.cc +++ b/test/small-0.cc @@ -28,6 +28,11 @@ std::string typecheck(auto && a) int main() { TestRecorder tr; + tr.section("std::array is used internally so these are fundamental"); + { + static_assert(3==ra::size(std::array { 3, 4, 5 })); + static_assert(3==ra::size_s(std::array { 3, 4, 5 })); + } tr.section("Small isn't an aggregate so T; and T {}; are the same, unlike std::array"); { std::array a; // default init, unlike {} which is aggregate init @@ -386,11 +391,21 @@ int main() tr.section("raveling constructor from iterators"); { int AA[4] = { 1, 2, 3, 4 }; - auto a = ra::ravel_from_iterators>(AA, AA+4); + auto a = ra::from_ravel>(std::ranges::subrange(AA, AA+4)); tr.test_eq(1, a(0, 0)); tr.test_eq(2, a(0, 1)); tr.test_eq(3, a(1, 0)); tr.test_eq(4, a(1, 1)); + auto b = ra::from_ravel>(AA); + tr.test_eq(1, b(0, 0)); + tr.test_eq(2, b(0, 1)); + tr.test_eq(3, b(1, 0)); + tr.test_eq(4, b(1, 1)); + auto c = ra::from_ravel>(ra::Small { 1, 2, 3, 4}); + tr.test_eq(1, c(0, 0)); + tr.test_eq(2, c(0, 1)); + tr.test_eq(3, c(1, 0)); + tr.test_eq(4, c(1, 1)); } tr.section("nested Small I"); {