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