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 E, class... S>
293 concept contiguous_view_concept = detail::is_contiguous_view<E, S...>::value;
294 template <class E, class... S>
295 concept strided_view_concept = detail::is_strided_view<std::decay_t<E>, S...>::value;
296
297 template <class CT, class... S>
299 {
300 using xexpression_type = std::decay_t<CT>;
301 using reference = inner_reference_t<CT>;
302 using const_reference = typename xexpression_type::const_reference;
303 using size_type = typename xexpression_type::size_type;
304 using temporary_type = view_temporary_type_t<xexpression_type, S...>;
305
306 static constexpr layout_type layout = detail::is_contiguous_view<xexpression_type, S...>::value
307 ? xexpression_type::static_layout
309
310 static constexpr bool is_const = std::is_const<std::remove_reference_t<CT>>::value;
311
312 using extract_storage_type = xtl::mpl::eval_if_t<
314 detail::expr_storage_type<xexpression_type>,
316 using storage_type = std::conditional_t<is_const, const extract_storage_type, extract_storage_type>;
317 };
318
319 template <class CT, class... S>
320 struct xiterable_inner_types<xview<CT, S...>>
321 {
322 using xexpression_type = std::decay_t<CT>;
323
324 static constexpr bool is_strided_view = detail::is_strided_view<xexpression_type, S...>::value;
325 static constexpr bool is_contiguous_view = detail::is_contiguous_view<xexpression_type, S...>::value;
326
327 using inner_shape_type = std::conditional_t<
328 is_contiguous_view,
329 typename detail::get_contigous_shape_type<xexpression_type, S...>::type,
330 typename xview_shape_type<typename xexpression_type::shape_type, S...>::type>;
331
332 using stepper = std::conditional_t<
333 is_strided_view,
334 xstepper<xview<CT, S...>>,
336
337 using const_stepper = std::conditional_t<
338 is_strided_view,
339 xstepper<const xview<CT, S...>>,
341 };
342
357 template <class CT, class... S>
358 class xview : public xview_semantic<xview<CT, S...>>,
359 public std::conditional_t<
360 detail::is_contiguous_view<std::decay_t<CT>, S...>::value,
361 xcontiguous_iterable<xview<CT, S...>>,
362 xiterable<xview<CT, S...>>>,
363 public xaccessible<xview<CT, S...>>,
364 public extension::xview_base_t<CT, S...>
365 {
366 public:
367
368 using self_type = xview<CT, S...>;
369 using inner_types = xcontainer_inner_types<self_type>;
370 using xexpression_type = std::decay_t<CT>;
371 using semantic_base = xview_semantic<self_type>;
372 using temporary_type = typename xcontainer_inner_types<self_type>::temporary_type;
373
374 using accessible_base = xaccessible<self_type>;
375 using extension_base = extension::xview_base_t<CT, S...>;
376 using expression_tag = typename extension_base::expression_tag;
377
378 static constexpr bool is_const = std::is_const<std::remove_reference_t<CT>>::value;
379 using value_type = typename xexpression_type::value_type;
380 using simd_value_type = xt_simd::simd_type<value_type>;
381 using bool_load_type = typename xexpression_type::bool_load_type;
382 using reference = typename inner_types::reference;
383 using const_reference = typename inner_types::const_reference;
384 using pointer = std::
385 conditional_t<is_const, typename xexpression_type::const_pointer, typename xexpression_type::pointer>;
386 using const_pointer = typename xexpression_type::const_pointer;
387 using size_type = typename inner_types::size_type;
388 using difference_type = typename xexpression_type::difference_type;
389
390 static constexpr layout_type static_layout = inner_types::layout;
391 static constexpr bool contiguous_layout = static_layout != layout_type::dynamic;
392
393 static constexpr bool is_strided_view = detail::is_strided_view<xexpression_type, S...>::value;
394 static constexpr bool is_contiguous_view = contiguous_layout;
395
396 using iterable_base = xiterable<self_type>;
397 using inner_shape_type = typename iterable_base::inner_shape_type;
398 using shape_type = typename xview_shape_type<typename xexpression_type::shape_type, S...>::type;
399
400 using xexpression_inner_strides_type = xtl::mpl::eval_if_t<
402 detail::expr_inner_strides_type<xexpression_type>,
404
405 using xexpression_inner_backstrides_type = xtl::mpl::eval_if_t<
407 detail::expr_inner_backstrides_type<xexpression_type>,
409
410 using storage_type = typename inner_types::storage_type;
411
412 static constexpr bool has_trivial_strides = is_contiguous_view
413 && !std::disjunction<detail::is_xrange<S>...>::value;
414 using inner_strides_type = std::conditional_t<
415 has_trivial_strides,
416 typename detail::unwrap_offset_container<
417 xexpression_type::static_layout,
418 xexpression_inner_strides_type,
419 integral_count<S...>()>::type,
420 get_strides_t<shape_type>>;
421
422 using inner_backstrides_type = std::conditional_t<
423 has_trivial_strides,
424 typename detail::unwrap_offset_container<
425 xexpression_type::static_layout,
426 xexpression_inner_backstrides_type,
427 integral_count<S...>()>::type,
428 get_strides_t<shape_type>>;
429
430 using strides_type = get_strides_t<shape_type>;
431 using backstrides_type = strides_type;
432
433
434 using slice_type = std::tuple<S...>;
435
436 using stepper = typename iterable_base::stepper;
437 using const_stepper = typename iterable_base::const_stepper;
438
439 using linear_iterator = std::conditional_t<
441 std::conditional_t<is_const, typename xexpression_type::const_linear_iterator, typename xexpression_type::linear_iterator>,
442 typename iterable_base::linear_iterator>;
443 using const_linear_iterator = std::conditional_t<
445 typename xexpression_type::const_linear_iterator,
446 typename iterable_base::const_linear_iterator>;
447
448 using reverse_linear_iterator = std::reverse_iterator<linear_iterator>;
449 using const_reverse_linear_iterator = std::reverse_iterator<const_linear_iterator>;
450
451 using container_iterator = pointer;
452 using const_container_iterator = const_pointer;
453 static constexpr std::size_t rank = SIZE_MAX;
454
455 // The FSL argument prevents the compiler from calling this constructor
456 // instead of the copy constructor when sizeof...(SL) == 0.
457 template <class CTA, class FSL, class... SL>
458 explicit xview(CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
459
460 xview(const xview&) = default;
461 self_type& operator=(const xview& rhs);
462
463 template <class E>
464 self_type& operator=(const xexpression<E>& e);
465
466 template <class E>
467 disable_xexpression<E, self_type>& operator=(const E& e);
468
469 const inner_shape_type& shape() const noexcept;
470 const slice_type& slices() const noexcept;
471 layout_type layout() const noexcept;
472 bool is_contiguous() const noexcept;
473 using accessible_base::shape;
474
475 template <class T>
476 void fill(const T& value);
477
478 template <class... Args>
479 reference operator()(Args... args);
480 template <class... Args>
481 reference unchecked(Args... args);
482 template <class It>
483 reference element(It first, It last);
484
485 template <class... Args>
486 const_reference operator()(Args... args) const;
487 template <class... Args>
488 const_reference unchecked(Args... args) const;
489 template <class It>
490 const_reference element(It first, It last) const;
491
492 xexpression_type& expression() noexcept;
493 const xexpression_type& expression() const noexcept;
494
495 template <class ST>
496 bool broadcast_shape(ST& shape, bool reuse_cache = false) const;
497
498 template <class ST>
499 bool has_linear_assign(const ST& strides) const;
500
501 template <class ST>
502 stepper stepper_begin(const ST& shape);
503 template <class ST>
504 stepper stepper_end(const ST& shape, layout_type l);
505
506 template <class ST>
507 const_stepper stepper_begin(const ST& shape) const;
508 template <class ST>
509 const_stepper stepper_end(const ST& shape, layout_type l) const;
510
511 template <class T = xexpression_type>
512 storage_type& storage()
513 requires(has_data_interface_concept<T>);
514
515 template <class T = xexpression_type>
516 const storage_type& storage() const
517 requires(has_data_interface_concept<T>);
518
519 template <class T = xexpression_type>
520 linear_iterator linear_begin()
521 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
522
523 template <class T = xexpression_type>
524 linear_iterator linear_end()
525 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
526
527 template <class T = xexpression_type>
528 const_linear_iterator linear_begin() const
529 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
530
531 template <class T = xexpression_type>
532 const_linear_iterator linear_end() const
533 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
534
535 template <class T = xexpression_type>
536 const_linear_iterator linear_cbegin() const
537 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
538
539 template <class T = xexpression_type>
540 const_linear_iterator linear_cend() const
541 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
542
543 template <class T = xexpression_type>
544 reverse_linear_iterator linear_rbegin()
545 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
546
547 template <class T = xexpression_type>
548 reverse_linear_iterator linear_rend()
549 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
550
551 template <class T = xexpression_type>
552 const_reverse_linear_iterator linear_rbegin() const
553 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
554
555 template <class T = xexpression_type>
556 const_reverse_linear_iterator linear_rend() const
557 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
558
559 template <class T = xexpression_type>
560 const_reverse_linear_iterator linear_crbegin() const
561 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
562
563 template <class T = xexpression_type>
564 const_reverse_linear_iterator linear_crend() const
565 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
566
567 template <class T = xexpression_type>
568 const inner_strides_type& strides() const
569 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
570
571 template <class T = xexpression_type>
572 const inner_strides_type& backstrides() const
573 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
574
575 template <class T = xexpression_type>
576 const_pointer data() const
577 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
578
579 template <class T = xexpression_type>
580 pointer data()
581 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
582
583 template <class T = xexpression_type>
584 std::size_t data_offset() const noexcept
585 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>);
586
587 template <class It>
588 inline It data_xbegin_impl(It begin) const noexcept;
589
590 template <class It>
591 inline It data_xend_impl(It begin, layout_type l, size_type offset) const noexcept;
592 inline container_iterator data_xbegin() noexcept;
593 inline const_container_iterator data_xbegin() const noexcept;
594 inline container_iterator data_xend(layout_type l, size_type offset) noexcept;
595
596 inline const_container_iterator data_xend(layout_type l, size_type offset) const noexcept;
597
598 // Conversion operator enabled for statically "scalar" views
599 template <xscalar_concept ST = self_type>
600 operator reference()
601 {
602 return (*this)();
603 }
604
605 template <xscalar_concept ST = self_type>
606 operator const_reference() const
607 {
608 return (*this)();
609 }
610
611 size_type underlying_size(size_type dim) const;
612
613 xtl::xclosure_pointer<self_type&> operator&() &;
614 xtl::xclosure_pointer<const self_type&> operator&() const&;
615 xtl::xclosure_pointer<self_type> operator&() &&;
616
617 template <class E, class T = xexpression_type>
618 void assign_to(xexpression<E>& e, bool force_resize) const
619 requires(has_data_interface_concept<T> and contiguous_view_concept<E, S...>);
620
621 template <class E>
622 using rebind_t = xview<E, S...>;
623
624 template <class E>
625 rebind_t<E> build_view(E&& e) const;
626
627 //
628 // SIMD interface
629 //
630
631 template <class requested_type>
632 using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>;
633
634 template <class align, class simd, class T = xexpression_type>
635 void store_simd(size_type i, const simd& e)
636 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>);
637
638 template <
639 class align,
640 class requested_type = value_type,
641 std::size_t N = xt_simd::simd_traits<requested_type>::size,
642 class T = xexpression_type>
643 simd_return_type<requested_type> load_simd(size_type i) const
644 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>);
645
646 template <class T = xexpression_type>
647 reference data_element(size_type i)
648 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>);
649
650 template <class T = xexpression_type>
651 const_reference data_element(size_type i) const
652 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>);
653
654 template <class T = xexpression_type>
655 reference flat(size_type i)
656 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>);
657
658 template <class T = xexpression_type>
659 const_reference flat(size_type i) const
660 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>);
661
662 private:
663
664 // VS 2015 workaround (yes, really)
665 template <std::size_t I>
666 struct lesser_condition
667 {
668 static constexpr bool value = (I + newaxis_count_before<S...>(I + 1) < sizeof...(S));
669 };
670
671 CT m_e;
672 slice_type m_slices;
673 inner_shape_type m_shape;
674 mutable inner_strides_type m_strides;
675 mutable inner_backstrides_type m_backstrides;
676 mutable std::size_t m_data_offset;
677 mutable bool m_strides_computed;
678
679 template <class CTA, class FSL, class... SL>
680 explicit xview(std::true_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
681
682 template <class CTA, class FSL, class... SL>
683 explicit xview(std::false_type, CTA&& e, FSL&& first_slice, SL&&... slices) noexcept;
684
685 template <class... Args>
686 auto make_index_sequence(Args... args) const noexcept;
687
688 void compute_strides(std::true_type) const;
689 void compute_strides(std::false_type) const;
690
691 reference access();
692
693 template <class Arg, class... Args>
694 reference access(Arg arg, Args... args);
695
696 const_reference access() const;
697
698 template <class Arg, class... Args>
699 const_reference access(Arg arg, Args... args) const;
700
701 template <typename std::decay_t<CT>::size_type... I, class... Args>
702 reference unchecked_impl(std::index_sequence<I...>, Args... args);
703
704 template <typename std::decay_t<CT>::size_type... I, class... Args>
705 const_reference unchecked_impl(std::index_sequence<I...>, Args... args) const;
706
707 template <typename std::decay_t<CT>::size_type... I, class... Args>
708 reference access_impl(std::index_sequence<I...>, Args... args);
709
710 template <typename std::decay_t<CT>::size_type... I, class... Args>
711 const_reference access_impl(std::index_sequence<I...>, Args... args) const;
712
713 template <typename std::decay_t<CT>::size_type I, class... Args>
714 size_type index(Args... args) const;
715
716 template <typename std::decay_t<CT>::size_type, class T>
717 size_type sliced_access(const xslice<T>& slice) const;
718
719 template <typename std::decay_t<CT>::size_type I, class T, class Arg, class... Args>
720 size_type sliced_access(const xslice<T>& slice, Arg arg, Args... args) const;
721
722 template <typename std::decay_t<CT>::size_type I, class T, class... Args>
723 size_type sliced_access(const T& squeeze, Args...) const
724 requires(!is_xslice<T>::value);
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() -> storage_type&
1157 {
1158 return m_e.storage();
1159 }
1160
1161 template <class CT, class... S>
1162 template <class T>
1163 inline auto xview<CT, S...>::storage() const -> const storage_type&
1164 requires(has_data_interface_concept<T>)
1165 {
1166 return m_e.storage();
1167 }
1168
1169 template <class CT, class... S>
1170 template <class T>
1171 auto xview<CT, S...>::linear_begin() -> linear_iterator
1172 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1173 {
1174 return m_e.storage().begin() + data_offset();
1175 }
1176
1177 template <class CT, class... S>
1178 template <class T>
1179 auto xview<CT, S...>::linear_end() -> linear_iterator
1180 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1181 {
1182 return m_e.storage().begin() + data_offset() + this->size();
1183 }
1184
1185 template <class CT, class... S>
1186 template <class T>
1187 auto xview<CT, S...>::linear_begin() const -> const_linear_iterator
1188 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1189 {
1190 return linear_cbegin();
1191 }
1192
1193 template <class CT, class... S>
1194 template <class T>
1195 auto xview<CT, S...>::linear_end() const -> const_linear_iterator
1196 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1197 {
1198 return linear_cend();
1199 }
1200
1201 template <class CT, class... S>
1202 template <class T>
1203 auto xview<CT, S...>::linear_cbegin() const -> const_linear_iterator
1204 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1205 {
1206 return m_e.storage().cbegin() + data_offset();
1207 }
1208
1209 template <class CT, class... S>
1210 template <class T>
1211 auto xview<CT, S...>::linear_cend() const -> const_linear_iterator
1212 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1213 {
1214 return m_e.storage().cbegin() + data_offset() + this->size();
1215 }
1216
1217 template <class CT, class... S>
1218 template <class T>
1219 auto xview<CT, S...>::linear_rbegin() -> reverse_linear_iterator
1220 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1221 {
1222 return reverse_linear_iterator(linear_end());
1223 }
1224
1225 template <class CT, class... S>
1226 template <class T>
1227 auto xview<CT, S...>::linear_rend() -> reverse_linear_iterator
1228 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1229 {
1230 return reverse_linear_iterator(linear_begin());
1231 }
1232
1233 template <class CT, class... S>
1234 template <class T>
1235 auto xview<CT, S...>::linear_rbegin() const -> const_reverse_linear_iterator
1236 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1237 {
1238 return linear_crbegin();
1239 }
1240
1241 template <class CT, class... S>
1242 template <class T>
1243 auto xview<CT, S...>::linear_rend() const -> const_reverse_linear_iterator
1244 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1245 {
1246 return linear_crend();
1247 }
1248
1249 template <class CT, class... S>
1250 template <class T>
1251 auto xview<CT, S...>::linear_crbegin() const -> const_reverse_linear_iterator
1252 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1253 {
1254 return const_reverse_linear_iterator(linear_end());
1255 }
1256
1257 template <class CT, class... S>
1258 template <class T>
1259 auto xview<CT, S...>::linear_crend() const -> const_reverse_linear_iterator
1260 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1261 {
1262 return const_reverse_linear_iterator(linear_begin());
1263 }
1264
1268 template <class CT, class... S>
1269 template <class T>
1270 inline auto xview<CT, S...>::strides() const
1271 -> const inner_strides_type& requires(has_data_interface_concept<T>and strided_view_concept<CT, S...>) {
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 -> const inner_strides_type& requires(has_data_interface_concept<T>and strided_view_concept<CT, S...>) {
1284 if (!m_strides_computed)
1285 {
1286 compute_strides(std::integral_constant<bool, has_trivial_strides>{});
1287 m_strides_computed = true;
1288 }
1289 return m_backstrides;
1290 }
1291
1295 template <class CT, class... S>
1296 template <class T>
1297 inline auto xview<CT, S...>::data() const -> const_pointer
1298 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1299 {
1300 return m_e.data();
1301 }
1302
1303 template <class CT, class... S>
1304 template <class T>
1305 inline auto xview<CT, S...>::data() -> pointer
1307 {
1308 return m_e.data();
1309 }
1310
1311 template <class CT, class... S>
1312 template <std::size_t... I>
1313 inline std::size_t xview<CT, S...>::data_offset_impl(std::index_sequence<I...>) const noexcept
1314 {
1315 auto temp = std::array<std::ptrdiff_t, sizeof...(S)>(
1316 {(static_cast<ptrdiff_t>(xt::value(std::get<I>(m_slices), 0)))...}
1317 );
1318
1319 std::ptrdiff_t result = 0;
1320 std::size_t i = 0;
1321 for (; i < std::min(sizeof...(S), m_e.strides().size()); ++i)
1322 {
1323 result += temp[i] * m_e.strides()[i - newaxis_count_before<S...>(i)];
1324 }
1325 for (; i < sizeof...(S); ++i)
1326 {
1327 result += temp[i];
1328 }
1329 return static_cast<std::size_t>(result) + m_e.data_offset();
1330 }
1331
1335 template <class CT, class... S>
1336 template <class T>
1337 inline std::size_t xview<CT, S...>::data_offset() const noexcept
1338 requires(has_data_interface_concept<T> and strided_view_concept<CT, S...>)
1339 {
1340 if (!m_strides_computed)
1341 {
1342 compute_strides(std::integral_constant<bool, has_trivial_strides>{});
1343 m_strides_computed = true;
1344 }
1345 return m_data_offset;
1346 }
1347
1349
1350 template <class CT, class... S>
1351 inline auto xview<CT, S...>::underlying_size(size_type dim) const -> size_type
1352 {
1353 return m_e.shape()[dim];
1354 }
1355
1356 template <class CT, class... S>
1357 inline auto xview<CT, S...>::operator&() & -> xtl::xclosure_pointer<self_type&>
1358 {
1359 return xtl::closure_pointer(*this);
1360 }
1361
1362 template <class CT, class... S>
1363 inline auto xview<CT, S...>::operator&() const& -> xtl::xclosure_pointer<const self_type&>
1364 {
1365 return xtl::closure_pointer(*this);
1366 }
1367
1368 template <class CT, class... S>
1369 inline auto xview<CT, S...>::operator&() && -> xtl::xclosure_pointer<self_type>
1370 {
1371 return xtl::closure_pointer(std::move(*this));
1372 }
1373
1378
1384 template <class CT, class... S>
1385 template <class ST>
1386 inline bool xview<CT, S...>::broadcast_shape(ST& shape, bool) const
1387 {
1388 return xt::broadcast_shape(m_shape, shape);
1389 }
1390
1396 template <class CT, class... S>
1397 template <class ST>
1398 inline bool xview<CT, S...>::has_linear_assign(const ST& str) const
1399 {
1400 if constexpr (is_strided_view)
1401 {
1402 return str.size() == strides().size() && std::equal(str.cbegin(), str.cend(), strides().begin());
1403 }
1404 else
1405 {
1406 return false;
1407 }
1408 }
1409
1411
1412 template <class CT, class... S>
1413 template <class It>
1414 inline It xview<CT, S...>::data_xbegin_impl(It begin) const noexcept
1415 {
1416 return begin + data_offset();
1417 }
1418
1419 template <class CT, class... S>
1420 template <class It>
1421 inline It xview<CT, S...>::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept
1422 {
1423 return strided_data_end(*this, begin, l, offset);
1424 }
1425
1426 template <class CT, class... S>
1427 inline auto xview<CT, S...>::data_xbegin() noexcept -> container_iterator
1428 {
1429 return data_xbegin_impl(data());
1430 }
1431
1432 template <class CT, class... S>
1433 inline auto xview<CT, S...>::data_xbegin() const noexcept -> const_container_iterator
1434 {
1435 return data_xbegin_impl(data());
1436 }
1437
1438 template <class CT, class... S>
1439 inline auto xview<CT, S...>::data_xend(layout_type l, size_type offset) noexcept -> container_iterator
1440 {
1441 return data_xend_impl(data() + data_offset(), l, offset);
1442 }
1443
1444 template <class CT, class... S>
1445 inline auto xview<CT, S...>::data_xend(layout_type l, size_type offset) const noexcept
1446 -> const_container_iterator
1447 {
1448 return data_xend_impl(data() + data_offset(), l, offset);
1449 }
1450
1451 // Assign to operator enabled for contigous views
1452 template <class CT, class... S>
1453 template <class E, class T>
1454 void xview<CT, S...>::assign_to(xexpression<E>& e, bool force_resize) const
1455 requires(has_data_interface_concept<T> and contiguous_view_concept<E, S...>)
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) -> void
1479 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>)
1480 {
1481 return m_e.template store_simd<xt_simd::unaligned_mode>(data_offset() + i, e);
1482 }
1483
1484 template <class CT, class... S>
1485 template <class align, class requested_type, std::size_t N, class T>
1486 inline auto xview<CT, S...>::load_simd(size_type i) const -> simd_return_type<requested_type>
1487 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>)
1488 {
1489 return m_e.template load_simd<xt_simd::unaligned_mode, requested_type>(data_offset() + i);
1490 }
1491
1492 template <class CT, class... S>
1493 template <class T>
1494 inline auto xview<CT, S...>::data_element(size_type i) -> reference
1495 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>)
1496 {
1497 return m_e.data_element(data_offset() + i);
1498 }
1499
1500 template <class CT, class... S>
1501 template <class T>
1502 inline auto xview<CT, S...>::data_element(size_type i) const -> const_reference
1503 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>)
1504 {
1505 return m_e.data_element(data_offset() + i);
1506 }
1507
1508 template <class CT, class... S>
1509 template <class T>
1510 inline auto xview<CT, S...>::flat(size_type i) -> reference
1511 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>)
1512 {
1513 XTENSOR_ASSERT(is_contiguous());
1514 return m_e.flat(data_offset() + i);
1515 }
1516
1517 template <class CT, class... S>
1518 template <class T>
1519 inline auto xview<CT, S...>::flat(size_type i) const -> const_reference
1520 requires(has_simd_interface_concept<T> and strided_view_concept<CT, S...>)
1521 {
1522 XTENSOR_ASSERT(is_contiguous());
1523 return m_e.flat(data_offset() + i);
1524 }
1525
1526 template <class CT, class... S>
1527 template <class... Args>
1528 inline auto xview<CT, S...>::make_index_sequence(Args...) const noexcept
1529 {
1530 return std::make_index_sequence<
1531 (sizeof...(Args) + integral_count<S...>() > newaxis_count<S...>()
1532 ? sizeof...(Args) + integral_count<S...>() - newaxis_count<S...>()
1533 : 0)>();
1534 }
1535
1536 template <class CT, class... S>
1537 template <std::size_t... I>
1538 inline auto xview<CT, S...>::compute_strides_impl(std::index_sequence<I...>) const noexcept
1539 {
1540 std::size_t original_dim = m_e.dimension();
1541 return std::array<std::ptrdiff_t, sizeof...(I)>(
1542 {(static_cast<std::ptrdiff_t>(xt::step_size(std::get<integral_skip<S...>(I)>(m_slices), 1))
1543 * ((integral_skip<S...>(I) - newaxis_count_before<S...>(integral_skip<S...>(I))) < original_dim
1544 ? m_e.strides()[integral_skip<S...>(I) - newaxis_count_before<S...>(integral_skip<S...>(I))]
1545 : 1))...}
1546 );
1547 }
1548
1549 template <class CT, class... S>
1550 inline void xview<CT, S...>::compute_strides(std::false_type) const
1551 {
1552 m_strides = xtl::make_sequence<inner_strides_type>(this->dimension(), 0);
1553 m_backstrides = xtl::make_sequence<inner_strides_type>(this->dimension(), 0);
1554
1555 constexpr std::size_t n_strides = sizeof...(S) - integral_count<S...>();
1556
1557 auto slice_strides = compute_strides_impl(std::make_index_sequence<n_strides>());
1558
1559 for (std::size_t i = 0; i < n_strides; ++i)
1560 {
1561 m_strides[i] = slice_strides[i];
1562 // adapt strides for shape[i] == 1 to make consistent with rest of xtensor
1563 detail::adapt_strides(shape(), m_strides, &m_backstrides, i);
1564 }
1565 for (std::size_t i = n_strides; i < this->dimension(); ++i)
1566 {
1567 m_strides[i] = m_e.strides()[i + integral_count<S...>() - newaxis_count<S...>()];
1568 detail::adapt_strides(shape(), m_strides, &m_backstrides, i);
1569 }
1570
1571 m_data_offset = data_offset_impl(std::make_index_sequence<sizeof...(S)>());
1572 }
1573
1574 template <class CT, class... S>
1575 inline void xview<CT, S...>::compute_strides(std::true_type) const
1576 {
1577 }
1578
1579 template <class CT, class... S>
1580 inline auto xview<CT, S...>::access() -> reference
1581 {
1582 return access_impl(make_index_sequence());
1583 }
1584
1585 template <class CT, class... S>
1586 template <class Arg, class... Args>
1587 inline auto xview<CT, S...>::access(Arg arg, Args... args) -> reference
1588 {
1589 if (sizeof...(Args) >= this->dimension())
1590 {
1591 return access(args...);
1592 }
1593 return access_impl(make_index_sequence(arg, args...), arg, args...);
1594 }
1595
1596 template <class CT, class... S>
1597 inline auto xview<CT, S...>::access() const -> const_reference
1598 {
1599 return access_impl(make_index_sequence());
1600 }
1601
1602 template <class CT, class... S>
1603 template <class Arg, class... Args>
1604 inline auto xview<CT, S...>::access(Arg arg, Args... args) const -> const_reference
1605 {
1606 if (sizeof...(Args) >= this->dimension())
1607 {
1608 return access(args...);
1609 }
1610 return access_impl(make_index_sequence(arg, args...), arg, args...);
1611 }
1612
1613 template <class CT, class... S>
1614 template <typename std::decay_t<CT>::size_type... I, class... Args>
1615 inline auto xview<CT, S...>::unchecked_impl(std::index_sequence<I...>, Args... args) -> reference
1616 {
1617 return m_e.unchecked(index<I>(args...)...);
1618 }
1619
1620 template <class CT, class... S>
1621 template <typename std::decay_t<CT>::size_type... I, class... Args>
1622 inline auto xview<CT, S...>::unchecked_impl(std::index_sequence<I...>, Args... args) const
1623 -> const_reference
1624 {
1625 return m_e.unchecked(index<I>(args...)...);
1626 }
1627
1628 template <class CT, class... S>
1629 template <typename std::decay_t<CT>::size_type... I, class... Args>
1630 inline auto xview<CT, S...>::access_impl(std::index_sequence<I...>, Args... args) -> reference
1631 {
1632 return m_e(index<I>(args...)...);
1633 }
1634
1635 template <class CT, class... S>
1636 template <typename std::decay_t<CT>::size_type... I, class... Args>
1637 inline auto xview<CT, S...>::access_impl(std::index_sequence<I...>, Args... args) const -> const_reference
1638 {
1639 return m_e(index<I>(args...)...);
1640 }
1641
1642 template <class CT, class... S>
1643 template <typename std::decay_t<CT>::size_type I, class... Args>
1644 inline auto xview<CT, S...>::index(Args... args) const -> size_type
1645 {
1646 if constexpr (lesser_condition<I>::value)
1647 {
1648 constexpr size_type slice_index = newaxis_skip<S...>(I);
1649 return sliced_access<slice_index - integral_count_before<S...>(slice_index)>(
1650 std::get<slice_index>(m_slices),
1651 args...
1652 );
1653 }
1654 else
1655 {
1656 return argument<I - integral_count<S...>() + newaxis_count<S...>()>(args...);
1657 }
1658 }
1659
1660 template <class CT, class... S>
1661 template <typename std::decay_t<CT>::size_type I, class T>
1662 inline auto xview<CT, S...>::sliced_access(const xslice<T>& slice) const -> size_type
1663 {
1664 return static_cast<size_type>(slice.derived_cast()(0));
1665 }
1666
1667 template <class CT, class... S>
1668 template <typename std::decay_t<CT>::size_type I, class T, class Arg, class... Args>
1669 inline auto xview<CT, S...>::sliced_access(const xslice<T>& slice, Arg arg, Args... args) const -> size_type
1670 {
1671 using ST = typename T::size_type;
1672 return static_cast<size_type>(
1673 slice.derived_cast()(argument<I>(static_cast<ST>(arg), static_cast<ST>(args)...))
1674 );
1675 }
1676
1677 template <class CT, class... S>
1678 template <typename std::decay_t<CT>::size_type I, class T, class... Args>
1679 inline auto xview<CT, S...>::sliced_access(const T& squeeze, Args...) const -> size_type
1680 requires(!is_xslice<T>::value)
1681 {
1682 return static_cast<size_type>(squeeze);
1683 }
1684
1685 template <class CT, class... S>
1686 template <class It>
1687 inline auto xview<CT, S...>::make_index(It first, It last) const -> base_index_type
1688 {
1689 auto index = xtl::make_sequence<base_index_type>(m_e.dimension(), 0);
1690 using diff_type = typename std::iterator_traits<It>::difference_type;
1691 using ivalue_type = typename base_index_type::value_type;
1692 auto func1 = [&first](const auto& s) noexcept
1693 {
1694 return get_slice_value(s, first);
1695 };
1696 auto func2 = [](const auto& s) noexcept
1697 {
1698 return xt::value(s, 0);
1699 };
1700
1701 auto s = static_cast<diff_type>(
1702 (std::min)(static_cast<size_type>(std::distance(first, last)), this->dimension())
1703 );
1704 auto first_copy = last - s;
1705 for (size_type i = 0; i != m_e.dimension(); ++i)
1706 {
1707 size_type k = newaxis_skip<S...>(i);
1708
1709 // need to advance captured `first`
1710 first = first_copy;
1711 std::advance(first, static_cast<diff_type>(k - xt::integral_count_before<S...>(i)));
1712
1713 if (first < last)
1714 {
1715 index[i] = k < sizeof...(S) ? apply<size_type>(k, func1, m_slices)
1716 : static_cast<ivalue_type>(*first);
1717 }
1718 else
1719 {
1720 index[i] = k < sizeof...(S) ? apply<size_type>(k, func2, m_slices) : ivalue_type(0);
1721 }
1722 }
1723 return index;
1724 }
1725
1726 template <class CT, class... S>
1727 inline auto xview<CT, S...>::compute_shape(std::true_type) const -> inner_shape_type
1728 {
1729 return inner_shape_type(m_e.shape());
1730 }
1731
1732 template <class CT, class... S>
1733 inline auto xview<CT, S...>::compute_shape(std::false_type) const -> inner_shape_type
1734 {
1735 std::size_t dim = m_e.dimension() - integral_count<S...>() + newaxis_count<S...>();
1736 auto shape = xtl::make_sequence<inner_shape_type>(dim, 0);
1737 auto func = [](const auto& s) noexcept
1738 {
1739 return get_size(s);
1740 };
1741 for (size_type i = 0; i != dim; ++i)
1742 {
1743 size_type index = integral_skip<S...>(i);
1744 shape[i] = index < sizeof...(S) ? apply<size_type>(index, func, m_slices)
1745 : m_e.shape()[index - newaxis_count_before<S...>(index)];
1746 }
1747 return shape;
1748 }
1749
1750 namespace xview_detail
1751 {
1752 template <class V, class T>
1753 inline void run_assign_temporary_impl(V& v, const T& t, std::true_type /* enable strided assign */)
1754 {
1755 strided_loop_assigner<true>::run(v, t);
1756 }
1757
1758 template <class V, class T>
1759 inline void
1760 run_assign_temporary_impl(V& v, const T& t, std::false_type /* fallback to iterator assign */)
1761 {
1762 std::copy(t.cbegin(), t.cend(), v.begin());
1763 }
1764 }
1765
1766 template <class CT, class... S>
1767 inline void xview<CT, S...>::assign_temporary_impl(temporary_type&& tmp)
1768 {
1769 constexpr bool fast_assign = detail::is_strided_view<xexpression_type, S...>::value
1770 && xassign_traits<xview<CT, S...>, temporary_type>::simd_strided_assign();
1771 xview_detail::run_assign_temporary_impl(*this, tmp, std::integral_constant<bool, fast_assign>{});
1772 }
1773
1774 namespace detail
1775 {
1776 template <class E, class... S>
1777 inline std::size_t get_underlying_shape_index(std::size_t I)
1778 {
1779 return I - newaxis_count_before<get_slice_type<E, S>...>(I);
1780 }
1781
1782 template <class... S>
1783 struct check_slice;
1784
1785 template <>
1786 struct check_slice<>
1787 {
1788 using type = void_t<>;
1789 };
1790
1791 template <class S, class... SL>
1792 struct check_slice<S, SL...>
1793 {
1794 static_assert(!std::is_same<S, xellipsis_tag>::value, "ellipsis not supported vith xview");
1795 using type = typename check_slice<SL...>::type;
1796 };
1797
1798 template <class E, std::size_t... I, class... S>
1799 inline auto make_view_impl(E&& e, std::index_sequence<I...>, S&&... slices)
1800 {
1801 // Checks that no ellipsis slice is used
1802 using view_type = xview<xtl::closure_type_t<E>, get_slice_type<std::decay_t<E>, S>...>;
1803 return view_type(
1804 std::forward<E>(e),
1805 get_slice_implementation(
1806 e,
1807 std::forward<S>(slices),
1808 get_underlying_shape_index<std::decay_t<E>, S...>(I)
1809 )...
1810 );
1811 }
1812 }
1813
1823 template <class E, class... S>
1824 inline auto view(E&& e, S&&... slices)
1825 {
1826 return detail::make_view_impl(
1827 std::forward<E>(e),
1828 std::make_index_sequence<sizeof...(S)>(),
1829 std::forward<S>(slices)...
1830 );
1831 }
1832
1833 namespace detail
1834 {
1835 class row_impl
1836 {
1837 public:
1838
1839 template <class E>
1840 inline static auto make(E&& e, const std::ptrdiff_t index)
1841 {
1842 const auto shape = e.shape();
1843 check_dimension(shape);
1844 return view(e, index, xt::all());
1845 }
1846
1847 private:
1848
1849 template <class S>
1850 inline static void check_dimension(const S& shape)
1851 {
1852 if (shape.size() != 2)
1853 {
1854 XTENSOR_THROW(
1855 std::invalid_argument,
1856 "A row can only be accessed on an expression with exact two dimensions"
1857 );
1858 }
1859 }
1860
1861 template <class T, std::size_t N>
1862 inline static void check_dimension(const std::array<T, N>&)
1863 {
1864 static_assert(N == 2, "A row can only be accessed on an expression with exact two dimensions");
1865 }
1866 };
1867
1868 class column_impl
1869 {
1870 public:
1871
1872 template <class E>
1873 inline static auto make(E&& e, const std::ptrdiff_t index)
1874 {
1875 const auto shape = e.shape();
1876 check_dimension(shape);
1877 return view(e, xt::all(), index);
1878 }
1879
1880 private:
1881
1882 template <class S>
1883 inline static void check_dimension(const S& shape)
1884 {
1885 if (shape.size() != 2)
1886 {
1887 XTENSOR_THROW(
1888 std::invalid_argument,
1889 "A column can only be accessed on an expression with exact two dimensions"
1890 );
1891 }
1892 }
1893
1894 template <class T, std::size_t N>
1895 inline static void check_dimension(const std::array<T, N>&)
1896 {
1897 static_assert(N == 2, "A column can only be accessed on an expression with exact two dimensions");
1898 }
1899 };
1900 }
1901
1911 template <class E>
1912 inline auto row(E&& e, std::ptrdiff_t index)
1913 {
1914 return detail::row_impl::make(e, index);
1915 }
1916
1926 template <class E>
1927 inline auto col(E&& e, std::ptrdiff_t index)
1928 {
1929 return detail::column_impl::make(e, index);
1930 }
1931
1932 /***************
1933 * stepper api *
1934 ***************/
1935
1936 template <class CT, class... S>
1937 template <class ST>
1938 inline auto xview<CT, S...>::stepper_begin(const ST& shape) -> stepper
1939 {
1940 const size_type offset = shape.size() - this->dimension();
1941 if constexpr (is_strided_view)
1942 {
1943 return stepper(this, data_xbegin(), offset);
1944 }
1945 else
1946 {
1947 return stepper(this, m_e.stepper_begin(m_e.shape()), offset);
1948 }
1949 }
1950
1951 template <class CT, class... S>
1952 template <class ST>
1953 inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l) -> stepper
1954 {
1955 const size_type offset = shape.size() - this->dimension();
1956 if constexpr (is_strided_view)
1957 {
1958 return stepper(this, data_xend(l, offset), offset);
1959 }
1960 else
1961 {
1962 return stepper(this, m_e.stepper_end(m_e.shape(), l), offset, true, l);
1963 }
1964 }
1965
1966 template <class CT, class... S>
1967 template <class ST>
1968 inline auto xview<CT, S...>::stepper_begin(const ST& shape) const -> const_stepper
1969 {
1970 const size_type offset = shape.size() - this->dimension();
1971 if constexpr (is_strided_view)
1972 {
1973 return const_stepper(this, data_xbegin(), offset);
1974 }
1975 else
1976 {
1977 const xexpression_type& e = m_e;
1978 return const_stepper(this, e.stepper_begin(m_e.shape()), offset);
1979 }
1980 }
1981
1982 template <class CT, class... S>
1983 template <class ST>
1984 inline auto xview<CT, S...>::stepper_end(const ST& shape, layout_type l) const -> const_stepper
1985 {
1986 const size_type offset = shape.size() - this->dimension();
1987 if constexpr (is_strided_view)
1988 {
1989 return const_stepper(this, data_xend(l, offset), offset);
1990 }
1991 else
1992 {
1993 const xexpression_type& e = m_e;
1994 return const_stepper(this, e.stepper_end(m_e.shape(), l), offset, true, l);
1995 }
1996 }
1997
1998 /********************************
1999 * xview_stepper implementation *
2000 ********************************/
2001
2002 template <bool is_const, class CT, class... S>
2003 inline xview_stepper<is_const, CT, S...>::xview_stepper(
2004 view_type* view,
2005 substepper_type it,
2006 size_type offset,
2007 bool end,
2008 layout_type l
2009 )
2010 : p_view(view)
2011 , m_it(it)
2012 , m_offset(offset)
2013 {
2014 if (!end)
2015 {
2016 std::fill(m_index_keeper.begin(), m_index_keeper.end(), 0);
2017 auto func = [](const auto& s) noexcept
2018 {
2019 return xt::value(s, 0);
2020 };
2021 for (size_type i = 0; i < sizeof...(S); ++i)
2022 {
2023 if (!is_newaxis_slice(i))
2024 {
2025 size_type s = apply<size_type>(i, func, p_view->slices());
2026 size_type index = i - newaxis_count_before<S...>(i);
2027 m_it.step(index, s);
2028 }
2029 }
2030 }
2031 else
2032 {
2033 to_end_impl(l);
2034 }
2035 }
2036
2037 template <bool is_const, class CT, class... S>
2038 inline auto xview_stepper<is_const, CT, S...>::operator*() const -> reference
2039 {
2040 return *m_it;
2041 }
2042
2043 template <bool is_const, class CT, class... S>
2044 inline void xview_stepper<is_const, CT, S...>::step(size_type dim)
2045 {
2046 auto func = [this](size_type index, size_type offset)
2047 {
2048 m_it.step(index, offset);
2049 };
2050 common_step_forward(dim, func);
2051 }
2052
2053 template <bool is_const, class CT, class... S>
2054 inline void xview_stepper<is_const, CT, S...>::step_back(size_type dim)
2055 {
2056 auto func = [this](size_type index, size_type offset)
2057 {
2058 m_it.step_back(index, offset);
2059 };
2060 common_step_backward(dim, func);
2061 }
2062
2063 template <bool is_const, class CT, class... S>
2064 inline void xview_stepper<is_const, CT, S...>::step(size_type dim, size_type n)
2065 {
2066 auto func = [this](size_type index, size_type offset)
2067 {
2068 m_it.step(index, offset);
2069 };
2070 common_step_forward(dim, n, func);
2071 }
2072
2073 template <bool is_const, class CT, class... S>
2074 inline void xview_stepper<is_const, CT, S...>::step_back(size_type dim, size_type n)
2075 {
2076 auto func = [this](size_type index, size_type offset)
2077 {
2078 m_it.step_back(index, offset);
2079 };
2080 common_step_backward(dim, n, func);
2081 }
2082
2083 template <bool is_const, class CT, class... S>
2084 inline void xview_stepper<is_const, CT, S...>::reset(size_type dim)
2085 {
2086 auto func = [this](size_type index, size_type offset)
2087 {
2088 m_it.step_back(index, offset);
2089 };
2090 common_reset(dim, func, false);
2091 }
2092
2093 template <bool is_const, class CT, class... S>
2094 inline void xview_stepper<is_const, CT, S...>::reset_back(size_type dim)
2095 {
2096 auto func = [this](size_type index, size_type offset)
2097 {
2098 m_it.step(index, offset);
2099 };
2100 common_reset(dim, func, true);
2101 }
2102
2103 template <bool is_const, class CT, class... S>
2104 inline void xview_stepper<is_const, CT, S...>::to_begin()
2105 {
2106 std::fill(m_index_keeper.begin(), m_index_keeper.end(), 0);
2107 m_it.to_begin();
2108 }
2109
2110 template <bool is_const, class CT, class... S>
2111 inline void xview_stepper<is_const, CT, S...>::to_end(layout_type l)
2112 {
2113 m_it.to_end(l);
2114 to_end_impl(l);
2115 }
2116
2117 template <bool is_const, class CT, class... S>
2118 inline bool xview_stepper<is_const, CT, S...>::is_newaxis_slice(size_type index) const noexcept
2119 {
2120 // A bit tricky but avoids a lot of template instantiations
2121 return newaxis_count_before<S...>(index + 1) != newaxis_count_before<S...>(index);
2122 }
2123
2124 template <bool is_const, class CT, class... S>
2125 inline void xview_stepper<is_const, CT, S...>::to_end_impl(layout_type l)
2126 {
2127 auto func = [](const auto& s) noexcept
2128 {
2129 return xt::value(s, get_size(s) - 1);
2130 };
2131 auto size_func = [](const auto& s) noexcept
2132 {
2133 return get_size(s);
2134 };
2135
2136 for (size_type i = 0; i < sizeof...(S); ++i)
2137 {
2138 if (!is_newaxis_slice(i))
2139 {
2140 size_type s = apply<size_type>(i, func, p_view->slices());
2141 size_type ix = apply<size_type>(i, size_func, p_view->slices());
2142 m_index_keeper[i] = ix - size_type(1);
2143 size_type index = i - newaxis_count_before<S...>(i);
2144 s = p_view->underlying_size(index) - 1 - s;
2145 m_it.step_back(index, s);
2146 }
2147 }
2148 if (l == layout_type::row_major)
2149 {
2150 for (size_type i = sizeof...(S); i > 0; --i)
2151 {
2152 if (!is_newaxis_slice(i - 1))
2153 {
2154 m_index_keeper[i - 1]++;
2155 break;
2156 }
2157 }
2158 }
2159 else if (l == layout_type::column_major)
2160 {
2161 for (size_type i = 0; i < sizeof...(S); ++i)
2162 {
2163 if (!is_newaxis_slice(i))
2164 {
2165 m_index_keeper[i]++;
2166 break;
2167 }
2168 }
2169 }
2170 else
2171 {
2172 XTENSOR_THROW(std::runtime_error, "Iteration only allowed in row or column major.");
2173 }
2174 }
2175
2176 template <bool is_const, class CT, class... S>
2177 template <class F>
2178 void xview_stepper<is_const, CT, S...>::common_step_forward(size_type dim, F f)
2179 {
2180 if (dim >= m_offset)
2181 {
2182 auto func = [&dim, this](const auto& s) noexcept
2183 {
2184 return step_size(s, this->m_index_keeper[dim]++, 1);
2185 };
2186 size_type index = integral_skip<S...>(dim);
2187 if (!is_newaxis_slice(index))
2188 {
2189 size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
2190 : 1;
2191 index -= newaxis_count_before<S...>(index);
2192 f(index, step_size);
2193 }
2194 }
2195 }
2196
2197 template <bool is_const, class CT, class... S>
2198 template <class F>
2199 void xview_stepper<is_const, CT, S...>::common_step_forward(size_type dim, size_type n, F f)
2200 {
2201 if (dim >= m_offset)
2202 {
2203 auto func = [&dim, &n, this](const auto& s) noexcept
2204 {
2205 auto st_size = step_size(s, this->m_index_keeper[dim], n);
2206 this->m_index_keeper[dim] += n;
2207 return size_type(st_size);
2208 };
2209
2210 size_type index = integral_skip<S...>(dim);
2211 if (!is_newaxis_slice(index))
2212 {
2213 size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
2214 : n;
2215 index -= newaxis_count_before<S...>(index);
2216 f(index, step_size);
2217 }
2218 }
2219 }
2220
2221 template <bool is_const, class CT, class... S>
2222 template <class F>
2223 void xview_stepper<is_const, CT, S...>::common_step_backward(size_type dim, F f)
2224 {
2225 if (dim >= m_offset)
2226 {
2227 auto func = [&dim, this](const auto& s) noexcept
2228 {
2229 this->m_index_keeper[dim]--;
2230 return step_size(s, this->m_index_keeper[dim], 1);
2231 };
2232 size_type index = integral_skip<S...>(dim);
2233 if (!is_newaxis_slice(index))
2234 {
2235 size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
2236 : 1;
2237 index -= newaxis_count_before<S...>(index);
2238 f(index, step_size);
2239 }
2240 }
2241 }
2242
2243 template <bool is_const, class CT, class... S>
2244 template <class F>
2245 void xview_stepper<is_const, CT, S...>::common_step_backward(size_type dim, size_type n, F f)
2246 {
2247 if (dim >= m_offset)
2248 {
2249 auto func = [&dim, &n, this](const auto& s) noexcept
2250 {
2251 this->m_index_keeper[dim] -= n;
2252 return step_size(s, this->m_index_keeper[dim], n);
2253 };
2254
2255 size_type index = integral_skip<S...>(dim);
2256 if (!is_newaxis_slice(index))
2257 {
2258 size_type step_size = index < sizeof...(S) ? apply<size_type>(index, func, p_view->slices())
2259 : n;
2260 index -= newaxis_count_before<S...>(index);
2261 f(index, step_size);
2262 }
2263 }
2264 }
2265
2266 template <bool is_const, class CT, class... S>
2267 template <class F>
2268 void xview_stepper<is_const, CT, S...>::common_reset(size_type dim, F f, bool backwards)
2269 {
2270 auto size_func = [](const auto& s) noexcept
2271 {
2272 return get_size(s);
2273 };
2274 auto end_func = [](const auto& s) noexcept
2275 {
2276 return xt::value(s, get_size(s) - 1) - xt::value(s, 0);
2277 };
2278
2279 size_type index = integral_skip<S...>(dim);
2280 if (!is_newaxis_slice(index))
2281 {
2282 if (dim < m_index_keeper.size())
2283 {
2284 size_type size = index < sizeof...(S) ? apply<size_type>(index, size_func, p_view->slices())
2285 : p_view->shape()[dim];
2286 m_index_keeper[dim] = backwards ? size - 1 : 0;
2287 }
2288
2289 size_type reset_n = index < sizeof...(S) ? apply<size_type>(index, end_func, p_view->slices())
2290 : p_view->shape()[dim] - 1;
2291 index -= newaxis_count_before<S...>(index);
2292 f(index, reset_n);
2293 }
2294 }
2295}
2296
2297#endif
Fixed shape implementation for compile time defined arrays.
size_type size() const noexcept(noexcept(derived_cast().shape()))
Base class for xexpressions.
Base class for multidimensional iterable expressions.
derived_type & assign_temporary(temporary_type &&)
Multidimensional view with tensor semantic.
Definition xview.hpp:365
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)
std::size_t data_offset() const noexcept
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:570
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:221
auto row(E &&e, std::ptrdiff_t index)
Constructs and returns a row (sliced view) on the specified expression.
Definition xview.hpp:1912
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:1927
auto view(E &&e, S &&... slices)
Constructs and returns a view on the specified xexpression.
Definition xview.hpp:1824