From d3d4245ccd85140cf3e6cfbb78aa8d81f711dd7b Mon Sep 17 00:00:00 2001 From: sbstndb/sbstndbs Date: Wed, 22 Oct 2025 00:24:45 +0200 Subject: [PATCH 1/7] refactor: convert slices from CRTP to C++20 concepts Use if constexpr with auto return types for slice helper functions. --- include/xtensor/views/xdynamic_view.hpp | 2 +- include/xtensor/views/xslice.hpp | 124 +++++++++++++----------- include/xtensor/views/xview.hpp | 22 ++--- include/xtensor/views/xview_utils.hpp | 2 +- 4 files changed, 82 insertions(+), 68 deletions(-) diff --git a/include/xtensor/views/xdynamic_view.hpp b/include/xtensor/views/xdynamic_view.hpp index 5ab298f23..b270392b8 100644 --- a/include/xtensor/views/xdynamic_view.hpp +++ b/include/xtensor/views/xdynamic_view.hpp @@ -324,7 +324,7 @@ namespace xt namespace detail { template - class xfake_slice : public xslice> + class xfake_slice { public: diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index a7a4dae6e..a36767cfe 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -10,6 +10,7 @@ #ifndef XTENSOR_SLICE_HPP #define XTENSOR_SLICE_HPP +#include #include #include #include @@ -35,33 +36,73 @@ namespace xt { /********************** - * xslice declaration * + * xslice type traits * **********************/ - template - class xslice + // Forward declarations + template + class xrange; + + template + class xstepped_range; + + template + class xall; + + template + class xnewaxis; + + template + class xkeep_slice; + + template + class xdrop_slice; + + namespace detail { - public: + template + struct is_xslice_impl : std::false_type + { + }; + + template + struct is_xslice_impl> : std::true_type + { + }; - using derived_type = D; + template + struct is_xslice_impl> : std::true_type + { + }; - derived_type& derived_cast() noexcept; - const derived_type& derived_cast() const noexcept; + template + struct is_xslice_impl> : std::true_type + { + }; - protected: + template + struct is_xslice_impl> : std::true_type + { + }; - xslice() = default; - ~xslice() = default; + template + struct is_xslice_impl> : std::true_type + { + }; - xslice(const xslice&) = default; - xslice& operator=(const xslice&) = default; + template + struct is_xslice_impl> : std::true_type + { + }; + } - xslice(xslice&&) = default; - xslice& operator=(xslice&&) = default; + template + struct is_xslice : detail::is_xslice_impl + { }; template - using is_xslice = std::is_base_of, S>; + concept xslice_concept = is_xslice::value; template using has_xslice = std::disjunction...>; @@ -99,7 +140,7 @@ namespace xt **********************/ template - class xrange : public xslice> + class xrange { public: @@ -143,7 +184,7 @@ namespace xt ******************************/ template - class xstepped_range : public xslice> + class xstepped_range { public: @@ -188,7 +229,7 @@ namespace xt ********************/ template - class xall : public xslice> + class xall { public: @@ -259,7 +300,7 @@ namespace xt ************************/ template - class xnewaxis : public xslice> + class xnewaxis { public: @@ -320,7 +361,7 @@ namespace xt } template - class xkeep_slice : public xslice> + class xkeep_slice { public: @@ -428,7 +469,7 @@ namespace xt } template - class xdrop_slice : public xslice> + class xdrop_slice { public: @@ -778,14 +819,11 @@ namespace xt template inline std::size_t get_size(const S& slice) noexcept { - if constexpr (is_xslice::value) + if constexpr (xslice_concept) { return slice.size(); } - else - { - return 1; - } + return 1; } /******************************************************* @@ -795,27 +833,21 @@ namespace xt template inline std::size_t step_size(const S& slice, std::size_t idx) noexcept { - if constexpr (is_xslice::value) + if constexpr (xslice_concept) { return slice.step_size(idx); } - else - { - return 0; - } + return 0; } template inline std::size_t step_size(const S& slice, std::size_t idx, std::size_t n) noexcept { - if constexpr (is_xslice::value) + if constexpr (xslice_concept) { return slice.step_size(idx, n); } - else - { - return 0; - } + return 0; } /********************************************* @@ -823,9 +855,9 @@ namespace xt *********************************************/ template - inline std::size_t value(const S& slice, I i) noexcept + inline auto value(const S& slice, I i) noexcept { - if constexpr (is_xslice::value) + if constexpr (xslice_concept) { using ST = typename S::size_type; return slice(static_cast(i)); @@ -966,22 +998,6 @@ namespace xt template using get_slice_type = typename detail::get_slice_type_impl>::type; - /************************* - * xslice implementation * - *************************/ - - template - inline auto xslice::derived_cast() noexcept -> derived_type& - { - return *static_cast(this); - } - - template - inline auto xslice::derived_cast() const noexcept -> const derived_type& - { - return *static_cast(this); - } - /************************* * xrange implementation * *************************/ diff --git a/include/xtensor/views/xview.hpp b/include/xtensor/views/xview.hpp index ea546d4ff..a70259adc 100644 --- a/include/xtensor/views/xview.hpp +++ b/include/xtensor/views/xview.hpp @@ -713,11 +713,11 @@ namespace xt template ::size_type I, class... Args> size_type index(Args... args) const; - template ::size_type, class T> - size_type sliced_access(const xslice& slice) const; + template ::size_type I, xslice_concept T> + size_type sliced_access(const T& slice) const; - template ::size_type I, class T, class Arg, class... Args> - size_type sliced_access(const xslice& slice, Arg arg, Args... args) const; + template ::size_type I, xslice_concept T, class Arg, class... Args> + size_type sliced_access(const T& slice, Arg arg, Args... args) const; template ::size_type I, class T, class... Args> size_type sliced_access(const T& squeeze, Args...) const @@ -1657,20 +1657,18 @@ namespace xt } template - template ::size_type I, class T> - inline auto xview::sliced_access(const xslice& slice) const -> size_type + template ::size_type I, xslice_concept T> + inline auto xview::sliced_access(const T& slice) const -> size_type { - return static_cast(slice.derived_cast()(0)); + return static_cast(slice(0)); } template - template ::size_type I, class T, class Arg, class... Args> - inline auto xview::sliced_access(const xslice& slice, Arg arg, Args... args) const -> size_type + template ::size_type I, xslice_concept T, class Arg, class... Args> + inline auto xview::sliced_access(const T& slice, Arg arg, Args... args) const -> size_type { using ST = typename T::size_type; - return static_cast( - slice.derived_cast()(argument(static_cast(arg), static_cast(args)...)) - ); + return static_cast(slice(argument(static_cast(arg), static_cast(args)...))); } template diff --git a/include/xtensor/views/xview_utils.hpp b/include/xtensor/views/xview_utils.hpp index f74eb07e2..8ea89302f 100644 --- a/include/xtensor/views/xview_utils.hpp +++ b/include/xtensor/views/xview_utils.hpp @@ -50,7 +50,7 @@ namespace xt template inline auto get_slice_value(const S& slice, It& it) noexcept { - if constexpr (is_xslice::value) + if constexpr (xslice_concept) { return slice(typename S::size_type(*it)); } From 73e4823f999e1ba4d782c3113f4d51b60a75f6ae Mon Sep 17 00:00:00 2001 From: sbstndb/sbstndbs Date: Wed, 22 Oct 2025 12:52:13 +0200 Subject: [PATCH 2/7] refactor: use xtl::integral_concept in slices Replace xtl::is_integral::value trait with xtl::integral_concept for consistency with existing C++20 concepts. --- include/xtensor/views/xslice.hpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index a36767cfe..a52e70a24 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -20,6 +20,7 @@ #include "../containers/xstorage.hpp" #include "../core/xtensor_config.hpp" +#include "../misc/xtl_concepts.hpp" #include "../utils/xutils.hpp" #ifndef XTENSOR_CONSTEXPR @@ -426,7 +427,7 @@ namespace xt template inline auto keep(T&& indices) { - if constexpr (xtl::is_integral>::value) + if constexpr (xtl::integral_concept>) { using slice_type = xkeep_slice; using container_type = typename slice_type::container_type; @@ -535,7 +536,7 @@ namespace xt template inline auto drop(T&& indices) { - if constexpr (xtl::is_integral::value) + if constexpr (xtl::integral_concept) { using slice_type = xdrop_slice; using container_type = typename slice_type::container_type; @@ -574,11 +575,11 @@ namespace xt template auto get(std::size_t size) const { - if constexpr (xtl::is_integral::value && xtl::is_integral::value && xtl::is_integral::value) + if constexpr (xtl::integral_concept && xtl::integral_concept && xtl::integral_concept) { return get_stepped_range(m_start, m_stop, m_step, size); } - else if constexpr (!xtl::is_integral::value && xtl::is_integral::value && xtl::is_integral::value) + else if constexpr (!xtl::integral_concept && xtl::integral_concept && xtl::integral_concept) { return get_stepped_range( m_step > 0 ? 0 : static_cast(size) - 1, @@ -587,30 +588,30 @@ namespace xt size ); } - else if constexpr (xtl::is_integral::value && !xtl::is_integral::value && xtl::is_integral::value) + else if constexpr (xtl::integral_concept && !xtl::integral_concept && xtl::integral_concept) { auto sz = static_cast(size); return get_stepped_range(m_start, m_step > 0 ? sz : -(sz + 1), m_step, size); } - else if constexpr (xtl::is_integral::value && xtl::is_integral::value && !xtl::is_integral::value) + else if constexpr (xtl::integral_concept && xtl::integral_concept && !xtl::integral_concept) { return xrange(normalize(m_start, size), normalize(m_stop, size)); } - else if constexpr (!xtl::is_integral::value && !xtl::is_integral::value && xtl::is_integral::value) + else if constexpr (!xtl::integral_concept && !xtl::integral_concept && xtl::integral_concept) { std::ptrdiff_t start = m_step >= 0 ? 0 : static_cast(size) - 1; std::ptrdiff_t stop = m_step >= 0 ? static_cast(size) : -1; return xstepped_range(start, stop, m_step); } - else if constexpr (xtl::is_integral::value && !xtl::is_integral::value && !xtl::is_integral::value) + else if constexpr (xtl::integral_concept && !xtl::integral_concept && !xtl::integral_concept) { return xrange(normalize(m_start, size), static_cast(size)); } - else if constexpr (!xtl::is_integral::value && xtl::is_integral::value && !xtl::is_integral::value) + else if constexpr (!xtl::integral_concept && xtl::integral_concept && !xtl::integral_concept) { return xrange(0, normalize(m_stop, size)); } - else if constexpr (!xtl::is_integral::value && !xtl::is_integral::value && !xtl::is_integral::value) + else if constexpr (!xtl::integral_concept && !xtl::integral_concept && !xtl::integral_concept) { return xall(static_cast(size)); } @@ -755,11 +756,14 @@ namespace xt template struct cast_if_integer { - using type = std::conditional_t::value, std::ptrdiff_t, T>; + using type = std::conditional_t, std::ptrdiff_t, T>; type operator()(T t) { - return (xtl::is_integral::value) ? static_cast(t) : t; + if constexpr (xtl::integral_concept) + return static_cast(t); + else + return t; } }; From ab17eef5c7e954ee1143e750d77abf184ee852da Mon Sep 17 00:00:00 2001 From: sbstndb/sbstndbs Date: Wed, 22 Oct 2025 12:55:24 +0200 Subject: [PATCH 3/7] style: apply clang-format to slices Add braces to if constexpr blocks for consistency. --- include/xtensor/views/xslice.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index a52e70a24..b5268999c 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -761,9 +761,13 @@ namespace xt type operator()(T t) { if constexpr (xtl::integral_concept) + { return static_cast(t); + } else + { return t; + } } }; From f786365f8b5a15a14a8a7add91e9004f2bbdafb3 Mon Sep 17 00:00:00 2001 From: sbstndb/sbstndbs Date: Wed, 22 Oct 2025 16:37:28 +0200 Subject: [PATCH 4/7] refactor: add specific slice concepts and replace traits with fold expressions --- include/xtensor/views/xslice.hpp | 103 ++++++++++++++----------------- include/xtensor/views/xview.hpp | 17 +---- 2 files changed, 48 insertions(+), 72 deletions(-) diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index b5268999c..6a1c752fb 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -61,38 +61,25 @@ namespace xt namespace detail { - template - struct is_xslice_impl : std::false_type - { - }; - - template - struct is_xslice_impl> : std::true_type - { - }; - - template - struct is_xslice_impl> : std::true_type - { - }; - - template - struct is_xslice_impl> : std::true_type + template class SliceType> + struct is_specific_slice_impl : std::false_type { }; - template - struct is_xslice_impl> : std::true_type + template class SliceType> + struct is_specific_slice_impl, SliceType> : std::true_type { }; - template - struct is_xslice_impl> : std::true_type - { - }; - - template - struct is_xslice_impl> : std::true_type + template + struct is_xslice_impl : std::disjunction< + is_specific_slice_impl, + is_specific_slice_impl, + is_specific_slice_impl, + is_specific_slice_impl, + is_specific_slice_impl, + is_specific_slice_impl + > { }; } @@ -105,6 +92,36 @@ namespace xt template concept xslice_concept = is_xslice::value; + template + concept xrange_concept = detail::is_specific_slice_impl, xrange>::value; + + template + concept xstepped_range_concept = detail::is_specific_slice_impl, xstepped_range>::value; + + template + concept xall_concept = detail::is_specific_slice_impl, xall>::value; + + template + concept xnewaxis_concept = detail::is_specific_slice_impl, xnewaxis>::value; + + template + concept xkeep_slice_concept = detail::is_specific_slice_impl, xkeep_slice>::value; + + template + concept xdrop_slice_concept = detail::is_specific_slice_impl, xdrop_slice>::value; + + template + concept nonstrided_slice_concept = xkeep_slice_concept || xdrop_slice_concept; + + template + concept strided_slice_concept = xslice_concept && !nonstrided_slice_concept; + + template + concept slice_or_scalar_concept = xslice_concept || xtl::integral_concept; + + template + concept strided_compatible_concept = slice_or_scalar_concept && !nonstrided_slice_concept; + template using has_xslice = std::disjunction...>; @@ -348,19 +365,6 @@ namespace xt template class xkeep_slice; - namespace detail - { - template - struct is_xkeep_slice : std::false_type - { - }; - - template - struct is_xkeep_slice> : std::true_type - { - }; - } - template class xkeep_slice { @@ -372,7 +376,7 @@ namespace xt template explicit xkeep_slice(C& cont) - requires(!detail::is_xkeep_slice>::value); + requires(!xkeep_slice_concept); explicit xkeep_slice(container_type&& cont); template @@ -456,19 +460,6 @@ namespace xt template class xdrop_slice; - namespace detail - { - template - struct is_xdrop_slice : std::false_type - { - }; - - template - struct is_xdrop_slice> : std::true_type - { - }; - } - template class xdrop_slice { @@ -480,7 +471,7 @@ namespace xt template explicit xdrop_slice(C& cont) - requires(!detail::is_xdrop_slice>::value); + requires(!xdrop_slice_concept); explicit xdrop_slice(container_type&& cont); template @@ -1307,7 +1298,7 @@ namespace xt template template inline xkeep_slice::xkeep_slice(C& cont) - requires(!detail::is_xkeep_slice>::value) + requires(!xkeep_slice_concept) : m_raw_indices(cont.begin(), cont.end()) { } @@ -1451,7 +1442,7 @@ namespace xt template template inline xdrop_slice::xdrop_slice(C& cont) - requires(!detail::is_xdrop_slice>::value) + requires(!xdrop_slice_concept) : m_raw_indices(cont.begin(), cont.end()) { } diff --git a/include/xtensor/views/xview.hpp b/include/xtensor/views/xview.hpp index a70259adc..2c9a3b05f 100644 --- a/include/xtensor/views/xview.hpp +++ b/include/xtensor/views/xview.hpp @@ -135,27 +135,12 @@ namespace xt : false; }; - template - struct is_strided_slice_impl : std::true_type - { - }; - - template - struct is_strided_slice_impl> : std::false_type - { - }; - - template - struct is_strided_slice_impl> : std::false_type - { - }; - // If we have no discontiguous slices, we can calculate strides for this view. template struct is_strided_view : std::integral_constant< bool, - std::conjunction, is_strided_slice_impl>...>::value> + has_data_interface::value && (strided_compatible_concept> && ...)> { }; From a8c55a1583bb328e6dcfd8e939454168cad352bd Mon Sep 17 00:00:00 2001 From: sbstndb/sbstndbs Date: Wed, 22 Oct 2025 16:39:46 +0200 Subject: [PATCH 5/7] style: apply clang-format to slice concepts --- include/xtensor/views/xslice.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index 6a1c752fb..f99bf5389 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -73,13 +73,12 @@ namespace xt template struct is_xslice_impl : std::disjunction< - is_specific_slice_impl, - is_specific_slice_impl, - is_specific_slice_impl, - is_specific_slice_impl, - is_specific_slice_impl, - is_specific_slice_impl - > + is_specific_slice_impl, + is_specific_slice_impl, + is_specific_slice_impl, + is_specific_slice_impl, + is_specific_slice_impl, + is_specific_slice_impl> { }; } From 549c090b466230edd11263066562ffe212bc312a Mon Sep 17 00:00:00 2001 From: sbstndb/sbstndbs Date: Wed, 22 Oct 2025 18:56:23 +0200 Subject: [PATCH 6/7] refactor: replace is_xslice trait with xslice_concept in requires clauses --- include/xtensor/views/xview.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xtensor/views/xview.hpp b/include/xtensor/views/xview.hpp index 2c9a3b05f..6ca444044 100644 --- a/include/xtensor/views/xview.hpp +++ b/include/xtensor/views/xview.hpp @@ -706,7 +706,7 @@ namespace xt template ::size_type I, class T, class... Args> size_type sliced_access(const T& squeeze, Args...) const - requires(!is_xslice::value); + requires(!xslice_concept); using base_index_type = xindex_type_t; @@ -1659,7 +1659,7 @@ namespace xt template template ::size_type I, class T, class... Args> inline auto xview::sliced_access(const T& squeeze, Args...) const -> size_type - requires(!is_xslice::value) + requires(!xslice_concept) { return static_cast(squeeze); } From 793c5c1474b1e39d2b53bf65d73871eed17c49f0 Mon Sep 17 00:00:00 2001 From: sbstndb/sbstndbs Date: Wed, 22 Oct 2025 19:36:04 +0200 Subject: [PATCH 7/7] refactor: restore explicit else blocks and migrate has_xslice to concepts --- include/xtensor/views/xslice.hpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/include/xtensor/views/xslice.hpp b/include/xtensor/views/xslice.hpp index f99bf5389..4ea322152 100644 --- a/include/xtensor/views/xslice.hpp +++ b/include/xtensor/views/xslice.hpp @@ -122,7 +122,9 @@ namespace xt concept strided_compatible_concept = slice_or_scalar_concept && !nonstrided_slice_concept; template - using has_xslice = std::disjunction...>; + struct has_xslice : std::bool_constant<(xslice_concept || ...)> + { + }; /************** * slice tags * @@ -821,7 +823,10 @@ namespace xt { return slice.size(); } - return 1; + else + { + return 1; + } } /******************************************************* @@ -835,7 +840,10 @@ namespace xt { return slice.step_size(idx); } - return 0; + else + { + return 0; + } } template @@ -845,7 +853,10 @@ namespace xt { return slice.step_size(idx, n); } - return 0; + else + { + return 0; + } } /*********************************************