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<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 size_type n = stop_val - start_val;
1062 m_size = n / step + (((n < 0) ^ (step > 0)) && (n % step));
1066 template <std::convertible_to<T> S>
1070 ret.m_start =
static_cast<S
>(m_start);
1071 ret.m_size =
static_cast<S
>(m_size);
1072 ret.m_step =
static_cast<S
>(m_step);
1077 template <std::convertible_to<T> S>
1084 inline auto xstepped_range<T>::operator()(size_type i)
const noexcept -> size_type
1086 return m_start + i * m_step;
1090 inline auto xstepped_range<T>::size() const noexcept -> size_type
1096 inline auto xstepped_range<T>::step_size() const noexcept -> size_type
1102 inline auto xstepped_range<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1104 return m_step *
static_cast<size_type
>(n);
1108 inline auto xstepped_range<T>::revert_index(std::size_t i)
const noexcept -> size_type
1110 return (i - m_start) / m_step;
1114 inline bool xstepped_range<T>::contains(size_type i)
const noexcept
1116 return i >= m_start && i < m_start + m_size * m_step && ((i - m_start) % m_step == 0);
1120 inline bool xstepped_range<T>::operator==(
const self_type& rhs)
const noexcept
1122 return (m_start == rhs.m_start) && (m_size == rhs.m_size) && (m_step == rhs.m_step);
1126 inline bool xstepped_range<T>::operator!=(
const self_type& rhs)
const noexcept
1128 return !(*
this == rhs);
1136 inline xall<T>::xall(size_type size) noexcept
1142 template <std::convertible_to<T> S>
1145 return xall<S>(
static_cast<S
>(m_size));
1149 template <std::convertible_to<T> S>
1150 inline xall<S> xall<T>::convert() const noexcept
1156 inline auto xall<T>::operator()(size_type i)
const noexcept -> size_type
1162 inline auto xall<T>::size() const noexcept -> size_type
1168 inline auto xall<T>::step_size() const noexcept -> size_type
1174 inline auto xall<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1176 return static_cast<size_type
>(n);
1180 inline auto xall<T>::revert_index(std::size_t i)
const noexcept -> size_type
1186 inline bool xall<T>::contains(size_type i)
const noexcept
1192 inline bool xall<T>::operator==(
const self_type& rhs)
const noexcept
1194 return m_size == rhs.m_size;
1198 inline bool xall<T>::operator!=(
const self_type& rhs)
const noexcept
1200 return !(*
this == rhs);
1208 template <std::convertible_to<T> S>
1215 template <std::convertible_to<T> S>
1216 inline xnewaxis<S> xnewaxis<T>::convert() const noexcept
1222 inline auto xnewaxis<T>::operator()(size_type)
const noexcept -> size_type
1228 inline auto xnewaxis<T>::size() const noexcept -> size_type
1234 inline auto xnewaxis<T>::step_size() const noexcept -> size_type
1240 inline auto xnewaxis<T>::step_size(std::size_t , std::size_t )
const noexcept -> size_type
1246 inline auto xnewaxis<T>::revert_index(std::size_t i)
const noexcept -> size_type
1252 inline bool xnewaxis<T>::contains(size_type i)
const noexcept
1258 inline bool xnewaxis<T>::operator==(
const self_type& )
const noexcept
1264 inline bool xnewaxis<T>::operator!=(
const self_type& )
const noexcept
1275 inline xkeep_slice<T>::xkeep_slice(C& cont)
1276 requires(!detail::is_xkeep_slice<std::decay_t<C>>::value)
1277 : m_raw_indices(cont.begin(), cont.end())
1282 inline xkeep_slice<T>::xkeep_slice(container_type&& cont)
1283 : m_raw_indices(std::move(cont))
1289 inline xkeep_slice<T>::xkeep_slice(std::initializer_list<S> t)
1290 : m_raw_indices(t.size())
1295 m_raw_indices.begin(),
1298 return static_cast<size_type>(t);
1304 template <std::convertible_to<T> S>
1305 inline xkeep_slice<T>::operator xkeep_slice<S>() const noexcept
1308 using us_type =
typename container_type::size_type;
1309 us_type sz =
static_cast<us_type
>(size());
1310 ret.m_raw_indices.resize(sz);
1311 ret.m_indices.resize(sz);
1313 m_raw_indices.cbegin(),
1314 m_raw_indices.cend(),
1315 ret.m_raw_indices.begin(),
1318 return static_cast<S>(val);
1324 ret.m_indices.begin(),
1327 return static_cast<S>(val);
1334 template <std::convertible_to<T> S>
1335 inline xkeep_slice<S> xkeep_slice<T>::convert() const noexcept
1337 return xkeep_slice<S>(*
this);
1341 inline void xkeep_slice<T>::normalize(std::size_t shape)
1343 m_indices.resize(m_raw_indices.size());
1344 std::size_t sz = m_indices.size();
1345 for (std::size_t i = 0; i < sz; ++i)
1347 m_indices[i] = m_raw_indices[i] < 0 ?
static_cast<size_type
>(shape) + m_raw_indices[i]
1353 inline auto xkeep_slice<T>::operator()(size_type i)
const noexcept -> size_type
1355 return m_indices.size() == size_type(1) ? m_indices.front() : m_indices[
static_cast<std::size_t
>(i)];
1359 inline auto xkeep_slice<T>::size() const noexcept -> size_type
1361 return static_cast<size_type
>(m_raw_indices.size());
1365 inline auto xkeep_slice<T>::step_size(std::size_t i, std::size_t n)
const noexcept -> size_type
1367 if (m_indices.size() == 1)
1371 if (i + n >= m_indices.size())
1373 return m_indices.back() - m_indices[i] + 1;
1377 return m_indices[i + n] - m_indices[i];
1382 inline auto xkeep_slice<T>::revert_index(std::size_t i)
const -> size_type
1384 auto it = std::find(m_indices.begin(), m_indices.end(), i);
1385 if (it != m_indices.end())
1387 return std::distance(m_indices.begin(), it);
1391 XTENSOR_THROW(std::runtime_error,
"Index i (" + std::to_string(i) +
") not in indices of islice.");
1396 inline bool xkeep_slice<T>::contains(size_type i)
const noexcept
1398 return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? false :
true;
1402 inline bool xkeep_slice<T>::operator==(
const self_type& rhs)
const noexcept
1404 return m_indices == rhs.m_indices;
1408 inline bool xkeep_slice<T>::operator!=(
const self_type& rhs)
const noexcept
1410 return !(*
this == rhs);
1419 inline xdrop_slice<T>::xdrop_slice(C& cont)
1420 requires(!detail::is_xdrop_slice<std::decay_t<C>>::value)
1421 : m_raw_indices(cont.begin(), cont.end())
1426 inline xdrop_slice<T>::xdrop_slice(container_type&& cont)
1427 : m_raw_indices(std::move(cont))
1433 inline xdrop_slice<T>::xdrop_slice(std::initializer_list<S> t)
1434 : m_raw_indices(t.size())
1439 m_raw_indices.begin(),
1442 return static_cast<size_type>(t);
1448 template <std::convertible_to<T> S>
1449 inline xdrop_slice<T>::operator xdrop_slice<S>() const noexcept
1452 ret.m_raw_indices.resize(m_raw_indices.size());
1453 ret.m_indices.resize(m_indices.size());
1455 m_raw_indices.cbegin(),
1456 m_raw_indices.cend(),
1457 ret.m_raw_indices.begin(),
1460 return static_cast<S>(val);
1466 ret.m_indices.begin(),
1469 return static_cast<S>(val);
1475 std::inserter(ret.m_inc, ret.m_inc.begin()),
1478 return std::make_pair(static_cast<S>(val.first), static_cast<S>(val.second));
1481 ret.m_size =
static_cast<S
>(m_size);
1486 template <std::convertible_to<T> S>
1487 inline xdrop_slice<S> xdrop_slice<T>::convert() const noexcept
1489 return xdrop_slice<S>(*
this);
1493 inline void xdrop_slice<T>::normalize(std::size_t shape)
1495 m_size =
static_cast<size_type
>(shape - m_raw_indices.size());
1497 m_indices.resize(m_raw_indices.size());
1498 std::size_t sz = m_indices.size();
1499 for (std::size_t i = 0; i < sz; ++i)
1501 m_indices[i] = m_raw_indices[i] < 0 ?
static_cast<size_type
>(shape) + m_raw_indices[i]
1504 size_type cum = size_type(0);
1505 size_type prev_cum = cum;
1506 for (std::size_t i = 0; i < sz; ++i)
1508 std::size_t ind = i;
1509 size_type d = m_indices[i];
1510 while (i + 1 < sz && m_indices[i + 1] == m_indices[i] + 1)
1514 cum += (
static_cast<size_type
>(i) -
static_cast<size_type
>(ind)) + 1;
1515 m_inc[d - prev_cum] = cum;
1521 inline auto xdrop_slice<T>::operator()(size_type i)
const noexcept -> size_type
1523 if (m_inc.empty() || i < m_inc.begin()->first)
1529 auto iter = --m_inc.upper_bound(i);
1530 return i + iter->second;
1535 inline auto xdrop_slice<T>::size() const noexcept -> size_type
1541 inline auto xdrop_slice<T>::step_size(std::size_t i, std::size_t n)
const noexcept -> size_type
1543 if (i + n >=
static_cast<std::size_t
>(m_size))
1545 return (*
this)(
static_cast<size_type
>(m_size - 1)) - (*
this)(
static_cast<size_type
>(i)) + 1;
1549 return (*
this)(
static_cast<size_type
>(i + n)) - (*
this)(
static_cast<size_type
>(i));
1554 inline auto xdrop_slice<T>::revert_index(std::size_t i)
const -> size_type
1556 if (i < m_inc.begin()->first)
1562 auto iter = --m_inc.lower_bound(i);
1563 auto check = iter->first + iter->second;
1568 return i - iter->second;
1573 inline bool xdrop_slice<T>::contains(size_type i)
const noexcept
1575 return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? true :
false;
1579 inline bool xdrop_slice<T>::operator==(
const self_type& rhs)
const noexcept
1581 return m_indices == rhs.m_indices;
1585 inline bool xdrop_slice<T>::operator!=(
const self_type& rhs)
const noexcept
1587 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.