10#ifndef XTENSOR_SLICE_HPP
11#define XTENSOR_SLICE_HPP
18#include <xtl/xtype_traits.hpp>
20#include "../containers/xstorage.hpp"
21#include "../core/xtensor_config.hpp"
22#include "../utils/xutils.hpp"
36 using derived_type = D;
38 derived_type& derived_cast()
noexcept;
39 const derived_type& derived_cast()
const noexcept;
46 xslice(
const xslice&) =
default;
47 xslice& operator=(
const xslice&) =
default;
49 xslice(xslice&&) =
default;
50 xslice& operator=(xslice&&) =
default;
54 using is_xslice = std::is_base_of<xslice<S>, S>;
57 using has_xslice = std::disjunction<is_xslice<E>...>;
63#define DEFINE_TAG_CONVERSION(NAME) \
65 constexpr NAME convert() const noexcept \
85#undef DEFINE_TAG_CONVERSION
92 class xrange :
public xslice<xrange<T>>
97 using self_type = xrange<T>;
100 xrange(size_type start_val, size_type stop_val)
noexcept;
102 template <std::convertible_to<T> S>
103 operator xrange<S>()
const noexcept;
107 template <std::convertible_to<T> S>
108 xrange<S> convert()
const noexcept;
110 size_type operator()(size_type i)
const noexcept;
112 size_type size()
const noexcept;
113 size_type step_size()
const noexcept;
114 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
115 size_type revert_index(std::size_t i)
const noexcept;
117 bool contains(size_type i)
const noexcept;
119 bool operator==(
const self_type& rhs)
const noexcept;
120 bool operator!=(
const self_type& rhs)
const noexcept;
136 class xstepped_range :
public xslice<xstepped_range<T>>
141 using self_type = xstepped_range<T>;
143 xstepped_range() =
default;
144 xstepped_range(size_type start_val, size_type stop_val, size_type step)
noexcept;
146 template <std::convertible_to<T> S>
147 operator xstepped_range<S>()
const noexcept;
151 template <std::convertible_to<T> S>
152 xstepped_range<S> convert()
const noexcept;
154 size_type operator()(size_type i)
const noexcept;
156 size_type size()
const noexcept;
157 size_type step_size()
const noexcept;
158 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
159 size_type revert_index(std::size_t i)
const noexcept;
161 bool contains(size_type i)
const noexcept;
163 bool operator==(
const self_type& rhs)
const noexcept;
164 bool operator!=(
const self_type& rhs)
const noexcept;
173 friend class xstepped_range;
181 class xall :
public xslice<xall<T>>
186 using self_type = xall<T>;
189 explicit xall(size_type size)
noexcept;
191 template <std::convertible_to<T> S>
192 operator xall<S>()
const noexcept;
196 template <std::convertible_to<T> S>
197 xall<S> convert()
const noexcept;
199 size_type operator()(size_type i)
const noexcept;
201 size_type size()
const noexcept;
202 size_type step_size()
const noexcept;
203 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
204 size_type revert_index(std::size_t i)
const noexcept;
206 bool contains(size_type i)
const noexcept;
208 bool operator==(
const self_type& rhs)
const noexcept;
209 bool operator!=(
const self_type& rhs)
const noexcept;
221 inline auto all() noexcept
252 class xnewaxis :
public xslice<xnewaxis<T>>
257 using self_type = xnewaxis<T>;
259 xnewaxis() =
default;
261 template <std::convertible_to<T> S>
262 operator xnewaxis<S>()
const noexcept;
266 template <std::convertible_to<T> S>
267 xnewaxis<S> convert()
const noexcept;
269 size_type operator()(size_type i)
const noexcept;
271 size_type size()
const noexcept;
272 size_type step_size()
const noexcept;
273 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
274 size_type revert_index(std::size_t i)
const noexcept;
276 bool contains(size_type i)
const noexcept;
278 bool operator==(
const self_type& rhs)
const noexcept;
279 bool operator!=(
const self_type& rhs)
const noexcept;
302 struct is_xkeep_slice : std::false_type
307 struct is_xkeep_slice<xkeep_slice<T>> : std::true_type
313 class xkeep_slice :
public xslice<xkeep_slice<T>>
318 using size_type =
typename container_type::value_type;
319 using self_type = xkeep_slice<T>;
322 explicit xkeep_slice(C& cont)
323 requires(!detail::is_xkeep_slice<std::decay_t<C>>::value);
324 explicit xkeep_slice(container_type&& cont);
327 xkeep_slice(std::initializer_list<S> t);
329 template <std::convertible_to<T> S>
330 operator xkeep_slice<S>()
const noexcept;
334 template <std::convertible_to<T> S>
335 xkeep_slice<S> convert()
const noexcept;
337 size_type operator()(size_type i)
const noexcept;
338 size_type size()
const noexcept;
340 void normalize(std::size_t s);
342 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
343 size_type revert_index(std::size_t i)
const;
345 bool contains(size_type i)
const noexcept;
347 bool operator==(
const self_type& rhs)
const noexcept;
348 bool operator!=(
const self_type& rhs)
const noexcept;
352 xkeep_slice() =
default;
354 container_type m_indices;
355 container_type m_raw_indices;
358 friend class xkeep_slice;
375 template <
class R = std::ptrdiff_t,
class T>
378 if constexpr (xtl::is_integral<std::decay_t<T>>::value)
381 using container_type =
typename slice_type::container_type;
382 container_type tmp = {
static_cast<R
>(std::forward<T>(indices))};
383 return slice_type(std::move(tmp));
391 template <
class R = std::ptrdiff_t,
class Arg0,
class Arg1,
class... Args>
392 inline xkeep_slice<R>
keep(Arg0 i0, Arg1 i1, Args... args)
394 using slice_type = xkeep_slice<R>;
395 using container_type =
typename slice_type::container_type;
396 container_type tmp = {
static_cast<R
>(i0),
static_cast<R
>(i1),
static_cast<R
>(args)...};
397 return slice_type(std::move(tmp));
410 struct is_xdrop_slice : std::false_type
415 struct is_xdrop_slice<xdrop_slice<T>> : std::true_type
421 class xdrop_slice :
public xslice<xdrop_slice<T>>
426 using size_type =
typename container_type::value_type;
427 using self_type = xdrop_slice<T>;
430 explicit xdrop_slice(C& cont)
431 requires(!detail::is_xdrop_slice<std::decay_t<C>>::value);
432 explicit xdrop_slice(container_type&& cont);
435 xdrop_slice(std::initializer_list<S> t);
437 template <std::convertible_to<T> S>
438 operator xdrop_slice<S>()
const noexcept;
442 template <std::convertible_to<T> S>
443 xdrop_slice<S> convert()
const noexcept;
445 size_type operator()(size_type i)
const noexcept;
446 size_type size()
const noexcept;
448 void normalize(std::size_t s);
450 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
451 size_type revert_index(std::size_t i)
const;
453 bool contains(size_type i)
const noexcept;
455 bool operator==(
const self_type& rhs)
const noexcept;
456 bool operator!=(
const self_type& rhs)
const noexcept;
460 xdrop_slice() =
default;
462 container_type m_indices;
463 container_type m_raw_indices;
464 std::map<size_type, size_type> m_inc;
468 friend class xdrop_slice;
484 template <
class R = std::ptrdiff_t,
class T>
487 if constexpr (xtl::is_integral<std::remove_cvref_t<T>>::value)
490 using container_type =
typename slice_type::container_type;
491 container_type tmp = {
static_cast<R
>(std::forward<T>(indices))};
492 return slice_type(std::move(tmp));
500 template <
class R = std::ptrdiff_t,
class Arg0,
class Arg1,
class... Args>
501 inline xdrop_slice<R>
drop(Arg0 i0, Arg1 i1, Args... args)
503 using slice_type = xdrop_slice<R>;
504 using container_type =
typename slice_type::container_type;
505 container_type tmp = {
static_cast<R
>(i0),
static_cast<R
>(i1),
static_cast<R
>(args)...};
506 return slice_type(std::move(tmp));
513 template <
class A,
class B = A,
class C = A>
514 struct xrange_adaptor
516 xrange_adaptor(A start_val, B stop_val, C step)
523 template <
class MI = A,
class MA = B,
class STEP = C>
524 auto get(std::size_t size)
const
526 if constexpr (xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
528 return get_stepped_range(m_start, m_stop, m_step, size);
530 else if constexpr (!xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
532 return get_stepped_range(
533 m_step > 0 ? 0 :
static_cast<std::ptrdiff_t
>(size) - 1,
539 else if constexpr (xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
541 auto sz =
static_cast<std::ptrdiff_t
>(size);
542 return get_stepped_range(m_start, m_step > 0 ? sz : -(sz + 1), m_step, size);
544 else if constexpr (xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
548 else if constexpr (!xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
550 std::ptrdiff_t start = m_step >= 0 ? 0 :
static_cast<std::ptrdiff_t
>(size) - 1;
551 std::ptrdiff_t stop = m_step >= 0 ?
static_cast<std::ptrdiff_t
>(size) : -1;
554 else if constexpr (xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
558 else if constexpr (!xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
562 else if constexpr (!xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
585 static auto normalize(std::ptrdiff_t val, std::size_t ssize)
587 std::ptrdiff_t size =
static_cast<std::ptrdiff_t
>(ssize);
588 val = (val >= 0) ? val : val + size;
589 return (std::max)(std::ptrdiff_t(0), (std::min)(size, val));
593 get_stepped_range(std::ptrdiff_t start, std::ptrdiff_t stop, std::ptrdiff_t step, std::size_t ssize)
595 std::ptrdiff_t size =
static_cast<std::ptrdiff_t
>(ssize);
596 start = (start >= 0) ? start : start + size;
597 stop = (stop >= 0) ? stop : stop + size;
601 start = (std::max)(std::ptrdiff_t(0), (std::min)(size, start));
602 stop = (std::max)(std::ptrdiff_t(0), (std::min)(size, stop));
606 start = (std::max)(std::ptrdiff_t(-1), (std::min)(size - 1, start));
607 stop = (std::max)(std::ptrdiff_t(-1), (std::min)(size - 1, stop));
622 namespace placeholders
629 template <
class... Args>
632 std::ptrdiff_t rng[3];
635 constexpr xtuph get_tuph_or_val(std::ptrdiff_t , std::true_type)
640 constexpr std::ptrdiff_t get_tuph_or_val(std::ptrdiff_t val, std::false_type)
645 template <
class A,
class B,
class C>
651 {get_tuph_or_val(rng[0], std::is_same<A, xtuph>()),
652 get_tuph_or_val(rng[1], std::is_same<B, xtuph>()),
653 get_tuph_or_val(rng[2], std::is_same<C, xtuph>())}
657 std::ptrdiff_t rng[3];
660 template <
class A,
class B>
666 {get_tuph_or_val(rng[0], std::is_same<A, xtuph>()),
667 get_tuph_or_val(rng[1], std::is_same<B, xtuph>()),
672 std::ptrdiff_t rng[3];
675 template <
class... OA>
678 auto nrng =
rangemaker<OA..., std::ptrdiff_t>({rng.rng[0], rng.rng[1], rng.rng[2]});
679 nrng.rng[
sizeof...(OA)] = t;
683 template <
class... OA>
692 constexpr xall_tag _a{};
693 constexpr xnewaxis_tag _n{};
694 constexpr xellipsis_tag _e{};
705 struct cast_if_integer
707 using type = std::conditional_t<xtl::is_integral<T>::value, std::ptrdiff_t, T>;
711 return static_cast<type
>(t);
716 using cast_if_integer_t =
typename cast_if_integer<T>::type;
733 template <
class A,
class B>
734 inline auto range(A start_val, B stop_val)
737 detail::cast_if_integer<A>{}(start_val),
738 detail::cast_if_integer<B>{}(stop_val),
754 template <
class A,
class B,
class C>
755 inline auto range(A start_val, B stop_val, C step)
758 detail::cast_if_integer<A>{}(start_val),
759 detail::cast_if_integer<B>{}(stop_val),
760 detail::cast_if_integer<C>{}(step)
769 inline std::size_t get_size(
const S& slice)
noexcept
771 if constexpr (is_xslice<S>::value)
773 return static_cast<std::size_t
>(slice.size());
786 inline std::size_t step_size(
const S& slice, std::size_t idx)
noexcept
788 if constexpr (is_xslice<S>::value)
790 return static_cast<std::size_t
>(slice.step_size(idx));
799 inline std::size_t step_size(
const S& slice, std::size_t idx, std::size_t n)
noexcept
801 if constexpr (is_xslice<S>::value)
803 return static_cast<std::size_t
>(slice.step_size(idx, n));
815 template <
class S,
class I>
816 inline std::size_t value(
const S& slice, I i)
noexcept
818 if constexpr (is_xslice<S>::value)
820 using ST =
typename S::size_type;
821 return static_cast<std::size_t
>(slice(
static_cast<ST
>(i)));
825 return static_cast<std::size_t
>(slice);
836 struct slice_implementation_getter
838 template <
class E,
class SL>
839 inline decltype(
auto)
operator()(E& e, SL&& slice, std::size_t index)
const
841 return get_slice(e, std::forward<SL>(slice), index, xtl::is_signed<std::decay_t<SL>>());
846 template <
class E,
class SL>
847 inline decltype(
auto) get_slice(E&, SL&& slice, std::size_t, std::false_type)
const
849 return std::forward<SL>(slice);
852 template <
class E,
class SL>
853 inline decltype(
auto) get_slice(E& e, SL&& slice, std::size_t index, std::true_type)
const
855 using int_type = std::decay_t<SL>;
856 return slice < int_type(0) ? slice + static_cast<std::ptrdiff_t>(e.shape(index))
857 : std::ptrdiff_t(slice);
861 struct keep_drop_getter
863 template <
class E,
class SL>
864 inline decltype(
auto)
operator()(E& e, SL&& slice, std::size_t index)
const
866 slice.normalize(e.shape()[index]);
867 return std::forward<SL>(slice);
870 template <
class E,
class SL>
871 inline auto operator()(E& e,
const SL& slice, std::size_t index)
const
873 return this->operator()(e, SL(slice), index);
878 struct slice_implementation_getter<xkeep_slice<T>> : keep_drop_getter
883 struct slice_implementation_getter<xdrop_slice<T>> : keep_drop_getter
888 struct slice_implementation_getter<xall_tag>
890 template <
class E,
class SL>
891 inline auto operator()(E& e, SL&&, std::size_t index)
const
893 return xall<typename E::size_type>(e.shape()[index]);
898 struct slice_implementation_getter<xnewaxis_tag>
900 template <
class E,
class SL>
901 inline auto operator()(E&, SL&&, std::size_t)
const
903 return xnewaxis<typename E::size_type>();
907 template <
class A,
class B,
class C>
908 struct slice_implementation_getter<xrange_adaptor<A, B, C>>
910 template <
class E,
class SL>
911 inline auto operator()(E& e, SL&& adaptor, std::size_t index)
const
913 return adaptor.get(e.shape()[index]);
918 template <
class E,
class SL>
919 inline auto get_slice_implementation(E& e, SL&& slice, std::size_t index)
921 detail::slice_implementation_getter<std::decay_t<SL>> getter;
922 return getter(e, std::forward<SL>(slice), index);
931 template <
class E,
class SL>
932 struct get_slice_type_impl
938 struct get_slice_type_impl<E, xall_tag>
940 using type = xall<typename E::size_type>;
944 struct get_slice_type_impl<E, xnewaxis_tag>
946 using type = xnewaxis<typename E::size_type>;
949 template <
class E,
class A,
class B,
class C>
950 struct get_slice_type_impl<E, xrange_adaptor<A, B, C>>
952 using type =
decltype(xrange_adaptor<A, B, C>(A(), B(), C()).get(0));
956 template <
class E,
class SL>
957 using get_slice_type =
typename detail::get_slice_type_impl<E, std::remove_reference_t<SL>>::type;
964 inline auto xslice<D>::derived_cast() noexcept -> derived_type&
966 return *
static_cast<derived_type*
>(
this);
970 inline auto xslice<D>::derived_cast() const noexcept -> const derived_type&
972 return *
static_cast<const derived_type*
>(
this);
980 inline xrange<T>::xrange(size_type start_val, size_type stop_val) noexcept
982 , m_size(stop_val > start_val ? stop_val - start_val : 0)
987 template <std::convertible_to<T> S>
991 ret.m_start =
static_cast<S
>(m_start);
992 ret.m_size =
static_cast<S
>(m_size);
997 template <std::convertible_to<T> S>
998 inline xrange<S> xrange<T>::convert() const noexcept
1004 inline auto xrange<T>::operator()(size_type i)
const noexcept -> size_type
1010 inline auto xrange<T>::size() const noexcept -> size_type
1016 inline auto xrange<T>::step_size() const noexcept -> size_type
1022 inline auto xrange<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1024 return static_cast<size_type
>(n);
1028 inline auto xrange<T>::revert_index(std::size_t i)
const noexcept -> size_type
1034 inline bool xrange<T>::contains(size_type i)
const noexcept
1036 return i >= m_start && i < m_start + m_size;
1040 inline bool xrange<T>::operator==(
const self_type& rhs)
const noexcept
1042 return (m_start == rhs.m_start) && (m_size == rhs.m_size);
1046 inline bool xrange<T>::operator!=(
const self_type& rhs)
const noexcept
1048 return !(*
this == rhs);
1056 inline xstepped_range<T>::xstepped_range(size_type start_val, size_type stop_val, size_type step) noexcept
1057 : m_start(start_val)
1058 , m_size(size_type(0))
1061 if ((step > 0 && start_val >= stop_val) || (step < 0 && start_val <= stop_val))
1066 size_type n = stop_val - start_val;
1067 m_size = n / step +
static_cast<bool>(n % step);
1071 template <std::convertible_to<T> S>
1075 ret.m_start =
static_cast<S
>(m_start);
1076 ret.m_size =
static_cast<S
>(m_size);
1077 ret.m_step =
static_cast<S
>(m_step);
1082 template <std::convertible_to<T> S>
1089 inline auto xstepped_range<T>::operator()(size_type i)
const noexcept -> size_type
1091 return m_start + i * m_step;
1095 inline auto xstepped_range<T>::size() const noexcept -> size_type
1101 inline auto xstepped_range<T>::step_size() const noexcept -> size_type
1107 inline auto xstepped_range<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1109 return m_step *
static_cast<size_type
>(n);
1113 inline auto xstepped_range<T>::revert_index(std::size_t i)
const noexcept -> size_type
1115 return (i - m_start) / m_step;
1119 inline bool xstepped_range<T>::contains(size_type i)
const noexcept
1121 return i >= m_start && i < m_start + m_size * m_step && ((i - m_start) % m_step == 0);
1125 inline bool xstepped_range<T>::operator==(
const self_type& rhs)
const noexcept
1127 return (m_start == rhs.m_start) && (m_size == rhs.m_size) && (m_step == rhs.m_step);
1131 inline bool xstepped_range<T>::operator!=(
const self_type& rhs)
const noexcept
1133 return !(*
this == rhs);
1141 inline xall<T>::xall(size_type size) noexcept
1147 template <std::convertible_to<T> S>
1150 return xall<S>(
static_cast<S
>(m_size));
1154 template <std::convertible_to<T> S>
1155 inline xall<S> xall<T>::convert() const noexcept
1161 inline auto xall<T>::operator()(size_type i)
const noexcept -> size_type
1167 inline auto xall<T>::size() const noexcept -> size_type
1173 inline auto xall<T>::step_size() const noexcept -> size_type
1179 inline auto xall<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1181 return static_cast<size_type
>(n);
1185 inline auto xall<T>::revert_index(std::size_t i)
const noexcept -> size_type
1191 inline bool xall<T>::contains(size_type i)
const noexcept
1197 inline bool xall<T>::operator==(
const self_type& rhs)
const noexcept
1199 return m_size == rhs.m_size;
1203 inline bool xall<T>::operator!=(
const self_type& rhs)
const noexcept
1205 return !(*
this == rhs);
1213 template <std::convertible_to<T> S>
1220 template <std::convertible_to<T> S>
1221 inline xnewaxis<S> xnewaxis<T>::convert() const noexcept
1227 inline auto xnewaxis<T>::operator()(size_type)
const noexcept -> size_type
1233 inline auto xnewaxis<T>::size() const noexcept -> size_type
1239 inline auto xnewaxis<T>::step_size() const noexcept -> size_type
1245 inline auto xnewaxis<T>::step_size(std::size_t , std::size_t )
const noexcept -> size_type
1251 inline auto xnewaxis<T>::revert_index(std::size_t i)
const noexcept -> size_type
1257 inline bool xnewaxis<T>::contains(size_type i)
const noexcept
1263 inline bool xnewaxis<T>::operator==(
const self_type& )
const noexcept
1269 inline bool xnewaxis<T>::operator!=(
const self_type& )
const noexcept
1280 inline xkeep_slice<T>::xkeep_slice(C& cont)
1281 requires(!detail::is_xkeep_slice<std::decay_t<C>>::value)
1282 : m_raw_indices(cont.begin(), cont.end())
1287 inline xkeep_slice<T>::xkeep_slice(container_type&& cont)
1288 : m_raw_indices(std::move(cont))
1294 inline xkeep_slice<T>::xkeep_slice(std::initializer_list<S> t)
1295 : m_raw_indices(t.size())
1300 m_raw_indices.begin(),
1303 return static_cast<size_type>(t);
1309 template <std::convertible_to<T> S>
1310 inline xkeep_slice<T>::operator xkeep_slice<S>() const noexcept
1313 using us_type =
typename container_type::size_type;
1314 us_type sz =
static_cast<us_type
>(size());
1315 ret.m_raw_indices.resize(sz);
1316 ret.m_indices.resize(sz);
1318 m_raw_indices.cbegin(),
1319 m_raw_indices.cend(),
1320 ret.m_raw_indices.begin(),
1323 return static_cast<S>(val);
1329 ret.m_indices.begin(),
1332 return static_cast<S>(val);
1339 template <std::convertible_to<T> S>
1340 inline xkeep_slice<S> xkeep_slice<T>::convert() const noexcept
1342 return xkeep_slice<S>(*
this);
1346 inline void xkeep_slice<T>::normalize(std::size_t shape)
1348 m_indices.resize(m_raw_indices.size());
1349 std::size_t sz = m_indices.size();
1350 for (std::size_t i = 0; i < sz; ++i)
1352 m_indices[i] = m_raw_indices[i] < 0 ?
static_cast<size_type
>(shape) + m_raw_indices[i]
1358 inline auto xkeep_slice<T>::operator()(size_type i)
const noexcept -> size_type
1360 return m_indices.size() == size_type(1) ? m_indices.front() : m_indices[
static_cast<std::size_t
>(i)];
1364 inline auto xkeep_slice<T>::size() const noexcept -> size_type
1366 return static_cast<size_type
>(m_raw_indices.size());
1370 inline auto xkeep_slice<T>::step_size(std::size_t i, std::size_t n)
const noexcept -> size_type
1372 if (m_indices.size() == 1)
1376 if (i + n >= m_indices.size())
1378 return m_indices.back() - m_indices[i] + 1;
1382 return m_indices[i + n] - m_indices[i];
1387 inline auto xkeep_slice<T>::revert_index(std::size_t i)
const -> size_type
1389 auto it = std::find(m_indices.begin(), m_indices.end(), i);
1390 if (it != m_indices.end())
1392 return std::distance(m_indices.begin(), it);
1396 XTENSOR_THROW(std::runtime_error,
"Index i (" + std::to_string(i) +
") not in indices of islice.");
1401 inline bool xkeep_slice<T>::contains(size_type i)
const noexcept
1403 return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? false :
true;
1407 inline bool xkeep_slice<T>::operator==(
const self_type& rhs)
const noexcept
1409 return m_indices == rhs.m_indices;
1413 inline bool xkeep_slice<T>::operator!=(
const self_type& rhs)
const noexcept
1415 return !(*
this == rhs);
1424 inline xdrop_slice<T>::xdrop_slice(C& cont)
1425 requires(!detail::is_xdrop_slice<std::decay_t<C>>::value)
1426 : m_raw_indices(cont.begin(), cont.end())
1431 inline xdrop_slice<T>::xdrop_slice(container_type&& cont)
1432 : m_raw_indices(std::move(cont))
1438 inline xdrop_slice<T>::xdrop_slice(std::initializer_list<S> t)
1439 : m_raw_indices(t.size())
1444 m_raw_indices.begin(),
1447 return static_cast<size_type>(t);
1453 template <std::convertible_to<T> S>
1454 inline xdrop_slice<T>::operator xdrop_slice<S>() const noexcept
1457 ret.m_raw_indices.resize(m_raw_indices.size());
1458 ret.m_indices.resize(m_indices.size());
1460 m_raw_indices.cbegin(),
1461 m_raw_indices.cend(),
1462 ret.m_raw_indices.begin(),
1465 return static_cast<S>(val);
1471 ret.m_indices.begin(),
1474 return static_cast<S>(val);
1480 std::inserter(ret.m_inc, ret.m_inc.begin()),
1483 return std::make_pair(static_cast<S>(val.first), static_cast<S>(val.second));
1486 ret.m_size =
static_cast<S
>(m_size);
1491 template <std::convertible_to<T> S>
1492 inline xdrop_slice<S> xdrop_slice<T>::convert() const noexcept
1494 return xdrop_slice<S>(*
this);
1498 inline void xdrop_slice<T>::normalize(std::size_t shape)
1500 m_size =
static_cast<size_type
>(shape - m_raw_indices.size());
1502 m_indices.resize(m_raw_indices.size());
1503 std::size_t sz = m_indices.size();
1504 for (std::size_t i = 0; i < sz; ++i)
1506 m_indices[i] = m_raw_indices[i] < 0 ?
static_cast<size_type
>(shape) + m_raw_indices[i]
1509 size_type cum = size_type(0);
1510 size_type prev_cum = cum;
1511 for (std::size_t i = 0; i < sz; ++i)
1513 std::size_t ind = i;
1514 size_type d = m_indices[i];
1515 while (i + 1 < sz && m_indices[i + 1] == m_indices[i] + 1)
1519 cum += (
static_cast<size_type
>(i) -
static_cast<size_type
>(ind)) + 1;
1520 m_inc[d - prev_cum] = cum;
1526 inline auto xdrop_slice<T>::operator()(size_type i)
const noexcept -> size_type
1528 if (m_inc.empty() || i < m_inc.begin()->first)
1534 auto iter = --m_inc.upper_bound(i);
1535 return i + iter->second;
1540 inline auto xdrop_slice<T>::size() const noexcept -> size_type
1546 inline auto xdrop_slice<T>::step_size(std::size_t i, std::size_t n)
const noexcept -> size_type
1548 if (i + n >=
static_cast<std::size_t
>(m_size))
1550 return (*
this)(
static_cast<size_type
>(m_size - 1)) - (*
this)(
static_cast<size_type
>(i)) + 1;
1554 return (*
this)(
static_cast<size_type
>(i + n)) - (*
this)(
static_cast<size_type
>(i));
1559 inline auto xdrop_slice<T>::revert_index(std::size_t i)
const -> size_type
1561 if (i < m_inc.begin()->first)
1567 auto iter = --m_inc.lower_bound(i);
1568 auto check = iter->first + iter->second;
1573 return i - iter->second;
1578 inline bool xdrop_slice<T>::contains(size_type i)
const noexcept
1580 return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? true :
false;
1584 inline bool xdrop_slice<T>::operator==(
const self_type& rhs)
const noexcept
1586 return m_indices == rhs.m_indices;
1590 inline bool xdrop_slice<T>::operator!=(
const self_type& rhs)
const noexcept
1592 return !(*
this == rhs);
standard mathematical functions for xexpressions
auto range(A start_val, B stop_val)
Select a range from start_val to stop_val (excluded).
auto all() noexcept
Returns a slice representing a full dimension, to be used as an argument of view function.
auto newaxis() noexcept
Returns a slice representing a new axis of length one, to be used as an argument of view function.
auto ellipsis() noexcept
Returns a slice representing all remaining dimensions, and selecting all in these dimensions.
auto drop(T &&indices)
Create a non-contigous slice from a container of indices to drop.
auto keep(T &&indices)
Create a non-contigous slice from a container of indices to keep.