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_SCALAR_HPP
11 #define XTENSOR_SCALAR_HPP
12 
13 #include <array>
14 #include <cstddef>
15 #include <utility>
16 
17 #include <xtl/xtype_traits.hpp>
18 
19 #include "xaccessible.hpp"
20 #include "xexpression.hpp"
21 #include "xiterable.hpp"
22 #include "xlayout.hpp"
23 #include "xtensor_simd.hpp"
24 
25 namespace xt
26 {
27 
28     /*********************
29      * xscalar extension *
30      *********************/
31 
32     namespace extension
33     {
34         template <class Tag, class CT>
35         struct xscalar_base_impl;
36 
37         template <class CT>
38         struct xscalar_base_impl<xtensor_expression_tag, CT>
39         {
40             using type = xtensor_empty_base;
41         };
42 
43         template <class CT>
44         struct xscalar_base : xscalar_base_impl<get_expression_tag_t<std::decay_t<CT>>, CT>
45         {
46         };
47 
48         template <class CT>
49         using xscalar_base_t = typename xscalar_base<CT>::type;
50     }
51 
52     /***********
53      * xscalar *
54      ***********/
55 
56     // xscalar is a cheap wrapper for a scalar value as an xexpression.
57     template <class CT>
58     class xscalar;
59 
60     template <bool is_const, class CT>
61     class xscalar_stepper;
62 
63     template <bool is_const, class CT>
64     class xdummy_iterator;
65 
66     template <class CT>
67     struct xiterable_inner_types<xscalar<CT>>
68     {
69         using value_type = std::decay_t<CT>;
70         using inner_shape_type = std::array<std::size_t, 0>;
71         using shape_type = inner_shape_type;
72         using const_stepper = xscalar_stepper<true, CT>;
73         using stepper = xscalar_stepper<false, CT>;
74     };
75 
76     template <class CT>
77     struct xcontainer_inner_types<xscalar<CT>>
78     {
79         using value_type = std::decay_t<CT>;
80         using reference = value_type&;
81         using const_reference = const value_type&;
82         using size_type = std::size_t;
83     };
84 
85     template <class CT>
86     class xscalar : public xsharable_expression<xscalar<CT>>,
87                     private xiterable<xscalar<CT>>,
88                     private xaccessible<xscalar<CT>>,
89                     public extension::xscalar_base_t<CT>
90     {
91     public:
92 
93         using self_type = xscalar<CT>;
94         using xexpression_type = std::decay_t<CT>;
95         using extension_base = extension::xscalar_base_t<CT>;
96         using accessible_base = xaccessible<self_type>;
97         using expression_tag = typename extension_base::expression_tag;
98         using inner_types = xcontainer_inner_types<self_type>;
99 
100         using value_type = typename inner_types::value_type;
101         using reference = typename inner_types::reference;
102         using const_reference = typename inner_types::const_reference;
103         using pointer = value_type*;
104         using const_pointer = const value_type*;
105         using size_type = typename inner_types::size_type;
106         using difference_type = std::ptrdiff_t;
107         using simd_value_type = xt_simd::simd_type<value_type>;
108         using bool_load_type = xt::bool_load_type<value_type>;
109 
110         using iterable_base = xiterable<self_type>;
111         using inner_shape_type = typename iterable_base::inner_shape_type;
112         using shape_type = inner_shape_type;
113 
114         using stepper = typename iterable_base::stepper;
115         using const_stepper = typename iterable_base::const_stepper;
116 
117         template <layout_type L>
118         using layout_iterator = typename iterable_base::template layout_iterator<L>;
119         template <layout_type L>
120         using const_layout_iterator = typename iterable_base::template const_layout_iterator<L>;
121 
122         template <layout_type L>
123         using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator<L>;
124         template <layout_type L>
125         using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator<L>;
126 
127         template <class S, layout_type L>
128         using broadcast_iterator = typename iterable_base::template broadcast_iterator<S, L>;
129         template <class S, layout_type L>
130         using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator<S, L>;
131 
132         template <class S, layout_type L>
133         using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator<S, L>;
134         template <class S, layout_type L>
135         using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator<S, L>;
136 
137         using iterator = value_type*;
138         using const_iterator = const value_type*;
139         using reverse_iterator = std::reverse_iterator<iterator>;
140         using const_reverse_iterator = std::reverse_iterator<const_iterator>;
141 
142         using dummy_iterator = xdummy_iterator<false, CT>;
143         using const_dummy_iterator = xdummy_iterator<true, CT>;
144 
145         static constexpr layout_type static_layout = layout_type::any;
146         static constexpr bool contiguous_layout = true;
147 
148         xscalar() noexcept;
149         xscalar(CT value) noexcept;
150 
151         operator value_type&() noexcept;
152         operator const value_type&() const noexcept;
153 
154         size_type size() const noexcept;
155         const shape_type& shape() const noexcept;
156         size_type shape(size_type i) const noexcept;
157         layout_type layout() const noexcept;
158         bool is_contiguous() const noexcept;
159         using accessible_base::dimension;
160         using accessible_base::shape;
161 
162         template <class... Args>
163         reference operator()(Args...) noexcept;
164         template <class... Args>
165         reference unchecked(Args...) noexcept;
166 
167         template <class... Args>
168         const_reference operator()(Args...) const noexcept;
169         template <class... Args>
170         const_reference unchecked(Args...) const noexcept;
171 
172         using accessible_base::at;
173         using accessible_base::operator[];
174         using accessible_base::periodic;
175         using accessible_base::in_bounds;
176         using accessible_base::front;
177         using accessible_base::back;
178 
179         template <class It>
180         reference element(It, It) noexcept;
181 
182         template <class It>
183         const_reference element(It, It) const noexcept;
184 
185         xexpression_type& expression() noexcept;
186         const xexpression_type& expression() const noexcept;
187 
188         template <class S>
189         bool broadcast_shape(S& shape, bool reuse_cache = false) const noexcept;
190 
191         template <class S>
192         bool has_linear_assign(const S& strides) const noexcept;
193 
194         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
195         iterator begin() noexcept;
196         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
197         iterator end() noexcept;
198 
199         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
200         const_iterator begin() const noexcept;
201         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
202         const_iterator end() const noexcept;
203         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
204         const_iterator cbegin() const noexcept;
205         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
206         const_iterator cend() const noexcept;
207 
208         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
209         reverse_iterator rbegin() noexcept;
210         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
211         reverse_iterator rend() noexcept;
212 
213         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
214         const_reverse_iterator rbegin() const noexcept;
215         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
216         const_reverse_iterator rend() const noexcept;
217         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
218         const_reverse_iterator crbegin() const noexcept;
219         template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
220         const_reverse_iterator crend() const noexcept;
221 
222         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
223         broadcast_iterator<S, L> begin(const S& shape) noexcept;
224         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
225         broadcast_iterator<S, L> end(const S& shape) noexcept;
226 
227         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
228         const_broadcast_iterator<S, L> begin(const S& shape) const noexcept;
229         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
230         const_broadcast_iterator<S, L> end(const S& shape) const noexcept;
231         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
232         const_broadcast_iterator<S, L> cbegin(const S& shape) const noexcept;
233         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
234         const_broadcast_iterator<S, L> cend(const S& shape) const noexcept;
235 
236 
237         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
238         reverse_broadcast_iterator<S, L> rbegin(const S& shape) noexcept;
239         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
240         reverse_broadcast_iterator<S, L> rend(const S& shape) noexcept;
241 
242         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
243         const_reverse_broadcast_iterator<S, L> rbegin(const S& shape) const noexcept;
244         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
245         const_reverse_broadcast_iterator<S, L> rend(const S& shape) const noexcept;
246         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
247         const_reverse_broadcast_iterator<S, L> crbegin(const S& shape) const noexcept;
248         template <class S, layout_type L = XTENSOR_DEFAULT_TRAVERSAL>
249         const_reverse_broadcast_iterator<S, L> crend(const S& shape) const noexcept;
250 
251         iterator storage_begin() noexcept;
252         iterator storage_end() noexcept;
253 
254         const_iterator storage_begin() const noexcept;
255         const_iterator storage_end() const noexcept;
256         const_iterator storage_cbegin() const noexcept;
257         const_iterator storage_cend() const noexcept;
258 
259         reverse_iterator storage_rbegin() noexcept;
260         reverse_iterator storage_rend() noexcept;
261 
262         const_reverse_iterator storage_rbegin() const noexcept;
263         const_reverse_iterator storage_rend() const noexcept;
264         const_reverse_iterator storage_crbegin() const noexcept;
265         const_reverse_iterator storage_crend() const noexcept;
266 
267         template <class S>
268         stepper stepper_begin(const S& shape) noexcept;
269         template <class S>
270         stepper stepper_end(const S& shape, layout_type l) noexcept;
271 
272         template <class S>
273         const_stepper stepper_begin(const S& shape) const noexcept;
274         template <class S>
275         const_stepper stepper_end(const S& shape, layout_type l) const noexcept;
276 
277         dummy_iterator dummy_begin() noexcept;
278         dummy_iterator dummy_end() noexcept;
279 
280         const_dummy_iterator dummy_begin() const noexcept;
281         const_dummy_iterator dummy_end() const noexcept;
282 
283         reference data_element(size_type i) noexcept;
284         const_reference data_element(size_type i) const noexcept;
285 
286         reference flat(size_type i) noexcept;
287         const_reference flat(size_type i) const noexcept;
288 
289         template <class align, class simd = simd_value_type>
290         void store_simd(size_type i, const simd& e);
291         template <class align, class requested_type = value_type,
292                   std::size_t N = xt_simd::simd_traits<requested_type>::size>
293         xt_simd::simd_return_type<value_type, requested_type>
294         load_simd(size_type i) const;
295 
296     private:
297 
298         CT m_value;
299 
300         friend class xconst_iterable<self_type>;
301         friend class xiterable<self_type>;
302         friend class xaccessible<self_type>;
303         friend class xconst_accessible<self_type>;
304     };
305 
306     namespace detail
307     {
308         template <class E>
309         struct is_xscalar_impl : std::false_type
310         {
311         };
312 
313         template <class E>
314         struct is_xscalar_impl<xscalar<E>> : std::true_type
315         {
316         };
317     }
318 
319     template <class E>
320     using is_xscalar = detail::is_xscalar_impl<E>;
321 
322     namespace detail
323     {
324         template <class... E>
325         struct all_xscalar
326         {
327             static constexpr bool value = xtl::conjunction<is_xscalar<std::decay_t<E>>...>::value;
328         };
329     }
330 
331     // Note: MSVC bug workaround. Cannot just define
332     // template <class... E>
333     // using all_xscalar = xtl::conjunction<is_xscalar<std::decay_t<E>>...>;
334 
335     template <class... E>
336     using all_xscalar = detail::all_xscalar<E...>;
337 
338     /******************
339      * xref and xcref *
340      ******************/
341 
342     template <class T>
343     xscalar<T&> xref(T& t);
344 
345     template <class T>
346     xscalar<const T&> xcref(T& t);
347 
348     /*******************
349      * xscalar_stepper *
350      *******************/
351 
352     template <bool is_const, class CT>
353     class xscalar_stepper
354     {
355     public:
356 
357         using self_type = xscalar_stepper<is_const, CT>;
358         using storage_type = std::conditional_t<is_const,
359                                                 const xscalar<CT>,
360                                                 xscalar<CT>>;
361 
362         using value_type = typename storage_type::value_type;
363         using reference = std::conditional_t<is_const,
364                                              typename storage_type::const_reference,
365                                              typename storage_type::reference>;
366         using pointer = std::conditional_t<is_const,
367                                            typename storage_type::const_pointer,
368                                            typename storage_type::pointer>;
369         using size_type = typename storage_type::size_type;
370         using difference_type = typename storage_type::difference_type;
371         using shape_type = typename storage_type::shape_type;
372 
373         template <class requested_type>
374         using simd_return_type = xt_simd::simd_return_type<value_type, requested_type>;
375 
376         xscalar_stepper(storage_type* c) noexcept;
377 
378         reference operator*() const noexcept;
379 
380         void step(size_type dim, size_type n = 1) noexcept;
381         void step_back(size_type dim, size_type n = 1) noexcept;
382         void reset(size_type dim) noexcept;
383         void reset_back(size_type dim) noexcept;
384 
385         void to_begin() noexcept;
386         void to_end(layout_type l) noexcept;
387 
388         template <class T>
389         simd_return_type<T> step_simd();
390 
391         void step_leading();
392 
393     private:
394 
395         storage_type* p_c;
396     };
397 
398     /*******************
399      * xdummy_iterator *
400      *******************/
401 
402     namespace detail
403     {
404         template <bool is_const, class CT>
405         using dummy_reference_t = std::conditional_t<is_const,
406                                                      typename xscalar<CT>::const_reference,
407                                                      typename xscalar<CT>::reference>;
408 
409         template <bool is_const, class CT>
410         using dummy_pointer_t = std::conditional_t<is_const,
411                                                    typename xscalar<CT>::const_pointer,
412                                                    typename xscalar<CT>::pointer>;
413     }
414 
415     template <bool is_const, class CT>
416     class xdummy_iterator
417         : public xtl::xrandom_access_iterator_base<xdummy_iterator<is_const, CT>,
418                                                    typename xscalar<CT>::value_type,
419                                                    typename xscalar<CT>::difference_type,
420                                                    detail::dummy_pointer_t<is_const, CT>,
421                                                    detail::dummy_reference_t<is_const, CT>>
422     {
423     public:
424 
425         using self_type = xdummy_iterator<is_const, CT>;
426         using storage_type = std::conditional_t<is_const,
427                                                 const xscalar<CT>,
428                                                 xscalar<CT>>;
429 
430         using value_type = typename storage_type::value_type;
431         using reference = detail::dummy_reference_t<is_const, CT>;
432         using pointer = detail::dummy_pointer_t<is_const, CT>;
433         using difference_type = typename storage_type::difference_type;
434         using iterator_category = std::random_access_iterator_tag;
435 
436         explicit xdummy_iterator(storage_type* c) noexcept;
437 
438         self_type& operator++() noexcept;
439         self_type& operator--() noexcept;
440 
441         self_type& operator+=(difference_type n) noexcept;
442         self_type& operator-=(difference_type n) noexcept;
443 
444         difference_type operator-(const self_type& rhs) const noexcept;
445 
446         reference operator*() const noexcept;
447 
448         bool equal(const self_type& rhs) const noexcept;
449         bool less_than(const self_type& rhs) const noexcept;
450 
451     private:
452 
453         storage_type* p_c;
454     };
455 
456     template <bool is_const, class CT>
457     bool operator==(const xdummy_iterator<is_const, CT>& lhs,
458                     const xdummy_iterator<is_const, CT>& rhs) noexcept;
459 
460     template <bool is_const, class CT>
461     bool operator<(const xdummy_iterator<is_const, CT>& lhs,
462                    const xdummy_iterator<is_const, CT>& rhs) noexcept;
463 
464     template <class T>
465     struct is_not_xdummy_iterator : std::true_type
466     {
467     };
468 
469     template <bool is_const, class CT>
470     struct is_not_xdummy_iterator<xdummy_iterator<is_const, CT>> : std::false_type
471     {
472     };
473 
474     /*****************************
475      * linear_begin / linear_end *
476      *****************************/
477 
478     template <class CT>
linear_begin(xscalar<CT> & c)479     XTENSOR_CONSTEXPR_RETURN auto linear_begin(xscalar<CT>& c) noexcept -> decltype(c.dummy_begin())
480     {
481         return c.dummy_begin();
482     }
483 
484     template <class CT>
linear_end(xscalar<CT> & c)485     XTENSOR_CONSTEXPR_RETURN auto linear_end(xscalar<CT>& c) noexcept -> decltype(c.dummy_end())
486     {
487         return c.dummy_end();
488     }
489 
490     template <class CT>
linear_begin(const xscalar<CT> & c)491     XTENSOR_CONSTEXPR_RETURN auto linear_begin(const xscalar<CT>& c) noexcept -> decltype(c.dummy_begin())
492     {
493         return c.dummy_begin();
494     }
495 
496     template <class CT>
linear_end(const xscalar<CT> & c)497     XTENSOR_CONSTEXPR_RETURN auto linear_end(const xscalar<CT>& c) noexcept -> decltype(c.dummy_end())
498     {
499         return c.dummy_end();
500     }
501 
502     /**************************
503      * xscalar implementation *
504      **************************/
505 
506     // This constructor will not compile when CT is a reference type.
507     template <class CT>
xscalar()508     inline xscalar<CT>::xscalar() noexcept
509         : m_value()
510     {
511     }
512 
513     template <class CT>
xscalar(CT value)514     inline xscalar<CT>::xscalar(CT value) noexcept
515         : m_value(value)
516     {
517     }
518 
519     template <class CT>
operator value_type&()520     inline xscalar<CT>::operator value_type&() noexcept
521     {
522         return m_value;
523     }
524 
525     template <class CT>
operator const value_type&() const526     inline xscalar<CT>::operator const value_type&() const noexcept
527     {
528         return m_value;
529     }
530 
531     template <class CT>
size() const532     inline auto xscalar<CT>::size() const noexcept -> size_type
533     {
534         return 1;
535     }
536 
537     template <class CT>
shape() const538     inline auto xscalar<CT>::shape() const noexcept -> const shape_type&
539     {
540         static std::array<size_type, 0> zero_shape;
541         return zero_shape;
542     }
543 
544     template <class CT>
shape(size_type) const545     inline auto xscalar<CT>::shape(size_type) const noexcept -> size_type
546     {
547         return 0;
548     }
549 
550     template <class CT>
layout() const551     inline layout_type xscalar<CT>::layout() const noexcept
552     {
553         return static_layout;
554     }
555 
556     template <class CT>
is_contiguous() const557     inline bool xscalar<CT>::is_contiguous() const noexcept
558     {
559         return true;
560     }
561 
562     template <class CT>
563     template <class... Args>
operator ()(Args...)564     inline auto xscalar<CT>::operator()(Args...) noexcept -> reference
565     {
566         XTENSOR_CHECK_DIMENSION((std::array<int, 0>()), Args()...);
567         return m_value;
568     }
569 
570     template <class CT>
571     template <class... Args>
unchecked(Args...)572     inline auto xscalar<CT>::unchecked(Args...) noexcept -> reference
573     {
574         return m_value;
575     }
576 
577     template <class CT>
578     template <class... Args>
operator ()(Args...) const579     inline auto xscalar<CT>::operator()(Args...) const noexcept -> const_reference
580     {
581         XTENSOR_CHECK_DIMENSION((std::array<int, 0>()), Args()...);
582         return m_value;
583     }
584 
585     template <class CT>
586     template <class... Args>
unchecked(Args...) const587     inline auto xscalar<CT>::unchecked(Args...) const noexcept -> const_reference
588     {
589         return m_value;
590     }
591 
592     template <class CT>
593     template <class It>
element(It,It)594     inline auto xscalar<CT>::element(It, It) noexcept -> reference
595     {
596         return m_value;
597     }
598 
599     template <class CT>
600     template <class It>
element(It,It) const601     inline auto xscalar<CT>::element(It, It) const noexcept -> const_reference
602     {
603         return m_value;
604     }
605 
606     template <class CT>
expression()607     inline auto xscalar<CT>::expression() noexcept -> xexpression_type&
608     {
609         return m_value;
610     }
611 
612     template <class CT>
expression() const613     inline auto xscalar<CT>::expression() const noexcept -> const xexpression_type&
614     {
615         return m_value;
616     }
617 
618     template <class CT>
619     template <class S>
broadcast_shape(S &,bool) const620     inline bool xscalar<CT>::broadcast_shape(S&, bool) const noexcept
621     {
622         return true;
623     }
624 
625     template <class CT>
626     template <class S>
has_linear_assign(const S &) const627     inline bool xscalar<CT>::has_linear_assign(const S&) const noexcept
628     {
629         return true;
630     }
631 
632     template <class CT>
633     template <layout_type L>
begin()634     inline auto xscalar<CT>::begin() noexcept -> iterator
635     {
636         return &m_value;
637     }
638 
639     template <class CT>
640     template <layout_type L>
end()641     inline auto xscalar<CT>::end() noexcept -> iterator
642     {
643         return &m_value + 1;
644     }
645 
646     template <class CT>
647     template <layout_type L>
begin() const648     inline auto xscalar<CT>::begin() const noexcept -> const_iterator
649     {
650         return &m_value;
651     }
652 
653     template <class CT>
654     template <layout_type L>
end() const655     inline auto xscalar<CT>::end() const noexcept -> const_iterator
656     {
657         return &m_value + 1;
658     }
659 
660     template <class CT>
661     template <layout_type L>
cbegin() const662     inline auto xscalar<CT>::cbegin() const noexcept -> const_iterator
663     {
664         return &m_value;
665     }
666 
667     template <class CT>
668     template <layout_type L>
cend() const669     inline auto xscalar<CT>::cend() const noexcept -> const_iterator
670     {
671         return &m_value + 1;
672     }
673 
674     template <class CT>
675     template <layout_type L>
rbegin()676     inline auto xscalar<CT>::rbegin() noexcept -> reverse_iterator
677     {
678         return reverse_iterator(end());
679     }
680 
681     template <class CT>
682     template <layout_type L>
rend()683     inline auto xscalar<CT>::rend() noexcept -> reverse_iterator
684     {
685         return reverse_iterator(begin());
686     }
687 
688     template <class CT>
689     template <layout_type L>
rbegin() const690     inline auto xscalar<CT>::rbegin() const noexcept -> const_reverse_iterator
691     {
692         return crbegin();
693     }
694 
695     template <class CT>
696     template <layout_type L>
rend() const697     inline auto xscalar<CT>::rend() const noexcept -> const_reverse_iterator
698     {
699         return crend();
700     }
701 
702     template <class CT>
703     template <layout_type L>
crbegin() const704     inline auto xscalar<CT>::crbegin() const noexcept -> const_reverse_iterator
705     {
706         return const_reverse_iterator(cend());
707     }
708 
709     template <class CT>
710     template <layout_type L>
crend() const711     inline auto xscalar<CT>::crend() const noexcept -> const_reverse_iterator
712     {
713         return const_reverse_iterator(cbegin());
714     }
715 
716     /*****************************
717     * Broadcasting iterator api *
718     *****************************/
719 
720     template <class CT>
721     template <class S, layout_type L>
begin(const S & shape)722     inline auto xscalar<CT>::begin(const S& shape) noexcept -> broadcast_iterator<S, L>
723     {
724         return iterable_base::template begin<S, L>(shape);
725     }
726 
727     template <class CT>
728     template <class S, layout_type L>
end(const S & shape)729     inline auto xscalar<CT>::end(const S& shape) noexcept -> broadcast_iterator<S, L>
730     {
731         return iterable_base::template end<S, L>(shape);
732     }
733 
734     template <class CT>
735     template <class S, layout_type L>
begin(const S & shape) const736     inline auto xscalar<CT>::begin(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
737     {
738         return iterable_base::template begin<S, L>(shape);
739     }
740 
741     template <class CT>
742     template <class S, layout_type L>
end(const S & shape) const743     inline auto xscalar<CT>::end(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
744     {
745         return iterable_base::template end<S, L>(shape);
746     }
747 
748     template <class CT>
749     template <class S, layout_type L>
cbegin(const S & shape) const750     inline auto xscalar<CT>::cbegin(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
751     {
752         return iterable_base::template cbegin<S, L>(shape);
753     }
754 
755     template <class CT>
756     template <class S, layout_type L>
cend(const S & shape) const757     inline auto xscalar<CT>::cend(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
758     {
759         return iterable_base::template cend<S, L>(shape);
760     }
761 
762     template <class CT>
763     template <class S, layout_type L>
rbegin(const S & shape)764     inline auto xscalar<CT>::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator<S, L>
765     {
766         return iterable_base::template rbegin<S, L>(shape);
767     }
768 
769     template <class CT>
770     template <class S, layout_type L>
rend(const S & shape)771     inline auto xscalar<CT>::rend(const S& shape) noexcept -> reverse_broadcast_iterator<S, L>
772     {
773         return iterable_base::template rend<S, L>(shape);
774     }
775 
776     template <class CT>
777     template <class S, layout_type L>
rbegin(const S & shape) const778     inline auto xscalar<CT>::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
779     {
780         return iterable_base::template rbegin<S, L>(shape);
781     }
782 
783     template <class CT>
784     template <class S, layout_type L>
rend(const S & shape) const785     inline auto xscalar<CT>::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
786     {
787         return iterable_base::template rend<S, L>(shape);
788     }
789 
790     template <class CT>
791     template <class S, layout_type L>
crbegin(const S & shape) const792     inline auto xscalar<CT>::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
793     {
794         return iterable_base::template crbegin<S, L>(shape);
795     }
796 
797     template <class CT>
798     template <class S, layout_type L>
crend(const S & shape) const799     inline auto xscalar<CT>::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
800     {
801         return iterable_base::template crend<S, L>(shape);
802     }
803 
804     template <class CT>
storage_begin()805     inline auto xscalar<CT>::storage_begin() noexcept -> iterator
806     {
807         return this->template begin<XTENSOR_DEFAULT_LAYOUT>();
808     }
809 
810     template <class CT>
storage_end()811     inline auto xscalar<CT>::storage_end() noexcept -> iterator
812     {
813         return this->template end<XTENSOR_DEFAULT_LAYOUT>();
814     }
815 
816     template <class CT>
storage_begin() const817     inline auto xscalar<CT>::storage_begin() const noexcept -> const_iterator
818     {
819         return this->template begin<XTENSOR_DEFAULT_LAYOUT>();
820     }
821 
822     template <class CT>
storage_end() const823     inline auto xscalar<CT>::storage_end() const noexcept -> const_iterator
824     {
825         return this->template end<XTENSOR_DEFAULT_LAYOUT>();
826     }
827 
828     template <class CT>
storage_cbegin() const829     inline auto xscalar<CT>::storage_cbegin() const noexcept -> const_iterator
830     {
831         return this->template cbegin<XTENSOR_DEFAULT_LAYOUT>();
832     }
833 
834     template <class CT>
storage_cend() const835     inline auto xscalar<CT>::storage_cend() const noexcept -> const_iterator
836     {
837         return this->template cend<XTENSOR_DEFAULT_LAYOUT>();
838     }
839 
840     template <class CT>
storage_rbegin()841     inline auto xscalar<CT>::storage_rbegin() noexcept -> reverse_iterator
842     {
843         return this->template rbegin<XTENSOR_DEFAULT_LAYOUT>();
844     }
845 
846     template <class CT>
storage_rend()847     inline auto xscalar<CT>::storage_rend() noexcept -> reverse_iterator
848     {
849         return this->template rend<XTENSOR_DEFAULT_LAYOUT>();
850     }
851 
852     template <class CT>
storage_rbegin() const853     inline auto xscalar<CT>::storage_rbegin() const noexcept -> const_reverse_iterator
854     {
855         return this->template rbegin<XTENSOR_DEFAULT_LAYOUT>();
856     }
857 
858     template <class CT>
storage_rend() const859     inline auto xscalar<CT>::storage_rend() const noexcept -> const_reverse_iterator
860     {
861         return this->template rend<XTENSOR_DEFAULT_LAYOUT>();
862     }
863 
864     template <class CT>
storage_crbegin() const865     inline auto xscalar<CT>::storage_crbegin() const noexcept -> const_reverse_iterator
866     {
867         return this->template crbegin<XTENSOR_DEFAULT_LAYOUT>();
868     }
869 
870     template <class CT>
storage_crend() const871     inline auto xscalar<CT>::storage_crend() const noexcept -> const_reverse_iterator
872     {
873         return this->template crend<XTENSOR_DEFAULT_LAYOUT>();
874     }
875 
876     template <class CT>
877     template <class S>
stepper_begin(const S &)878     inline auto xscalar<CT>::stepper_begin(const S&) noexcept -> stepper
879     {
880         return stepper(this, false);
881     }
882 
883     template <class CT>
884     template <class S>
stepper_end(const S &,layout_type)885     inline auto xscalar<CT>::stepper_end(const S&, layout_type) noexcept -> stepper
886     {
887         return stepper(this);
888     }
889 
890     template <class CT>
891     template <class S>
stepper_begin(const S &) const892     inline auto xscalar<CT>::stepper_begin(const S&) const noexcept -> const_stepper
893     {
894         return const_stepper(this);
895     }
896 
897     template <class CT>
898     template <class S>
stepper_end(const S &,layout_type) const899     inline auto xscalar<CT>::stepper_end(const S&, layout_type) const noexcept -> const_stepper
900     {
901         return const_stepper(this);
902     }
903 
904     template <class CT>
dummy_begin()905     inline auto xscalar<CT>::dummy_begin() noexcept -> dummy_iterator
906     {
907         return dummy_iterator(this);
908     }
909 
910     template <class CT>
dummy_end()911     inline auto xscalar<CT>::dummy_end() noexcept -> dummy_iterator
912     {
913         return dummy_iterator(this);
914     }
915 
916     template <class CT>
dummy_begin() const917     inline auto xscalar<CT>::dummy_begin() const noexcept -> const_dummy_iterator
918     {
919         return const_dummy_iterator(this);
920     }
921 
922     template <class CT>
dummy_end() const923     inline auto xscalar<CT>::dummy_end() const noexcept -> const_dummy_iterator
924     {
925         return const_dummy_iterator(this);
926     }
927 
928     template <class CT>
data_element(size_type)929     inline auto xscalar<CT>::data_element(size_type) noexcept -> reference
930     {
931         return m_value;
932     }
933 
934     template <class CT>
data_element(size_type) const935     inline auto xscalar<CT>::data_element(size_type) const noexcept -> const_reference
936     {
937         return m_value;
938     }
939 
940     template <class CT>
flat(size_type)941     inline auto xscalar<CT>::flat(size_type) noexcept -> reference
942     {
943         return m_value;
944     }
945 
946     template <class CT>
flat(size_type) const947     inline auto xscalar<CT>::flat(size_type) const noexcept -> const_reference
948     {
949         return m_value;
950     }
951 
952     template <class CT>
953     template <class align, class simd>
store_simd(size_type,const simd & e)954     inline void xscalar<CT>::store_simd(size_type, const simd& e)
955     {
956         m_value = static_cast<value_type>(e[0]);
957     }
958 
959     template <class CT>
960     template <class align, class requested_type, std::size_t N>
load_simd(size_type) const961     inline auto xscalar<CT>::load_simd(size_type) const
962         -> xt_simd::simd_return_type<value_type, requested_type>
963     {
964         return xt_simd::broadcast_as<requested_type>(m_value);
965     }
966 
967     template <class T>
xref(T & t)968     inline xscalar<T&> xref(T& t)
969     {
970         return xscalar<T&>(t);
971     }
972 
973     template <class T>
xcref(T & t)974     inline xscalar<const T&> xcref(T& t)
975     {
976         return xscalar<const T&>(t);
977     }
978 
979     /**********************************
980      * xscalar_stepper implementation *
981      **********************************/
982 
983     template <bool is_const, class CT>
xscalar_stepper(storage_type * c)984     inline xscalar_stepper<is_const, CT>::xscalar_stepper(storage_type* c) noexcept
985         : p_c(c)
986     {
987     }
988 
989     template <bool is_const, class CT>
operator *() const990     inline auto xscalar_stepper<is_const, CT>::operator*() const noexcept -> reference
991     {
992         return p_c->operator()();
993     }
994 
995     template <bool is_const, class CT>
step(size_type,size_type)996     inline void xscalar_stepper<is_const, CT>::step(size_type /*dim*/, size_type /*n*/) noexcept
997     {
998     }
999 
1000     template <bool is_const, class CT>
step_back(size_type,size_type)1001     inline void xscalar_stepper<is_const, CT>::step_back(size_type /*dim*/, size_type /*n*/) noexcept
1002     {
1003     }
1004 
1005     template <bool is_const, class CT>
reset(size_type)1006     inline void xscalar_stepper<is_const, CT>::reset(size_type /*dim*/) noexcept
1007     {
1008     }
1009 
1010     template <bool is_const, class CT>
reset_back(size_type)1011     inline void xscalar_stepper<is_const, CT>::reset_back(size_type /*dim*/) noexcept
1012     {
1013     }
1014 
1015     template <bool is_const, class CT>
to_begin()1016     inline void xscalar_stepper<is_const, CT>::to_begin() noexcept
1017     {
1018     }
1019 
1020     template <bool is_const, class CT>
to_end(layout_type)1021     inline void xscalar_stepper<is_const, CT>::to_end(layout_type /*l*/) noexcept
1022     {
1023     }
1024 
1025     template <bool is_const, class CT>
1026     template <class T>
step_simd()1027     inline auto xscalar_stepper<is_const, CT>::step_simd() -> simd_return_type<T>
1028     {
1029         return simd_return_type<T>(p_c->operator()());
1030     }
1031 
1032     template <bool is_const, class CT>
step_leading()1033     inline void xscalar_stepper<is_const, CT>::step_leading()
1034     {
1035     }
1036 
1037     /**********************************
1038      * xdummy_iterator implementation *
1039      **********************************/
1040 
1041     template <bool is_const, class CT>
xdummy_iterator(storage_type * c)1042     inline xdummy_iterator<is_const, CT>::xdummy_iterator(storage_type* c) noexcept
1043         : p_c(c)
1044     {
1045     }
1046 
1047     template <bool is_const, class CT>
operator ++()1048     inline auto xdummy_iterator<is_const, CT>::operator++() noexcept -> self_type&
1049     {
1050         return *this;
1051     }
1052 
1053     template <bool is_const, class CT>
operator --()1054     inline auto xdummy_iterator<is_const, CT>::operator--() noexcept -> self_type&
1055     {
1056         return *this;
1057     }
1058 
1059     template <bool is_const, class CT>
operator +=(difference_type)1060     inline auto xdummy_iterator<is_const, CT>::operator+=(difference_type) noexcept -> self_type&
1061     {
1062         return *this;
1063     }
1064 
1065     template <bool is_const, class CT>
operator -=(difference_type)1066     inline auto xdummy_iterator<is_const, CT>::operator-=(difference_type) noexcept -> self_type&
1067     {
1068         return *this;
1069     }
1070 
1071     template <bool is_const, class CT>
operator -(const self_type &) const1072     inline auto xdummy_iterator<is_const, CT>::operator-(const self_type&) const noexcept -> difference_type
1073     {
1074         return 0;
1075     }
1076 
1077     template <bool is_const, class CT>
operator *() const1078     inline auto xdummy_iterator<is_const, CT>::operator*() const noexcept -> reference
1079     {
1080         return p_c->operator()();
1081     }
1082 
1083     template <bool is_const, class CT>
equal(const self_type & rhs) const1084     inline bool xdummy_iterator<is_const, CT>::equal(const self_type& rhs) const noexcept
1085     {
1086         return p_c == rhs.p_c;
1087     }
1088 
1089     template <bool is_const, class CT>
less_than(const self_type & rhs) const1090     inline bool xdummy_iterator<is_const, CT>::less_than(const self_type& rhs) const noexcept
1091     {
1092         return p_c < rhs.p_c;
1093     }
1094 
1095     template <bool is_const, class CT>
operator ==(const xdummy_iterator<is_const,CT> & lhs,const xdummy_iterator<is_const,CT> & rhs)1096     inline bool operator==(const xdummy_iterator<is_const, CT>& lhs,
1097                            const xdummy_iterator<is_const, CT>& rhs) noexcept
1098     {
1099         return lhs.equal(rhs);
1100     }
1101 
1102     template <bool is_const, class CT>
operator <(const xdummy_iterator<is_const,CT> & lhs,const xdummy_iterator<is_const,CT> & rhs)1103     inline bool operator<(const xdummy_iterator<is_const, CT>& lhs,
1104                           const xdummy_iterator<is_const, CT>& rhs) noexcept
1105     {
1106         return lhs.less_than(rhs);
1107     }
1108 }
1109 
1110 #endif
1111