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;
487 template <
class R = std::ptrdiff_t,
class T>
490 if constexpr (xtl::is_integral<std::remove_cvref_t<T>>::value)
493 using container_type =
typename slice_type::container_type;
494 container_type tmp = {
static_cast<R
>(std::forward<T>(indices))};
495 return slice_type(std::move(tmp));
503 template <
class R = std::ptrdiff_t,
class Arg0,
class Arg1,
class... Args>
504 inline xdrop_slice<R>
drop(Arg0 i0, Arg1 i1, Args... args)
506 using slice_type = xdrop_slice<R>;
507 using container_type =
typename slice_type::container_type;
508 container_type tmp = {
static_cast<R
>(i0),
static_cast<R
>(i1),
static_cast<R
>(args)...};
509 return slice_type(std::move(tmp));
516 template <
class A,
class B = A,
class C = A>
517 struct xrange_adaptor
519 xrange_adaptor(A start_val, B stop_val, C step)
526 template <
class MI = A,
class MA = B,
class STEP = C>
527 auto get(std::size_t size)
const
529 if constexpr (xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
531 return get_stepped_range(m_start, m_stop, m_step, size);
533 else if constexpr (!xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
535 return get_stepped_range(
536 m_step > 0 ? 0 :
static_cast<std::ptrdiff_t
>(size) - 1,
542 else if constexpr (xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
544 auto sz =
static_cast<std::ptrdiff_t
>(size);
545 return get_stepped_range(m_start, m_step > 0 ? sz : -(sz + 1), m_step, size);
547 else if constexpr (xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
551 else if constexpr (!xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
553 std::ptrdiff_t start = m_step >= 0 ? 0 :
static_cast<std::ptrdiff_t
>(size) - 1;
554 std::ptrdiff_t stop = m_step >= 0 ?
static_cast<std::ptrdiff_t
>(size) : -1;
557 else if constexpr (xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
561 else if constexpr (!xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
565 else if constexpr (!xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
588 static auto normalize(std::ptrdiff_t val, std::size_t ssize)
590 std::ptrdiff_t size =
static_cast<std::ptrdiff_t
>(ssize);
591 val = (val >= 0) ? val : val + size;
592 return (std::max)(std::ptrdiff_t(0), (std::min)(size, val));
596 get_stepped_range(std::ptrdiff_t start, std::ptrdiff_t stop, std::ptrdiff_t step, std::size_t ssize)
598 std::ptrdiff_t size =
static_cast<std::ptrdiff_t
>(ssize);
599 start = (start >= 0) ? start : start + size;
600 stop = (stop >= 0) ? stop : stop + size;
604 start = (std::max)(std::ptrdiff_t(0), (std::min)(size, start));
605 stop = (std::max)(std::ptrdiff_t(0), (std::min)(size, stop));
609 start = (std::max)(std::ptrdiff_t(-1), (std::min)(size - 1, start));
610 stop = (std::max)(std::ptrdiff_t(-1), (std::min)(size - 1, stop));
625 namespace placeholders
632 template <
class... Args>
635 std::ptrdiff_t rng[3];
638 constexpr xtuph get_tuph_or_val(std::ptrdiff_t , std::true_type)
643 constexpr std::ptrdiff_t get_tuph_or_val(std::ptrdiff_t val, std::false_type)
648 template <
class A,
class B,
class C>
654 {get_tuph_or_val(rng[0], std::is_same<A, xtuph>()),
655 get_tuph_or_val(rng[1], std::is_same<B, xtuph>()),
656 get_tuph_or_val(rng[2], std::is_same<C, xtuph>())}
660 std::ptrdiff_t rng[3];
663 template <
class A,
class B>
669 {get_tuph_or_val(rng[0], std::is_same<A, xtuph>()),
670 get_tuph_or_val(rng[1], std::is_same<B, xtuph>()),
675 std::ptrdiff_t rng[3];
678 template <
class... OA>
681 auto nrng =
rangemaker<OA..., std::ptrdiff_t>({rng.rng[0], rng.rng[1], rng.rng[2]});
682 nrng.rng[
sizeof...(OA)] = t;
686 template <
class... OA>
695 constexpr xall_tag _a{};
696 constexpr xnewaxis_tag _n{};
697 constexpr xellipsis_tag _e{};
708 struct cast_if_integer
710 using type = std::conditional_t<xtl::is_integral<T>::value, std::ptrdiff_t, T>;
714 return static_cast<type
>(t);
719 using cast_if_integer_t =
typename cast_if_integer<T>::type;
736 template <
class A,
class B>
737 inline auto range(A start_val, B stop_val)
740 detail::cast_if_integer<A>{}(start_val),
741 detail::cast_if_integer<B>{}(stop_val),
757 template <
class A,
class B,
class C>
758 inline auto range(A start_val, B stop_val, C step)
761 detail::cast_if_integer<A>{}(start_val),
762 detail::cast_if_integer<B>{}(stop_val),
763 detail::cast_if_integer<C>{}(step)
772 inline std::size_t get_size(
const S& slice)
noexcept
774 if constexpr (is_xslice<S>::value)
776 return static_cast<std::size_t
>(slice.size());
789 inline std::size_t step_size(
const S& slice, std::size_t idx)
noexcept
791 if constexpr (is_xslice<S>::value)
793 return static_cast<std::size_t
>(slice.step_size(idx));
802 inline std::size_t step_size(
const S& slice, std::size_t idx, std::size_t n)
noexcept
804 if constexpr (is_xslice<S>::value)
806 return static_cast<std::size_t
>(slice.step_size(idx, n));
818 template <
class S,
class I>
819 inline std::size_t value(
const S& slice, I i)
noexcept
821 if constexpr (is_xslice<S>::value)
823 using ST =
typename S::size_type;
824 return static_cast<std::size_t
>(slice(
static_cast<ST
>(i)));
828 return static_cast<std::size_t
>(slice);
839 struct slice_implementation_getter
841 template <
class E,
class SL>
842 inline decltype(
auto)
operator()(E& e, SL&& slice, std::size_t index)
const
844 return get_slice(e, std::forward<SL>(slice), index, xtl::is_signed<std::decay_t<SL>>());
849 template <
class E,
class SL>
850 inline decltype(
auto) get_slice(E&, SL&& slice, std::size_t, std::false_type)
const
852 return std::forward<SL>(slice);
855 template <
class E,
class SL>
856 inline decltype(
auto) get_slice(E& e, SL&& slice, std::size_t index, std::true_type)
const
858 using int_type = std::decay_t<SL>;
859 return slice < int_type(0) ? slice + static_cast<std::ptrdiff_t>(e.shape(index))
860 : std::ptrdiff_t(slice);
864 struct keep_drop_getter
866 template <
class E,
class SL>
867 inline decltype(
auto)
operator()(E& e, SL&& slice, std::size_t index)
const
869 slice.normalize(e.shape()[index]);
870 return std::forward<SL>(slice);
873 template <
class E,
class SL>
874 inline auto operator()(E& e,
const SL& slice, std::size_t index)
const
876 return this->operator()(e, SL(slice), index);
881 struct slice_implementation_getter<xkeep_slice<T>> : keep_drop_getter
886 struct slice_implementation_getter<xdrop_slice<T>> : keep_drop_getter
891 struct slice_implementation_getter<xall_tag>
893 template <
class E,
class SL>
894 inline auto operator()(E& e, SL&&, std::size_t index)
const
896 return xall<typename E::size_type>(e.shape()[index]);
901 struct slice_implementation_getter<xnewaxis_tag>
903 template <
class E,
class SL>
904 inline auto operator()(E&, SL&&, std::size_t)
const
906 return xnewaxis<typename E::size_type>();
910 template <
class A,
class B,
class C>
911 struct slice_implementation_getter<xrange_adaptor<A, B, C>>
913 template <
class E,
class SL>
914 inline auto operator()(E& e, SL&& adaptor, std::size_t index)
const
916 return adaptor.get(e.shape()[index]);
921 template <
class E,
class SL>
922 inline auto get_slice_implementation(E& e, SL&& slice, std::size_t index)
924 detail::slice_implementation_getter<std::decay_t<SL>> getter;
925 return getter(e, std::forward<SL>(slice), index);
934 template <
class E,
class SL>
935 struct get_slice_type_impl
941 struct get_slice_type_impl<E, xall_tag>
943 using type = xall<typename E::size_type>;
947 struct get_slice_type_impl<E, xnewaxis_tag>
949 using type = xnewaxis<typename E::size_type>;
952 template <
class E,
class A,
class B,
class C>
953 struct get_slice_type_impl<E, xrange_adaptor<A, B, C>>
955 using type =
decltype(xrange_adaptor<A, B, C>(A(), B(), C()).get(0));
959 template <
class E,
class SL>
960 using get_slice_type =
typename detail::get_slice_type_impl<E, std::remove_reference_t<SL>>::type;
967 inline auto xslice<D>::derived_cast() noexcept -> derived_type&
969 return *
static_cast<derived_type*
>(
this);
973 inline auto xslice<D>::derived_cast() const noexcept -> const derived_type&
975 return *
static_cast<const derived_type*
>(
this);
983 inline xrange<T>::xrange(size_type start_val, size_type stop_val) noexcept
985 , m_size(stop_val > start_val ? stop_val - start_val : 0)
990 template <std::convertible_to<T> S>
994 ret.m_start =
static_cast<S
>(m_start);
995 ret.m_size =
static_cast<S
>(m_size);
1000 template <std::convertible_to<T> S>
1001 inline xrange<S> xrange<T>::convert() const noexcept
1007 inline auto xrange<T>::operator()(size_type i)
const noexcept -> size_type
1013 inline auto xrange<T>::size() const noexcept -> size_type
1019 inline auto xrange<T>::step_size() const noexcept -> size_type
1025 inline auto xrange<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1027 return static_cast<size_type
>(n);
1031 inline auto xrange<T>::revert_index(std::size_t i)
const noexcept -> size_type
1037 inline bool xrange<T>::contains(size_type i)
const noexcept
1039 return i >= m_start && i < m_start + m_size;
1043 inline bool xrange<T>::operator==(
const self_type& rhs)
const noexcept
1045 return (m_start == rhs.m_start) && (m_size == rhs.m_size);
1049 inline bool xrange<T>::operator!=(
const self_type& rhs)
const noexcept
1051 return !(*
this == rhs);
1059 inline xstepped_range<T>::xstepped_range(size_type start_val, size_type stop_val, size_type step) noexcept
1060 : m_start(start_val)
1061 , m_size(size_type(0))
1064 if ((step > 0 && start_val >= stop_val) || (step < 0 && start_val <= stop_val))
1069 size_type n = stop_val - start_val;
1070 m_size = n / step +
static_cast<bool>(n % step);
1074 template <std::convertible_to<T> S>
1078 ret.m_start =
static_cast<S
>(m_start);
1079 ret.m_size =
static_cast<S
>(m_size);
1080 ret.m_step =
static_cast<S
>(m_step);
1085 template <std::convertible_to<T> S>
1092 inline auto xstepped_range<T>::operator()(size_type i)
const noexcept -> size_type
1094 return m_start + i * m_step;
1098 inline auto xstepped_range<T>::size() const noexcept -> size_type
1104 inline auto xstepped_range<T>::step_size() const noexcept -> size_type
1110 inline auto xstepped_range<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1112 return m_step *
static_cast<size_type
>(n);
1116 inline auto xstepped_range<T>::revert_index(std::size_t i)
const noexcept -> size_type
1118 return (i - m_start) / m_step;
1122 inline bool xstepped_range<T>::contains(size_type i)
const noexcept
1124 return i >= m_start && i < m_start + m_size * m_step && ((i - m_start) % m_step == 0);
1128 inline bool xstepped_range<T>::operator==(
const self_type& rhs)
const noexcept
1130 return (m_start == rhs.m_start) && (m_size == rhs.m_size) && (m_step == rhs.m_step);
1134 inline bool xstepped_range<T>::operator!=(
const self_type& rhs)
const noexcept
1136 return !(*
this == rhs);
1144 inline xall<T>::xall(size_type size) noexcept
1150 template <std::convertible_to<T> S>
1153 return xall<S>(
static_cast<S
>(m_size));
1157 template <std::convertible_to<T> S>
1158 inline xall<S> xall<T>::convert() const noexcept
1164 inline auto xall<T>::operator()(size_type i)
const noexcept -> size_type
1170 inline auto xall<T>::size() const noexcept -> size_type
1176 inline auto xall<T>::step_size() const noexcept -> size_type
1182 inline auto xall<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1184 return static_cast<size_type
>(n);
1188 inline auto xall<T>::revert_index(std::size_t i)
const noexcept -> size_type
1194 inline bool xall<T>::contains(size_type i)
const noexcept
1200 inline bool xall<T>::operator==(
const self_type& rhs)
const noexcept
1202 return m_size == rhs.m_size;
1206 inline bool xall<T>::operator!=(
const self_type& rhs)
const noexcept
1208 return !(*
this == rhs);
1216 template <std::convertible_to<T> S>
1223 template <std::convertible_to<T> S>
1224 inline xnewaxis<S> xnewaxis<T>::convert() const noexcept
1230 inline auto xnewaxis<T>::operator()(size_type)
const noexcept -> size_type
1236 inline auto xnewaxis<T>::size() const noexcept -> size_type
1242 inline auto xnewaxis<T>::step_size() const noexcept -> size_type
1248 inline auto xnewaxis<T>::step_size(std::size_t , std::size_t )
const noexcept -> size_type
1254 inline auto xnewaxis<T>::revert_index(std::size_t i)
const noexcept -> size_type
1260 inline bool xnewaxis<T>::contains(size_type i)
const noexcept
1266 inline bool xnewaxis<T>::operator==(
const self_type& )
const noexcept
1272 inline bool xnewaxis<T>::operator!=(
const self_type& )
const noexcept
1283 inline xkeep_slice<T>::xkeep_slice(C& cont)
1284 requires(!detail::is_xkeep_slice<std::decay_t<C>>::value)
1285 : m_raw_indices(cont.begin(), cont.end())
1290 inline xkeep_slice<T>::xkeep_slice(container_type&& cont)
1291 : m_raw_indices(std::move(cont))
1297 inline xkeep_slice<T>::xkeep_slice(std::initializer_list<S> t)
1298 : m_raw_indices(t.size())
1303 m_raw_indices.begin(),
1306 return static_cast<size_type>(t);
1312 template <std::convertible_to<T> S>
1313 inline xkeep_slice<T>::operator xkeep_slice<S>() const noexcept
1316 using us_type =
typename container_type::size_type;
1317 us_type sz =
static_cast<us_type
>(size());
1318 ret.m_raw_indices.resize(sz);
1319 ret.m_indices.resize(sz);
1321 m_raw_indices.cbegin(),
1322 m_raw_indices.cend(),
1323 ret.m_raw_indices.begin(),
1326 return static_cast<S>(val);
1332 ret.m_indices.begin(),
1335 return static_cast<S>(val);
1342 template <std::convertible_to<T> S>
1343 inline xkeep_slice<S> xkeep_slice<T>::convert() const noexcept
1345 return xkeep_slice<S>(*
this);
1349 inline void xkeep_slice<T>::normalize(std::size_t shape)
1351 m_indices.resize(m_raw_indices.size());
1352 std::size_t sz = m_indices.size();
1353 for (std::size_t i = 0; i < sz; ++i)
1355 m_indices[i] = m_raw_indices[i] < 0 ?
static_cast<size_type
>(shape) + m_raw_indices[i]
1361 inline auto xkeep_slice<T>::operator()(size_type i)
const noexcept -> size_type
1363 return m_indices.size() == size_type(1) ? m_indices.front() : m_indices[
static_cast<std::size_t
>(i)];
1367 inline auto xkeep_slice<T>::size() const noexcept -> size_type
1369 return static_cast<size_type
>(m_raw_indices.size());
1373 inline auto xkeep_slice<T>::step_size(std::size_t i, std::size_t n)
const noexcept -> size_type
1375 if (m_indices.size() == 1)
1379 if (i + n >= m_indices.size())
1381 return m_indices.back() - m_indices[i] + 1;
1385 return m_indices[i + n] - m_indices[i];
1390 inline auto xkeep_slice<T>::revert_index(std::size_t i)
const -> size_type
1392 auto it = std::find(m_indices.begin(), m_indices.end(), i);
1393 if (it != m_indices.end())
1395 return std::distance(m_indices.begin(), it);
1399 XTENSOR_THROW(std::runtime_error,
"Index i (" + std::to_string(i) +
") not in indices of islice.");
1404 inline bool xkeep_slice<T>::contains(size_type i)
const noexcept
1406 return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? false :
true;
1410 inline bool xkeep_slice<T>::operator==(
const self_type& rhs)
const noexcept
1412 return m_indices == rhs.m_indices;
1416 inline bool xkeep_slice<T>::operator!=(
const self_type& rhs)
const noexcept
1418 return !(*
this == rhs);
1427 inline xdrop_slice<T>::xdrop_slice(C& cont)
1428 requires(!detail::is_xdrop_slice<std::decay_t<C>>::value)
1429 : m_raw_indices(cont.begin(), cont.end())
1434 inline xdrop_slice<T>::xdrop_slice(container_type&& cont)
1435 : m_raw_indices(std::move(cont))
1441 inline xdrop_slice<T>::xdrop_slice(std::initializer_list<S> t)
1442 : m_raw_indices(t.size())
1447 m_raw_indices.begin(),
1450 return static_cast<size_type>(t);
1456 template <std::convertible_to<T> S>
1457 inline xdrop_slice<T>::operator xdrop_slice<S>() const noexcept
1460 ret.m_raw_indices.resize(m_raw_indices.size());
1461 ret.m_indices.resize(m_indices.size());
1463 m_raw_indices.cbegin(),
1464 m_raw_indices.cend(),
1465 ret.m_raw_indices.begin(),
1468 return static_cast<S>(val);
1474 ret.m_indices.begin(),
1477 return static_cast<S>(val);
1483 std::inserter(ret.m_inc, ret.m_inc.begin()),
1486 return std::make_pair(static_cast<S>(val.first), static_cast<S>(val.second));
1489 ret.m_size =
static_cast<S
>(m_size);
1494 template <std::convertible_to<T> S>
1495 inline xdrop_slice<S> xdrop_slice<T>::convert() const noexcept
1497 return xdrop_slice<S>(*
this);
1501 inline void xdrop_slice<T>::normalize(std::size_t shape)
1503 m_size =
static_cast<size_type
>(shape - m_raw_indices.size());
1505 m_indices.resize(m_raw_indices.size());
1506 std::size_t sz = m_indices.size();
1507 for (std::size_t i = 0; i < sz; ++i)
1509 m_indices[i] = m_raw_indices[i] < 0 ?
static_cast<size_type
>(shape) + m_raw_indices[i]
1513 size_type cum = size_type(0);
1514 size_type prev_cum = cum;
1515 for (std::size_t i = 0; i < sz; ++i)
1517 std::size_t ind = i;
1518 size_type d = m_indices[i];
1519 while (i + 1 < sz && m_indices[i + 1] == m_indices[i] + 1)
1523 cum += (
static_cast<size_type
>(i) -
static_cast<size_type
>(ind)) + 1;
1524 m_inc[d - prev_cum] = cum;
1530 inline auto xdrop_slice<T>::operator()(size_type i)
const noexcept -> size_type
1532 if (m_inc.empty() || i < m_inc.begin()->first)
1538 auto iter = --m_inc.upper_bound(i);
1539 return i + iter->second;
1544 inline auto xdrop_slice<T>::size() const noexcept -> size_type
1550 inline auto xdrop_slice<T>::step_size(std::size_t i, std::size_t n)
const noexcept -> size_type
1552 if (i + n >=
static_cast<std::size_t
>(m_size))
1554 return (*
this)(
static_cast<size_type
>(m_size - 1)) - (*
this)(
static_cast<size_type
>(i)) + 1;
1558 return (*
this)(
static_cast<size_type
>(i + n)) - (*
this)(
static_cast<size_type
>(i));
1563 inline auto xdrop_slice<T>::revert_index(std::size_t i)
const -> size_type
1565 if (i < m_inc.begin()->first)
1571 auto iter = --m_inc.lower_bound(i);
1572 auto check = iter->first + iter->second;
1577 return i - iter->second;
1582 inline bool xdrop_slice<T>::contains(size_type i)
const noexcept
1584 return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? true :
false;
1588 inline bool xdrop_slice<T>::operator==(
const self_type& rhs)
const noexcept
1590 return m_indices == rhs.m_indices;
1594 inline bool xdrop_slice<T>::operator!=(
const self_type& rhs)
const noexcept
1596 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 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.