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_ITERABLE_HPP
11 #define XTENSOR_ITERABLE_HPP
12 
13 #include "xiterator.hpp"
14 
15 namespace xt
16 {
17 
18     /*******************
19      * xconst_iterable *
20      *******************/
21 
22     template <class D>
23     struct xiterable_inner_types;
24 
25     /**
26      * @class xconst_iterable
27      * @brief Base class for multidimensional iterable constant expressions
28      *
29      * The xconst_iterable class defines the interface for multidimensional
30      * constant expressions that can be iterated.
31      *
32      * @tparam D The derived type, i.e. the inheriting class for which xconst_iterable
33      *           provides the interface.
34      */
35     template <class D>
36     class xconst_iterable
37     {
38     public:
39 
40         using derived_type = D;
41 
42         using iterable_types = xiterable_inner_types<D>;
43         using inner_shape_type = typename iterable_types::inner_shape_type;
44 
45         using stepper = typename iterable_types::stepper;
46         using const_stepper = typename iterable_types::const_stepper;
47 
48         template <layout_type L>
49         using layout_iterator = xiterator<stepper, inner_shape_type*, L>;
50         template <layout_type L>
51         using const_layout_iterator = xiterator<const_stepper, inner_shape_type*, L>;
52         template <layout_type L>
53         using reverse_layout_iterator = std::reverse_iterator<layout_iterator<L>>;
54         template <layout_type L>
55         using const_reverse_layout_iterator = std::reverse_iterator<const_layout_iterator<L>>;
56 
57         using storage_iterator = layout_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
58         using const_storage_iterator = const_layout_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
59         using reverse_storage_iterator = reverse_layout_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
60         using const_reverse_storage_iterator = const_reverse_layout_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
61 
62         template <class S, layout_type L>
63         using broadcast_iterator = xiterator<stepper, S, L>;
64         template <class S, layout_type L>
65         using const_broadcast_iterator = xiterator<const_stepper, S, L>;
66         template <class S, layout_type L>
67         using reverse_broadcast_iterator = std::reverse_iterator<broadcast_iterator<S, L>>;
68         template <class S, layout_type L>
69         using const_reverse_broadcast_iterator = std::reverse_iterator<const_broadcast_iterator<S, L>>;
70 
71         using iterator = layout_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
72         using const_iterator = const_layout_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
73         using reverse_iterator = reverse_layout_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
74         using const_reverse_iterator = const_reverse_layout_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
75 
76         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
77         const_layout_iterator<L> begin() const noexcept;
78         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
79         const_layout_iterator<L> end() const noexcept;
80         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
81         const_layout_iterator<L> cbegin() const noexcept;
82         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
83         const_layout_iterator<L> cend() const noexcept;
84 
85         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
86         const_reverse_layout_iterator<L> rbegin() const noexcept;
87         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
88         const_reverse_layout_iterator<L> rend() const noexcept;
89         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
90         const_reverse_layout_iterator<L> crbegin() const noexcept;
91         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
92         const_reverse_layout_iterator<L> crend() const noexcept;
93 
94         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
95         const_broadcast_iterator<S, L> begin(const S& shape) const noexcept;
96         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
97         const_broadcast_iterator<S, L> end(const S& shape) const noexcept;
98         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
99         const_broadcast_iterator<S, L> cbegin(const S& shape) const noexcept;
100         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
101         const_broadcast_iterator<S, L> cend(const S& shape) const noexcept;
102 
103         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
104         const_reverse_broadcast_iterator<S, L> rbegin(const S& shape) const noexcept;
105         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
106         const_reverse_broadcast_iterator<S, L> rend(const S& shape) const noexcept;
107         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
108         const_reverse_broadcast_iterator<S, L> crbegin(const S& shape) const noexcept;
109         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
110         const_reverse_broadcast_iterator<S, L> crend(const S& shape) const noexcept;
111 
112     protected:
113 
114         const inner_shape_type& get_shape() const;
115 
116     private:
117 
118         template <layout_type L>
119         const_layout_iterator<L> get_cbegin(bool end_index) const noexcept;
120         template <layout_type L>
121         const_layout_iterator<L> get_cend(bool end_index) const noexcept;
122 
123         template <layout_type L, class S>
124         const_broadcast_iterator<S, L> get_cbegin(const S& shape, bool end_index) const noexcept;
125         template <layout_type L, class S>
126         const_broadcast_iterator<S, L> get_cend(const S& shape, bool end_index) const noexcept;
127 
128         template <class S>
129         const_stepper get_stepper_begin(const S& shape) const noexcept;
130         template <class S>
131         const_stepper get_stepper_end(const S& shape, layout_type l) const noexcept;
132 
133         const derived_type& derived_cast() const;
134     };
135 
136     /*************
137      * xiterable *
138      *************/
139 
140     /**
141      * @class xiterable
142      * @brief Base class for multidimensional iterable expressions
143      *
144      * The xiterable class defines the interface for multidimensional
145      * expressions that can be iterated.
146      *
147      * @tparam D The derived type, i.e. the inheriting class for which xiterable
148      *           provides the interface.
149      */
150     template <class D>
151     class xiterable : public xconst_iterable<D>
152     {
153     public:
154 
155         using derived_type = D;
156 
157         using base_type = xconst_iterable<D>;
158         using inner_shape_type = typename base_type::inner_shape_type;
159 
160         using stepper = typename base_type::stepper;
161         using const_stepper = typename base_type::const_stepper;
162 
163         using storage_iterator = typename base_type::storage_iterator;
164         using reverse_storage_iterator = typename base_type::reverse_storage_iterator;
165 
166         template <layout_type L>
167         using layout_iterator = typename base_type::template layout_iterator<L>;
168         template <layout_type L>
169         using const_layout_iterator = typename base_type::template const_layout_iterator<L>;
170         template <layout_type L>
171         using reverse_layout_iterator = typename base_type::template reverse_layout_iterator<L>;
172         template <layout_type L>
173         using const_reverse_layout_iterator = typename base_type::template const_reverse_layout_iterator<L>;
174 
175         template <class S, layout_type L>
176         using broadcast_iterator = typename base_type::template broadcast_iterator<S, L>;
177         template <class S, layout_type L>
178         using const_broadcast_iterator = typename base_type::template const_broadcast_iterator<S, L>;
179         template <class S, layout_type L>
180         using reverse_broadcast_iterator = typename base_type::template reverse_broadcast_iterator<S, L>;
181         template <class S, layout_type L>
182         using const_reverse_broadcast_iterator = typename base_type::template const_reverse_broadcast_iterator<S, L>;
183 
184         using iterator = typename base_type::iterator;
185         using const_iterator = typename base_type::const_iterator;
186         using reverse_iterator = typename base_type::reverse_iterator;
187         using const_reverse_iterator = typename base_type::const_reverse_iterator;
188 
189         using base_type::begin;
190         using base_type::end;
191         using base_type::rbegin;
192         using base_type::rend;
193 
194         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
195         layout_iterator<L> begin() noexcept;
196         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
197         layout_iterator<L> end() noexcept;
198 
199         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
200         reverse_layout_iterator<L> rbegin() noexcept;
201         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
202         reverse_layout_iterator<L> rend() noexcept;
203 
204         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
205         broadcast_iterator<S, L> begin(const S& shape) noexcept;
206         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
207         broadcast_iterator<S, L> end(const S& shape) noexcept;
208 
209         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
210         reverse_broadcast_iterator<S, L> rbegin(const S& shape) noexcept;
211         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
212         reverse_broadcast_iterator<S, L> rend(const S& shape) noexcept;
213 
214     private:
215 
216         template <layout_type L>
217         layout_iterator<L> get_begin(bool end_index) noexcept;
218         template <layout_type L>
219         layout_iterator<L> get_end(bool end_index) noexcept;
220 
221         template <layout_type L, class S>
222         broadcast_iterator<S, L> get_begin(const S& shape, bool end_index) noexcept;
223         template <layout_type L, class S>
224         broadcast_iterator<S, L> get_end(const S& shape, bool end_index) noexcept;
225 
226         template <class S>
227         stepper get_stepper_begin(const S& shape) noexcept;
228         template <class S>
229         stepper get_stepper_end(const S& shape, layout_type l) noexcept;
230 
231         template <class S>
232         const_stepper get_stepper_begin(const S& shape) const noexcept;
233         template <class S>
234         const_stepper get_stepper_end(const S& shape, layout_type l) const noexcept;
235 
236         derived_type& derived_cast();
237     };
238 
239     /************************
240      * xcontiguous_iterable *
241      ************************/
242 
243     template <class D>
244     struct xcontainer_inner_types;
245 
246     namespace detail
247     {
248         template <class C>
249         struct storage_iterator_traits
250         {
251             using iterator = typename C::iterator;
252             using const_iterator = typename C::const_iterator;
253             using reverse_iterator = typename C::reverse_iterator;
254             using const_reverse_iterator = typename C::const_reverse_iterator;
255         };
256 
257         template <class C>
258         struct storage_iterator_traits<const C>
259         {
260             using iterator = typename C::const_iterator;
261             using const_iterator = iterator;
262             using reverse_iterator = typename C::const_reverse_iterator;
263             using const_reverse_iterator = reverse_iterator;
264         };
265     }
266 
267     /**
268      * @class xcontiguous_iterable
269      * @brief Base class for multidimensional iterable expressions with
270      * contiguous storage
271      *
272      * The xcontiguous_iterable class defines the interface for multidimensional
273      * expressions with contiguous that can be iterated.
274      *
275      * @tparam D The derived type, i.e. the inheriting class for which xcontiguous_iterable
276      *           provides the interface.
277      */
278     template <class D>
279     class xcontiguous_iterable : private xiterable<D>
280     {
281     public:
282 
283         using derived_type = D;
284 
285         using inner_types = xcontainer_inner_types<D>;
286         using storage_type = typename inner_types::storage_type;
287 
288         using iterable_base = xiterable<D>;
289         using stepper = typename iterable_base::stepper;
290         using const_stepper = typename iterable_base::const_stepper;
291 
292         static constexpr layout_type static_layout = inner_types::layout;
293 
294 #if defined(_MSC_VER) && _MSC_VER >= 1910
295         // Workaround for compiler bug in Visual Studio 2017 with respect to alias templates with non-type parameters.
296         template <layout_type L>
297         using layout_iterator = xiterator<typename iterable_base::stepper, typename iterable_base::inner_shape_type*, L>;
298         template <layout_type L>
299         using const_layout_iterator = xiterator<typename iterable_base::const_stepper, typename iterable_base::inner_shape_type*, L>;
300         template <layout_type L>
301         using reverse_layout_iterator = std::reverse_iterator<layout_iterator<L>>;
302         template <layout_type L>
303         using const_reverse_layout_iterator = std::reverse_iterator<const_layout_iterator<L>>;
304 #else
305         template <layout_type L>
306         using layout_iterator = typename iterable_base::template layout_iterator<L>;
307         template <layout_type L>
308         using const_layout_iterator = typename iterable_base::template const_layout_iterator<L>;
309         template <layout_type L>
310         using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator<L>;
311         template <layout_type L>
312         using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator<L>;
313 #endif
314 
315         template <class S, layout_type L>
316         using broadcast_iterator = typename iterable_base::template broadcast_iterator<S, L>;
317         template <class S, layout_type L>
318         using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator<S, L>;
319         template <class S, layout_type L>
320         using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator<S, L>;
321         template <class S, layout_type L>
322         using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator<S, L>;
323 
324         using storage_traits = detail::storage_iterator_traits<storage_type>;
325         using storage_iterator = typename storage_traits::iterator;
326         using const_storage_iterator = typename storage_traits::const_iterator;
327         using reverse_storage_iterator = typename storage_traits::reverse_iterator;
328         using const_reverse_storage_iterator = typename storage_traits::const_reverse_iterator;
329 
330         template <layout_type L, class It1, class It2>
331         using select_iterator_impl = std::conditional_t<L == static_layout, It1, It2>;
332 
333         template <layout_type L>
334         using select_iterator = select_iterator_impl<L, storage_iterator, layout_iterator<L>>;
335         template <layout_type L>
336         using select_const_iterator = select_iterator_impl<L, const_storage_iterator, const_layout_iterator<L>>;
337         template <layout_type L>
338         using select_reverse_iterator = select_iterator_impl<L, reverse_storage_iterator, reverse_layout_iterator<L>>;
339         template <layout_type L>
340         using select_const_reverse_iterator = select_iterator_impl<L, const_reverse_storage_iterator, const_reverse_layout_iterator<L>>;
341 
342         using iterator = select_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
343         using const_iterator = select_const_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
344         using reverse_iterator = select_reverse_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
345         using const_reverse_iterator = select_const_reverse_iterator<XTENSOR_DEFAULT_TRAVERSAL>;
346 
347         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
348         select_iterator<L> begin() noexcept;
349         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
350         select_iterator<L> end() noexcept;
351 
352         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
353         select_const_iterator<L> begin() const noexcept;
354         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
355         select_const_iterator<L> end() const noexcept;
356         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
357         select_const_iterator<L> cbegin() const noexcept;
358         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
359         select_const_iterator<L> cend() const noexcept;
360 
361         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
362         select_reverse_iterator<L> rbegin() noexcept;
363         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
364         select_reverse_iterator<L> rend() noexcept;
365 
366         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
367         select_const_reverse_iterator<L> rbegin() const noexcept;
368         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
369         select_const_reverse_iterator<L> rend() const noexcept;
370         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
371         select_const_reverse_iterator<L> crbegin() const noexcept;
372         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
373         select_const_reverse_iterator<L> crend() const noexcept;
374 
375         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
376         broadcast_iterator<S, L> begin(const S& shape) noexcept;
377         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
378         broadcast_iterator<S, L> end(const S& shape) noexcept;
379 
380         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
381         const_broadcast_iterator<S, L> begin(const S& shape) const noexcept;
382         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
383         const_broadcast_iterator<S, L> end(const S& shape) const noexcept;
384         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
385         const_broadcast_iterator<S, L> cbegin(const S& shape) const noexcept;
386         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
387         const_broadcast_iterator<S, L> cend(const S& shape) const noexcept;
388 
389         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
390         reverse_broadcast_iterator<S, L> rbegin(const S& shape) noexcept;
391         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
392         reverse_broadcast_iterator<S, L> rend(const S& shape) noexcept;
393 
394         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
395         const_reverse_broadcast_iterator<S, L> rbegin(const S& shape) const noexcept;
396         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
397         const_reverse_broadcast_iterator<S, L> rend(const S& shape) const noexcept;
398         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
399         const_reverse_broadcast_iterator<S, L> crbegin(const S& shape) const noexcept;
400         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S>
401         const_reverse_broadcast_iterator<S, L> crend(const S& shape) const noexcept;
402 
403     private:
404 
405         derived_type& derived_cast();
406         const derived_type& derived_cast() const;
407 
408         friend class xiterable<D>;
409         friend class xconst_iterable<D>;
410     };
411 
412     /**********************************
413      * xconst_iterable implementation *
414      **********************************/
415 
416     /**
417      * @name Constant iterators
418      */
419     //@{
420     /**
421      * Returns a constant iterator to the first element of the expression.
422      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
423      */
424     template <class D>
425     template <layout_type L>
begin() const426     inline auto xconst_iterable<D>::begin() const noexcept -> const_layout_iterator<L>
427     {
428         return this->template cbegin<L>();
429     }
430 
431     /**
432      * Returns a constant iterator to the element following the last element
433      * of the expression.
434      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
435      */
436     template <class D>
437     template <layout_type L>
end() const438     inline auto xconst_iterable<D>::end() const noexcept -> const_layout_iterator<L>
439     {
440         return this->template cend<L>();
441     }
442 
443     /**
444      * Returns a constant iterator to the first element of the expression.
445      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
446      */
447     template <class D>
448     template <layout_type L>
cbegin() const449     inline auto xconst_iterable<D>::cbegin() const noexcept -> const_layout_iterator<L>
450     {
451         return this->template get_cbegin<L>(false);
452     }
453 
454     /**
455      * Returns a constant iterator to the element following the last element
456      * of the expression.
457      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
458      */
459     template <class D>
460     template <layout_type L>
cend() const461     inline auto xconst_iterable<D>::cend() const noexcept -> const_layout_iterator<L>
462     {
463         return this->template get_cend<L>(true);
464     }
465     //@}
466 
467     /**
468      * @name Constant reverse iterators
469      */
470     //@{
471     /**
472      * Returns a constant iterator to the first element of the reversed expression.
473      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
474      */
475     template <class D>
476     template <layout_type L>
rbegin() const477     inline auto xconst_iterable<D>::rbegin() const noexcept -> const_reverse_layout_iterator<L>
478     {
479         return this->template crbegin<L>();
480     }
481 
482     /**
483      * Returns a constant iterator to the element following the last element
484      * of the reversed expression.
485      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
486      */
487     template <class D>
488     template <layout_type L>
rend() const489     inline auto xconst_iterable<D>::rend() const noexcept -> const_reverse_layout_iterator<L>
490     {
491         return this->template crend<L>();
492     }
493 
494     /**
495      * Returns a constant iterator to the first element of the reversed expression.
496      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
497      */
498     template <class D>
499     template <layout_type L>
crbegin() const500     inline auto xconst_iterable<D>::crbegin() const noexcept -> const_reverse_layout_iterator<L>
501     {
502         return const_reverse_layout_iterator<L>(get_cend<L>(true));
503     }
504 
505     /**
506      * Returns a constant iterator to the element following the last element
507      * of the reversed expression.
508      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
509      */
510     template <class D>
511     template <layout_type L>
crend() const512     inline auto xconst_iterable<D>::crend() const noexcept -> const_reverse_layout_iterator<L>
513     {
514         return const_reverse_layout_iterator<L>(get_cbegin<L>(false));
515     }
516     //@}
517 
518     /**
519      * @name Constant broadcast iterators
520      */
521     //@{
522     /**
523      * Returns a constant iterator to the first element of the expression. The
524      * iteration is broadcasted to the specified shape.
525      * @param shape the shape used for broadcasting
526      * @tparam S type of the \c shape parameter.
527      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
528      */
529     template <class D>
530     template <layout_type L, class S>
begin(const S & shape) const531     inline auto xconst_iterable<D>::begin(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
532     {
533         return cbegin<L>(shape);
534     }
535 
536     /**
537      * Returns a constant iterator to the element following the last element of the
538      * expression. The iteration is broadcasted to the specified shape.
539      * @param shape the shape used for broadcasting
540      * @tparam S type of the \c shape parameter.
541      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
542      */
543     template <class D>
544     template <layout_type L, class S>
end(const S & shape) const545     inline auto xconst_iterable<D>::end(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
546     {
547         return cend<L>(shape);
548     }
549 
550     /**
551      * Returns a constant iterator to the first element of the expression. The
552      * iteration is broadcasted to the specified shape.
553      * @param shape the shape used for broadcasting
554      * @tparam S type of the \c shape parameter.
555      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
556      */
557     template <class D>
558     template <layout_type L, class S>
cbegin(const S & shape) const559     inline auto xconst_iterable<D>::cbegin(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
560     {
561         return get_cbegin<L, S>(shape, false);
562     }
563 
564     /**
565      * Returns a constant iterator to the element following the last element of the
566      * expression. The iteration is broadcasted to the specified shape.
567      * @param shape the shape used for broadcasting
568      * @tparam S type of the \c shape parameter.
569      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
570      */
571     template <class D>
572     template <layout_type L, class S>
cend(const S & shape) const573     inline auto xconst_iterable<D>::cend(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
574     {
575         return get_cend<L, S>(shape, true);
576     }
577     //@}
578 
579     /**
580      * @name Constant reverse broadcast iterators
581      */
582     //@{
583     /**
584      * Returns a constant iterator to the first element of the reversed expression.
585      * The iteration is broadcasted to the specified shape.
586      * @param shape the shape used for broadcasting
587      * @tparam S type of the \c shape parameter.
588      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
589      */
590     template <class D>
591     template <layout_type L, class S>
rbegin(const S & shape) const592     inline auto xconst_iterable<D>::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
593     {
594         return crbegin<L, S>(shape);
595     }
596 
597     /**
598      * Returns a constant iterator to the element following the last element of the
599      * reversed expression. The iteration is broadcasted to the specified shape.
600      * @param shape the shape used for broadcasting
601      * @tparam S type of the \c shape parameter.
602      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
603      */
604     template <class D>
605     template <layout_type L, class S>
rend(const S & shape) const606     inline auto xconst_iterable<D>::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
607     {
608         return crend<L, S>(shape);
609     }
610 
611     /**
612      * Returns a constant iterator to the first element of the reversed expression.
613      * The iteration is broadcasted to the specified shape.
614      * @param shape the shape used for broadcasting
615      * @tparam S type of the \c shape parameter.
616      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
617      */
618     template <class D>
619     template <layout_type L, class S>
crbegin(const S & shape) const620     inline auto xconst_iterable<D>::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
621     {
622         return const_reverse_broadcast_iterator<S, L>(get_cend<L, S>(shape, true));
623     }
624 
625     /**
626      * Returns a constant iterator to the element following the last element of the
627      * reversed expression. The iteration is broadcasted to the specified shape.
628      * @param shape the shape used for broadcasting
629      * @tparam S type of the \c shape parameter.
630      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
631      */
632     template <class D>
633     template <layout_type L, class S>
crend(const S & shape) const634     inline auto xconst_iterable<D>::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
635     {
636         return const_reverse_broadcast_iterator<S, L>(get_cbegin<L, S>(shape, false));
637     }
638     //@}
639 
640     template <class D>
641     template <layout_type L>
get_cbegin(bool end_index) const642     inline auto xconst_iterable<D>::get_cbegin(bool end_index) const noexcept -> const_layout_iterator<L>
643     {
644         return const_layout_iterator<L>(get_stepper_begin(get_shape()), &get_shape(), end_index);
645     }
646 
647     template <class D>
648     template <layout_type L>
get_cend(bool end_index) const649     inline auto xconst_iterable<D>::get_cend(bool end_index) const noexcept -> const_layout_iterator<L>
650     {
651         return const_layout_iterator<L>(get_stepper_end(get_shape(), L), &get_shape(), end_index);
652     }
653 
654     template <class D>
655     template <layout_type L, class S>
get_cbegin(const S & shape,bool end_index) const656     inline auto xconst_iterable<D>::get_cbegin(const S& shape, bool end_index) const noexcept -> const_broadcast_iterator<S, L>
657     {
658         return const_broadcast_iterator<S, L>(get_stepper_begin(shape), shape, end_index);
659     }
660 
661     template <class D>
662     template <layout_type L, class S>
get_cend(const S & shape,bool end_index) const663     inline auto xconst_iterable<D>::get_cend(const S& shape, bool end_index) const noexcept -> const_broadcast_iterator<S, L>
664     {
665         return const_broadcast_iterator<S, L>(get_stepper_end(shape, L), shape, end_index);
666     }
667 
668     template <class D>
669     template <class S>
get_stepper_begin(const S & shape) const670     inline auto xconst_iterable<D>::get_stepper_begin(const S& shape) const noexcept -> const_stepper
671     {
672         return derived_cast().stepper_begin(shape);
673     }
674 
675     template <class D>
676     template <class S>
get_stepper_end(const S & shape,layout_type l) const677     inline auto xconst_iterable<D>::get_stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper
678     {
679         return derived_cast().stepper_end(shape, l);
680     }
681 
682     template <class D>
get_shape() const683     inline auto xconst_iterable<D>::get_shape() const -> const inner_shape_type&
684     {
685         return derived_cast().shape();
686     }
687 
688     template <class D>
derived_cast() const689     inline auto xconst_iterable<D>::derived_cast() const -> const derived_type&
690     {
691         return *static_cast<const derived_type*>(this);
692     }
693 
694     /****************************
695      * xiterable implementation *
696      ****************************/
697 
698     /**
699      * @name Iterators
700      */
701     //@{
702     /**
703      * Returns an iterator to the first element of the expression.
704      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
705      */
706     template <class D>
707     template <layout_type L>
begin()708     inline auto xiterable<D>::begin() noexcept -> layout_iterator<L>
709     {
710         return get_begin<L>(false);
711     }
712 
713     /**
714      * Returns an iterator to the element following the last element
715      * of the expression.
716      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
717      */
718     template <class D>
719     template <layout_type L>
end()720     inline auto xiterable<D>::end() noexcept -> layout_iterator<L>
721     {
722         return get_end<L>(true);
723     }
724     //@}
725 
726     /**
727      * @name Reverse iterators
728      */
729     //@{
730     /**
731      * Returns an iterator to the first element of the reversed expression.
732      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
733      */
734     template <class D>
735     template <layout_type L>
rbegin()736     inline auto xiterable<D>::rbegin() noexcept -> reverse_layout_iterator<L>
737     {
738         return reverse_layout_iterator<L>(get_end<L>(true));
739     }
740 
741     /**
742      * Returns an iterator to the element following the last element
743      * of the reversed expression.
744      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
745      */
746     template <class D>
747     template <layout_type L>
rend()748     inline auto xiterable<D>::rend() noexcept -> reverse_layout_iterator<L>
749     {
750         return reverse_layout_iterator<L>(get_begin<L>(false));
751     }
752     //@}
753 
754     /**
755      * @name Broadcast iterators
756      */
757     //@{
758     /**
759      * Returns an iterator to the first element of the expression. The
760      * iteration is broadcasted to the specified shape.
761      * @param shape the shape used for broadcasting
762      * @tparam S type of the \c shape parameter.
763      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
764      */
765     template <class D>
766     template <layout_type L, class S>
begin(const S & shape)767     inline auto xiterable<D>::begin(const S& shape) noexcept -> broadcast_iterator<S, L>
768     {
769         return get_begin<L, S>(shape, false);
770     }
771 
772     /**
773      * Returns an iterator to the element following the last element of the
774      * expression. The iteration is broadcasted to the specified shape.
775      * @param shape the shape used for broadcasting
776      * @tparam S type of the \c shape parameter.
777      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
778      */
779     template <class D>
780     template <layout_type L, class S>
end(const S & shape)781     inline auto xiterable<D>::end(const S& shape) noexcept -> broadcast_iterator<S, L>
782     {
783         return get_end<L, S>(shape, true);
784     }
785     //@}
786 
787     /**
788      * @name Reverse broadcast iterators
789      */
790     //@{
791     /**
792      * Returns an iterator to the first element of the reversed expression. The
793      * iteration is broadcasted to the specified shape.
794      * @param shape the shape used for broadcasting
795      * @tparam S type of the \c shape parameter.
796      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
797      */
798     template <class D>
799     template <layout_type L, class S>
rbegin(const S & shape)800     inline auto xiterable<D>::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator<S, L>
801     {
802         return reverse_broadcast_iterator<S, L>(get_end<L, S>(shape, true));
803     }
804 
805     /**
806      * Returns an iterator to the element following the last element of the
807      * reversed expression. The iteration is broadcasted to the specified shape.
808      * @param shape the shape used for broadcasting
809      * @tparam S type of the \c shape parameter.
810      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
811      */
812     template <class D>
813     template <layout_type L, class S>
rend(const S & shape)814     inline auto xiterable<D>::rend(const S& shape) noexcept -> reverse_broadcast_iterator<S, L>
815     {
816         return reverse_broadcast_iterator<S, L>(get_begin<L, S>(shape, false));
817     }
818     //@}
819 
820     template <class D>
821     template <layout_type L>
get_begin(bool end_index)822     inline auto xiterable<D>::get_begin(bool end_index) noexcept -> layout_iterator<L>
823     {
824         return layout_iterator<L>(get_stepper_begin(this->get_shape()), &(this->get_shape()), end_index);
825     }
826 
827     template <class D>
828     template <layout_type L>
get_end(bool end_index)829     inline auto xiterable<D>::get_end(bool end_index) noexcept -> layout_iterator<L>
830     {
831         return layout_iterator<L>(get_stepper_end(this->get_shape(), L), &(this->get_shape()), end_index);
832     }
833 
834     template <class D>
835     template <layout_type L, class S>
get_begin(const S & shape,bool end_index)836     inline auto xiterable<D>::get_begin(const S& shape, bool end_index) noexcept -> broadcast_iterator<S, L>
837     {
838         return broadcast_iterator<S, L>(get_stepper_begin(shape), shape, end_index);
839     }
840 
841     template <class D>
842     template <layout_type L, class S>
get_end(const S & shape,bool end_index)843     inline auto xiterable<D>::get_end(const S& shape, bool end_index) noexcept -> broadcast_iterator<S, L>
844     {
845         return broadcast_iterator<S, L>(get_stepper_end(shape, L), shape, end_index);
846     }
847 
848     template <class D>
849     template <class S>
get_stepper_begin(const S & shape)850     inline auto xiterable<D>::get_stepper_begin(const S& shape) noexcept -> stepper
851     {
852         return derived_cast().stepper_begin(shape);
853     }
854 
855     template <class D>
856     template <class S>
get_stepper_end(const S & shape,layout_type l)857     inline auto xiterable<D>::get_stepper_end(const S& shape, layout_type l) noexcept -> stepper
858     {
859         return derived_cast().stepper_end(shape, l);
860     }
861 
862     template <class D>
863     template <class S>
get_stepper_begin(const S & shape) const864     inline auto xiterable<D>::get_stepper_begin(const S& shape) const noexcept -> const_stepper
865     {
866         return derived_cast().stepper_begin(shape);
867     }
868 
869     template <class D>
870     template <class S>
get_stepper_end(const S & shape,layout_type l) const871     inline auto xiterable<D>::get_stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper
872     {
873         return derived_cast().stepper_end(shape, l);
874     }
875 
876     template <class D>
derived_cast()877     inline auto xiterable<D>::derived_cast() -> derived_type&
878     {
879         return *static_cast<derived_type*>(this);
880     }
881 
882     /***************************************
883      * xcontiguous_iterable implementation *
884      ***************************************/
885 
886      /**
887       * @name Iterators
888       */
889      //@{
890      /**
891       * Returns an iterator to the first element of the expression.
892       * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
893       */
894     template <class D>
895     template <layout_type L>
begin()896     inline auto xcontiguous_iterable<D>::begin() noexcept -> select_iterator<L>
897     {
898         return xtl::mpl::static_if<L == static_layout>([&](auto self)
899         {
900             return self(*this).derived_cast().storage_begin();
901         }, /*else*/ [&](auto self)
902         {
903             return self(*this).iterable_base::template begin<L>();
904         });
905     }
906 
907     /**
908      * Returns an iterator to the element following the last element
909      * of the expression.
910      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
911      */
912     template <class D>
913     template <layout_type L>
end()914     inline auto xcontiguous_iterable<D>::end() noexcept -> select_iterator<L>
915     {
916         return xtl::mpl::static_if<L == static_layout>([&](auto self)
917         {
918             return self(*this).derived_cast().storage_end();
919         }, /*else*/ [&](auto self)
920         {
921             return self(*this).iterable_base::template end<L>();
922         });
923     }
924 
925     /**
926      * Returns a constant iterator to the first element of the expression.
927      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
928      */
929     template <class D>
930     template <layout_type L>
begin() const931     inline auto xcontiguous_iterable<D>::begin() const noexcept -> select_const_iterator<L>
932     {
933         return this->template cbegin<L>();
934     }
935 
936     /**
937      * Returns a constant iterator to the element following the last element
938      * of the expression.
939      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
940      */
941     template <class D>
942     template <layout_type L>
end() const943     inline auto xcontiguous_iterable<D>::end() const noexcept -> select_const_iterator<L>
944     {
945         return this->template cend<L>();
946     }
947 
948     /**
949      * Returns a constant iterator to the first element of the expression.
950      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
951      */
952     template <class D>
953     template <layout_type L>
cbegin() const954     inline auto xcontiguous_iterable<D>::cbegin() const noexcept -> select_const_iterator<L>
955     {
956         return xtl::mpl::static_if<L == static_layout>([&](auto self)
957         {
958             return self(*this).derived_cast().storage_cbegin();
959         }, /*else*/ [&](auto self)
960         {
961             return self(*this).iterable_base::template cbegin<L>();
962         });
963     }
964 
965     /**
966      * Returns a constant iterator to the element following the last element
967      * of the expression.
968      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
969      */
970     template <class D>
971     template <layout_type L>
cend() const972     inline auto xcontiguous_iterable<D>::cend() const noexcept -> select_const_iterator<L>
973     {
974         return xtl::mpl::static_if<L == static_layout>([&](auto self)
975         {
976             return self(*this).derived_cast().storage_cend();
977         }, /*else*/ [&](auto self)
978         {
979             return self(*this).iterable_base::template cend<L>();
980         });
981     }
982     //@}
983 
984     /**
985      * @name Reverse iterators
986      */
987     //@{
988     /**
989      * Returns an iterator to the first element of the reversed expression.
990      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
991      */
992     template <class D>
993     template <layout_type L>
rbegin()994     inline auto xcontiguous_iterable<D>::rbegin() noexcept -> select_reverse_iterator<L>
995     {
996         return xtl::mpl::static_if<L == static_layout>([&](auto self)
997         {
998             return self(*this).derived_cast().storage_rbegin();
999         }, /*else*/ [&](auto self)
1000         {
1001             return self(*this).iterable_base::template rbegin<L>();
1002         });
1003     }
1004 
1005     /**
1006      * Returns an iterator to the element following the last element
1007      * of the reversed expression.
1008      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1009      */
1010     template <class D>
1011     template <layout_type L>
rend()1012     inline auto xcontiguous_iterable<D>::rend() noexcept -> select_reverse_iterator<L>
1013     {
1014         return xtl::mpl::static_if<L == static_layout>([&](auto self)
1015         {
1016             return self(*this).derived_cast().storage_rend();
1017         }, /*else*/ [&](auto self)
1018         {
1019             return self(*this).iterable_base::template rend<L>();
1020         });
1021     }
1022 
1023     /**
1024      * Returns a constant iterator to the first element of the reversed expression.
1025      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1026      */
1027     template <class D>
1028     template <layout_type L>
rbegin() const1029     inline auto xcontiguous_iterable<D>::rbegin() const noexcept -> select_const_reverse_iterator<L>
1030     {
1031         return this->template crbegin<L>();
1032     }
1033 
1034 
1035     /**
1036      * Returns a constant iterator to the element following the last element
1037      * of the reversed expression.
1038      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1039      */
1040     template <class D>
1041     template <layout_type L>
rend() const1042     inline auto xcontiguous_iterable<D>::rend() const noexcept -> select_const_reverse_iterator<L>
1043     {
1044         return this->template crend<L>();
1045     }
1046 
1047     /**
1048      * Returns a constant iterator to the first element of the reversed expression.
1049      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1050      */
1051     template <class D>
1052     template <layout_type L>
crbegin() const1053     inline auto xcontiguous_iterable<D>::crbegin() const noexcept -> select_const_reverse_iterator<L>
1054     {
1055         return xtl::mpl::static_if<L == static_layout>([&](auto self)
1056         {
1057             return self(*this).derived_cast().storage_crbegin();
1058         }, /*else*/ [&](auto self)
1059         {
1060             return self(*this).iterable_base::template crbegin<L>();
1061         });
1062     }
1063 
1064     /**
1065      * Returns a constant iterator to the element following the last element
1066      * of the reversed expression.
1067      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1068      */
1069     template <class D>
1070     template <layout_type L>
crend() const1071     inline auto xcontiguous_iterable<D>::crend() const noexcept -> select_const_reverse_iterator<L>
1072     {
1073         return xtl::mpl::static_if<L == static_layout>([&](auto self)
1074         {
1075             return self(*this).derived_cast().storage_crend();
1076         }, /*else*/ [&](auto self)
1077         {
1078             return self(*this).iterable_base::template crend<L>();
1079         });
1080     }
1081     //@}
1082 
1083     /**
1084      * @name Broadcast iterators
1085      */
1086      /**
1087       * Returns an iterator to the first element of the expression. The
1088       * iteration is broadcasted to the specified shape.
1089       * @param shape the shape used for broadcasting
1090       * @tparam S type of the \c shape parameter.
1091       * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1092       */
1093     //@{
1094     template <class D>
1095     template <layout_type L, class S>
begin(const S & shape)1096     inline auto xcontiguous_iterable<D>::begin(const S& shape) noexcept -> broadcast_iterator<S, L>
1097     {
1098         return iterable_base::template begin<L, S>(shape);
1099     }
1100 
1101     /**
1102      * Returns an iterator to the element following the last element of the
1103      * expression. The iteration is broadcasted to the specified shape.
1104      * @param shape the shape used for broadcasting
1105      * @tparam S type of the \c shape parameter.
1106      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1107      */
1108     template <class D>
1109     template <layout_type L, class S>
end(const S & shape)1110     inline auto xcontiguous_iterable<D>::end(const S& shape) noexcept -> broadcast_iterator<S, L>
1111     {
1112         return iterable_base::template end<L, S>(shape);
1113     }
1114 
1115     /**
1116      * Returns a constant iterator to the first element of the expression. The
1117      * iteration is broadcasted to the specified shape.
1118      * @param shape the shape used for broadcasting
1119      * @tparam S type of the \c shape parameter.
1120      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1121      */
1122     template <class D>
1123     template <layout_type L, class S>
begin(const S & shape) const1124     inline auto xcontiguous_iterable<D>::begin(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
1125     {
1126         return iterable_base::template begin<L, S>(shape);
1127     }
1128 
1129     /**
1130      * Returns a constant iterator to the element following the last element of the
1131      * expression. The iteration is broadcasted to the specified shape.
1132      * @param shape the shape used for broadcasting
1133      * @tparam S type of the \c shape parameter.
1134      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1135      */
1136     template <class D>
1137     template <layout_type L, class S>
end(const S & shape) const1138     inline auto xcontiguous_iterable<D>::end(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
1139     {
1140         return iterable_base::template end<L, S>(shape);
1141     }
1142 
1143     /**
1144      * Returns a constant iterator to the first element of the expression. The
1145      * iteration is broadcasted to the specified shape.
1146      * @param shape the shape used for broadcasting
1147      * @tparam S type of the \c shape parameter.
1148      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1149      */
1150     template <class D>
1151     template <layout_type L, class S>
cbegin(const S & shape) const1152     inline auto xcontiguous_iterable<D>::cbegin(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
1153     {
1154         return iterable_base::template cbegin<L, S>(shape);
1155     }
1156 
1157     /**
1158      * Returns a constant iterator to the element following the last element of the
1159      * expression. The iteration is broadcasted to the specified shape.
1160      * @param shape the shape used for broadcasting
1161      * @tparam S type of the \c shape parameter.
1162      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1163      */
1164     template <class D>
1165     template <layout_type L, class S>
cend(const S & shape) const1166     inline auto xcontiguous_iterable<D>::cend(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
1167     {
1168         return iterable_base::template cend<L, S>(shape);
1169     }
1170     //@}
1171 
1172     /**
1173      * @name Reverse broadcast iterators
1174      */
1175     //@{
1176     /**
1177      * Returns an iterator to the first element of the reversed expression. The
1178      * iteration is broadcasted to the specified shape.
1179      * @param shape the shape used for broadcasting
1180      * @tparam S type of the \c shape parameter.
1181      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1182      */
1183     template <class D>
1184     template <layout_type L, class S>
rbegin(const S & shape)1185     inline auto xcontiguous_iterable<D>::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator<S, L>
1186     {
1187         return iterable_base::template rbegin<L, S>(shape);
1188     }
1189 
1190     /**
1191      * Returns an iterator to the element following the last element of the
1192      * reversed expression. The iteration is broadcasted to the specified shape.
1193      * @param shape the shape used for broadcasting
1194      * @tparam S type of the \c shape parameter.
1195      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1196      */
1197     template <class D>
1198     template <layout_type L, class S>
rend(const S & shape)1199     inline auto xcontiguous_iterable<D>::rend(const S& shape) noexcept -> reverse_broadcast_iterator<S, L>
1200     {
1201         return iterable_base::template rend<L, S>(shape);
1202     }
1203 
1204     /**
1205      * Returns a constant iterator to the first element of the reversed expression.
1206      * The iteration is broadcasted to the specified shape.
1207      * @param shape the shape used for broadcasting
1208      * @tparam S type of the \c shape parameter.
1209      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1210      */
1211     template <class D>
1212     template <layout_type L, class S>
rbegin(const S & shape) const1213     inline auto xcontiguous_iterable<D>::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
1214     {
1215         return iterable_base::template rbegin<L, S>(shape);
1216     }
1217 
1218     /**
1219      * Returns a constant iterator to the element following the last element of the
1220      * reversed expression. The iteration is broadcasted to the specified shape.
1221      * @param shape the shape used for broadcasting
1222      * @tparam S type of the \c shape parameter.
1223      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1224      */
1225     template <class D>
1226     template <layout_type L, class S>
rend(const S & shape) const1227     inline auto xcontiguous_iterable<D>::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
1228     {
1229         return iterable_base::template rend<L, S>(shape);
1230     }
1231 
1232     /**
1233      * Returns a constant iterator to the first element of the reversed expression.
1234      * The iteration is broadcasted to the specified shape.
1235      * @param shape the shape used for broadcasting
1236      * @tparam S type of the \c shape parameter.
1237      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1238      */
1239     template <class D>
1240     template <layout_type L, class S>
crbegin(const S & shape) const1241     inline auto xcontiguous_iterable<D>::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
1242     {
1243         return iterable_base::template crbegin<L, S>(shape);
1244     }
1245 
1246     /**
1247      * Returns a constant iterator to the element following the last element of the
1248      * reversed expression. The iteration is broadcasted to the specified shape.
1249      * @param shape the shape used for broadcasting
1250      * @tparam S type of the \c shape parameter.
1251      * @tparam L order used for the traversal. Default value is \c XTENSOR_DEFAULT_TRAVERSAL.
1252      */
1253     template <class D>
1254     template <layout_type L, class S>
crend(const S & shape) const1255     inline auto xcontiguous_iterable<D>::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
1256     {
1257         return iterable_base::template crend<L, S>(shape);
1258     }
1259     //@}
1260 
1261     template <class D>
derived_cast()1262     inline auto xcontiguous_iterable<D>::derived_cast() -> derived_type&
1263     {
1264         return *static_cast<derived_type*>(this);
1265     }
1266 
1267     template <class D>
derived_cast() const1268     inline auto xcontiguous_iterable<D>::derived_cast() const -> const derived_type&
1269     {
1270         return *static_cast<const derived_type*>(this);
1271     }
1272 
1273 }
1274 
1275 #endif
1276