From 68a21c5a5952913d6192be747efd245887bc36cc Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:24:54 +0200 Subject: [PATCH 1/2] Fix substring calculation in CSV cell parsing and add lexical_cast for signed and unsigned char --- include/xtensor/io/xcsv.hpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/xtensor/io/xcsv.hpp b/include/xtensor/io/xcsv.hpp index 080ccaf54..2fd347745 100644 --- a/include/xtensor/io/xcsv.hpp +++ b/include/xtensor/io/xcsv.hpp @@ -66,7 +66,7 @@ namespace xt } size_t last = cell.find_last_not_of(' '); - return cell.substr(first, last == std::string::npos ? cell.size() : last + 1); + return cell.substr(first, last == std::string::npos ? cell.size() : last - first + 1); } template <> @@ -93,6 +93,18 @@ namespace xt return std::stoi(cell); } + template <> + inline signed char lexical_cast(const std::string& cell) + { + return static_cast(std::stoi(cell)); + } + + template <> + inline unsigned char lexical_cast(const std::string& cell) + { + return static_cast(std::stoul(cell)); + } + template <> inline long lexical_cast(const std::string& cell) { From d8553adfecf0dae33517f73ea92e94e07fbf25c4 Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Mon, 24 Aug 2026 15:10:21 +0200 Subject: [PATCH 2/2] Fix SIMD assign through reshape_view of lazy expressions (#2929) load_simd/store_simd take the address of the view's flat storage, which requires lvalue references. Gate provides_simd_interface on the storage exposing lvalue references so strided views over lazy expressions fall back to the scalar assign path instead of hard-erroring. --- include/xtensor/views/xstrided_view.hpp | 7 ++++++- test/test_xstrided_view.cpp | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/xtensor/views/xstrided_view.hpp b/include/xtensor/views/xstrided_view.hpp index 3faff70c8..b0fe2c6e0 100644 --- a/include/xtensor/views/xstrided_view.hpp +++ b/include/xtensor/views/xstrided_view.hpp @@ -179,8 +179,13 @@ namespace xt using simd_value_type = xt_simd::simd_type; using bool_load_type = typename base_type::bool_load_type; + // load_simd/store_simd take the address of the flat storage, which requires the + // storage to expose lvalue references (not the case for lazy expressions wrapped + // in a flat_expression_adaptor). static constexpr bool provides_simd_interface = has_simd_interface::value - && L != layout_type::dynamic; + && L != layout_type::dynamic + && std::is_lvalue_reference_v< + decltype(std::declval()[0])>; template xstrided_view(CTA&& e, SA&& shape, strides_type&& strides, std::size_t offset, layout_type layout) noexcept; diff --git a/test/test_xstrided_view.cpp b/test/test_xstrided_view.cpp index 5b8f8c01d..b916d2473 100644 --- a/test/test_xstrided_view.cpp +++ b/test/test_xstrided_view.cpp @@ -723,6 +723,29 @@ namespace xt EXPECT_TRUE(std::equal(nv.shape().begin(), nv.shape().end(), expected_shape.begin())); } + TEST(xstrided_view, reshape_view_lazy_expression) + { + const std::size_t G = 8, N = 4; + xtensor w = xt::arange(G) + 1.0; + xtensor Phi = 3.0 * xt::ones({G, N}); + + // reshape_view over a lazy expression must not enable the SIMD assign path, + // which takes the address of the (computed) flat storage. + auto col = xt::reshape_view(w * w, {G, std::size_t(1)}); + xtensor out = Phi * col; + +#if XTENSOR_USE_XSIMD + using lazy_traits = xassign_traits, decltype(Phi * col)>; + EXPECT_FALSE(lazy_traits::simd_linear_assign()); + + auto colc = xt::reshape_view(w, {G, std::size_t(1)}); + using cont_traits = xassign_traits, decltype(Phi * colc)>; + EXPECT_TRUE(cont_traits::simd_linear_assign()); +#endif + + EXPECT_EQ(108.0, out(5, 2)); + } + TEST(xstrided_view, reshape_view_assign) { xarray xa = {{1, 2, 3}, {4, 5, 6}};