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"
24#ifndef XTENSOR_CONSTEXPR
25#if (defined(_MSC_VER) || __GNUC__ < 8)
26#define XTENSOR_CONSTEXPR inline
27#define XTENSOR_GLOBAL_CONSTEXPR static const
29#define XTENSOR_CONSTEXPR constexpr
30#define XTENSOR_GLOBAL_CONSTEXPR constexpr
46 using derived_type = D;
48 derived_type& derived_cast()
noexcept;
49 const derived_type& derived_cast()
const noexcept;
56 xslice(
const xslice&) =
default;
57 xslice& operator=(
const xslice&) =
default;
59 xslice(xslice&&) =
default;
60 xslice& operator=(xslice&&) =
default;
64 using is_xslice = std::is_base_of<xslice<S>, S>;
67 using has_xslice = std::disjunction<is_xslice<E>...>;
73#define DEFINE_TAG_CONVERSION(NAME) \
75 XTENSOR_CONSTEXPR NAME convert() const noexcept \
95#undef DEFINE_TAG_CONVERSION
102 class xrange :
public xslice<xrange<T>>
107 using self_type = xrange<T>;
110 xrange(size_type start_val, size_type stop_val)
noexcept;
112 template <std::convertible_to<T> S>
113 operator xrange<S>()
const noexcept;
117 template <std::convertible_to<T> S>
118 xrange<S> convert()
const noexcept;
120 size_type operator()(size_type i)
const noexcept;
122 size_type size()
const noexcept;
123 size_type step_size()
const noexcept;
124 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
125 size_type revert_index(std::size_t i)
const noexcept;
127 bool contains(size_type i)
const noexcept;
129 bool operator==(
const self_type& rhs)
const noexcept;
130 bool operator!=(
const self_type& rhs)
const noexcept;
146 class xstepped_range :
public xslice<xstepped_range<T>>
151 using self_type = xstepped_range<T>;
153 xstepped_range() =
default;
154 xstepped_range(size_type start_val, size_type stop_val, size_type step)
noexcept;
156 template <std::convertible_to<T> S>
157 operator xstepped_range<S>()
const noexcept;
161 template <std::convertible_to<T> S>
162 xstepped_range<S> convert()
const noexcept;
164 size_type operator()(size_type i)
const noexcept;
166 size_type size()
const noexcept;
167 size_type step_size()
const noexcept;
168 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
169 size_type revert_index(std::size_t i)
const noexcept;
171 bool contains(size_type i)
const noexcept;
173 bool operator==(
const self_type& rhs)
const noexcept;
174 bool operator!=(
const self_type& rhs)
const noexcept;
183 friend class xstepped_range;
191 class xall :
public xslice<xall<T>>
196 using self_type = xall<T>;
199 explicit xall(size_type size)
noexcept;
201 template <std::convertible_to<T> S>
202 operator xall<S>()
const noexcept;
206 template <std::convertible_to<T> S>
207 xall<S> convert()
const noexcept;
209 size_type operator()(size_type i)
const noexcept;
211 size_type size()
const noexcept;
212 size_type step_size()
const noexcept;
213 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
214 size_type revert_index(std::size_t i)
const noexcept;
216 bool contains(size_type i)
const noexcept;
218 bool operator==(
const self_type& rhs)
const noexcept;
219 bool operator!=(
const self_type& rhs)
const noexcept;
231 inline auto all() noexcept
262 class xnewaxis :
public xslice<xnewaxis<T>>
267 using self_type = xnewaxis<T>;
269 xnewaxis() =
default;
271 template <std::convertible_to<T> S>
272 operator xnewaxis<S>()
const noexcept;
276 template <std::convertible_to<T> S>
277 xnewaxis<S> convert()
const noexcept;
279 size_type operator()(size_type i)
const noexcept;
281 size_type size()
const noexcept;
282 size_type step_size()
const noexcept;
283 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
284 size_type revert_index(std::size_t i)
const noexcept;
286 bool contains(size_type i)
const noexcept;
288 bool operator==(
const self_type& rhs)
const noexcept;
289 bool operator!=(
const self_type& rhs)
const noexcept;
312 struct is_xkeep_slice : std::false_type
317 struct is_xkeep_slice<xkeep_slice<T>> : std::true_type
323 class xkeep_slice :
public xslice<xkeep_slice<T>>
328 using size_type =
typename container_type::value_type;
329 using self_type = xkeep_slice<T>;
332 explicit xkeep_slice(C& cont)
333 requires(!detail::is_xkeep_slice<std::decay_t<C>>::value);
334 explicit xkeep_slice(container_type&& cont);
337 xkeep_slice(std::initializer_list<S> t);
339 template <std::convertible_to<T> S>
340 operator xkeep_slice<S>()
const noexcept;
344 template <std::convertible_to<T> S>
345 xkeep_slice<S> convert()
const noexcept;
347 size_type operator()(size_type i)
const noexcept;
348 size_type size()
const noexcept;
350 void normalize(std::size_t s);
352 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
353 size_type revert_index(std::size_t i)
const;
355 bool contains(size_type i)
const noexcept;
357 bool operator==(
const self_type& rhs)
const noexcept;
358 bool operator!=(
const self_type& rhs)
const noexcept;
362 xkeep_slice() =
default;
364 container_type m_indices;
365 container_type m_raw_indices;
368 friend class xkeep_slice;
385 template <
class R = std::ptrdiff_t,
class T>
388 if constexpr (xtl::is_integral<std::decay_t<T>>::value)
391 using container_type =
typename slice_type::container_type;
392 container_type tmp = {
static_cast<R
>(std::forward<T>(indices))};
393 return slice_type(std::move(tmp));
401 template <
class R = std::ptrdiff_t,
class Arg0,
class Arg1,
class... Args>
402 inline xkeep_slice<R>
keep(Arg0 i0, Arg1 i1, Args... args)
404 using slice_type = xkeep_slice<R>;
405 using container_type =
typename slice_type::container_type;
406 container_type tmp = {
static_cast<R
>(i0),
static_cast<R
>(i1),
static_cast<R
>(args)...};
407 return slice_type(std::move(tmp));
420 struct is_xdrop_slice : std::false_type
425 struct is_xdrop_slice<xdrop_slice<T>> : std::true_type
431 class xdrop_slice :
public xslice<xdrop_slice<T>>
436 using size_type =
typename container_type::value_type;
437 using self_type = xdrop_slice<T>;
440 explicit xdrop_slice(C& cont)
441 requires(!detail::is_xdrop_slice<std::decay_t<C>>::value);
442 explicit xdrop_slice(container_type&& cont);
445 xdrop_slice(std::initializer_list<S> t);
447 template <std::convertible_to<T> S>
448 operator xdrop_slice<S>()
const noexcept;
452 template <std::convertible_to<T> S>
453 xdrop_slice<S> convert()
const noexcept;
455 size_type operator()(size_type i)
const noexcept;
456 size_type size()
const noexcept;
458 void normalize(std::size_t s);
460 size_type step_size(std::size_t i, std::size_t n = 1)
const noexcept;
461 size_type revert_index(std::size_t i)
const;
463 bool contains(size_type i)
const noexcept;
465 bool operator==(
const self_type& rhs)
const noexcept;
466 bool operator!=(
const self_type& rhs)
const noexcept;
470 xdrop_slice() =
default;
472 container_type m_indices;
473 container_type m_raw_indices;
474 std::map<size_type, size_type> m_inc;
478 friend class xdrop_slice;
494 template <
class R = std::ptrdiff_t,
class T>
497 if constexpr (xtl::is_integral<T>::value)
500 using container_type =
typename slice_type::container_type;
501 container_type tmp = {
static_cast<R
>(std::forward<T>(indices))};
502 return slice_type(std::move(tmp));
510 template <
class R = std::ptrdiff_t,
class Arg0,
class Arg1,
class... Args>
511 inline xdrop_slice<R>
drop(Arg0 i0, Arg1 i1, Args... args)
513 using slice_type = xdrop_slice<R>;
514 using container_type =
typename slice_type::container_type;
515 container_type tmp = {
static_cast<R
>(i0),
static_cast<R
>(i1),
static_cast<R
>(args)...};
516 return slice_type(std::move(tmp));
523 template <
class A,
class B = A,
class C = A>
524 struct xrange_adaptor
526 xrange_adaptor(A start_val, B stop_val, C step)
533 template <
class MI = A,
class MA = B,
class STEP = C>
534 auto get(std::size_t size)
const
536 if constexpr (xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
538 return get_stepped_range(m_start, m_stop, m_step, size);
540 else if constexpr (!xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
542 return get_stepped_range(
543 m_step > 0 ? 0 :
static_cast<std::ptrdiff_t
>(size) - 1,
549 else if constexpr (xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && xtl::is_integral<STEP>::value)
551 auto sz =
static_cast<std::ptrdiff_t
>(size);
552 return get_stepped_range(m_start, m_step > 0 ? sz : -(sz + 1), m_step, size);
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)
560 std::ptrdiff_t start = m_step >= 0 ? 0 :
static_cast<std::ptrdiff_t
>(size) - 1;
561 std::ptrdiff_t stop = m_step >= 0 ?
static_cast<std::ptrdiff_t
>(size) : -1;
564 else if constexpr (xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
568 else if constexpr (!xtl::is_integral<MI>::value && xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
572 else if constexpr (!xtl::is_integral<MI>::value && !xtl::is_integral<MA>::value && !xtl::is_integral<STEP>::value)
595 static auto normalize(std::ptrdiff_t val, std::size_t ssize)
597 std::ptrdiff_t size =
static_cast<std::ptrdiff_t
>(ssize);
598 val = (val >= 0) ? val : val + size;
599 return (std::max)(std::ptrdiff_t(0), (std::min)(size, val));
603 get_stepped_range(std::ptrdiff_t start, std::ptrdiff_t stop, std::ptrdiff_t step, std::size_t ssize)
605 std::ptrdiff_t size =
static_cast<std::ptrdiff_t
>(ssize);
606 start = (start >= 0) ? start : start + size;
607 stop = (stop >= 0) ? stop : stop + size;
611 start = (std::max)(std::ptrdiff_t(0), (std::min)(size, start));
612 stop = (std::max)(std::ptrdiff_t(0), (std::min)(size, stop));
616 start = (std::max)(std::ptrdiff_t(-1), (std::min)(size - 1, start));
617 stop = (std::max)(std::ptrdiff_t(-1), (std::min)(size - 1, stop));
632 namespace placeholders
639 template <
class... Args>
642 std::ptrdiff_t rng[3];
645 XTENSOR_CONSTEXPR
xtuph get_tuph_or_val(std::ptrdiff_t , std::true_type)
650 XTENSOR_CONSTEXPR std::ptrdiff_t get_tuph_or_val(std::ptrdiff_t val, std::false_type)
655 template <
class A,
class B,
class C>
661 {get_tuph_or_val(rng[0], std::is_same<A, xtuph>()),
662 get_tuph_or_val(rng[1], std::is_same<B, xtuph>()),
663 get_tuph_or_val(rng[2], std::is_same<C, xtuph>())}
667 std::ptrdiff_t rng[3];
670 template <
class A,
class B>
676 {get_tuph_or_val(rng[0], std::is_same<A, xtuph>()),
677 get_tuph_or_val(rng[1], std::is_same<B, xtuph>()),
682 std::ptrdiff_t rng[3];
685 template <
class... OA>
686 XTENSOR_CONSTEXPR
auto operator|(
const rangemaker<OA...>& rng,
const std::ptrdiff_t& t)
688 auto nrng =
rangemaker<OA..., std::ptrdiff_t>({rng.rng[0], rng.rng[1], rng.rng[2]});
689 nrng.rng[
sizeof...(OA)] = t;
693 template <
class... OA>
700 XTENSOR_GLOBAL_CONSTEXPR
xtuph _{};
702 XTENSOR_GLOBAL_CONSTEXPR xall_tag _a{};
703 XTENSOR_GLOBAL_CONSTEXPR xnewaxis_tag _n{};
704 XTENSOR_GLOBAL_CONSTEXPR xellipsis_tag _e{};
715 struct cast_if_integer
717 using type = std::conditional_t<xtl::is_integral<T>::value, std::ptrdiff_t, T>;
721 return (xtl::is_integral<T>::value) ?
static_cast<type
>(t) : t;
726 using cast_if_integer_t =
typename cast_if_integer<T>::type;
743 template <
class A,
class B>
744 inline auto range(A start_val, B stop_val)
747 detail::cast_if_integer<A>{}(start_val),
748 detail::cast_if_integer<B>{}(stop_val),
764 template <
class A,
class B,
class C>
765 inline auto range(A start_val, B stop_val, C step)
768 detail::cast_if_integer<A>{}(start_val),
769 detail::cast_if_integer<B>{}(stop_val),
770 detail::cast_if_integer<C>{}(step)
779 inline std::size_t get_size(
const S& slice)
noexcept
781 if constexpr (is_xslice<S>::value)
796 inline std::size_t step_size(
const S& slice, std::size_t idx)
noexcept
798 if constexpr (is_xslice<S>::value)
800 return slice.step_size(idx);
809 inline std::size_t step_size(
const S& slice, std::size_t idx, std::size_t n)
noexcept
811 if constexpr (is_xslice<S>::value)
813 return slice.step_size(idx, n);
825 template <
class S,
class I>
826 inline std::size_t value(
const S& slice, I i)
noexcept
828 if constexpr (is_xslice<S>::value)
830 using ST =
typename S::size_type;
831 return slice(
static_cast<ST
>(i));
835 return static_cast<std::size_t
>(slice);
846 struct slice_implementation_getter
848 template <
class E,
class SL>
849 inline decltype(
auto)
operator()(E& e, SL&& slice, std::size_t index)
const
851 return get_slice(e, std::forward<SL>(slice), index, xtl::is_signed<std::decay_t<SL>>());
856 template <
class E,
class SL>
857 inline decltype(
auto) get_slice(E&, SL&& slice, std::size_t, std::false_type)
const
859 return std::forward<SL>(slice);
862 template <
class E,
class SL>
863 inline decltype(
auto) get_slice(E& e, SL&& slice, std::size_t index, std::true_type)
const
865 using int_type = std::decay_t<SL>;
866 return slice < int_type(0) ? slice + static_cast<std::ptrdiff_t>(e.shape(index))
867 : std::ptrdiff_t(slice);
871 struct keep_drop_getter
873 template <
class E,
class SL>
874 inline decltype(
auto)
operator()(E& e, SL&& slice, std::size_t index)
const
876 slice.normalize(e.shape()[index]);
877 return std::forward<SL>(slice);
880 template <
class E,
class SL>
881 inline auto operator()(E& e,
const SL& slice, std::size_t index)
const
883 return this->operator()(e, SL(slice), index);
888 struct slice_implementation_getter<xkeep_slice<T>> : keep_drop_getter
893 struct slice_implementation_getter<xdrop_slice<T>> : keep_drop_getter
898 struct slice_implementation_getter<xall_tag>
900 template <
class E,
class SL>
901 inline auto operator()(E& e, SL&&, std::size_t index)
const
903 return xall<typename E::size_type>(e.shape()[index]);
908 struct slice_implementation_getter<xnewaxis_tag>
910 template <
class E,
class SL>
911 inline auto operator()(E&, SL&&, std::size_t)
const
913 return xnewaxis<typename E::size_type>();
917 template <
class A,
class B,
class C>
918 struct slice_implementation_getter<xrange_adaptor<A, B, C>>
920 template <
class E,
class SL>
921 inline auto operator()(E& e, SL&& adaptor, std::size_t index)
const
923 return adaptor.get(e.shape()[index]);
928 template <
class E,
class SL>
929 inline auto get_slice_implementation(E& e, SL&& slice, std::size_t index)
931 detail::slice_implementation_getter<std::decay_t<SL>> getter;
932 return getter(e, std::forward<SL>(slice), index);
941 template <
class E,
class SL>
942 struct get_slice_type_impl
948 struct get_slice_type_impl<E, xall_tag>
950 using type = xall<typename E::size_type>;
954 struct get_slice_type_impl<E, xnewaxis_tag>
956 using type = xnewaxis<typename E::size_type>;
959 template <
class E,
class A,
class B,
class C>
960 struct get_slice_type_impl<E, xrange_adaptor<A, B, C>>
962 using type =
decltype(xrange_adaptor<A, B, C>(A(), B(), C()).get(0));
966 template <
class E,
class SL>
967 using get_slice_type =
typename detail::get_slice_type_impl<E, std::remove_reference_t<SL>>::type;
974 inline auto xslice<D>::derived_cast() noexcept -> derived_type&
976 return *
static_cast<derived_type*
>(
this);
980 inline auto xslice<D>::derived_cast() const noexcept -> const derived_type&
982 return *
static_cast<const derived_type*
>(
this);
990 inline xrange<T>::xrange(size_type start_val, size_type stop_val) noexcept
992 , m_size(stop_val > start_val ? stop_val - start_val : 0)
997 template <std::convertible_to<T> S>
1001 ret.m_start =
static_cast<S
>(m_start);
1002 ret.m_size =
static_cast<S
>(m_size);
1007 template <std::convertible_to<T> S>
1008 inline xrange<S> xrange<T>::convert() const noexcept
1014 inline auto xrange<T>::operator()(size_type i)
const noexcept -> size_type
1020 inline auto xrange<T>::size() const noexcept -> size_type
1026 inline auto xrange<T>::step_size() const noexcept -> size_type
1032 inline auto xrange<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1034 return static_cast<size_type
>(n);
1038 inline auto xrange<T>::revert_index(std::size_t i)
const noexcept -> size_type
1044 inline bool xrange<T>::contains(size_type i)
const noexcept
1046 return i >= m_start && i < m_start + m_size;
1050 inline bool xrange<T>::operator==(
const self_type& rhs)
const noexcept
1052 return (m_start == rhs.m_start) && (m_size == rhs.m_size);
1056 inline bool xrange<T>::operator!=(
const self_type& rhs)
const noexcept
1058 return !(*
this == rhs);
1066 inline xstepped_range<T>::xstepped_range(size_type start_val, size_type stop_val, size_type step) noexcept
1067 : m_start(start_val)
1068 , m_size(size_type(0))
1071 size_type n = stop_val - start_val;
1072 m_size = n / step + (((n < 0) ^ (step > 0)) && (n % step));
1076 template <std::convertible_to<T> S>
1080 ret.m_start =
static_cast<S
>(m_start);
1081 ret.m_size =
static_cast<S
>(m_size);
1082 ret.m_step =
static_cast<S
>(m_step);
1087 template <std::convertible_to<T> S>
1094 inline auto xstepped_range<T>::operator()(size_type i)
const noexcept -> size_type
1096 return m_start + i * m_step;
1100 inline auto xstepped_range<T>::size() const noexcept -> size_type
1106 inline auto xstepped_range<T>::step_size() const noexcept -> size_type
1112 inline auto xstepped_range<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1114 return m_step *
static_cast<size_type
>(n);
1118 inline auto xstepped_range<T>::revert_index(std::size_t i)
const noexcept -> size_type
1120 return (i - m_start) / m_step;
1124 inline bool xstepped_range<T>::contains(size_type i)
const noexcept
1126 return i >= m_start && i < m_start + m_size * m_step && ((i - m_start) % m_step == 0);
1130 inline bool xstepped_range<T>::operator==(
const self_type& rhs)
const noexcept
1132 return (m_start == rhs.m_start) && (m_size == rhs.m_size) && (m_step == rhs.m_step);
1136 inline bool xstepped_range<T>::operator!=(
const self_type& rhs)
const noexcept
1138 return !(*
this == rhs);
1146 inline xall<T>::xall(size_type size) noexcept
1152 template <std::convertible_to<T> S>
1155 return xall<S>(
static_cast<S
>(m_size));
1159 template <std::convertible_to<T> S>
1160 inline xall<S> xall<T>::convert() const noexcept
1166 inline auto xall<T>::operator()(size_type i)
const noexcept -> size_type
1172 inline auto xall<T>::size() const noexcept -> size_type
1178 inline auto xall<T>::step_size() const noexcept -> size_type
1184 inline auto xall<T>::step_size(std::size_t , std::size_t n)
const noexcept -> size_type
1186 return static_cast<size_type
>(n);
1190 inline auto xall<T>::revert_index(std::size_t i)
const noexcept -> size_type
1196 inline bool xall<T>::contains(size_type i)
const noexcept
1202 inline bool xall<T>::operator==(
const self_type& rhs)
const noexcept
1204 return m_size == rhs.m_size;
1208 inline bool xall<T>::operator!=(
const self_type& rhs)
const noexcept
1210 return !(*
this == rhs);
1218 template <std::convertible_to<T> S>
1225 template <std::convertible_to<T> S>
1226 inline xnewaxis<S> xnewaxis<T>::convert() const noexcept
1232 inline auto xnewaxis<T>::operator()(size_type)
const noexcept -> size_type
1238 inline auto xnewaxis<T>::size() const noexcept -> size_type
1244 inline auto xnewaxis<T>::step_size() const noexcept -> size_type
1250 inline auto xnewaxis<T>::step_size(std::size_t , std::size_t )
const noexcept -> size_type
1256 inline auto xnewaxis<T>::revert_index(std::size_t i)
const noexcept -> size_type
1262 inline bool xnewaxis<T>::contains(size_type i)
const noexcept
1268 inline bool xnewaxis<T>::operator==(
const self_type& )
const noexcept
1274 inline bool xnewaxis<T>::operator!=(
const self_type& )
const noexcept
1285 inline xkeep_slice<T>::xkeep_slice(C& cont)
1286 requires(!detail::is_xkeep_slice<std::decay_t<C>>::value)
1287 : m_raw_indices(cont.begin(), cont.end())
1292 inline xkeep_slice<T>::xkeep_slice(container_type&& cont)
1293 : m_raw_indices(std::move(cont))
1299 inline xkeep_slice<T>::xkeep_slice(std::initializer_list<S> t)
1300 : m_raw_indices(t.size())
1305 m_raw_indices.begin(),
1308 return static_cast<size_type>(t);
1314 template <std::convertible_to<T> S>
1315 inline xkeep_slice<T>::operator xkeep_slice<S>() const noexcept
1318 using us_type =
typename container_type::size_type;
1319 us_type sz =
static_cast<us_type
>(size());
1320 ret.m_raw_indices.resize(sz);
1321 ret.m_indices.resize(sz);
1323 m_raw_indices.cbegin(),
1324 m_raw_indices.cend(),
1325 ret.m_raw_indices.begin(),
1328 return static_cast<S>(val);
1334 ret.m_indices.begin(),
1337 return static_cast<S>(val);
1344 template <std::convertible_to<T> S>
1345 inline xkeep_slice<S> xkeep_slice<T>::convert() const noexcept
1347 return xkeep_slice<S>(*
this);
1351 inline void xkeep_slice<T>::normalize(std::size_t shape)
1353 m_indices.resize(m_raw_indices.size());
1354 std::size_t sz = m_indices.size();
1355 for (std::size_t i = 0; i < sz; ++i)
1357 m_indices[i] = m_raw_indices[i] < 0 ?
static_cast<size_type
>(shape) + m_raw_indices[i]
1363 inline auto xkeep_slice<T>::operator()(size_type i)
const noexcept -> size_type
1365 return m_indices.size() == size_type(1) ? m_indices.front() : m_indices[
static_cast<std::size_t
>(i)];
1369 inline auto xkeep_slice<T>::size() const noexcept -> size_type
1371 return static_cast<size_type
>(m_raw_indices.size());
1375 inline auto xkeep_slice<T>::step_size(std::size_t i, std::size_t n)
const noexcept -> size_type
1377 if (m_indices.size() == 1)
1381 if (i + n >= m_indices.size())
1383 return m_indices.back() - m_indices[i] + 1;
1387 return m_indices[i + n] - m_indices[i];
1392 inline auto xkeep_slice<T>::revert_index(std::size_t i)
const -> size_type
1394 auto it = std::find(m_indices.begin(), m_indices.end(), i);
1395 if (it != m_indices.end())
1397 return std::distance(m_indices.begin(), it);
1401 XTENSOR_THROW(std::runtime_error,
"Index i (" + std::to_string(i) +
") not in indices of islice.");
1406 inline bool xkeep_slice<T>::contains(size_type i)
const noexcept
1408 return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? false :
true;
1412 inline bool xkeep_slice<T>::operator==(
const self_type& rhs)
const noexcept
1414 return m_indices == rhs.m_indices;
1418 inline bool xkeep_slice<T>::operator!=(
const self_type& rhs)
const noexcept
1420 return !(*
this == rhs);
1429 inline xdrop_slice<T>::xdrop_slice(C& cont)
1430 requires(!detail::is_xdrop_slice<std::decay_t<C>>::value)
1431 : m_raw_indices(cont.begin(), cont.end())
1436 inline xdrop_slice<T>::xdrop_slice(container_type&& cont)
1437 : m_raw_indices(std::move(cont))
1443 inline xdrop_slice<T>::xdrop_slice(std::initializer_list<S> t)
1444 : m_raw_indices(t.size())
1449 m_raw_indices.begin(),
1452 return static_cast<size_type>(t);
1458 template <std::convertible_to<T> S>
1459 inline xdrop_slice<T>::operator xdrop_slice<S>() const noexcept
1462 ret.m_raw_indices.resize(m_raw_indices.size());
1463 ret.m_indices.resize(m_indices.size());
1465 m_raw_indices.cbegin(),
1466 m_raw_indices.cend(),
1467 ret.m_raw_indices.begin(),
1470 return static_cast<S>(val);
1476 ret.m_indices.begin(),
1479 return static_cast<S>(val);
1485 std::inserter(ret.m_inc, ret.m_inc.begin()),
1488 return std::make_pair(static_cast<S>(val.first), static_cast<S>(val.second));
1491 ret.m_size =
static_cast<S
>(m_size);
1496 template <std::convertible_to<T> S>
1497 inline xdrop_slice<S> xdrop_slice<T>::convert() const noexcept
1499 return xdrop_slice<S>(*
this);
1503 inline void xdrop_slice<T>::normalize(std::size_t shape)
1505 m_size =
static_cast<size_type
>(shape - m_raw_indices.size());
1507 m_indices.resize(m_raw_indices.size());
1508 std::size_t sz = m_indices.size();
1509 for (std::size_t i = 0; i < sz; ++i)
1511 m_indices[i] = m_raw_indices[i] < 0 ?
static_cast<size_type
>(shape) + m_raw_indices[i]
1514 size_type cum = size_type(0);
1515 size_type prev_cum = cum;
1516 for (std::size_t i = 0; i < sz; ++i)
1518 std::size_t ind = i;
1519 size_type d = m_indices[i];
1520 while (i + 1 < sz && m_indices[i + 1] == m_indices[i] + 1)
1524 cum += (
static_cast<size_type
>(i) -
static_cast<size_type
>(ind)) + 1;
1525 m_inc[d - prev_cum] = cum;
1531 inline auto xdrop_slice<T>::operator()(size_type i)
const noexcept -> size_type
1533 if (m_inc.empty() || i < m_inc.begin()->first)
1539 auto iter = --m_inc.upper_bound(i);
1540 return i + iter->second;
1545 inline auto xdrop_slice<T>::size() const noexcept -> size_type
1551 inline auto xdrop_slice<T>::step_size(std::size_t i, std::size_t n)
const noexcept -> size_type
1553 if (i + n >=
static_cast<std::size_t
>(m_size))
1555 return (*
this)(
static_cast<size_type
>(m_size - 1)) - (*
this)(
static_cast<size_type
>(i)) + 1;
1559 return (*
this)(
static_cast<size_type
>(i + n)) - (*
this)(
static_cast<size_type
>(i));
1564 inline auto xdrop_slice<T>::revert_index(std::size_t i)
const -> size_type
1566 if (i < m_inc.begin()->first)
1572 auto iter = --m_inc.lower_bound(i);
1573 auto check = iter->first + iter->second;
1578 return i - iter->second;
1583 inline bool xdrop_slice<T>::contains(size_type i)
const noexcept
1585 return (std::find(m_indices.begin(), m_indices.end(), i) == m_indices.end()) ? true :
false;
1589 inline bool xdrop_slice<T>::operator==(
const self_type& rhs)
const noexcept
1591 return m_indices == rhs.m_indices;
1595 inline bool xdrop_slice<T>::operator!=(
const self_type& rhs)
const noexcept
1597 return !(*
this == rhs);
1601#undef XTENSOR_CONSTEXPR
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.