mirror of
				https://github.com/pocketpy/pocketpy
				synced 2025-10-30 16:30:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1672 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1672 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /***************************************************************************
 | |
|  * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
 | |
|  * Copyright (c) QuantStack                                                 *
 | |
|  *                                                                          *
 | |
|  * Distributed under the terms of the BSD 3-Clause License.                 *
 | |
|  *                                                                          *
 | |
|  * The full license is in the file LICENSE, distributed with this software. *
 | |
|  ****************************************************************************/
 | |
| 
 | |
| #ifndef XTENSOR_SLICE_HPP
 | |
| #define XTENSOR_SLICE_HPP
 | |
| 
 | |
| #include <cstddef>
 | |
| #include <map>
 | |
| #include <type_traits>
 | |
| #include <utility>
 | |
| 
 | |
| #include <xtl/xtype_traits.hpp>
 | |
| 
 | |
| #include "xstorage.hpp"
 | |
| #include "xtensor_config.hpp"
 | |
| #include "xutils.hpp"
 | |
| 
 | |
| #ifndef XTENSOR_CONSTEXPR
 | |
| #if (defined(_MSC_VER) || __GNUC__ < 8)
 | |
| #define XTENSOR_CONSTEXPR inline
 | |
| #define XTENSOR_GLOBAL_CONSTEXPR static const
 | |
| #else
 | |
| #define XTENSOR_CONSTEXPR constexpr
 | |
| #define XTENSOR_GLOBAL_CONSTEXPR constexpr
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| namespace xt
 | |
| {
 | |
| 
 | |
|     /**********************
 | |
|      * xslice declaration *
 | |
|      **********************/
 | |
| 
 | |
|     template <class D>
 | |
|     class xslice
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using derived_type = D;
 | |
| 
 | |
|         derived_type& derived_cast() noexcept;
 | |
|         const derived_type& derived_cast() const noexcept;
 | |
| 
 | |
|     protected:
 | |
| 
 | |
|         xslice() = default;
 | |
|         ~xslice() = default;
 | |
| 
 | |
|         xslice(const xslice&) = default;
 | |
|         xslice& operator=(const xslice&) = default;
 | |
| 
 | |
|         xslice(xslice&&) = default;
 | |
|         xslice& operator=(xslice&&) = default;
 | |
|     };
 | |
| 
 | |
|     template <class S>
 | |
|     using is_xslice = std::is_base_of<xslice<S>, S>;
 | |
| 
 | |
|     template <class E, class R = void>
 | |
|     using disable_xslice = typename std::enable_if<!is_xslice<E>::value, R>::type;
 | |
| 
 | |
|     template <class... E>
 | |
|     using has_xslice = xtl::disjunction<is_xslice<E>...>;
 | |
| 
 | |
|     /**************
 | |
|      * slice tags *
 | |
|      **************/
 | |
| 
 | |
| #define DEFINE_TAG_CONVERSION(NAME)                 \
 | |
|     template <class T>                              \
 | |
|     XTENSOR_CONSTEXPR NAME convert() const noexcept \
 | |
|     {                                               \
 | |
|         return NAME();                              \
 | |
|     }
 | |
| 
 | |
|     struct xall_tag
 | |
|     {
 | |
|         DEFINE_TAG_CONVERSION(xall_tag)
 | |
|     };
 | |
| 
 | |
|     struct xnewaxis_tag
 | |
|     {
 | |
|         DEFINE_TAG_CONVERSION(xnewaxis_tag)
 | |
|     };
 | |
| 
 | |
|     struct xellipsis_tag
 | |
|     {
 | |
|         DEFINE_TAG_CONVERSION(xellipsis_tag)
 | |
|     };
 | |
| 
 | |
| #undef DEFINE_TAG_CONVERSION
 | |
| 
 | |
|     /**********************
 | |
|      * xrange declaration *
 | |
|      **********************/
 | |
| 
 | |
|     template <class T>
 | |
|     class xrange : public xslice<xrange<T>>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using size_type = T;
 | |
|         using self_type = xrange<T>;
 | |
| 
 | |
|         xrange() = default;
 | |
|         xrange(size_type start_val, size_type stop_val) noexcept;
 | |
| 
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         operator xrange<S>() const noexcept;
 | |
| 
 | |
|         // Same as implicit conversion operator but more convenient to call
 | |
|         // from a variant visitor
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         xrange<S> convert() const noexcept;
 | |
| 
 | |
|         size_type operator()(size_type i) const noexcept;
 | |
| 
 | |
|         size_type size() const noexcept;
 | |
|         size_type step_size() const noexcept;
 | |
|         size_type step_size(std::size_t i, std::size_t n = 1) const noexcept;
 | |
|         size_type revert_index(std::size_t i) const noexcept;
 | |
| 
 | |
|         bool contains(size_type i) const noexcept;
 | |
| 
 | |
|         bool operator==(const self_type& rhs) const noexcept;
 | |
|         bool operator!=(const self_type& rhs) const noexcept;
 | |
| 
 | |
|     private:
 | |
| 
 | |
|         size_type m_start;
 | |
|         size_type m_size;
 | |
| 
 | |
|         template <class S>
 | |
|         friend class xrange;
 | |
|     };
 | |
| 
 | |
|     /******************************
 | |
|      * xstepped_range declaration *
 | |
|      ******************************/
 | |
| 
 | |
|     template <class T>
 | |
|     class xstepped_range : public xslice<xstepped_range<T>>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using size_type = T;
 | |
|         using self_type = xstepped_range<T>;
 | |
| 
 | |
|         xstepped_range() = default;
 | |
|         xstepped_range(size_type start_val, size_type stop_val, size_type step) noexcept;
 | |
| 
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         operator xstepped_range<S>() const noexcept;
 | |
| 
 | |
|         // Same as implicit conversion operator but more convenient to call
 | |
|         // from a variant visitor
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         xstepped_range<S> convert() const noexcept;
 | |
| 
 | |
|         size_type operator()(size_type i) const noexcept;
 | |
| 
 | |
|         size_type size() const noexcept;
 | |
|         size_type step_size() const noexcept;
 | |
|         size_type step_size(std::size_t i, std::size_t n = 1) const noexcept;
 | |
|         size_type revert_index(std::size_t i) const noexcept;
 | |
| 
 | |
|         bool contains(size_type i) const noexcept;
 | |
| 
 | |
|         bool operator==(const self_type& rhs) const noexcept;
 | |
|         bool operator!=(const self_type& rhs) const noexcept;
 | |
| 
 | |
|     private:
 | |
| 
 | |
|         size_type m_start;
 | |
|         size_type m_size;
 | |
|         size_type m_step;
 | |
| 
 | |
|         template <class S>
 | |
|         friend class xstepped_range;
 | |
|     };
 | |
| 
 | |
|     /********************
 | |
|      * xall declaration *
 | |
|      ********************/
 | |
| 
 | |
|     template <class T>
 | |
|     class xall : public xslice<xall<T>>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using size_type = T;
 | |
|         using self_type = xall<T>;
 | |
| 
 | |
|         xall() = default;
 | |
|         explicit xall(size_type size) noexcept;
 | |
| 
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         operator xall<S>() const noexcept;
 | |
| 
 | |
|         // Same as implicit conversion operator but more convenient to call
 | |
|         // from a variant visitor
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         xall<S> convert() const noexcept;
 | |
| 
 | |
|         size_type operator()(size_type i) const noexcept;
 | |
| 
 | |
|         size_type size() const noexcept;
 | |
|         size_type step_size() const noexcept;
 | |
|         size_type step_size(std::size_t i, std::size_t n = 1) const noexcept;
 | |
|         size_type revert_index(std::size_t i) const noexcept;
 | |
| 
 | |
|         bool contains(size_type i) const noexcept;
 | |
| 
 | |
|         bool operator==(const self_type& rhs) const noexcept;
 | |
|         bool operator!=(const self_type& rhs) const noexcept;
 | |
| 
 | |
|     private:
 | |
| 
 | |
|         size_type m_size;
 | |
|     };
 | |
| 
 | |
|     /**
 | |
|      * Returns a slice representing a full dimension,
 | |
|      * to be used as an argument of view function.
 | |
|      * @sa view, strided_view
 | |
|      */
 | |
|     inline auto all() noexcept
 | |
|     {
 | |
|         return xall_tag();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns a slice representing all remaining dimensions,
 | |
|      * and selecting all in these dimensions. Ellipsis will expand
 | |
|      * to a series of `all()` slices, until the number of slices is
 | |
|      * equal to the number of dimensions of the source array.
 | |
|      *
 | |
|      * Note: ellipsis can only be used in strided_view!
 | |
|      *
 | |
|      * @code{.cpp}
 | |
|      * xarray<double> a = xarray<double>::from_shape({5, 5, 1, 1, 5});
 | |
|      * auto v = xt::strided_view(a, {2, xt::ellipsis(), 2});
 | |
|      * // equivalent to using {2, xt::all(), xt::all(), xt::all(), 2};
 | |
|      * @endcode
 | |
|      *
 | |
|      * @sa strided_view
 | |
|      */
 | |
|     inline auto ellipsis() noexcept
 | |
|     {
 | |
|         return xellipsis_tag();
 | |
|     }
 | |
| 
 | |
|     /************************
 | |
|      * xnewaxis declaration *
 | |
|      ************************/
 | |
| 
 | |
|     template <class T>
 | |
|     class xnewaxis : public xslice<xnewaxis<T>>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using size_type = T;
 | |
|         using self_type = xnewaxis<T>;
 | |
| 
 | |
|         xnewaxis() = default;
 | |
| 
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         operator xnewaxis<S>() const noexcept;
 | |
| 
 | |
|         // Same as implicit conversion operator but more convenient to call
 | |
|         // from a variant visitor
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         xnewaxis<S> convert() const noexcept;
 | |
| 
 | |
|         size_type operator()(size_type i) const noexcept;
 | |
| 
 | |
|         size_type size() const noexcept;
 | |
|         size_type step_size() const noexcept;
 | |
|         size_type step_size(std::size_t i, std::size_t n = 1) const noexcept;
 | |
|         size_type revert_index(std::size_t i) const noexcept;
 | |
| 
 | |
|         bool contains(size_type i) const noexcept;
 | |
| 
 | |
|         bool operator==(const self_type& rhs) const noexcept;
 | |
|         bool operator!=(const self_type& rhs) const noexcept;
 | |
|     };
 | |
| 
 | |
|     /**
 | |
|      * Returns a slice representing a new axis of length one,
 | |
|      * to be used as an argument of view function.
 | |
|      * @sa view, strided_view
 | |
|      */
 | |
|     inline auto newaxis() noexcept
 | |
|     {
 | |
|         return xnewaxis_tag();
 | |
|     }
 | |
| 
 | |
|     /***************************
 | |
|      * xkeep_slice declaration *
 | |
|      ***************************/
 | |
| 
 | |
|     template <class T>
 | |
|     class xkeep_slice;
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class T>
 | |
|         struct is_xkeep_slice : std::false_type
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         struct is_xkeep_slice<xkeep_slice<T>> : std::true_type
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         using disable_xkeep_slice_t = std::enable_if_t<!is_xkeep_slice<std::decay_t<T>>::value, void>;
 | |
| 
 | |
|         template <class T>
 | |
|         using enable_xkeep_slice_t = std::enable_if_t<is_xkeep_slice<std::decay_t<T>>::value, void>;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     class xkeep_slice : public xslice<xkeep_slice<T>>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using container_type = svector<T>;
 | |
|         using size_type = typename container_type::value_type;
 | |
|         using self_type = xkeep_slice<T>;
 | |
| 
 | |
|         template <class C, typename = detail::disable_xkeep_slice_t<C>>
 | |
|         explicit xkeep_slice(C& cont);
 | |
|         explicit xkeep_slice(container_type&& cont);
 | |
| 
 | |
|         template <class S>
 | |
|         xkeep_slice(std::initializer_list<S> t);
 | |
| 
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         operator xkeep_slice<S>() const noexcept;
 | |
| 
 | |
|         // Same as implicit conversion operator but more convenient to call
 | |
|         // from a variant visitor
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         xkeep_slice<S> convert() const noexcept;
 | |
| 
 | |
|         size_type operator()(size_type i) const noexcept;
 | |
|         size_type size() const noexcept;
 | |
| 
 | |
|         void normalize(std::size_t s);
 | |
| 
 | |
|         size_type step_size(std::size_t i, std::size_t n = 1) const noexcept;
 | |
|         size_type revert_index(std::size_t i) const;
 | |
| 
 | |
|         bool contains(size_type i) const noexcept;
 | |
| 
 | |
|         bool operator==(const self_type& rhs) const noexcept;
 | |
|         bool operator!=(const self_type& rhs) const noexcept;
 | |
| 
 | |
|     private:
 | |
| 
 | |
|         xkeep_slice() = default;
 | |
| 
 | |
|         container_type m_indices;
 | |
|         container_type m_raw_indices;
 | |
| 
 | |
|         template <class S>
 | |
|         friend class xkeep_slice;
 | |
|     };
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class T>
 | |
|         using disable_integral_keep = std::enable_if_t<
 | |
|             !xtl::is_integral<std::decay_t<T>>::value,
 | |
|             xkeep_slice<typename std::decay_t<T>::value_type>>;
 | |
| 
 | |
|         template <class T, class R>
 | |
|         using enable_integral_keep = std::enable_if_t<xtl::is_integral<T>::value, xkeep_slice<R>>;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Create a non-contigous slice from a container of indices to keep.
 | |
|      * Note: this slice cannot be used in the xstrided_view!
 | |
|      *
 | |
|      * @code{.cpp}
 | |
|      * xt::xarray<double> a = xt::arange(9);
 | |
|      * a.reshape({3, 3});
 | |
|      * xt::view(a, xt::keep(0, 2); // => {{0, 1, 2}, {6, 7, 8}}
 | |
|      * xt::view(a, xt::keep(1, 1, 1); // => {{3, 4, 5}, {3, 4, 5}, {3, 4, 5}}
 | |
|      * @endcode
 | |
|      *
 | |
|      * @param indices The indices container
 | |
|      * @return instance of xkeep_slice
 | |
|      */
 | |
|     template <class T>
 | |
|     inline detail::disable_integral_keep<T> keep(T&& indices)
 | |
|     {
 | |
|         return xkeep_slice<typename std::decay_t<T>::value_type>(std::forward<T>(indices));
 | |
|     }
 | |
| 
 | |
|     template <class R = std::ptrdiff_t, class T>
 | |
|     inline detail::enable_integral_keep<T, R> keep(T i)
 | |
|     {
 | |
|         using slice_type = xkeep_slice<R>;
 | |
|         using container_type = typename slice_type::container_type;
 | |
|         container_type tmp = {static_cast<R>(i)};
 | |
|         return slice_type(std::move(tmp));
 | |
|     }
 | |
| 
 | |
|     template <class R = std::ptrdiff_t, class Arg0, class Arg1, class... Args>
 | |
|     inline xkeep_slice<R> keep(Arg0 i0, Arg1 i1, Args... args)
 | |
|     {
 | |
|         using slice_type = xkeep_slice<R>;
 | |
|         using container_type = typename slice_type::container_type;
 | |
|         container_type tmp = {static_cast<R>(i0), static_cast<R>(i1), static_cast<R>(args)...};
 | |
|         return slice_type(std::move(tmp));
 | |
|     }
 | |
| 
 | |
|     /***************************
 | |
|      * xdrop_slice declaration *
 | |
|      ***************************/
 | |
| 
 | |
|     template <class T>
 | |
|     class xdrop_slice;
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class T>
 | |
|         struct is_xdrop_slice : std::false_type
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         struct is_xdrop_slice<xdrop_slice<T>> : std::true_type
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         using disable_xdrop_slice_t = std::enable_if_t<!is_xdrop_slice<std::decay_t<T>>::value, void>;
 | |
| 
 | |
|         template <class T>
 | |
|         using enable_xdrop_slice_t = std::enable_if_t<is_xdrop_slice<std::decay_t<T>>::value, void>;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     class xdrop_slice : public xslice<xdrop_slice<T>>
 | |
|     {
 | |
|     public:
 | |
| 
 | |
|         using container_type = svector<T>;
 | |
|         using size_type = typename container_type::value_type;
 | |
|         using self_type = xdrop_slice<T>;
 | |
| 
 | |
|         template <class C, typename = detail::disable_xdrop_slice_t<C>>
 | |
|         explicit xdrop_slice(C& cont);
 | |
|         explicit xdrop_slice(container_type&& cont);
 | |
| 
 | |
|         template <class S>
 | |
|         xdrop_slice(std::initializer_list<S> t);
 | |
| 
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         operator xdrop_slice<S>() const noexcept;
 | |
| 
 | |
|         // Same as implicit conversion operator but more convenient to call
 | |
|         // from a variant visitor
 | |
|         template <class S, typename = std::enable_if_t<std::is_convertible<S, T>::value, void>>
 | |
|         xdrop_slice<S> convert() const noexcept;
 | |
| 
 | |
|         size_type operator()(size_type i) const noexcept;
 | |
|         size_type size() const noexcept;
 | |
| 
 | |
|         void normalize(std::size_t s);
 | |
| 
 | |
|         size_type step_size(std::size_t i, std::size_t n = 1) const noexcept;
 | |
|         size_type revert_index(std::size_t i) const;
 | |
| 
 | |
|         bool contains(size_type i) const noexcept;
 | |
| 
 | |
|         bool operator==(const self_type& rhs) const noexcept;
 | |
|         bool operator!=(const self_type& rhs) const noexcept;
 | |
| 
 | |
|     private:
 | |
| 
 | |
|         xdrop_slice() = default;
 | |
| 
 | |
|         container_type m_indices;
 | |
|         container_type m_raw_indices;
 | |
|         std::map<size_type, size_type> m_inc;
 | |
|         size_type m_size;
 | |
| 
 | |
|         template <class S>
 | |
|         friend class xdrop_slice;
 | |
|     };
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class T>
 | |
|         using disable_integral_drop = std::enable_if_t<
 | |
|             !xtl::is_integral<std::decay_t<T>>::value,
 | |
|             xdrop_slice<typename std::decay_t<T>::value_type>>;
 | |
| 
 | |
|         template <class T, class R>
 | |
|         using enable_integral_drop = std::enable_if_t<xtl::is_integral<T>::value, xdrop_slice<R>>;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Create a non-contigous slice from a container of indices to drop.
 | |
|      * Note: this slice cannot be used in the xstrided_view!
 | |
|      *
 | |
|      * @code{.cpp}
 | |
|      * xt::xarray<double> a = xt::arange(9);
 | |
|      * a.reshape({3, 3});
 | |
|      * xt::view(a, xt::drop(0, 2); // => {{3, 4, 5}}
 | |
|      * @endcode
 | |
|      *
 | |
|      * @param indices The container of indices to drop
 | |
|      * @return instance of xdrop_slice
 | |
|      */
 | |
|     template <class T>
 | |
|     inline detail::disable_integral_drop<T> drop(T&& indices)
 | |
|     {
 | |
|         return xdrop_slice<typename std::decay_t<T>::value_type>(std::forward<T>(indices));
 | |
|     }
 | |
| 
 | |
|     template <class R = std::ptrdiff_t, class T>
 | |
|     inline detail::enable_integral_drop<T, R> drop(T i)
 | |
|     {
 | |
|         using slice_type = xdrop_slice<R>;
 | |
|         using container_type = typename slice_type::container_type;
 | |
|         container_type tmp = {static_cast<R>(i)};
 | |
|         return slice_type(std::move(tmp));
 | |
|     }
 | |
| 
 | |
|     template <class R = std::ptrdiff_t, class Arg0, class Arg1, class... Args>
 | |
|     inline xdrop_slice<R> drop(Arg0 i0, Arg1 i1, Args... args)
 | |
|     {
 | |
|         using slice_type = xdrop_slice<R>;
 | |
|         using container_type = typename slice_type::container_type;
 | |
|         container_type tmp = {static_cast<R>(i0), static_cast<R>(i1), static_cast<R>(args)...};
 | |
|         return slice_type(std::move(tmp));
 | |
|     }
 | |
| 
 | |
|     /******************************
 | |
|      * xrange_adaptor declaration *
 | |
|      ******************************/
 | |
| 
 | |
|     template <class A, class B = A, class C = A>
 | |
|     struct xrange_adaptor
 | |
|     {
 | |
|         xrange_adaptor(A start_val, B stop_val, C step)
 | |
|             : m_start(start_val)
 | |
|             , m_stop(stop_val)
 | |
|             , m_step(step)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         template <class MI = A, class MA = B, class STEP = C>
 | |
|         inline std::enable_if_t<
 | |
|             xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value,
 | |
|             xstepped_range<std::ptrdiff_t>>
 | |
|         get(std::size_t size) const
 | |
|         {
 | |
|             return get_stepped_range(m_start, m_stop, m_step, size);
 | |
|         }
 | |
| 
 | |
|         template <class MI = A, class MA = B, class STEP = C>
 | |
|         inline std::enable_if_t<
 | |
|             !xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value,
 | |
|             xstepped_range<std::ptrdiff_t>>
 | |
|         get(std::size_t size) const
 | |
|         {
 | |
|             return get_stepped_range(m_step > 0 ? 0 : static_cast<std::ptrdiff_t>(size) - 1, m_stop, m_step, size);
 | |
|         }
 | |
| 
 | |
|         template <class MI = A, class MA = B, class STEP = C>
 | |
|         inline std::enable_if_t<
 | |
|             xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value,
 | |
|             xstepped_range<std::ptrdiff_t>>
 | |
|         get(std::size_t size) const
 | |
|         {
 | |
|             auto sz = static_cast<std::ptrdiff_t>(size);
 | |
|             return get_stepped_range(m_start, m_step > 0 ? sz : -(sz + 1), m_step, size);
 | |
|         }
 | |
| 
 | |
|         template <class MI = A, class MA = B, class STEP = C>
 | |
|         inline std::enable_if_t<
 | |
|             xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value,
 | |
|             xrange<std::ptrdiff_t>>
 | |
|         get(std::size_t size) const
 | |
|         {
 | |
|             return xrange<std::ptrdiff_t>(normalize(m_start, size), normalize(m_stop, size));
 | |
|         }
 | |
| 
 | |
|         template <class MI = A, class MA = B, class STEP = C>
 | |
|         inline std::enable_if_t<
 | |
|             !xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value,
 | |
|             xstepped_range<std::ptrdiff_t>>
 | |
|         get(std::size_t size) const
 | |
|         {
 | |
|             std::ptrdiff_t start = m_step >= 0 ? 0 : static_cast<std::ptrdiff_t>(size) - 1;
 | |
|             std::ptrdiff_t stop = m_step >= 0 ? static_cast<std::ptrdiff_t>(size) : -1;
 | |
|             return xstepped_range<std::ptrdiff_t>(start, stop, m_step);
 | |
|         }
 | |
| 
 | |
|         template <class MI = A, class MA = B, class STEP = C>
 | |
|         inline std::enable_if_t<
 | |
|             xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value,
 | |
|             xrange<std::ptrdiff_t>>
 | |
|         get(std::size_t size) const
 | |
|         {
 | |
|             return xrange<std::ptrdiff_t>(normalize(m_start, size), static_cast<std::ptrdiff_t>(size));
 | |
|         }
 | |
| 
 | |
|         template <class MI = A, class MA = B, class STEP = C>
 | |
|         inline std::enable_if_t<
 | |
|             !xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value,
 | |
|             xrange<std::ptrdiff_t>>
 | |
|         get(std::size_t size) const
 | |
|         {
 | |
|             return xrange<std::ptrdiff_t>(0, normalize(m_stop, size));
 | |
|         }
 | |
| 
 | |
|         template <class MI = A, class MA = B, class STEP = C>
 | |
|         inline std::enable_if_t<
 | |
|             !xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value,
 | |
|             xall<std::ptrdiff_t>>
 | |
|         get(std::size_t size) const
 | |
|         {
 | |
|             return xall<std::ptrdiff_t>(static_cast<std::ptrdiff_t>(size));
 | |
|         }
 | |
| 
 | |
|         A start() const
 | |
|         {
 | |
|             return m_start;
 | |
|         }
 | |
| 
 | |
|         B stop() const
 | |
|         {
 | |
|             return m_stop;
 | |
|         }
 | |
| 
 | |
|         C step() const
 | |
|         {
 | |
|             return m_step;
 | |
|         }
 | |
| 
 | |
|     private:
 | |
| 
 | |
|         static auto normalize(std::ptrdiff_t val, std::size_t ssize)
 | |
|         {
 | |
|             std::ptrdiff_t size = static_cast<std::ptrdiff_t>(ssize);
 | |
|             val = (val >= 0) ? val : val + size;
 | |
|             return (std::max)(std::ptrdiff_t(0), (std::min)(size, val));
 | |
|         }
 | |
| 
 | |
|         static auto
 | |
|         get_stepped_range(std::ptrdiff_t start, std::ptrdiff_t stop, std::ptrdiff_t step, std::size_t ssize)
 | |
|         {
 | |
|             std::ptrdiff_t size = static_cast<std::ptrdiff_t>(ssize);
 | |
|             start = (start >= 0) ? start : start + size;
 | |
|             stop = (stop >= 0) ? stop : stop + size;
 | |
| 
 | |
|             if (step > 0)
 | |
|             {
 | |
|                 start = (std::max)(std::ptrdiff_t(0), (std::min)(size, start));
 | |
|                 stop = (std::max)(std::ptrdiff_t(0), (std::min)(size, stop));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 start = (std::max)(std::ptrdiff_t(-1), (std::min)(size - 1, start));
 | |
|                 stop = (std::max)(std::ptrdiff_t(-1), (std::min)(size - 1, stop));
 | |
|             }
 | |
| 
 | |
|             return xstepped_range<std::ptrdiff_t>(start, stop, step);
 | |
|         }
 | |
| 
 | |
|         A m_start;
 | |
|         B m_stop;
 | |
|         C m_step;
 | |
|     };
 | |
| 
 | |
|     /*******************************
 | |
|      * Placeholders and rangemaker *
 | |
|      *******************************/
 | |
| 
 | |
|     namespace placeholders
 | |
|     {
 | |
|         // xtensor universal placeholder
 | |
|         struct xtuph
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         template <class... Args>
 | |
|         struct rangemaker
 | |
|         {
 | |
|             std::ptrdiff_t rng[3];  // = { 0, 0, 0 };
 | |
|         };
 | |
| 
 | |
|         XTENSOR_CONSTEXPR xtuph get_tuph_or_val(std::ptrdiff_t /*val*/, std::true_type)
 | |
|         {
 | |
|             return xtuph();
 | |
|         }
 | |
| 
 | |
|         XTENSOR_CONSTEXPR std::ptrdiff_t get_tuph_or_val(std::ptrdiff_t val, std::false_type)
 | |
|         {
 | |
|             return val;
 | |
|         }
 | |
| 
 | |
|         template <class A, class B, class C>
 | |
|         struct rangemaker<A, B, C>
 | |
|         {
 | |
|             XTENSOR_CONSTEXPR operator xrange_adaptor<A, B, C>()
 | |
|             {
 | |
|                 return xrange_adaptor<A, B, C>(
 | |
|                     {get_tuph_or_val(rng[0], std::is_same<A, xtuph>()),
 | |
|                      get_tuph_or_val(rng[1], std::is_same<B, xtuph>()),
 | |
|                      get_tuph_or_val(rng[2], std::is_same<C, xtuph>())}
 | |
|                 );
 | |
|             }
 | |
| 
 | |
|             std::ptrdiff_t rng[3];  // = { 0, 0, 0 };
 | |
|         };
 | |
| 
 | |
|         template <class A, class B>
 | |
|         struct rangemaker<A, B>
 | |
|         {
 | |
|             XTENSOR_CONSTEXPR operator xrange_adaptor<A, B, xt::placeholders::xtuph>()
 | |
|             {
 | |
|                 return xrange_adaptor<A, B, xt::placeholders::xtuph>(
 | |
|                     {get_tuph_or_val(rng[0], std::is_same<A, xtuph>()),
 | |
|                      get_tuph_or_val(rng[1], std::is_same<B, xtuph>()),
 | |
|                      xtuph()}
 | |
|                 );
 | |
|             }
 | |
| 
 | |
|             std::ptrdiff_t rng[3];  // = { 0, 0, 0 };
 | |
|         };
 | |
| 
 | |
|         template <class... OA>
 | |
|         XTENSOR_CONSTEXPR auto operator|(const rangemaker<OA...>& rng, const std::ptrdiff_t& t)
 | |
|         {
 | |
|             auto nrng = rangemaker<OA..., std::ptrdiff_t>({rng.rng[0], rng.rng[1], rng.rng[2]});
 | |
|             nrng.rng[sizeof...(OA)] = t;
 | |
|             return nrng;
 | |
|         }
 | |
| 
 | |
|         template <class... OA>
 | |
|         XTENSOR_CONSTEXPR auto operator|(const rangemaker<OA...>& rng, const xt::placeholders::xtuph& /*t*/)
 | |
|         {
 | |
|             auto nrng = rangemaker<OA..., xt::placeholders::xtuph>({rng.rng[0], rng.rng[1], rng.rng[2]});
 | |
|             return nrng;
 | |
|         }
 | |
| 
 | |
|         XTENSOR_GLOBAL_CONSTEXPR xtuph _{};
 | |
|         XTENSOR_GLOBAL_CONSTEXPR rangemaker<> _r = rangemaker<>({0, 0, 0});
 | |
|         XTENSOR_GLOBAL_CONSTEXPR xall_tag _a{};
 | |
|         XTENSOR_GLOBAL_CONSTEXPR xnewaxis_tag _n{};
 | |
|         XTENSOR_GLOBAL_CONSTEXPR xellipsis_tag _e{};
 | |
|     }
 | |
| 
 | |
|     inline auto xnone()
 | |
|     {
 | |
|         return placeholders::xtuph();
 | |
|     }
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class T, class E = void>
 | |
|         struct cast_if_integer
 | |
|         {
 | |
|             using type = T;
 | |
| 
 | |
|             type operator()(T t)
 | |
|             {
 | |
|                 return t;
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         struct cast_if_integer<T, std::enable_if_t<xtl::is_integral<T>::value>>
 | |
|         {
 | |
|             using type = std::ptrdiff_t;
 | |
| 
 | |
|             type operator()(T t)
 | |
|             {
 | |
|                 return static_cast<type>(t);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         using cast_if_integer_t = typename cast_if_integer<T>::type;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Select a range from start_val to stop_val (excluded).
 | |
|      * You can use the shorthand `_` syntax to select from the start or until the end.
 | |
|      *
 | |
|      * @code{.cpp}
 | |
|      * using namespace xt::placeholders;  // to enable _ syntax
 | |
|      *
 | |
|      * range(3, _)  // select from index 3 to the end
 | |
|      * range(_, 5)  // select from index 0 to 5 (excluded)
 | |
|      * range(_, _)  // equivalent to `all()`
 | |
|      * @endcode
 | |
|      *
 | |
|      * @sa view, strided_view
 | |
|      */
 | |
|     template <class A, class B>
 | |
|     inline auto range(A start_val, B stop_val)
 | |
|     {
 | |
|         return xrange_adaptor<detail::cast_if_integer_t<A>, detail::cast_if_integer_t<B>, placeholders::xtuph>(
 | |
|             detail::cast_if_integer<A>{}(start_val),
 | |
|             detail::cast_if_integer<B>{}(stop_val),
 | |
|             placeholders::xtuph()
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Select a range from start_val to stop_val (excluded) with step
 | |
|      * You can use the shorthand `_` syntax to select from the start or until the end.
 | |
|      *
 | |
|      * @code{.cpp}
 | |
|      * using namespace xt::placeholders;  // to enable _ syntax
 | |
|      * range(3, _, 5)  // select from index 3 to the end with stepsize 5
 | |
|      * @endcode
 | |
|      *
 | |
|      * @sa view, strided_view
 | |
|      */
 | |
|     template <class A, class B, class C>
 | |
|     inline auto range(A start_val, B stop_val, C step)
 | |
|     {
 | |
|         return xrange_adaptor<detail::cast_if_integer_t<A>, detail::cast_if_integer_t<B>, detail::cast_if_integer_t<C>>(
 | |
|             detail::cast_if_integer<A>{}(start_val),
 | |
|             detail::cast_if_integer<B>{}(stop_val),
 | |
|             detail::cast_if_integer<C>{}(step)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /******************************************************
 | |
|      * homogeneous get_size for integral types and slices *
 | |
|      ******************************************************/
 | |
| 
 | |
|     template <class S>
 | |
|     inline disable_xslice<S, std::size_t> get_size(const S&) noexcept
 | |
|     {
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     template <class S>
 | |
|     inline auto get_size(const xslice<S>& slice) noexcept
 | |
|     {
 | |
|         return slice.derived_cast().size();
 | |
|     }
 | |
| 
 | |
|     /*******************************************************
 | |
|      * homogeneous step_size for integral types and slices *
 | |
|      *******************************************************/
 | |
| 
 | |
|     template <class S>
 | |
|     inline disable_xslice<S, std::size_t> step_size(const S&, std::size_t) noexcept
 | |
|     {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     template <class S>
 | |
|     inline disable_xslice<S, std::size_t> step_size(const S&, std::size_t, std::size_t) noexcept
 | |
|     {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     template <class S>
 | |
|     inline auto step_size(const xslice<S>& slice, std::size_t idx) noexcept
 | |
|     {
 | |
|         return slice.derived_cast().step_size(idx);
 | |
|     }
 | |
| 
 | |
|     template <class S>
 | |
|     inline auto step_size(const xslice<S>& slice, std::size_t idx, std::size_t n) noexcept
 | |
|     {
 | |
|         return slice.derived_cast().step_size(idx, n);
 | |
|     }
 | |
| 
 | |
|     /*********************************************
 | |
|      * homogeneous value for integral and slices *
 | |
|      *********************************************/
 | |
| 
 | |
|     template <class S, class I>
 | |
|     inline disable_xslice<S, std::size_t> value(const S& s, I) noexcept
 | |
|     {
 | |
|         return static_cast<std::size_t>(s);
 | |
|     }
 | |
| 
 | |
|     template <class S, class I>
 | |
|     inline auto value(const xslice<S>& slice, I i) noexcept
 | |
|     {
 | |
|         using ST = typename S::size_type;
 | |
|         return slice.derived_cast()(static_cast<ST>(i));
 | |
|     }
 | |
| 
 | |
|     /****************************************
 | |
|      * homogeneous get_slice_implementation *
 | |
|      ****************************************/
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class T>
 | |
|         struct slice_implementation_getter
 | |
|         {
 | |
|             template <class E, class SL>
 | |
|             inline decltype(auto) operator()(E& e, SL&& slice, std::size_t index) const
 | |
|             {
 | |
|                 return get_slice(e, std::forward<SL>(slice), index, xtl::is_signed<std::decay_t<SL>>());
 | |
|             }
 | |
| 
 | |
|         private:
 | |
| 
 | |
|             template <class E, class SL>
 | |
|             inline decltype(auto) get_slice(E&, SL&& slice, std::size_t, std::false_type) const
 | |
|             {
 | |
|                 return std::forward<SL>(slice);
 | |
|             }
 | |
| 
 | |
|             template <class E, class SL>
 | |
|             inline decltype(auto) get_slice(E& e, SL&& slice, std::size_t index, std::true_type) const
 | |
|             {
 | |
|                 using int_type = std::decay_t<SL>;
 | |
|                 return slice < int_type(0) ? slice + static_cast<std::ptrdiff_t>(e.shape(index))
 | |
|                                            : std::ptrdiff_t(slice);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct keep_drop_getter
 | |
|         {
 | |
|             template <class E, class SL>
 | |
|             inline decltype(auto) operator()(E& e, SL&& slice, std::size_t index) const
 | |
|             {
 | |
|                 slice.normalize(e.shape()[index]);
 | |
|                 return std::forward<SL>(slice);
 | |
|             }
 | |
| 
 | |
|             template <class E, class SL>
 | |
|             inline auto operator()(E& e, const SL& slice, std::size_t index) const
 | |
|             {
 | |
|                 return this->operator()(e, SL(slice), index);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         struct slice_implementation_getter<xkeep_slice<T>> : keep_drop_getter
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         template <class T>
 | |
|         struct slice_implementation_getter<xdrop_slice<T>> : keep_drop_getter
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         template <>
 | |
|         struct slice_implementation_getter<xall_tag>
 | |
|         {
 | |
|             template <class E, class SL>
 | |
|             inline auto operator()(E& e, SL&&, std::size_t index) const
 | |
|             {
 | |
|                 return xall<typename E::size_type>(e.shape()[index]);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <>
 | |
|         struct slice_implementation_getter<xnewaxis_tag>
 | |
|         {
 | |
|             template <class E, class SL>
 | |
|             inline auto operator()(E&, SL&&, std::size_t) const
 | |
|             {
 | |
|                 return xnewaxis<typename E::size_type>();
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <class A, class B, class C>
 | |
|         struct slice_implementation_getter<xrange_adaptor<A, B, C>>
 | |
|         {
 | |
|             template <class E, class SL>
 | |
|             inline auto operator()(E& e, SL&& adaptor, std::size_t index) const
 | |
|             {
 | |
|                 return adaptor.get(e.shape()[index]);
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     template <class E, class SL>
 | |
|     inline auto get_slice_implementation(E& e, SL&& slice, std::size_t index)
 | |
|     {
 | |
|         detail::slice_implementation_getter<std::decay_t<SL>> getter;
 | |
|         return getter(e, std::forward<SL>(slice), index);
 | |
|     }
 | |
| 
 | |
|     /******************************
 | |
|      * homogeneous get_slice_type *
 | |
|      ******************************/
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class E, class SL>
 | |
|         struct get_slice_type_impl
 | |
|         {
 | |
|             using type = SL;
 | |
|         };
 | |
| 
 | |
|         template <class E>
 | |
|         struct get_slice_type_impl<E, xall_tag>
 | |
|         {
 | |
|             using type = xall<typename E::size_type>;
 | |
|         };
 | |
| 
 | |
|         template <class E>
 | |
|         struct get_slice_type_impl<E, xnewaxis_tag>
 | |
|         {
 | |
|             using type = xnewaxis<typename E::size_type>;
 | |
|         };
 | |
| 
 | |
|         template <class E, class A, class B, class C>
 | |
|         struct get_slice_type_impl<E, xrange_adaptor<A, B, C>>
 | |
|         {
 | |
|             using type = decltype(xrange_adaptor<A, B, C>(A(), B(), C()).get(0));
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     template <class E, class SL>
 | |
|     using get_slice_type = typename detail::get_slice_type_impl<E, std::remove_reference_t<SL>>::type;
 | |
| 
 | |
|     /*************************
 | |
|      * xslice implementation *
 | |
|      *************************/
 | |
| 
 | |
|     template <class D>
 | |
|     inline auto xslice<D>::derived_cast() noexcept -> derived_type&
 | |
|     {
 | |
|         return *static_cast<derived_type*>(this);
 | |
|     }
 | |
| 
 | |
|     template <class D>
 | |
|     inline auto xslice<D>::derived_cast() const noexcept -> const derived_type&
 | |
|     {
 | |
|         return *static_cast<const derived_type*>(this);
 | |
|     }
 | |
| 
 | |
|     /*************************
 | |
|      * xrange implementation *
 | |
|      *************************/
 | |
| 
 | |
|     template <class T>
 | |
|     inline xrange<T>::xrange(size_type start_val, size_type stop_val) noexcept
 | |
|         : m_start(start_val)
 | |
|         , m_size(stop_val > start_val ? stop_val - start_val : 0)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xrange<T>::operator xrange<S>() const noexcept
 | |
|     {
 | |
|         xrange<S> ret;
 | |
|         ret.m_start = static_cast<S>(m_start);
 | |
|         ret.m_size = static_cast<S>(m_size);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xrange<S> xrange<T>::convert() const noexcept
 | |
|     {
 | |
|         return xrange<S>(*this);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xrange<T>::operator()(size_type i) const noexcept -> size_type
 | |
|     {
 | |
|         return m_start + i;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xrange<T>::size() const noexcept -> size_type
 | |
|     {
 | |
|         return m_size;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xrange<T>::step_size() const noexcept -> size_type
 | |
|     {
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xrange<T>::step_size(std::size_t /*i*/, std::size_t n) const noexcept -> size_type
 | |
|     {
 | |
|         return static_cast<size_type>(n);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xrange<T>::revert_index(std::size_t i) const noexcept -> size_type
 | |
|     {
 | |
|         return i - m_start;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xrange<T>::contains(size_type i) const noexcept
 | |
|     {
 | |
|         return i >= m_start && i < m_start + m_size;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xrange<T>::operator==(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return (m_start == rhs.m_start) && (m_size == rhs.m_size);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xrange<T>::operator!=(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return !(*this == rhs);
 | |
|     }
 | |
| 
 | |
|     /********************************
 | |
|      * xtepped_range implementation *
 | |
|      ********************************/
 | |
| 
 | |
|     template <class T>
 | |
|     inline xstepped_range<T>::xstepped_range(size_type start_val, size_type stop_val, size_type step) noexcept
 | |
|         : m_start(start_val)
 | |
|         , m_size(size_type(0))
 | |
|         , m_step(step)
 | |
|     {
 | |
|         size_type n = stop_val - start_val;
 | |
|         m_size = n / step + (((n < 0) ^ (step > 0)) && (n % step));
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xstepped_range<T>::operator xstepped_range<S>() const noexcept
 | |
|     {
 | |
|         xstepped_range<S> ret;
 | |
|         ret.m_start = static_cast<S>(m_start);
 | |
|         ret.m_size = static_cast<S>(m_size);
 | |
|         ret.m_step = static_cast<S>(m_step);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xstepped_range<S> xstepped_range<T>::convert() const noexcept
 | |
|     {
 | |
|         return xstepped_range<S>(*this);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xstepped_range<T>::operator()(size_type i) const noexcept -> size_type
 | |
|     {
 | |
|         return m_start + i * m_step;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xstepped_range<T>::size() const noexcept -> size_type
 | |
|     {
 | |
|         return m_size;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xstepped_range<T>::step_size() const noexcept -> size_type
 | |
|     {
 | |
|         return m_step;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xstepped_range<T>::step_size(std::size_t /*i*/, std::size_t n) const noexcept -> size_type
 | |
|     {
 | |
|         return m_step * static_cast<size_type>(n);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xstepped_range<T>::revert_index(std::size_t i) const noexcept -> size_type
 | |
|     {
 | |
|         return (i - m_start) / m_step;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xstepped_range<T>::contains(size_type i) const noexcept
 | |
|     {
 | |
|         return i >= m_start && i < m_start + m_size * m_step && ((i - m_start) % m_step == 0);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xstepped_range<T>::operator==(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return (m_start == rhs.m_start) && (m_size == rhs.m_size) && (m_step == rhs.m_step);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xstepped_range<T>::operator!=(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return !(*this == rhs);
 | |
|     }
 | |
| 
 | |
|     /***********************
 | |
|      * xall implementation *
 | |
|      ***********************/
 | |
| 
 | |
|     template <class T>
 | |
|     inline xall<T>::xall(size_type size) noexcept
 | |
|         : m_size(size)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xall<T>::operator xall<S>() const noexcept
 | |
|     {
 | |
|         return xall<S>(static_cast<S>(m_size));
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xall<S> xall<T>::convert() const noexcept
 | |
|     {
 | |
|         return xall<S>(*this);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xall<T>::operator()(size_type i) const noexcept -> size_type
 | |
|     {
 | |
|         return i;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xall<T>::size() const noexcept -> size_type
 | |
|     {
 | |
|         return m_size;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xall<T>::step_size() const noexcept -> size_type
 | |
|     {
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xall<T>::step_size(std::size_t /*i*/, std::size_t n) const noexcept -> size_type
 | |
|     {
 | |
|         return static_cast<size_type>(n);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xall<T>::revert_index(std::size_t i) const noexcept -> size_type
 | |
|     {
 | |
|         return i;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xall<T>::contains(size_type i) const noexcept
 | |
|     {
 | |
|         return i < m_size;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xall<T>::operator==(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return m_size == rhs.m_size;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xall<T>::operator!=(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return !(*this == rhs);
 | |
|     }
 | |
| 
 | |
|     /***************************
 | |
|      * xnewaxis implementation *
 | |
|      ***************************/
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xnewaxis<T>::operator xnewaxis<S>() const noexcept
 | |
|     {
 | |
|         return xnewaxis<S>();
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xnewaxis<S> xnewaxis<T>::convert() const noexcept
 | |
|     {
 | |
|         return xnewaxis<S>(*this);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xnewaxis<T>::operator()(size_type) const noexcept -> size_type
 | |
|     {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xnewaxis<T>::size() const noexcept -> size_type
 | |
|     {
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xnewaxis<T>::step_size() const noexcept -> size_type
 | |
|     {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xnewaxis<T>::step_size(std::size_t /*i*/, std::size_t /*n*/) const noexcept -> size_type
 | |
|     {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xnewaxis<T>::revert_index(std::size_t i) const noexcept -> size_type
 | |
|     {
 | |
|         return i;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xnewaxis<T>::contains(size_type i) const noexcept
 | |
|     {
 | |
|         return i == 0;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xnewaxis<T>::operator==(const self_type& /*rhs*/) const noexcept
 | |
|     {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xnewaxis<T>::operator!=(const self_type& /*rhs*/) const noexcept
 | |
|     {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /******************************
 | |
|      * xkeep_slice implementation *
 | |
|      ******************************/
 | |
| 
 | |
|     template <class T>
 | |
|     template <class C, typename>
 | |
|     inline xkeep_slice<T>::xkeep_slice(C& cont)
 | |
|         : m_raw_indices(cont.begin(), cont.end())
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline xkeep_slice<T>::xkeep_slice(container_type&& cont)
 | |
|         : m_raw_indices(std::move(cont))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S>
 | |
|     inline xkeep_slice<T>::xkeep_slice(std::initializer_list<S> t)
 | |
|         : m_raw_indices(t.size())
 | |
|     {
 | |
|         std::transform(
 | |
|             t.begin(),
 | |
|             t.end(),
 | |
|             m_raw_indices.begin(),
 | |
|             [](auto t)
 | |
|             {
 | |
|                 return static_cast<size_type>(t);
 | |
|             }
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xkeep_slice<T>::operator xkeep_slice<S>() const noexcept
 | |
|     {
 | |
|         xkeep_slice<S> ret;
 | |
|         using us_type = typename container_type::size_type;
 | |
|         us_type sz = static_cast<us_type>(size());
 | |
|         ret.m_raw_indices.resize(sz);
 | |
|         ret.m_indices.resize(sz);
 | |
|         std::transform(
 | |
|             m_raw_indices.cbegin(),
 | |
|             m_raw_indices.cend(),
 | |
|             ret.m_raw_indices.begin(),
 | |
|             [](const T& val)
 | |
|             {
 | |
|                 return static_cast<S>(val);
 | |
|             }
 | |
|         );
 | |
|         std::transform(
 | |
|             m_indices.cbegin(),
 | |
|             m_indices.cend(),
 | |
|             ret.m_indices.begin(),
 | |
|             [](const T& val)
 | |
|             {
 | |
|                 return static_cast<S>(val);
 | |
|             }
 | |
|         );
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xkeep_slice<S> xkeep_slice<T>::convert() const noexcept
 | |
|     {
 | |
|         return xkeep_slice<S>(*this);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline void xkeep_slice<T>::normalize(std::size_t shape)
 | |
|     {
 | |
|         m_indices.resize(m_raw_indices.size());
 | |
|         std::size_t sz = m_indices.size();
 | |
|         for (std::size_t i = 0; i < sz; ++i)
 | |
|         {
 | |
|             m_indices[i] = m_raw_indices[i] < 0 ? static_cast<size_type>(shape) + m_raw_indices[i]
 | |
|                                                 : m_raw_indices[i];
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xkeep_slice<T>::operator()(size_type i) const noexcept -> size_type
 | |
|     {
 | |
|         return m_indices.size() == size_type(1) ? m_indices.front() : m_indices[static_cast<std::size_t>(i)];
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xkeep_slice<T>::size() const noexcept -> size_type
 | |
|     {
 | |
|         return static_cast<size_type>(m_raw_indices.size());
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xkeep_slice<T>::step_size(std::size_t i, std::size_t n) const noexcept -> size_type
 | |
|     {
 | |
|         if (m_indices.size() == 1)
 | |
|         {
 | |
|             return 0;
 | |
|         }
 | |
|         if (i + n >= m_indices.size())
 | |
|         {
 | |
|             return m_indices.back() - m_indices[i] + 1;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return m_indices[i + n] - m_indices[i];
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xkeep_slice<T>::revert_index(std::size_t i) const -> size_type
 | |
|     {
 | |
|         auto it = std::find(m_indices.begin(), m_indices.end(), i);
 | |
|         if (it != m_indices.end())
 | |
|         {
 | |
|             return std::distance(m_indices.begin(), it);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             XTENSOR_THROW(std::runtime_error, "Index i (" + std::to_string(i) + ") not in indices of islice.");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xkeep_slice<T>::contains(size_type i) const noexcept
 | |
|     {
 | |
|         return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? false : true;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xkeep_slice<T>::operator==(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return m_indices == rhs.m_indices;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xkeep_slice<T>::operator!=(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return !(*this == rhs);
 | |
|     }
 | |
| 
 | |
|     /******************************
 | |
|      * xdrop_slice implementation *
 | |
|      ******************************/
 | |
| 
 | |
|     template <class T>
 | |
|     template <class C, typename>
 | |
|     inline xdrop_slice<T>::xdrop_slice(C& cont)
 | |
|         : m_raw_indices(cont.begin(), cont.end())
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline xdrop_slice<T>::xdrop_slice(container_type&& cont)
 | |
|         : m_raw_indices(std::move(cont))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S>
 | |
|     inline xdrop_slice<T>::xdrop_slice(std::initializer_list<S> t)
 | |
|         : m_raw_indices(t.size())
 | |
|     {
 | |
|         std::transform(
 | |
|             t.begin(),
 | |
|             t.end(),
 | |
|             m_raw_indices.begin(),
 | |
|             [](auto t)
 | |
|             {
 | |
|                 return static_cast<size_type>(t);
 | |
|             }
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xdrop_slice<T>::operator xdrop_slice<S>() const noexcept
 | |
|     {
 | |
|         xdrop_slice<S> ret;
 | |
|         ret.m_raw_indices.resize(m_raw_indices.size());
 | |
|         ret.m_indices.resize(m_indices.size());
 | |
|         std::transform(
 | |
|             m_raw_indices.cbegin(),
 | |
|             m_raw_indices.cend(),
 | |
|             ret.m_raw_indices.begin(),
 | |
|             [](const T& val)
 | |
|             {
 | |
|                 return static_cast<S>(val);
 | |
|             }
 | |
|         );
 | |
|         std::transform(
 | |
|             m_indices.cbegin(),
 | |
|             m_indices.cend(),
 | |
|             ret.m_indices.begin(),
 | |
|             [](const T& val)
 | |
|             {
 | |
|                 return static_cast<S>(val);
 | |
|             }
 | |
|         );
 | |
|         std::transform(
 | |
|             m_inc.cbegin(),
 | |
|             m_inc.cend(),
 | |
|             std::inserter(ret.m_inc, ret.m_inc.begin()),
 | |
|             [](const auto& val)
 | |
|             {
 | |
|                 return std::make_pair(static_cast<S>(val.first), static_cast<S>(val.second));
 | |
|             }
 | |
|         );
 | |
|         ret.m_size = static_cast<S>(m_size);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     template <class S, typename>
 | |
|     inline xdrop_slice<S> xdrop_slice<T>::convert() const noexcept
 | |
|     {
 | |
|         return xdrop_slice<S>(*this);
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline void xdrop_slice<T>::normalize(std::size_t shape)
 | |
|     {
 | |
|         m_size = static_cast<size_type>(shape - m_raw_indices.size());
 | |
| 
 | |
|         m_indices.resize(m_raw_indices.size());
 | |
|         std::size_t sz = m_indices.size();
 | |
|         for (std::size_t i = 0; i < sz; ++i)
 | |
|         {
 | |
|             m_indices[i] = m_raw_indices[i] < 0 ? static_cast<size_type>(shape) + m_raw_indices[i]
 | |
|                                                 : m_raw_indices[i];
 | |
|         }
 | |
|         size_type cum = size_type(0);
 | |
|         size_type prev_cum = cum;
 | |
|         for (std::size_t i = 0; i < sz; ++i)
 | |
|         {
 | |
|             std::size_t ind = i;
 | |
|             size_type d = m_indices[i];
 | |
|             while (i + 1 < sz && m_indices[i + 1] == m_indices[i] + 1)
 | |
|             {
 | |
|                 ++i;
 | |
|             }
 | |
|             cum += (static_cast<size_type>(i) - static_cast<size_type>(ind)) + 1;
 | |
|             m_inc[d - prev_cum] = cum;
 | |
|             prev_cum = cum;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xdrop_slice<T>::operator()(size_type i) const noexcept -> size_type
 | |
|     {
 | |
|         if (m_inc.empty() || i < m_inc.begin()->first)
 | |
|         {
 | |
|             return i;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             auto iter = --m_inc.upper_bound(i);
 | |
|             return i + iter->second;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xdrop_slice<T>::size() const noexcept -> size_type
 | |
|     {
 | |
|         return m_size;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xdrop_slice<T>::step_size(std::size_t i, std::size_t n) const noexcept -> size_type
 | |
|     {
 | |
|         if (i + n >= static_cast<std::size_t>(m_size))
 | |
|         {
 | |
|             return (*this)(static_cast<size_type>(m_size - 1)) - (*this)(static_cast<size_type>(i)) + 1;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return (*this)(static_cast<size_type>(i + n)) - (*this)(static_cast<size_type>(i));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline auto xdrop_slice<T>::revert_index(std::size_t i) const -> size_type
 | |
|     {
 | |
|         if (i < m_inc.begin()->first)
 | |
|         {
 | |
|             return i;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             auto iter = --m_inc.lower_bound(i);
 | |
|             auto check = iter->first + iter->second;
 | |
|             if (check > i)
 | |
|             {
 | |
|                 --iter;
 | |
|             }
 | |
|             return i - iter->second;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xdrop_slice<T>::contains(size_type i) const noexcept
 | |
|     {
 | |
|         return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? true : false;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xdrop_slice<T>::operator==(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return m_indices == rhs.m_indices;
 | |
|     }
 | |
| 
 | |
|     template <class T>
 | |
|     inline bool xdrop_slice<T>::operator!=(const self_type& rhs) const noexcept
 | |
|     {
 | |
|         return !(*this == rhs);
 | |
|     }
 | |
| }
 | |
| 
 | |
| #undef XTENSOR_CONSTEXPR
 | |
| 
 | |
| #endif
 |