xtensor
 
Loading...
Searching...
No Matches
xview.hpp
1/***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
3 * Copyright (c) QuantStack *
4 * *
5 * Distributed under the terms of the BSD 3-Clause License. *
6 * *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9
10#ifndef XTENSOR_VIEW_HPP
11#define XTENSOR_VIEW_HPP
12
13#include <algorithm>
14#include <array>
15#include <cstddef>
16#include <tuple>
17#include <type_traits>
18#include <utility>
19
20#include <xtl/xclosure.hpp>
21#include <xtl/xmeta_utils.hpp>
22#include <xtl/xsequence.hpp>
23#include <xtl/xtype_traits.hpp>
24
25#include "../containers/xarray.hpp"
26#include "../containers/xcontainer.hpp"
27#include "../containers/xtensor.hpp"
28#include "../core/xaccessible.hpp"
29#include "../core/xiterable.hpp"
30#include "../core/xsemantic.hpp"
31#include "../core/xtensor_config.hpp"
32#include "../core/xtensor_forward.hpp"
33#include "../views/xbroadcast.hpp"
34#include "../views/xslice.hpp"
35#include "../views/xview_utils.hpp"
36
37namespace xt
38{
39
40 /*******************
41 * xview extension *
42 *******************/
43
44 namespace extension
45 {
46 template <class Tag, class CT, class... S>
48
49 template <class CT, class... S>
51 {
52 using type = xtensor_empty_base;
53 };
54
55 template <class CT, class... S>
56 struct xview_base : xview_base_impl<xexpression_tag_t<CT>, CT, S...>
57 {
58 };
59
60 template <class CT, class... S>
61 using xview_base_t = typename xview_base<CT, S...>::type;
62 }
63
64 /*********************
65 * xview declaration *
66 *********************/
67
68 template <bool is_const, class CT, class... S>
69 class xview_stepper;
70
71 template <class ST, class... S>
72 struct xview_shape_type;
73
74 namespace detail
75 {
76
77 template <class T>
78 struct is_xrange : std::false_type
79 {
80 };
81
82 template <class T>
83 struct is_xrange<xrange<T>> : std::true_type
84 {
85 };
86
87 template <class S>
88 struct is_xall_slice : std::false_type
89 {
90 };
91
92 template <class T>
93 struct is_xall_slice<xall<T>> : std::true_type
94 {
95 };
96
97 template <layout_type L, bool valid, bool all_seen, bool range_seen, class V>
98 struct is_contiguous_view_impl
99 {
100 static constexpr bool value = false;
101 };
102
103 template <class T>
104 struct static_dimension
105 {
106 static constexpr std::ptrdiff_t value = -1;
107 };
108
109 template <class T, std::size_t N>
110 struct static_dimension<std::array<T, N>>
111 {
112 static constexpr std::ptrdiff_t value = static_cast<std::ptrdiff_t>(N);
113 };
114
115 template <class T, std::size_t N>
116 struct static_dimension<xt::const_array<T, N>>
117 {
118 static constexpr std::ptrdiff_t value = static_cast<std::ptrdiff_t>(N);
119 };
120
121 template <std::size_t... I>
122 struct static_dimension<xt::fixed_shape<I...>>
123 {
124 static constexpr std::ptrdiff_t value = sizeof...(I);
125 };
126
127 // if we have the same number of integers as we have static dimensions
128 // this can be interpreted like a xscalar
129 template <class CT, class... S>
130 struct is_xscalar_impl<xview<CT, S...>>
131 {
132 static constexpr bool value = static_cast<std::ptrdiff_t>(integral_count<S...>()
133 ) == static_dimension<typename std::decay_t<CT>::shape_type>::value
134 ? true
135 : false;
136 };
137
138 template <class S>
139 struct is_strided_slice_impl : std::true_type
140 {
141 };
142
143 template <class T>
144 struct is_strided_slice_impl<xkeep_slice<T>> : std::false_type
145 {
146 };
147
148 template <class T>
149 struct is_strided_slice_impl<xdrop_slice<T>> : std::false_type
150 {
151 };
152
153 // If we have no discontiguous slices, we can calculate strides for this view.
154 template <class E, class... S>
155 struct is_strided_view
156 : std::integral_constant<
157 bool,
158 std::conjunction<has_data_interface<E>, is_strided_slice_impl<std::decay_t<S>>...>::value>
159 {
160 };
161
162 // if row major the view can only be (statically) computed as contiguous if:
163 // any number of integers is followed by either one or no range which
164 // are followed by explicit (or implicit) all's
165 //
166 // e.g.
167 // (i, j, all(), all()) == contiguous
168 // (i, range(0, 2), all()) == contiguous
169 // (i) == contiguous (implicit all slices)
170 // (i, all(), j) == *not* contiguous
171 // (i, range(0, 2), range(0, 2)) == *not* contiguous etc.
172 template <bool valid, bool all_seen, bool range_seen, class V>
173 struct is_contiguous_view_impl<layout_type::row_major, valid, all_seen, range_seen, V>
174 {
175 using slice = xtl::mpl::front_t<V>;
176 static constexpr bool is_range_slice = is_xrange<slice>::value;
177 static constexpr bool is_int_slice = xtl::is_integral<slice>::value;
178 static constexpr bool is_all_slice = is_xall_slice<slice>::value;
179 static constexpr bool have_all_seen = all_seen || is_all_slice;
180 static constexpr bool have_range_seen = is_range_slice;
181
182 static constexpr bool is_valid = valid
183 && (have_all_seen
184 ? is_all_slice
185 : (!range_seen && (is_int_slice || is_range_slice)));
186
187 static constexpr bool value = is_contiguous_view_impl < layout_type::row_major, is_valid,
188 have_all_seen, range_seen || is_range_slice,
189 xtl::mpl::pop_front_t < V >> ::value;
190 };
191
192 template <bool valid, bool all_seen, bool range_seen>
193 struct is_contiguous_view_impl<layout_type::row_major, valid, all_seen, range_seen, xtl::mpl::vector<>>
194 {
195 static constexpr bool value = valid;
196 };
197
198 // For column major the *same* but reverse is true -- with the additional
199 // constraint that we have to know the dimension at compile time otherwise
200 // we cannot make the decision as there might be implicit all's following.
201 template <bool valid, bool int_seen, bool range_seen, class V>
202 struct is_contiguous_view_impl<layout_type::column_major, valid, int_seen, range_seen, V>
203 {
204 using slice = xtl::mpl::front_t<V>;
205 static constexpr bool is_range_slice = is_xrange<slice>::value;
206 static constexpr bool is_int_slice = xtl::is_integral<slice>::value;
207 static constexpr bool is_all_slice = is_xall_slice<slice>::value;
208
209 static constexpr bool have_int_seen = int_seen || is_int_slice;
210
211 static constexpr bool is_valid = valid
212 && (have_int_seen
213 ? is_int_slice
214 : (!range_seen && (is_all_slice || is_range_slice)));
215 static constexpr bool value = is_contiguous_view_impl < layout_type::column_major, is_valid,
216 have_int_seen, is_range_slice || range_seen,
217 xtl::mpl::pop_front_t < V >> ::value;
218 };
219
220 template <bool valid, bool int_seen, bool range_seen>
221 struct is_contiguous_view_impl<layout_type::column_major, valid, int_seen, range_seen, xtl::mpl::vector<>>
222 {
223 static constexpr bool value = valid;
224 };
225
226 // TODO relax has_data_interface constraint here!
227 template <class E, class... S>
228 struct is_contiguous_view
229 : std::integral_constant<
230 bool,
231 has_data_interface<E>::value
232 && !(
233 E::static_layout == layout_type::column_major
234 && static_cast<std::size_t>(static_dimension<typename E::shape_type>::value) != sizeof...(S)
235 )
236 && is_contiguous_view_impl<E::static_layout, true, false, false, xtl::mpl::vector<S...>>::value>
237 {
238 };
239
240 template <layout_type L, class T, std::ptrdiff_t offset>
241 struct unwrap_offset_container
242 {
243 using type = void;
244 };
245
246 template <class T, std::ptrdiff_t offset>
247 struct unwrap_offset_container<layout_type::row_major, T, offset>
248 {
249 using type = sequence_view<T, offset, static_dimension<T>::value>;
250 };
251
252 template <class T, std::ptrdiff_t start, std::ptrdiff_t end, std::ptrdiff_t offset>
253 struct unwrap_offset_container<layout_type::row_major, sequence_view<T, start, end>, offset>
254 {
255 using type = sequence_view<T, start + offset, end>;
256 };
257
258 template <class T, std::ptrdiff_t offset>
259 struct unwrap_offset_container<layout_type::column_major, T, offset>
260 {
261 using type = sequence_view<T, 0, static_dimension<T>::value - offset>;
262 };
263
264 template <class T, std::ptrdiff_t start, std::ptrdiff_t end, std::ptrdiff_t offset>
265 struct unwrap_offset_container<layout_type::column_major, sequence_view<T, start, end>, offset>
266 {
267 using type = sequence_view<T, start, end - offset>;
268 };
269
270 template <class E, class... S>
271 struct get_contigous_shape_type
272 {
273 // if we have no `range` in the slices we can re-use the shape with an offset
274 using type = std::conditional_t<
275 std::disjunction<is_xrange<S>...>::value,
276 typename xview_shape_type<typename E::shape_type, S...>::type,
277 // In the false branch we know that we have only integers at the front OR end, and NO range
278 typename unwrap_offset_container<E::static_layout, typename E::inner_shape_type, integral_count<S...>()>::type>;
279 };
280
281 template <class T>
282 struct is_sequence_view : std::integral_constant<bool, false>
283 {
284 };
285
286 template <class T, std::ptrdiff_t S, std::ptrdiff_t E>
287 struct is_sequence_view<sequence_view<T, S, E>> : std::integral_constant<bool, true>
288 {
289 };
290 }
291
292 template <class CT, class... S>
294 {
295 using xexpression_type = std::decay_t<CT>;
296 using reference = inner_reference_t<CT>;
297 using const_reference = typename xexpression_type::const_reference;
298 using size_type = typename xexpression_type::size_type;
299 using temporary_type = view_temporary_type_t<xexpression_type, S...>;
300
301 static constexpr layout_type layout = detail::is_contiguous_view<xexpression_type, S...>::value
302 ? xexpression_type::static_layout
304
305 static constexpr bool is_const = std::is_const<std::remove_reference_t<CT>>::value;
306
307 using extract_storage_type = xtl::mpl::eval_if_t<
309 detail::expr_storage_type<xexpression_type>,
311 using storage_type = std::conditional_t<is_const, const extract_storage_type, extract_storage_type>;
312 };
313
314 template <class CT, class... S>
315 struct xiterable_inner_types<xview<CT, S...>>
316 {
317 using xexpression_type = std::decay_t<CT>;
318
319 static constexpr bool is_strided_view = detail::is_strided_view<xexpression_type, S...>::value;
320 static constexpr bool is_contiguous_view = detail::is_contiguous_view<xexpression_type, S...>::value;
321
322 using inner_shape_type = std::conditional_t<
323 is_contiguous_view,
324 typename detail::get_contigous_shape_type<xexpression_type, S...>::type,
325 typename xview_shape_type<typename xexpression_type::shape_type, S...>::type>;
326
327 using stepper = std::conditional_t<
328 is_strided_view,
329 xstepper<xview<CT, S...>>,
331
332 using const_stepper = std::conditional_t<
333 is_strided_view,
334 xstepper<const xview<CT, S...>>,
336 };
337
352 template <class CT, class... S>
353 class xview : public xview_semantic<xview<CT, S...>>,
354 public std::conditional_t<
355 detail::is_contiguous_view<std::decay_t<CT>, S...>::value,
356 xcontiguous_iterable<xview<CT, S...>>,
357 xiterable<xview<CT, S...>>>,
358 public xaccessible<xview<CT, S...>>,
359 public extension::xview_base_t<CT, S...>
360 {
361 public:
362
363 using self_type = xview<CT, S...>;
364 using inner_types = xcontainer_inner_types<self_type>;
365 using xexpression_type = std::decay_t<CT>;
366 using semantic_base = xview_semantic<self_type>;
367 using temporary_type = typename xcontainer_inner_types<self_type>::temporary_type;
368
369 using accessible_base = xaccessible<self_type>;
370 using extension_base = extension::xview_base_t<CT, S...>;
371 using expression_tag = typename extension_base::expression_tag;
372
373 static constexpr bool is_const = std::is_const<std::remove_reference_t<CT>>::value;
374 using value_type = typename xexpression_type::value_type;
375 using simd_value_type = xt_simd::simd_type<value_type>;
376 using bool_load_type = typename xexpression_type::bool_load_type;
377 using reference = typename inner_types::reference;
378 using const_reference = typename inner_types::const_reference;
379 using pointer = std::
380 conditional_t<is_const, typename xexpression_type::const_pointer, typename xexpression_type::pointer>;
381 using const_pointer = typename xexpression_type::const_pointer;
382 using size_type = typename inner_types::size_type;
383 using difference_type = typename xexpression_type::difference_type;
384
385 static constexpr layout_type static_layout = inner_types::layout;
386 static constexpr bool contiguous_layout = static_layout != layout_type::dynamic;
387
388 static constexpr bool is_strided_view = detail::is_strided_view<xexpression_type, S...>::value;
389 static constexpr bool is_contiguous_view = contiguous_layout;
390
391 using iterable_base = xiterable<self_type>;
392 using inner_shape_type = typename iterable_base::inner_shape_type;
393 using shape_type = typename xview_shape_type<typename xexpression_type::shape_type, S...>::type;
394
395 using xexpression_inner_strides_type = xtl::mpl::eval_if_t<
397 detail::expr_inner_strides_type<xexpression_type>,
399
400 using xexpression_inner_backstrides_type = xtl::mpl::eval_if_t<
402 detail::expr_inner_backstrides_type<xexpression_type>,
404
405 using storage_type = typename inner_types::storage_type;
406
407 static constexpr bool has_trivial_strides = is_contiguous_view
408 && !std::disjunction<detail::is_xrange<S>...>::value;
409 using inner_strides_type = std::conditional_t<
410 has_trivial_strides,
411 typename detail::unwrap_offset_container<
412 xexpression_type::static_layout,
413 xexpression_inner_strides_type,
414 integral_count<S...>()>::type,
415 get_strides_t<shape_type>>;
416
417 using inner_backstrides_type = std::conditional_t<
418 has_trivial_strides,
419 typename detail::unwrap_offset_container<
420 xexpression_type::static_layout,
421 xexpression_inner_backstrides_type,
422 integral_count<S...>()>::type,
423 get_strides_t<shape_type>>;
424
425 using strides_type = get_strides_t<shape_type>;
426 using backstrides_type = strides_type;
427
428
429 using slice_type = std::tuple<S...>;
430
431 using stepper = typename iterable_base::stepper;
432 using const_stepper = typename iterable_base::const_stepper;
433
434 using linear_iterator = std::conditional_t<
436 std::conditional_t<is_const, typename xexpression_type::const_linear_iterator, typename xexpression_type::linear_iterator>,
437 typename iterable_base::linear_iterator>;
438 using const_linear_iterator = std::conditional_t<
440 typename xexpression_type::const_linear_iterator,
441 typename iterable_base::const_linear_iterator>;
442
443 using reverse_linear_iterator = std::reverse_iterator<linear_iterator>;
444 using const_reverse_linear_iterator = std::reverse_iterator<const_linear_iterator>;
445
446 using container_iterator = pointer;
447 using const_container_iterator = const_pointer;
448 static constexpr std::size_t rank = SIZE_MAX;
449
450 // The FSL argument prevents the compiler from calling this constructor
451 // instead of the copy constructor when sizeof...(SL) == 0.
452 template <class CTA, class FSL, class... SL>
453 explicit xview(CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
454
455 xview(const xview&) = default;
456 self_type& operator=(const xview& rhs);
457
458 template <class E>
459 self_type& operator=(const xexpression<E>& e);
460
461 template <class E>
462 disable_xexpression<E, self_type>& operator=(const E& e);
463
464 const inner_shape_type& shape() const noexcept;
465 const slice_type& slices() const noexcept;
466 layout_type layout() const noexcept;
467 bool is_contiguous() const noexcept;
468 using accessible_base::shape;
469
470 template <class T>
471 void fill(const T& value);
472
473 template <class... Args>
474 reference operator()(Args... args);
475 template <class... Args>
476 reference unchecked(Args... args);
477 template <class It>
478 reference element(It first, It last);
479
480 template <class... Args>
481 const_reference operator()(Args... args) const;
482 template <class... Args>
483 const_reference unchecked(Args... args) const;
484 template <class It>
485 const_reference element(It first, It last) const;
486
487 xexpression_type& expression() noexcept;
488 const xexpression_type& expression() const noexcept;
489
490 template <class ST>
491 bool broadcast_shape(ST& shape, bool reuse_cache = false) const;
492
493 template <class ST>
494 bool has_linear_assign(const ST& strides) const;
495
496 template <class ST, bool Enable = is_strided_view>
497 std::enable_if_t<!Enable, stepper> stepper_begin(const ST& shape);
498 template <class ST, bool Enable = is_strided_view>
499 std::enable_if_t<!Enable, stepper> stepper_end(const ST& shape, layout_type l);
500
501 template <class ST, bool Enable = is_strided_view>
502 std::enable_if_t<!Enable, const_stepper> stepper_begin(const ST& shape) const;
503 template <class ST, bool Enable = is_strided_view>
504 std::enable_if_t<!Enable, const_stepper> stepper_end(const ST& shape, layout_type l) const;
505
506 template <class ST, bool Enable = is_strided_view>
507 std::enable_if_t<Enable, stepper> stepper_begin(const ST& shape);
508 template <class ST, bool Enable = is_strided_view>
509 std::enable_if_t<Enable, stepper> stepper_end(const ST& shape, layout_type l);
510
511 template <class ST, bool Enable = is_strided_view>
512 std::enable_if_t<Enable, const_stepper> stepper_begin(const ST& shape) const;
513 template <class ST, bool Enable = is_strided_view>
514 std::enable_if_t<Enable, const_stepper> stepper_end(const ST& shape, layout_type l) const;
515
516 template <class T = xexpression_type>
517 std::enable_if_t<has_data_interface<T>::value, storage_type&> storage();
518
519 template <class T = xexpression_type>
520 std::enable_if_t<has_data_interface<T>::value, const storage_type&> storage() const;
521
522 template <class T = xexpression_type>
523 std::enable_if_t<has_data_interface<T>::value && is_strided_view, linear_iterator> linear_begin();
524
525 template <class T = xexpression_type>
526 std::enable_if_t<has_data_interface<T>::value && is_strided_view, linear_iterator> linear_end();
527
528 template <class T = xexpression_type>
529 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
530 linear_begin() const;
531
532 template <class T = xexpression_type>
533 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
534 linear_end() const;
535
536 template <class T = xexpression_type>
537 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
538 linear_cbegin() const;
539
540 template <class T = xexpression_type>
541 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
542 linear_cend() const;
543
544 template <class T = xexpression_type>
545 std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_linear_iterator>
546 linear_rbegin();
547
548 template <class T = xexpression_type>
549 std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_linear_iterator>
550 linear_rend();
551
552 template <class T = xexpression_type>
553 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
554 linear_rbegin() const;
555
556 template <class T = xexpression_type>
557 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
558 linear_rend() const;
559
560 template <class T = xexpression_type>
561 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
562 linear_crbegin() const;
563
564 template <class T = xexpression_type>
565 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
566 linear_crend() const;
567
568 template <class T = xexpression_type>
569 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
570 strides() const;
571
572 template <class T = xexpression_type>
573 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
574 backstrides() const;
575
576 template <class T = xexpression_type>
577 std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_pointer> data() const;
578
579 template <class T = xexpression_type>
580 std::enable_if_t<has_data_interface<T>::value && is_strided_view, pointer> data();
581
582 template <class T = xexpression_type>
583 std::enable_if_t<has_data_interface<T>::value && is_strided_view, std::size_t>
584 data_offset() const noexcept;
585
586 template <class It>
587 inline It data_xbegin_impl(It begin) const noexcept;
588
589 template <class It>
590 inline It data_xend_impl(It begin, layout_type l, size_type offset) const noexcept;
591 inline container_iterator data_xbegin() noexcept;
592 inline const_container_iterator data_xbegin() const noexcept;
593 inline container_iterator data_xend(layout_type l, size_type offset) noexcept;
594
595 inline const_container_iterator data_xend(layout_type l, size_type offset) const noexcept;
596
597 // Conversion operator enabled for statically "scalar" views
598 template <class ST = self_type, class = std::enable_if_t<is_xscalar<std::decay_t<ST>>::value, int>>
599 operator reference()
600 {
601 return (*this)();
602 }
603
604 template <class ST = self_type, class = std::enable_if_t<is_xscalar<std::decay_t<ST>>::value, int>>
605 operator const_reference() const
606 {
607 return (*this)();
608 }
609
610 size_type underlying_size(size_type dim) const;
611
612 xtl::xclosure_pointer<self_type&> operator&() &;
613 xtl::xclosure_pointer<const self_type&> operator&() const&;
614 xtl::xclosure_pointer<self_type> operator&() &&;
615
616 template <
617 class E,
618 class T = xexpression_type,
619 class = std::enable_if_t<has_data_interface<T>::value && is_contiguous_view, int>>
620 void assign_to(xexpression<E>& e, bool force_resize) const;
621
622 template <class E>
623 using rebind_t = xview<E, S...>;
624
625 template <class E>
626 rebind_t<E> build_view(E&& e) const;
627
628 //
629 // SIMD interface
630 //
631
632 template <class requested_type>
633 using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>;
634
635 template <class T, class R>
636 using enable_simd_interface = std::enable_if_t<has_simd_interface<T>::value && is_strided_view, R>;
637
638 template <class align, class simd, class T = xexpression_type>
639 enable_simd_interface<T, void> store_simd(size_type i, const simd& e);
640
641 template <
642 class align,
643 class requested_type = value_type,
644 std::size_t N = xt_simd::simd_traits<requested_type>::size,
645 class T = xexpression_type>
646 enable_simd_interface<T, simd_return_type<requested_type>> load_simd(size_type i) const;
647
648 template <class T = xexpression_type>
649 enable_simd_interface<T, reference> data_element(size_type i);
650
651 template <class T = xexpression_type>
652 enable_simd_interface<T, const_reference> data_element(size_type i) const;
653
654 template <class T = xexpression_type>
655 enable_simd_interface<T, reference> flat(size_type i);
656
657 template <class T = xexpression_type>
658 enable_simd_interface<T, const_reference> flat(size_type i) const;
659
660 private:
661
662 // VS 2015 workaround (yes, really)
663 template <std::size_t I>
664 struct lesser_condition
665 {
666 static constexpr bool value = (I + newaxis_count_before<S...>(I + 1) < sizeof...(S));
667 };
668
669 CT m_e;
670 slice_type m_slices;
671 inner_shape_type m_shape;
672 mutable inner_strides_type m_strides;
673 mutable inner_backstrides_type m_backstrides;
674 mutable std::size_t m_data_offset;
675 mutable bool m_strides_computed;
676
677 template <class CTA, class FSL, class... SL>
678 explicit xview(std::true_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
679
680 template <class CTA, class FSL, class... SL>
681 explicit xview(std::false_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
682
683 template <class... Args>
684 auto make_index_sequence(Args... args) const noexcept;
685
686 void compute_strides(std::true_type) const;
687 void compute_strides(std::false_type) const;
688
689 reference access();
690
691 template <class Arg, class... Args>
692 reference access(Arg arg, Args... args);
693
694 const_reference access() const;
695
696 template <class Arg, class... Args>
697 const_reference access(Arg arg, Args... args) const;
698
699 template <typename std::decay_t<CT>::size_type... I, class... Args>
700 reference unchecked_impl(std::index_sequence<I...>, Args... args);
701
702 template <typename std::decay_t<CT>::size_type... I, class... Args>
703 const_reference unchecked_impl(std::index_sequence<I...>, Args... args) const;
704
705 template <typename std::decay_t<CT>::size_type... I, class... Args>
706 reference access_impl(std::index_sequence<I...>, Args... args);
707
708 template <typename std::decay_t<CT>::size_type... I, class... Args>
709 const_reference access_impl(std::index_sequence<I...>, Args... args) const;
710
711 template <typename std::decay_t<CT>::size_type I, class... Args>
712 std::enable_if_t<lesser_condition<I>::value, size_type> index(Args... args) const;
713
714 template <typename std::decay_t<CT>::size_type I, class... Args>
715 std::enable_if_t<!lesser_condition<I>::value, size_type> index(Args... args) const;
716
717 template <typename std::decay_t<CT>::size_type, class T>
718 size_type sliced_access(const xslice<T>& slice) const;
719
720 template <typename std::decay_t<CT>::size_type I, class T, class Arg, class... Args>
721 size_type sliced_access(const xslice<T>& slice, Arg arg, Args... args) const;
722
723 template <typename std::decay_t<CT>::size_type I, class T, class... Args>
724 disable_xslice<T, size_type> sliced_access(const T& squeeze, Args...) const;
725
726 using base_index_type = xindex_type_t<typename xexpression_type::shape_type>;
727
728 template <class It>
729 base_index_type make_index(It first, It last) const;
730
731 void assign_temporary_impl(temporary_type&& tmp);
732
733 template <std::size_t... I>
734 std::size_t data_offset_impl(std::index_sequence<I...>) const noexcept;
735
736 template <std::size_t... I>
737 auto compute_strides_impl(std::index_sequence<I...>) const noexcept;
738
739 inner_shape_type compute_shape(std::true_type) const;
740 inner_shape_type compute_shape(std::false_type) const;
741
742 template <class E, std::size_t... I>
743 rebind_t<E> build_view_impl(E&& e, std::index_sequence<I...>) const;
744
745 friend class xview_semantic<xview<CT, S...>>;
746 };
747
748 template <class E, class... S>
749 auto view(E&& e, S&&... slices);
750
751 template <class E>
752 auto row(E&& e, std::ptrdiff_t index);
753
754 template <class E>
755 auto col(E&& e, std::ptrdiff_t index);
756
757 /*****************************
758 * xview_stepper declaration *
759 *****************************/
760
761 namespace detail
762 {
763 template <class V>
764 struct get_stepper_impl
765 {
766 using xexpression_type = typename V::xexpression_type;
767 using type = typename xexpression_type::stepper;
768 };
769
770 template <class V>
771 struct get_stepper_impl<const V>
772 {
773 using xexpression_type = typename V::xexpression_type;
774 using type = typename xexpression_type::const_stepper;
775 };
776 }
777
778 template <class V>
779 using get_stepper = typename detail::get_stepper_impl<V>::type;
780
781 template <bool is_const, class CT, class... S>
782 class xview_stepper
783 {
784 public:
785
786 using view_type = std::conditional_t<is_const, const xview<CT, S...>, xview<CT, S...>>;
787 using substepper_type = get_stepper<view_type>;
788
789 using value_type = typename substepper_type::value_type;
790 using reference = typename substepper_type::reference;
791 using pointer = typename substepper_type::pointer;
792 using difference_type = typename substepper_type::difference_type;
793 using size_type = typename view_type::size_type;
794
795 using shape_type = typename substepper_type::shape_type;
796
797 xview_stepper() = default;
798 xview_stepper(
799 view_type* view,
800 substepper_type it,
801 size_type offset,
802 bool end = false,
803 layout_type l = XTENSOR_DEFAULT_TRAVERSAL
804 );
805
806 reference operator*() const;
807
808 void step(size_type dim);
809 void step_back(size_type dim);
810 void step(size_type dim, size_type n);
811 void step_back(size_type dim, size_type n);
812 void reset(size_type dim);
813 void reset_back(size_type dim);
814
815 void to_begin();
816 void to_end(layout_type l);
817
818 private:
819
820 bool is_newaxis_slice(size_type index) const noexcept;
821 void to_end_impl(layout_type l);
822
823 template <class F>
824 void common_step_forward(size_type dim, F f);
825 template <class F>
826 void common_step_backward(size_type dim, F f);
827
828 template <class F>
829 void common_step_forward(size_type dim, size_type n, F f);
830 template <class F>
831 void common_step_backward(size_type dim, size_type n, F f);
832
833 template <class F>
834 void common_reset(size_type dim, F f, bool backwards);
835
836 view_type* p_view;
837 substepper_type m_it;
838 size_type m_offset;
839 std::array<std::size_t, sizeof...(S)> m_index_keeper;
840 };
841
842 // meta-function returning the shape type for an xview
843 template <class ST, class... S>
845 {
846 using type = ST;
847 };
848
849 template <class I, std::size_t L, class... S>
850 struct xview_shape_type<std::array<I, L>, S...>
851 {
852 using type = std::array<I, L - integral_count<S...>() + newaxis_count<S...>()>;
853 };
854
855 template <std::size_t... I, class... S>
856 struct xview_shape_type<fixed_shape<I...>, S...>
857 {
858 using type = typename xview_shape_type<std::array<std::size_t, sizeof...(I)>, S...>::type;
859 };
860
861 /************************
862 * xview implementation *
863 ************************/
864
868
870
879 template <class CT, class... S>
880 template <class CTA, class FSL, class... SL>
881 xview<CT, S...>::xview(CTA&& e, FSL&& first_slice, SL&&... slices) noexcept
882 : xview(
883 std::integral_constant<bool, has_trivial_strides>{},
884 std::forward<CTA>(e),
885 std::forward<FSL>(first_slice),
886 std::forward<SL>(slices)...
887 )
888 {
889 }
890
891 // trivial strides initializer
892 template <class CT, class... S>
893 template <class CTA, class FSL, class... SL>
894 xview<CT, S...>::xview(std::true_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept
895 : m_e(std::forward<CTA>(e))
896 , m_slices(std::forward<FSL>(first_slice), std::forward<SL>(slices)...)
897 , m_shape(compute_shape(detail::is_sequence_view<inner_shape_type>{}))
898 , m_strides(m_e.strides())
899 , m_backstrides(m_e.backstrides())
900 , m_data_offset(data_offset_impl(std::make_index_sequence<sizeof...(S)>()))
901 , m_strides_computed(true)
902 {
903 }
904
905 template <class CT, class... S>
906 template <class CTA, class FSL, class... SL>
907 xview<CT, S...>::xview(std::false_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept
908 : m_e(std::forward<CTA>(e))
909 , m_slices(std::forward<FSL>(first_slice), std::forward<SL>(slices)...)
910 , m_shape(compute_shape(std::false_type{}))
911 , m_strides_computed(false)
912 {
913 }
914
916
917 template <class CT, class... S>
918 inline auto xview<CT, S...>::operator=(const xview& rhs) -> self_type&
919 {
920 temporary_type tmp(rhs);
921 return this->assign_temporary(std::move(tmp));
922 }
923
928
931 template <class CT, class... S>
932 template <class E>
933 inline auto xview<CT, S...>::operator=(const xexpression<E>& e) -> self_type&
934 {
935 return semantic_base::operator=(e);
936 }
937
939
940 template <class CT, class... S>
941 template <class E>
942 inline auto xview<CT, S...>::operator=(const E& e) -> disable_xexpression<E, self_type>&
943 {
944 this->fill(e);
945 return *this;
946 }
947
952
955 template <class CT, class... S>
956 inline auto xview<CT, S...>::shape() const noexcept -> const inner_shape_type&
957 {
958 return m_shape;
959 }
960
964 template <class CT, class... S>
965 inline auto xview<CT, S...>::slices() const noexcept -> const slice_type&
966 {
967 return m_slices;
968 }
969
973 template <class CT, class... S>
974 inline layout_type xview<CT, S...>::layout() const noexcept
975 {
976 if constexpr (is_strided_view)
977 {
978 if (static_layout != layout_type::dynamic)
979 {
980 return static_layout;
981 }
982 else
983 {
984 bool strides_match = do_strides_match(shape(), strides(), m_e.layout(), true);
985 return strides_match ? m_e.layout() : layout_type::dynamic;
986 }
987 }
988 else
989 {
991 }
992 }
993
994 template <class CT, class... S>
995 inline bool xview<CT, S...>::is_contiguous() const noexcept
996 {
997 return layout() != layout_type::dynamic;
998 }
999
1001
1006
1011 template <class CT, class... S>
1012 template <class T>
1013 inline void xview<CT, S...>::fill(const T& value)
1014 {
1015 if constexpr (static_layout != layout_type::dynamic)
1016 {
1017 std::fill(linear_begin(), linear_end(), value);
1018 }
1019 else
1020 {
1021 std::fill(this->begin(), this->end(), value);
1022 }
1023 }
1024
1031 template <class CT, class... S>
1032 template <class... Args>
1033 inline auto xview<CT, S...>::operator()(Args... args) -> reference
1034 {
1035 XTENSOR_TRY(check_index(shape(), args...));
1036 XTENSOR_CHECK_DIMENSION(shape(), args...);
1037 // The static cast prevents the compiler from instantiating the template methods with signed integers,
1038 // leading to warning about signed/unsigned conversions in the deeper layers of the access methods
1039 return access(static_cast<size_type>(args)...);
1040 }
1041
1061 template <class CT, class... S>
1062 template <class... Args>
1063 inline auto xview<CT, S...>::unchecked(Args... args) -> reference
1064 {
1065 return unchecked_impl(make_index_sequence(args...), static_cast<size_type>(args)...);
1066 }
1067
1068 template <class CT, class... S>
1069 template <class It>
1070 inline auto xview<CT, S...>::element(It first, It last) -> reference
1071 {
1072 XTENSOR_TRY(check_element_index(shape(), first, last));
1073 // TODO: avoid memory allocation
1074 auto index = make_index(first, last);
1075 return m_e.element(index.cbegin(), index.cend());
1076 }
1077
1084 template <class CT, class... S>
1085 template <class... Args>
1086 inline auto xview<CT, S...>::operator()(Args... args) const -> const_reference
1087 {
1088 XTENSOR_TRY(check_index(shape(), args...));
1089 XTENSOR_CHECK_DIMENSION(shape(), args...);
1090 // The static cast prevents the compiler from instantiating the template methods with signed integers,
1091 // leading to warning about signed/unsigned conversions in the deeper layers of the access methods
1092 return access(static_cast<size_type>(args)...);
1093 }
1094
1114 template <class CT, class... S>
1115 template <class... Args>
1116 inline auto xview<CT, S...>::unchecked(Args... args) const -> const_reference
1117 {
1118 return unchecked_impl(make_index_sequence(args...), static_cast<size_type>(args)...);
1119 }
1120
1121 template <class CT, class... S>
1122 template <class It>
1123 inline auto xview<CT, S...>::element(It first, It last) const -> const_reference
1124 {
1125 // TODO: avoid memory allocation
1126 auto index = make_index(first, last);
1127 return m_e.element(index.cbegin(), index.cend());
1128 }
1129
1133 template <class CT, class... S>
1134 inline auto xview<CT, S...>::expression() noexcept -> xexpression_type&
1135 {
1136 return m_e;
1137 }
1138
1142 template <class CT, class... S>
1143 inline auto xview<CT, S...>::expression() const noexcept -> const xexpression_type&
1144 {
1145 return m_e;
1146 }
1147
1153 template <class CT, class... S>
1154 template <class T>
1155 inline auto xview<CT, S...>::storage() -> std::enable_if_t<has_data_interface<T>::value, storage_type&>
1156 {
1157 return m_e.storage();
1158 }
1159
1160 template <class CT, class... S>
1161 template <class T>
1162 inline auto xview<CT, S...>::storage() const
1163 -> std::enable_if_t<has_data_interface<T>::value, const storage_type&>
1164 {
1165 return m_e.storage();
1166 }
1167
1168 template <class CT, class... S>
1169 template <class T>
1170 auto xview<CT, S...>::linear_begin()
1171 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, linear_iterator>
1172 {
1173 return m_e.storage().begin() + data_offset();
1174 }
1175
1176 template <class CT, class... S>
1177 template <class T>
1178 auto xview<CT, S...>::linear_end()
1179 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, linear_iterator>
1180 {
1181 return m_e.storage().begin() + data_offset() + this->size();
1182 }
1183
1184 template <class CT, class... S>
1185 template <class T>
1186 auto xview<CT, S...>::linear_begin() const
1187 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
1188 {
1189 return linear_cbegin();
1190 }
1191
1192 template <class CT, class... S>
1193 template <class T>
1194 auto xview<CT, S...>::linear_end() const
1195 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
1196 {
1197 return linear_cend();
1198 }
1199
1200 template <class CT, class... S>
1201 template <class T>
1202 auto xview<CT, S...>::linear_cbegin() const
1203 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
1204 {
1205 return m_e.storage().cbegin() + data_offset();
1206 }
1207
1208 template <class CT, class... S>
1209 template <class T>
1210 auto xview<CT, S...>::linear_cend() const
1211 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_linear_iterator>
1212 {
1213 return m_e.storage().cbegin() + data_offset() + this->size();
1214 }
1215
1216 template <class CT, class... S>
1217 template <class T>
1218 auto xview<CT, S...>::linear_rbegin()
1219 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_linear_iterator>
1220 {
1221 return reverse_linear_iterator(linear_end());
1222 }
1223
1224 template <class CT, class... S>
1225 template <class T>
1226 auto xview<CT, S...>::linear_rend()
1227 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_linear_iterator>
1228 {
1229 return reverse_linear_iterator(linear_begin());
1230 }
1231
1232 template <class CT, class... S>
1233 template <class T>
1234 auto xview<CT, S...>::linear_rbegin() const
1235 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
1236 {
1237 return linear_crbegin();
1238 }
1239
1240 template <class CT, class... S>
1241 template <class T>
1242 auto xview<CT, S...>::linear_rend() const
1243 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
1244 {
1245 return linear_crend();
1246 }
1247
1248 template <class CT, class... S>
1249 template <class T>
1250 auto xview<CT, S...>::linear_crbegin() const
1251 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
1252 {
1253 return const_reverse_linear_iterator(linear_end());
1254 }
1255
1256 template <class CT, class... S>
1257 template <class T>
1258 auto xview<CT, S...>::linear_crend() const
1259 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_linear_iterator>
1260 {
1261 return const_reverse_linear_iterator(linear_begin());
1262 }
1263
1267 template <class CT, class... S>
1268 template <class T>
1269 inline auto xview<CT, S...>::strides() const
1270 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
1271 {
1272 if (!m_strides_computed)
1273 {
1274 compute_strides(std::integral_constant<bool, has_trivial_strides>{});
1275 m_strides_computed = true;
1276 }
1277 return m_strides;
1278 }
1279
1280 template <class CT, class... S>
1281 template <class T>
1282 inline auto xview<CT, S...>::backstrides() const
1283 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
1284 {
1285 if (!m_strides_computed)
1286 {
1287 compute_strides(std::integral_constant<bool, has_trivial_strides>{});
1288 m_strides_computed = true;
1289 }
1290 return m_backstrides;
1291 }
1292
1296 template <class CT, class... S>
1297 template <class T>
1298 inline auto xview<CT, S...>::data() const
1299 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_pointer>
1300 {
1301 return m_e.data();
1302 }
1303
1304 template <class CT, class... S>
1305 template <class T>
1306 inline auto xview<CT, S...>::data()
1307 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, pointer>
1308 {
1309 return m_e.data();
1310 }
1311
1312 template <class CT, class... S>
1313 template <std::size_t... I>
1314 inline std::size_t xview<CT, S...>::data_offset_impl(std::index_sequence<I...>) const noexcept
1315 {
1316 auto temp = std::array<std::ptrdiff_t, sizeof...(S)>(
1317 {(static_cast<ptrdiff_t>(xt::value(std::get<I>(m_slices), 0)))...}
1318 );
1319
1320 std::ptrdiff_t result = 0;
1321 std::size_t i = 0;
1322 for (; i < std::min(sizeof...(S), m_e.strides().size()); ++i)
1323 {
1324 result += temp[i] * m_e.strides()[i - newaxis_count_before<S...>(i)];
1325 }
1326 for (; i < sizeof...(S); ++i)
1327 {
1328 result += temp[i];
1329 }
1330 return static_cast<std::size_t>(result) + m_e.data_offset();
1331 }
1332
1336 template <class CT, class... S>
1337 template <class T>
1338 inline auto xview<CT, S...>::data_offset() const noexcept
1339 -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, std::size_t>
1340 {
1341 if (!m_strides_computed)
1342 {
1343 compute_strides(std::integral_constant<bool, has_trivial_strides>{});
1344 m_strides_computed = true;
1345 }
1346 return m_data_offset;
1347 }
1348
1350
1351 template <class CT, class... S>
1352 inline auto xview<CT, S...>::underlying_size(size_type dim) const -> size_type
1353 {
1354 return m_e.shape()[dim];
1355 }
1356
1357 template <class CT, class... S>
1358 inline auto xview<CT, S...>::operator&() & -> xtl::xclosure_pointer<self_type&>
1359 {
1360 return xtl::closure_pointer(*this);
1361 }
1362
1363 template <class CT, class... S>
1364 inline auto xview<CT, S...>::operator&() const& -> xtl::xclosure_pointer<const self_type&>
1365 {
1366 return xtl::closure_pointer(*this);
1367 }
1368
1369 template <class CT, class... S>
1370 inline auto xview<CT, S...>::operator&() && -> xtl::xclosure_pointer<self_type>
1371 {
1372 return xtl::closure_pointer(std::move(*this));
1373 }
1374
1379
1385 template <class CT, class... S>
1386 template <class ST>
1387 inline bool xview<CT, S...>::broadcast_shape(ST& shape, bool) const
1388 {
1389 return xt::broadcast_shape(m_shape, shape);
1390 }
1391
1397 template <class CT, class... S>
1398 template <class ST>
1399 inline bool xview<CT, S...>::has_linear_assign(const ST& str) const
1400 {
1401 if constexpr (is_strided_view)
1402 {
1403 return str.size() == strides().size() && std::equal(str.cbegin(), str.cend(), strides().begin());
1404 }
1405 else
1406 {
1407 return false;
1408 }
1409 }
1410
1412
1413 template <class CT, class... S>
1414 template <class It>
1415 inline It xview<CT, S...>::data_xbegin_impl(It begin) const noexcept
1416 {
1417 return begin + data_offset();
1418 }
1419
1420 template <class CT, class... S>
1421 template <class It>
1422 inline It xview<CT, S...>::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept
1423 {
1424 return strided_data_end(*this, begin, l, offset);
1425 }
1426
1427 template <class CT, class... S>
1428 inline auto xview<CT, S...>::data_xbegin() noexcept -> container_iterator
1429 {
1430 return data_xbegin_impl(data());
1431 }
1432
1433 template <class CT, class... S>
1434 inline auto xview<CT, S...>::data_xbegin() const noexcept -> const_container_iterator
1435 {
1436 return data_xbegin_impl(data());
1437 }
1438
1439 template <class CT, class... S>
1440 inline auto xview<CT, S...>::data_xend(layout_type l, size_type offset) noexcept -> container_iterator
1441 {
1442 return data_xend_impl(data() + data_offset(), l, offset);
1443 }
1444
1445 template <class CT, class... S>
1446 inline auto xview<CT, S...>::data_xend(layout_type l, size_type offset) const noexcept
1447 -> const_container_iterator
1448 {
1449 return data_xend_impl(data() + data_offset(), l, offset);
1450 }
1451
1452 // Assign to operator enabled for contigous views
1453 template <class CT, class... S>
1454 template <class E, class T, class>
1455 void xview<CT, S...>::assign_to(xexpression<E>& e, bool force_resize) const
1456 {
1457 auto& de = e.derived_cast();
1458 de.resize(shape(), force_resize);
1459 std::copy(data() + data_offset(), data() + data_offset() + de.size(), de.template begin<static_layout>());
1460 }
1461
1462 template <class CT, class... S>
1463 template <class E, std::size_t... I>
1464 inline auto xview<CT, S...>::build_view_impl(E&& e, std::index_sequence<I...>) const -> rebind_t<E>
1465 {
1466 return rebind_t<E>(std::forward<E>(e), std::get<I>(m_slices)...);
1467 }
1468
1469 template <class CT, class... S>
1470 template <class E>
1471 inline auto xview<CT, S...>::build_view(E&& e) const -> rebind_t<E>
1472 {
1473 return build_view_impl(std::forward<E>(e), std::make_index_sequence<sizeof...(S)>());
1474 }
1475
1476 template <class CT, class... S>
1477 template <class align, class simd, class T>
1478 inline auto xview<CT, S...>::store_simd(size_type i, const simd& e) -> enable_simd_interface<T, void>
1479 {
1480 return m_e.template store_simd<xt_simd::unaligned_mode>(data_offset() + i, e);
1481 }
1482
1483 template <class CT, class... S>
1484 template <class align, class requested_type, std::size_t N, class T>
1485 inline auto xview<CT, S...>::load_simd(size_type i) const
1486 -> enable_simd_interface<T, simd_return_type<requested_type>>
1487 {
1488 return m_e.template load_simd<xt_simd::unaligned_mode, requested_type>(data_offset() + i);
1489 }
1490
1491 template <class CT, class... S>
1492 template <class T>
1493 inline auto xview<CT, S...>::data_element(size_type i) -> enable_simd_interface<T, reference>
1494 {
1495 return m_e.data_element(data_offset() + i);
1496 }
1497
1498 template <class CT, class... S>
1499 template <class T>
1500 inline auto xview<CT, S...>::data_element(size_type i) const -> enable_simd_interface<T, const_reference>
1501 {
1502 return m_e.data_element(data_offset() + i);
1503 }
1504
1505 template <class CT, class... S>
1506 template <class T>
1507 inline auto xview<CT, S...>::flat(size_type i) -> enable_simd_interface<T, reference>
1508 {
1509 XTENSOR_ASSERT(is_contiguous());
1510 return m_e.flat(data_offset() + i);
1511 }
1512
1513 template <class CT, class... S>
1514 template <class T>
1515 inline auto xview<CT, S...>::flat(size_type i) const -> enable_simd_interface<T, const_reference>
1516 {
1517 XTENSOR_ASSERT(is_contiguous());
1518 return m_e.flat(data_offset() + i);
1519 }
1520
1521 template <class CT, class... S>
1522 template <class... Args>
1523 inline auto xview<CT, S...>::make_index_sequence(Args...) const noexcept
1524 {
1525 return std::make_index_sequence<
1526 (sizeof...(Args) + integral_count<S...>() > newaxis_count<S...>()
1527 ? sizeof...(Args) + integral_count<S...>() - newaxis_count<S...>()
1528 : 0)>();
1529 }
1530
1531 template <class CT, class... S>
1532 template <std::size_t... I>
1533 inline auto xview<CT, S...>::compute_strides_impl(std::index_sequence<I...>) const noexcept
1534 {
1535 std::size_t original_dim = m_e.dimension();
1536 return std::array<std::ptrdiff_t, sizeof...(I)>(
1537 {(static_cast<std::ptrdiff_t>(xt::step_size(std::get<integral_skip<S...>(I)>(m_slices), 1))
1538 * ((integral_skip<S...>(I) - newaxis_count_before<S...>(integral_skip<S...>(I))) < original_dim
1539 ? m_e.strides()[integral_skip<S...>(I) - newaxis_count_before<S...>(integral_skip<S...>(I))]
1540 : 1))...}
1541 );
1542 }
1543
1544 template <class CT, class... S>
1545 inline void xview<CT, S...>::compute_strides(std::false_type) const
1546 {
1547 m_strides = xtl::make_sequence<inner_strides_type>(this->dimension(), 0);
1548 m_backstrides = xtl::make_sequence<inner_strides_type>(this->dimension(), 0);
1549
1550 constexpr std::size_t n_strides = sizeof...(S) - integral_count<S...>();
1551
1552 auto slice_strides = compute_strides_impl(std::make_index_sequence<n_strides>());
1553
1554 for (std::size_t i = 0; i < n_strides; ++i)
1555 {
1556 m_strides[i] = slice_strides[i];
1557 // adapt strides for shape[i] == 1 to make consistent with rest of xtensor
1558 detail::adapt_strides(shape(), m_strides, &m_backstrides, i);
1559 }
1560 for (std::size_t i = n_strides; i < this->dimension(); ++i)
1561 {
1562 m_strides[i] = m_e.strides()[i + integral_count<S...>() - newaxis_count<S...>()];
1563 detail::adapt_strides(shape(), m_strides, &m_backstrides, i);
1564 }
1565
1566 m_data_offset = data_offset_impl(std::make_index_sequence<sizeof...(S)>());
1567 }
1568
1569 template <class CT, class... S>
1570 inline void xview<CT, S...>::compute_strides(std::true_type) const
1571 {
1572 }
1573
1574 template <class CT, class... S>
1575 inline auto xview<CT, S...>::access() -> reference
1576 {
1577 return access_impl(make_index_sequence());
1578 }
1579
1580 template <class CT, class... S>
1581 template <class Arg, class... Args>
1582 inline auto xview<CT, S...>::access(Arg arg, Args... args) -> reference
1583 {
1584 if (sizeof...(Args) >= this->dimension())
1585 {
1586 return access(args...);
1587 }
1588 return access_impl(make_index_sequence(arg, args...), arg, args...);
1589 }
1590
1591 template <class CT, class... S>
1592 inline auto xview<CT, S...>::access() const -> const_reference
1593 {
1594 return access_impl(make_index_sequence());
1595 }
1596
1597 template <class CT, class... S>
1598 template <class Arg, class... Args>
1599 inline auto xview<CT, S...>::access(Arg arg, Args... args) const -> const_reference
1600 {
1601 if (sizeof...(Args) >= this->dimension())
1602 {
1603 return access(args...);
1604 }
1605 return access_impl(make_index_sequence(arg, args...), arg, args...);
1606 }
1607
1608 template <class CT, class... S>
1609 template <typename std::decay_t<CT>::size_type... I, class... Args>
1610 inline auto xview<CT, S...>::unchecked_impl(std::index_sequence<I...>, Args... args) -> reference
1611 {
1612 return m_e.unchecked(index<I>(args...)...);
1613 }
1614
1615 template <class CT, class... S>
1616 template <typename std::decay_t<CT>::size_type... I, class... Args>
1617 inline auto xview<CT, S...>::unchecked_impl(std::index_sequence<I...>, Args... args) const
1618 -> const_reference
1619 {
1620 return m_e.unchecked(index<I>(args...)...);
1621 }
1622
1623 template <class CT, class... S>
1624 template <typename std::decay_t<CT>::size_type... I, class... Args>
1625 inline auto xview<CT, S...>::access_impl(std::index_sequence<I...>, Args... args) -> reference
1626 {
1627 return m_e(index<I>(args...)...);
1628 }
1629
1630 template <class CT, class... S>
1631 template <typename std::decay_t<CT>::size_type... I, class... Args>
1632 inline auto xview<CT, S...>::access_impl(std::index_sequence<I...>, Args... args) const -> const_reference
1633 {
1634 return m_e(index<I>(args...)...);
1635 }
1636
1637 template <class CT, class... S>
1638 template <typename std::decay_t<CT>::size_type I, class... Args>
1639 inline auto xview<CT, S...>::index(Args... args) const
1640 -> std::enable_if_t<lesser_condition<I>::value, size_type>
1641 {
1642 return sliced_access<I - integral_count_before<S...>(I) + newaxis_count_before<S...>(I + 1)>(
1643 std::get<I + newaxis_count_before<S...>(I + 1)>(m_slices),
1644 args...
1645 );
1646 }
1647
1648 template <class CT, class... S>
1649 template <typename std::decay_t<CT>::size_type I, class... Args>
1650 inline auto xview<CT, S...>::index(Args... args) const
1651 -> std::enable_if_t<!lesser_condition<I>::value, size_type>
1652 {
1653 return argument<I - integral_count<S...>() + newaxis_count<S...>()>(args...);
1654 }
1655
1656 template <class CT, class... S>
1657 template <typename std::decay_t<CT>::size_type I, class T>
1658 inline auto xview<CT, S...>::sliced_access(const xslice<T>& slice) const -> size_type
1659 {
1660 return static_cast<size_type>(slice.derived_cast()(0));
1661 }
1662
1663 template <class CT, class... S>
1664 template <typename std::decay_t<CT>::size_type I, class T, class Arg, class... Args>
1665 inline auto xview<CT, S...>::sliced_access(const xslice<T>& slice, Arg arg, Args... args) const -> size_type
1666 {
1667 using ST = typename T::size_type;
1668 return static_cast<size_type>(
1669 slice.derived_cast()(argument<I>(static_cast<ST>(arg), static_cast<ST>(args)...))
1670 );
1671 }
1672
1673 template <class CT, class... S>
1674 template <typename std::decay_t<CT>::size_type I, class T, class... Args>
1675 inline auto xview<CT, S...>::sliced_access(const T& squeeze, Args...) const -> disable_xslice<T, size_type>
1676 {
1677 return static_cast<size_type>(squeeze);
1678 }
1679
1680 template <class CT, class... S>
1681 template <class It>
1682 inline auto xview<CT, S...>::make_index(It first, It last) const -> base_index_type
1683 {
1684 auto index = xtl::make_sequence<base_index_type>(m_e.dimension(), 0);
1685 using diff_type = typename std::iterator_traits<It>::difference_type;
1686 using ivalue_type = typename base_index_type::value_type;
1687 auto func1 = [&first](const auto& s) noexcept
1688 {
1689 return get_slice_value(s, first);
1690 };
1691 auto func2 = [](const auto& s) noexcept
1692 {
1693 return xt::value(s, 0);
1694 };
1695
1696 auto s = static_cast<diff_type>(
1697 (std::min)(static_cast<size_type>(std::distance(first, last)), this->dimension())
1698 );
1699 auto first_copy = last - s;
1700 for (size_type i = 0; i != m_e.dimension(); ++i)
1701 {
1702 size_type k = newaxis_skip<S...>(i);
1703
1704 // need to advance captured `first`
1705 first = first_copy;
1706 std::advance(first, static_cast<diff_type>(k - xt::integral_count_before<S...>(i)));
1707
1708 if (first < last)
1709 {
1710 index[i] = k < sizeof...(S) ? apply<size_type>(k, func1, m_slices)
1711 : static_cast<ivalue_type>(*first);
1712 }
1713 else
1714 {
1715 index[i] = k < sizeof...(S) ? apply<size_type>(k, func2, m_slices) : ivalue_type(0);
1716 }
1717 }
1718 return index;
1719 }
1720
1721 template <class CT, class... S>
1722 inline auto xview<CT, S...>::compute_shape(std::true_type) const -> inner_shape_type
1723 {
1724 return inner_shape_type(m_e.shape());
1725 }
1726
1727 template <class CT, class... S>
1728 inline auto xview<CT, S...>::compute_shape(std::false_type) const -> inner_shape_type
1729 {
1730 std::size_t dim = m_e.dimension() - integral_count<S...>() + newaxis_count<S...>();
1731 auto shape = xtl::make_sequence<inner_shape_type>(dim, 0);
1732 auto func = [](const auto& s) noexcept
1733 {
1734 return get_size(s);
1735 };
1736 for (size_type i = 0; i != dim; ++i)
1737 {
1738 size_type index = integral_skip<S...>(i);
1739 shape[i] = index < sizeof...(S) ? apply<size_type>(index, func, m_slices)
1740 : m_e.shape()[index - newaxis_count_before<S...>(index)];
1741 }
1742 return shape;
1743 }
1744
1745 namespace xview_detail
1746 {
1747 template <class V, class T>
1748 inline void run_assign_temporary_impl(V& v, const T& t, std::true_type /* enable strided assign */)
1749 {
1750 strided_loop_assigner<true>::run(v, t);
1751 }
1752
1753 template <class V, class T>
1754 inline void
1755 run_assign_temporary_impl(V& v, const T& t, std::false_type /* fallback to iterator assign */)
1756 {
1757 std::copy(t.cbegin(), t.cend(), v.begin());
1758 }
1759 }
1760
1761 template <class CT, class... S>
1762 inline void xview<CT, S...>::assign_temporary_impl(temporary_type&& tmp)
1763 {
1764 constexpr bool fast_assign = detail::is_strided_view<xexpression_type, S...>::value
1765 && xassign_traits<xview<CT, S...>, temporary_type>::simd_strided_assign();
1766 xview_detail::run_assign_temporary_impl(*this, tmp, std::integral_constant<bool, fast_assign>{});
1767 }
1768
1769 namespace detail
1770 {
1771 template <class E, class... S>
1772 inline std::size_t get_underlying_shape_index(std::size_t I)
1773 {
1774 return I - newaxis_count_before<get_slice_type<E, S>...>(I);
1775 }
1776
1777 template <class... S>
1778 struct check_slice;
1779
1780 template <>
1781 struct check_slice<>
1782 {
1783 using type = void_t<>;
1784 };
1785
1786 template <class S, class... SL>
1787 struct check_slice<S, SL...>
1788 {
1789 static_assert(!std::is_same<S, xellipsis_tag>::value, "ellipsis not supported vith xview");
1790 using type = typename check_slice<SL...>::type;
1791 };
1792
1793 template <class E, std::size_t... I, class... S>
1794 inline auto make_view_impl(E&& e, std::index_sequence<I...>, S&&... slices)
1795 {
1796 // Checks that no ellipsis slice is used
1797 using view_type = xview<xtl::closure_type_t<E>, get_slice_type<std::decay_t<E>, S>...>;
1798 return view_type(
1799 std::forward<E>(e),
1800 get_slice_implementation(
1801 e,
1802 std::forward<S>(slices),
1803 get_underlying_shape_index<std::decay_t<E>, S...>(I)
1804 )...
1805 );
1806 }
1807 }
1808
1818 template <class E, class... S>
1819 inline auto view(E&& e, S&&... slices)
1820 {
1821 return detail::make_view_impl(
1822 std::forward<E>(e),
1823 std::make_index_sequence<sizeof...(S)>(),
1824 std::forward<S>(slices)...
1825 );
1826 }
1827
1828 namespace detail
1829 {
1830 class row_impl
1831 {
1832 public:
1833
1834 template <class E>
1835 inline static auto make(E&& e, const std::ptrdiff_t index)
1836 {
1837 const auto shape = e.shape();
1838 check_dimension(shape);
1839 return view(e, index, xt::all());
1840 }
1841
1842 private:
1843
1844 template <class S>
1845 inline static void check_dimension(const S& shape)
1846 {
1847 if (shape.size() != 2)
1848 {
1849 XTENSOR_THROW(
1850 std::invalid_argument,
1851 "A row can only be accessed on an expression with exact two dimensions"
1852 );
1853 }
1854 }
1855
1856 template <class T, std::size_t N>
1857 inline static void check_dimension(const std::array<T, N>&)
1858 {
1859 static_assert(N == 2, "A row can only be accessed on an expression with exact two dimensions");
1860 }
1861 };
1862
1863 class column_impl
1864 {
1865 public:
1866
1867 template <class E>
1868 inline static auto make(E&& e, const std::ptrdiff_t index)
1869 {
1870 const auto shape = e.shape();
1871 check_dimension(shape);
1872 return view(e, xt::all(), index);
1873 }
1874
1875 private:
1876
1877 template <class S>
1878 inline static void check_dimension(const S& shape)
1879 {
1880 if (shape.size() != 2)
1881 {
1882 XTENSOR_THROW(
1883 std::invalid_argument,
1884 "A column can only be accessed on an expression with exact two dimensions"
1885 );
1886 }
1887 }
1888
1889 template <class T, std::size_t N>
1890 inline static void check_dimension(const std::array<T, N>&)
1891 {
1892 static_assert(N == 2, "A column can only be accessed on an expression with exact two dimensions");
1893 }
1894 };
1895 }
1896
1906 template <class E>
1907 inline auto row(E&& e, std::ptrdiff_t index)
1908 {
1909 return detail::row_impl::make(e, index);
1910 }
1911
1921 template <class E>
1922 inline auto col(E&& e, std::ptrdiff_t index)
1923 {
1924 return detail::column_impl::make(e, index);
1925 }
1926
1927 /***************
1928 * stepper api *
1929 ***************/
1930
1931 template <class CT, class... S>
1932 template <class ST, bool Enable>
1933 inline auto xview<CT, S...>::stepper_begin(const ST& shape) -> std::enable_if_t<!Enable, stepper>
1934 {
1935 size_type offset = shape.size() - this->dimension();
1936 return stepper(this, m_e.stepper_begin(m_e.shape()), offset);
1937 }
1938
1939 template <class CT, class... S>
1940 template <class ST, bool Enable>
1941 inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l)
1942 -> std::enable_if_t<!Enable, stepper>
1943 {
1944 size_type offset = shape.size() - this->dimension();
1945 return stepper(this, m_e.stepper_end(m_e.shape(), l), offset, true, l);
1946 }
1947
1948 template <class CT, class... S>
1949 template <class ST, bool Enable>
1950 inline auto xview<CT, S...>::stepper_begin(const ST& shape) const
1951 -> std::enable_if_t<!Enable, const_stepper>
1952 {
1953 size_type offset = shape.size() - this->dimension();
1954 const xexpression_type& e = m_e;
1955 return const_stepper(this, e.stepper_begin(m_e.shape()), offset);
1956 }
1957
1958 template <class CT, class... S>
1959 template <class ST, bool Enable>
1960 inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l) const
1961 -> std::enable_if_t<!Enable, const_stepper>
1962 {
1963 size_type offset = shape.size() - this->dimension();
1964 const xexpression_type& e = m_e;
1965 return const_stepper(this, e.stepper_end(m_e.shape(), l), offset, true, l);
1966 }
1967
1968 template <class CT, class... S>
1969 template <class ST, bool Enable>
1970 inline auto xview<CT, S...>::stepper_begin(const ST& shape) -> std::enable_if_t<Enable, stepper>
1971 {
1972 size_type offset = shape.size() - this->dimension();
1973 return stepper(this, data_xbegin(), offset);
1974 }
1975
1976 template <class CT, class... S>
1977 template <class ST, bool Enable>
1978 inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l)
1979 -> std::enable_if_t<Enable, stepper>
1980 {
1981 size_type offset = shape.size() - this->dimension();
1982 return stepper(this, data_xend(l, offset), offset);
1983 }
1984
1985 template <class CT, class... S>
1986 template <class ST, bool Enable>
1987 inline auto xview<CT, S...>::stepper_begin(const ST& shape) const
1988 -> std::enable_if_t<Enable, const_stepper>
1989 {
1990 size_type offset = shape.size() - this->dimension();
1991 return const_stepper(this, data_xbegin(), offset);
1992 }
1993
1994 template <class CT, class... S>
1995 template <class ST, bool Enable>
1996 inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l) const
1997 -> std::enable_if_t<Enable, const_stepper>
1998 {
1999 size_type offset = shape.size() - this->dimension();
2000 return const_stepper(this, data_xend(l, offset), offset);
2001 }
2002
2003 /********************************
2004 * xview_stepper implementation *
2005 ********************************/
2006
2007 template <bool is_const, class CT, class... S>
2008 inline xview_stepper<is_const, CT, S...>::xview_stepper(
2009 view_type* view,
2010 substepper_type it,
2011 size_type offset,
2012 bool end,
2013 layout_type l
2014 )
2015 : p_view(view)
2016 , m_it(it)
2017 , m_offset(offset)
2018 {
2019 if (!end)
2020 {
2021 std::fill(m_index_keeper.begin(), m_index_keeper.end(), 0);
2022 auto func = [](const auto& s) noexcept
2023 {
2024 return xt::value(s, 0);
2025 };
2026 for (size_type i = 0; i < sizeof...(S); ++i)
2027 {
2028 if (!is_newaxis_slice(i))
2029 {
2030 size_type s = apply<size_type>(i, func, p_view->slices());
2031 size_type index = i - newaxis_count_before<S...>(i);
2032 m_it.step(index, s);
2033 }
2034 }
2035 }
2036 else
2037 {
2038 to_end_impl(l);
2039 }
2040 }
2041
2042 template <bool is_const, class CT, class... S>
2043 inline auto xview_stepper<is_const, CT, S...>::operator*() const -> reference
2044 {
2045 return *m_it;
2046 }
2047
2048 template <bool is_const, class CT, class... S>
2049 inline void xview_stepper<is_const, CT, S...>::step(size_type dim)
2050 {
2051 auto func = [this](size_type index, size_type offset)
2052 {
2053 m_it.step(index, offset);
2054 };
2055 common_step_forward(dim, func);
2056 }
2057
2058 template <bool is_const, class CT, class... S>
2059 inline void xview_stepper<is_const, CT, S...>::step_back(size_type dim)
2060 {
2061 auto func = [this](size_type index, size_type offset)
2062 {
2063 m_it.step_back(index, offset);
2064 };
2065 common_step_backward(dim, func);
2066 }
2067
2068 template <bool is_const, class CT, class... S>
2069 inline void xview_stepper<is_const, CT, S...>::step(size_type dim, size_type n)
2070 {
2071 auto func = [this](size_type index, size_type offset)
2072 {
2073 m_it.step(index, offset);
2074 };
2075 common_step_forward(dim, n, func);
2076 }
2077
2078 template <bool is_const, class CT, class... S>
2079 inline void xview_stepper<is_const, CT, S...>::step_back(size_type dim, size_type n)
2080 {
2081 auto func = [this](size_type index, size_type offset)
2082 {
2083 m_it.step_back(index, offset);
2084 };
2085 common_step_backward(dim, n, func);
2086 }
2087
2088 template <bool is_const, class CT, class... S>
2089 inline void xview_stepper<is_const, CT, S...>::reset(size_type dim)
2090 {
2091 auto func = [this](size_type index, size_type offset)
2092 {
2093 m_it.step_back(index, offset);
2094 };
2095 common_reset(dim, func, false);
2096 }
2097
2098 template <bool is_const, class CT, class... S>
2099 inline void xview_stepper<is_const, CT, S...>::reset_back(size_type dim)
2100 {
2101 auto func = [this](size_type index, size_type offset)
2102 {
2103 m_it.step(index, offset);
2104 };
2105 common_reset(dim, func, true);
2106 }
2107
2108 template <bool is_const, class CT, class... S>
2109 inline void xview_stepper<is_const, CT, S...>::to_begin()
2110 {
2111 std::fill(m_index_keeper.begin(), m_index_keeper.end(), 0);
2112 m_it.to_begin();
2113 }
2114
2115 template <bool is_const, class CT, class... S>
2116 inline void xview_stepper<is_const, CT, S...>::to_end(layout_type l)
2117 {
2118 m_it.to_end(l);
2119 to_end_impl(l);
2120 }
2121
2122 template <bool is_const, class CT, class... S>
2123 inline bool xview_stepper<is_const, CT, S...>::is_newaxis_slice(size_type index) const noexcept
2124 {
2125 // A bit tricky but avoids a lot of template instantiations
2126 return newaxis_count_before<S...>(index + 1) != newaxis_count_before<S...>(index);
2127 }
2128
2129 template <bool is_const, class CT, class... S>
2130 inline void xview_stepper<is_const, CT, S...>::to_end_impl(layout_type l)
2131 {
2132 auto func = [](const auto& s) noexcept
2133 {
2134 return xt::value(s, get_size(s) - 1);
2135 };
2136 auto size_func = [](const auto& s) noexcept
2137 {
2138 return get_size(s);
2139 };
2140
2141 for (size_type i = 0; i < sizeof...(S); ++i)
2142 {
2143 if (!is_newaxis_slice(i))
2144 {
2145 size_type s = apply<size_type>(i, func, p_view->slices());
2146 size_type ix = apply<size_type>(i, size_func, p_view->slices());
2147 m_index_keeper[i] = ix - size_type(1);
2148 size_type index = i - newaxis_count_before<S...>(i);
2149 s = p_view->underlying_size(index) - 1 - s;
2150 m_it.step_back(index, s);
2151 }
2152 }
2153 if (l == layout_type::row_major)
2154 {
2155 for (size_type i = sizeof...(S); i > 0; --i)
2156 {
2157 if (!is_newaxis_slice(i - 1))
2158 {
2159 m_index_keeper[i - 1]++;
2160 break;
2161 }
2162 }
2163 }
2164 else if (l == layout_type::column_major)
2165 {
2166 for (size_type i = 0; i < sizeof...(S); ++i)
2167 {
2168 if (!is_newaxis_slice(i))
2169 {
2170 m_index_keeper[i]++;
2171 break;
2172 }
2173 }
2174 }
2175 else
2176 {
2177 XTENSOR_THROW(std::runtime_error, "Iteration only allowed in row or column major.");
2178 }
2179 }
2180
2181 template <bool is_const, class CT, class... S>
2182 template <class F>
2183 void xview_stepper<is_const, CT, S...>::common_step_forward(size_type dim, F f)
2184 {
2185 if (dim >= m_offset)
2186 {
2187 auto func = [&dim, this](const auto& s) noexcept
2188 {
2189 return step_size(s, this->m_index_keeper[dim]++, 1);
2190 };
2191 size_type index = integral_skip<S...>(dim);
2192 if (!is_newaxis_slice(index))
2193 {
2194 size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
2195 : 1;
2196 index -= newaxis_count_before<S...>(index);
2197 f(index, step_size);
2198 }
2199 }
2200 }
2201
2202 template <bool is_const, class CT, class... S>
2203 template <class F>
2204 void xview_stepper<is_const, CT, S...>::common_step_forward(size_type dim, size_type n, F f)
2205 {
2206 if (dim >= m_offset)
2207 {
2208 auto func = [&dim, &n, this](const auto& s) noexcept
2209 {
2210 auto st_size = step_size(s, this->m_index_keeper[dim], n);
2211 this->m_index_keeper[dim] += n;
2212 return size_type(st_size);
2213 };
2214
2215 size_type index = integral_skip<S...>(dim);
2216 if (!is_newaxis_slice(index))
2217 {
2218 size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
2219 : n;
2220 index -= newaxis_count_before<S...>(index);
2221 f(index, step_size);
2222 }
2223 }
2224 }
2225
2226 template <bool is_const, class CT, class... S>
2227 template <class F>
2228 void xview_stepper<is_const, CT, S...>::common_step_backward(size_type dim, F f)
2229 {
2230 if (dim >= m_offset)
2231 {
2232 auto func = [&dim, this](const auto& s) noexcept
2233 {
2234 this->m_index_keeper[dim]--;
2235 return step_size(s, this->m_index_keeper[dim], 1);
2236 };
2237 size_type index = integral_skip<S...>(dim);
2238 if (!is_newaxis_slice(index))
2239 {
2240 size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
2241 : 1;
2242 index -= newaxis_count_before<S...>(index);
2243 f(index, step_size);
2244 }
2245 }
2246 }
2247
2248 template <bool is_const, class CT, class... S>
2249 template <class F>
2250 void xview_stepper<is_const, CT, S...>::common_step_backward(size_type dim, size_type n, F f)
2251 {
2252 if (dim >= m_offset)
2253 {
2254 auto func = [&dim, &n, this](const auto& s) noexcept
2255 {
2256 this->m_index_keeper[dim] -= n;
2257 return step_size(s, this->m_index_keeper[dim], n);
2258 };
2259
2260 size_type index = integral_skip<S...>(dim);
2261 if (!is_newaxis_slice(index))
2262 {
2263 size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
2264 : n;
2265 index -= newaxis_count_before<S...>(index);
2266 f(index, step_size);
2267 }
2268 }
2269 }
2270
2271 template <bool is_const, class CT, class... S>
2272 template <class F>
2273 void xview_stepper<is_const, CT, S...>::common_reset(size_type dim, F f, bool backwards)
2274 {
2275 auto size_func = [](const auto& s) noexcept
2276 {
2277 return get_size(s);
2278 };
2279 auto end_func = [](const auto& s) noexcept
2280 {
2281 return xt::value(s, get_size(s) - 1) - xt::value(s, 0);
2282 };
2283
2284 size_type index = integral_skip<S...>(dim);
2285 if (!is_newaxis_slice(index))
2286 {
2287 if (dim < m_index_keeper.size())
2288 {
2289 size_type size = index < sizeof...(S) ? apply<size_type>(index, size_func, p_view->slices())
2290 : p_view->shape()[dim];
2291 m_index_keeper[dim] = backwards ? size - 1 : 0;
2292 }
2293
2294 size_type reset_n = index < sizeof...(S) ? apply<size_type>(index, end_func, p_view->slices())
2295 : p_view->shape()[dim] - 1;
2296 index -= newaxis_count_before<S...>(index);
2297 f(index, reset_n);
2298 }
2299 }
2300}
2301
2302#endif
Fixed shape implementation for compile time defined arrays.
Base class for xexpressions.
Base class for multidimensional iterable expressions.
Multidimensional view with tensor semantic.
Definition xview.hpp:360
xview(CTA &&e, FSL &&first_slice, SL &&... slices) noexcept
Constructs a view on the specified xexpression.
Definition xview.hpp:881
const slice_type & slices() const noexcept
bool has_linear_assign(const ST &strides) const
const inner_shape_type & shape() const noexcept
Returns the shape of the view.
Definition xview.hpp:956
bool broadcast_shape(ST &shape, bool reuse_cache=false) const
xexpression_type & expression() noexcept
void fill(const T &value)
layout_type layout() const noexcept
bool all(E &&e)
Any.
auto arg(E &&e) noexcept
Calculates the phase angle (in radians) elementwise for the complex numbers in e.
Definition xcomplex.hpp:221
auto squeeze(E &&e)
Returns a squeeze view of the given expression.
std::size_t compute_strides(const shape_type &shape, layout_type l, strides_type &strides)
Compute the strides given the shape and the layout of an array.
Definition xstrides.hpp:566
auto strides(const E &e, stride_type type=stride_type::normal) noexcept
Get strides of an object.
Definition xstrides.hpp:248
standard mathematical functions for xexpressions
auto all() noexcept
Returns a slice representing a full dimension, to be used as an argument of view function.
Definition xslice.hpp:234
auto row(E &&e, std::ptrdiff_t index)
Constructs and returns a row (sliced view) on the specified expression.
Definition xview.hpp:1907
layout_type
Definition xlayout.hpp:24
auto col(E &&e, std::ptrdiff_t index)
Constructs and returns a column (sliced view) on the specified expression.
Definition xview.hpp:1922
auto view(E &&e, S &&... slices)
Constructs and returns a view on the specified xexpression.
Definition xview.hpp:1819