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_FIXED_HPP
11 #define XTENSOR_FIXED_HPP
12 
13 #include <algorithm>
14 #include <array>
15 #include <cstddef>
16 #include <utility>
17 #include <vector>
18 
19 #include <xtl/xsequence.hpp>
20 
21 #include "xcontainer.hpp"
22 #include "xstrides.hpp"
23 #include "xstorage.hpp"
24 #include "xsemantic.hpp"
25 #include "xtensor_config.hpp"
26 
27 namespace xtl
28 {
29     namespace detail
30     {
31         template <class T, std::size_t N>
32         struct sequence_builder<xt::const_array<T, N>>
33         {
34             using sequence_type = xt::const_array<T, N>;
35             using value_type = typename sequence_type::value_type;
36             using size_type = typename sequence_type::size_type;
37 
makextl::detail::sequence_builder38             inline static sequence_type make(size_type /*size*/, value_type /*v*/)
39             {
40                 return sequence_type();
41             }
42         };
43     }
44 }
45 
46 namespace xt
47 {
48 
49     /**********************
50      * xfixed declaration *
51      **********************/
52 
53     template <class ET, class S, layout_type L, bool SH, class Tag>
54     class xfixed_container;
55 
56     namespace detail
57     {
58         /**************************************************************************************
59            The following is something we can currently only dream about -- for when we drop
60            support for a lot of the old compilers (e.g. GCC 4.9, MSVC 2017 ;)
61 
62         template <class T>
63         constexpr std::size_t calculate_stride(T& shape, std::size_t idx, layout_type L)
64         {
65             if (shape[idx] == 1)
66             {
67                 return std::size_t(0);
68             }
69 
70             std::size_t data_size = 1;
71             std::size_t stride = 1;
72             if (L == layout_type::row_major)
73             {
74                 // because we have a integer sequence that counts
75                 // from 0 to sz - 1, we need to "invert" idx here
76                 idx = shape.size() - idx;
77                 for (std::size_t i = idx; i != 0; --i)
78                 {
79                     stride = data_size;
80                     data_size = stride * shape[i - 1];
81                 }
82             }
83             else
84             {
85                 for (std::size_t i = 0; i < idx + 1; ++i)
86                 {
87                     stride = data_size;
88                     data_size = stride * shape[i];
89                 }
90             }
91             return stride;
92         }
93 
94         *****************************************************************************************/
95 
96         template <layout_type L, std::size_t I, std::size_t... X>
97         struct calculate_stride;
98 
99         template <std::size_t I, std::size_t Y, std::size_t... X>
100         struct calculate_stride<layout_type::column_major, I, Y, X...>
101         {
102             constexpr static std::ptrdiff_t value = Y * calculate_stride<layout_type::column_major, I - 1, X...>::value;
103         };
104 
105         template <std::size_t Y, std::size_t... X>
106         struct calculate_stride<layout_type::column_major, 0, Y, X...>
107         {
108             constexpr static std::ptrdiff_t value = 1;
109         };
110 
111         template <std::size_t I, std::size_t... X>
112         struct calculate_stride_row_major
113         {
114             constexpr static std::ptrdiff_t value = at<sizeof...(X) - I, X...>::value * calculate_stride_row_major<I - 1, X...>::value;
115         };
116 
117         template <std::size_t... X>
118         struct calculate_stride_row_major<0, X...>
119         {
120             constexpr static std::ptrdiff_t value = 1;
121         };
122 
123         template <std::size_t I, std::size_t... X>
124         struct calculate_stride<layout_type::row_major, I, X...>
125         {
126             constexpr static std::ptrdiff_t value = calculate_stride_row_major<sizeof...(X) - I - 1, X...>::value;
127         };
128 
129         namespace workaround
130         {
131             template <layout_type L, size_t I, class SEQ>
132             struct computed_strides;
133 
134             template <layout_type L, size_t I, size_t... X>
135             struct computed_strides<L, I, std::index_sequence<X...>>
136             {
137                 constexpr static std::ptrdiff_t value = calculate_stride<L, I, X...>::value;
138             };
139 
140             template <layout_type L, size_t I, class SEQ >
get_computed_strides(bool cond)141             constexpr std::ptrdiff_t get_computed_strides(bool cond)
142             {
143                 return cond ? 0 : computed_strides<L, I, SEQ>::value;
144             }
145         }
146 
147         template <layout_type L, class R, std::size_t... X, std::size_t... I>
get_strides_impl(const xt::fixed_shape<X...> & shape,std::index_sequence<I...>)148         constexpr R get_strides_impl(const xt::fixed_shape<X...>& shape, std::index_sequence<I...>)
149         {
150             static_assert((L == layout_type::row_major) || (L == layout_type::column_major),
151                           "Layout not supported for fixed array");
152 #if (_MSC_VER >= 1910)
153             using temp_type = std::index_sequence<X...>;
154             return R({ workaround::get_computed_strides<L, I, temp_type>(shape[I] == 1)... });
155 #else
156             return R({ shape[I] == 1 ? 0 : calculate_stride<L, I, X...>::value... });
157 #endif
158         }
159 
160         template <class S, class T, std::size_t... I>
get_backstrides_impl(const S & shape,const T & strides,std::index_sequence<I...>)161         constexpr T get_backstrides_impl(const S& shape, const T& strides, std::index_sequence<I...>)
162         {
163             return T({(strides[I] * std::ptrdiff_t(shape[I] - 1))...});
164         }
165 
166         template <std::size_t... X>
167         struct fixed_compute_size_impl;
168 
169         template <std::size_t Y, std::size_t... X>
170         struct fixed_compute_size_impl<Y, X...>
171         {
172             constexpr static std::size_t value = Y * fixed_compute_size_impl<X...>::value;
173         };
174 
175         template <std::size_t X>
176         struct fixed_compute_size_impl<X>
177         {
178             constexpr static std::size_t value = X;
179         };
180 
181         template <>
182         struct fixed_compute_size_impl<>
183         {
184             // support for 0D xtensor fixed (empty shape = xshape<>)
185             constexpr static std::size_t value = 1;
186         };
187 
188         // TODO unify with constexpr compute_size when dropping MSVC 2015
189         template <class T>
190         struct fixed_compute_size;
191 
192         template <std::size_t... X>
193         struct fixed_compute_size<xt::fixed_shape<X...>>
194         {
195             constexpr static std::size_t value = fixed_compute_size_impl<X...>::value;
196         };
197 
198         template <class V, std::size_t... X>
199         struct get_init_type_impl;
200 
201         template <class V, std::size_t Y>
202         struct get_init_type_impl<V, Y>
203         {
204             using type = V[Y];
205         };
206 
207         template <class V>
208         struct get_init_type_impl<V>
209         {
210             using type = V[1];
211         };
212 
213         template <class V, std::size_t Y, std::size_t... X>
214         struct get_init_type_impl<V, Y, X...>
215         {
216             using tmp_type = typename get_init_type_impl<V, X...>::type;
217             using type = tmp_type[Y];
218         };
219     }
220 
221     template <layout_type L, class R, std::size_t... X>
get_strides(const fixed_shape<X...> & shape)222     constexpr R get_strides(const fixed_shape<X...>& shape) noexcept
223     {
224         return detail::get_strides_impl<L, R>(shape, std::make_index_sequence<sizeof...(X)>{});
225     }
226 
227     template <class S, class T>
get_backstrides(const S & shape,const T & strides)228     constexpr T get_backstrides(const S& shape, const T& strides) noexcept
229     {
230         return detail::get_backstrides_impl(shape, strides,
231                                             std::make_index_sequence<std::tuple_size<T>::value>{});
232     }
233 
234     template <class V, class S>
235     struct get_init_type;
236 
237     template <class V, std::size_t... X>
238     struct get_init_type<V, fixed_shape<X...>>
239     {
240         using type = typename detail::get_init_type_impl<V, X...>::type;
241     };
242 
243     template <class V, class S>
244     using get_init_type_t = typename get_init_type<V, S>::type;
245 
246     template <class ET, class S, layout_type L, bool SH, class Tag>
247     struct xcontainer_inner_types<xfixed_container<ET, S, L, SH, Tag>>
248     {
249         using shape_type = S;
250         using inner_shape_type = typename S::cast_type;
251         using strides_type = get_strides_t<inner_shape_type>;
252         using inner_strides_type = strides_type;
253         using backstrides_type = inner_strides_type;
254         using inner_backstrides_type = backstrides_type;
255 
256         // NOTE: 0D (S::size() == 0) results in storage for 1 element (scalar)
257     #if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(_WIN64)
258         // WORKAROUND FOR MSVC 2015 32 bit, fallback to unaligned container for 0D scalar case
259         using storage_type = std::array<ET, detail::fixed_compute_size<S>::value>;
260     #else
261         using storage_type = aligned_array<ET, detail::fixed_compute_size<S>::value>;
262     #endif
263 
264         using reference = typename storage_type::reference;
265         using const_reference = typename storage_type::const_reference;
266         using size_type = typename storage_type::size_type;
267         using temporary_type = xfixed_container<ET, S, L, SH, Tag>;
268         static constexpr layout_type layout = L;
269     };
270 
271     template <class ET, class S, layout_type L, bool SH, class Tag>
272     struct xiterable_inner_types<xfixed_container<ET, S, L, SH, Tag>>
273         : xcontainer_iterable_types<xfixed_container<ET, S, L, SH, Tag>>
274     {
275     };
276 
277     /**
278      * @class xfixed_container
279      * @brief Dense multidimensional container with tensor semantic and fixed
280      * dimension.
281      *
282      * The xfixed_container class implements a dense multidimensional container
283      * with tensor semantic and fixed dimension
284      *
285      * @tparam ET The type of the elements.
286      * @tparam S The xshape template paramter of the container.
287      * @tparam L The layout_type of the tensor.
288      * @tparam SH Wether the tensor can be used as a shared expression.
289      * @tparam Tag The expression tag.
290      * @sa xtensor_fixed
291      */
292     template <class ET, class S, layout_type L, bool SH, class Tag>
293     class xfixed_container : public xcontainer<xfixed_container<ET, S, L, SH, Tag>>,
294                              public xcontainer_semantic<xfixed_container<ET, S, L, SH, Tag>>
295     {
296     public:
297 
298         using self_type = xfixed_container<ET, S, L, SH, Tag>;
299         using base_type = xcontainer<self_type>;
300         using semantic_base = xcontainer_semantic<self_type>;
301 
302         using storage_type = typename base_type::storage_type;
303         using value_type = typename base_type::value_type;
304         using reference = typename base_type::reference;
305         using const_reference = typename base_type::const_reference;
306         using pointer = typename base_type::pointer;
307         using const_pointer = typename base_type::const_pointer;
308         using shape_type = typename base_type::shape_type;
309         using inner_shape_type = typename base_type::inner_shape_type;
310         using strides_type = typename base_type::strides_type;
311         using backstrides_type = typename base_type::backstrides_type;
312         using inner_backstrides_type = typename base_type::inner_backstrides_type;
313         using inner_strides_type = typename base_type::inner_strides_type;
314         using temporary_type = typename semantic_base::temporary_type;
315         using expression_tag = Tag;
316 
317         constexpr static std::size_t N = std::tuple_size<shape_type>::value;
318         constexpr static std::size_t rank = N;
319 
320         xfixed_container() = default;
321         xfixed_container(const value_type& v);
322         explicit xfixed_container(const inner_shape_type& shape, layout_type l = L);
323         explicit xfixed_container(const inner_shape_type& shape, value_type v, layout_type l = L);
324 
325         // remove this enable_if when removing the other value_type constructor
326         template <class IX = std::integral_constant<std::size_t, N>, class EN = std::enable_if_t<IX::value != 0, int>>
327         xfixed_container(nested_initializer_list_t<value_type, N> t);
328 
329         ~xfixed_container() = default;
330 
331         xfixed_container(const xfixed_container&) = default;
332         xfixed_container& operator=(const xfixed_container&) = default;
333 
334         xfixed_container(xfixed_container&&) = default;
335         xfixed_container& operator=(xfixed_container&&) = default;
336 
337         template <class E>
338         xfixed_container(const xexpression<E>& e);
339 
340         template <class E>
341         xfixed_container& operator=(const xexpression<E>& e);
342 
343         template <class ST = std::array<std::size_t, N>>
344         static xfixed_container from_shape(ST&& /*s*/);
345 
346         template <class ST = std::array<std::size_t, N>>
347         void resize(ST&& shape, bool force = false) const;
348         template <class ST = shape_type>
349         void resize(ST&& shape, layout_type l) const;
350         template <class ST = shape_type>
351         void resize(ST&& shape, const strides_type& strides) const;
352 
353         template <class ST = std::array<std::size_t, N>>
354         auto const& reshape(ST&& shape, layout_type layout = L) const;
355 
356         template <class ST>
357         bool broadcast_shape(ST& s, bool reuse_cache = false) const;
358 
359         constexpr layout_type layout() const noexcept;
360         bool is_contiguous() const noexcept;
361 
362     private:
363 
364         storage_type m_storage;
365 
366         XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S();
367         XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides<L, inner_strides_type>(S());
368         XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides);
369 
370         storage_type& storage_impl() noexcept;
371         const storage_type& storage_impl() const noexcept;
372 
373         XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept;
374         XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept;
375         XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept;
376 
377         friend class xcontainer<xfixed_container<ET, S, L, SH, Tag>>;
378     };
379 
380 #ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED
381     // Out of line definitions to prevent linker errors prior to C++17
382     template <class ET, class S, layout_type L, bool SH, class Tag>
383     constexpr typename xfixed_container<ET, S, L, SH, Tag>::inner_shape_type xfixed_container<ET, S, L, SH, Tag>::m_shape;
384 
385     template <class ET, class S, layout_type L, bool SH, class Tag>
386     constexpr typename xfixed_container<ET, S, L, SH, Tag>::inner_strides_type xfixed_container<ET, S, L, SH, Tag>::m_strides;
387 
388     template <class ET, class S, layout_type L, bool SH, class Tag>
389     constexpr typename xfixed_container<ET, S, L, SH, Tag>::inner_backstrides_type xfixed_container<ET, S, L, SH, Tag>::m_backstrides;
390 #endif
391 
392     /****************************************
393      * xfixed_container_adaptor declaration *
394      ****************************************/
395 
396     template <class EC, class S, layout_type L, bool SH, class Tag>
397     class xfixed_adaptor;
398 
399     template <class EC, class S, layout_type L, bool SH, class Tag>
400     struct xcontainer_inner_types<xfixed_adaptor<EC, S, L, SH, Tag>>
401     {
402         using storage_type = std::remove_reference_t<EC>;
403         using reference = typename storage_type::reference;
404         using const_reference = typename storage_type::const_reference;
405         using size_type = typename storage_type::size_type;
406         using shape_type = S;
407         using inner_shape_type = typename S::cast_type;
408         using strides_type = get_strides_t<inner_shape_type>;
409         using backstrides_type = strides_type;
410         using inner_strides_type = strides_type;
411         using inner_backstrides_type = backstrides_type;
412         using temporary_type = xfixed_container<typename storage_type::value_type, S, L, SH, Tag>;
413         static constexpr layout_type layout = L;
414     };
415 
416     template <class EC, class S, layout_type L, bool SH, class Tag>
417     struct xiterable_inner_types<xfixed_adaptor<EC, S, L, SH, Tag>>
418         : xcontainer_iterable_types<xfixed_adaptor<EC, S, L, SH, Tag>>
419     {
420     };
421 
422     /**
423      * @class xfixed_adaptor
424      * @brief Dense multidimensional container adaptor with tensor semantic
425      * and fixed dimension.
426      *
427      * The xfixed_adaptor class implements a dense multidimensional
428      * container adaptor with tensor semantic and fixed dimension. It
429      * is used to provide a multidimensional container semantic and a
430      * tensor semantic to stl-like containers.
431      *
432      * @tparam EC The closure for the container type to adapt.
433      * @tparam S The xshape template parameter for the fixed shape of the adaptor
434      * @tparam L The layout_type of the adaptor.
435      * @tparam SH Wether the adaptor can be used as a shared expression.
436      * @tparam Tag The expression tag.
437      */
438     template <class EC, class S, layout_type L, bool SH, class Tag>
439     class xfixed_adaptor : public xcontainer<xfixed_adaptor<EC, S, L, SH, Tag>>,
440                            public xcontainer_semantic<xfixed_adaptor<EC, S, L, SH, Tag>>
441     {
442     public:
443 
444         using container_closure_type = EC;
445 
446         using self_type = xfixed_adaptor<EC, S, L, SH, Tag>;
447         using base_type = xcontainer<self_type>;
448         using semantic_base = xcontainer_semantic<self_type>;
449         using storage_type = typename base_type::storage_type;
450         using shape_type = typename base_type::shape_type;
451         using strides_type = typename base_type::strides_type;
452         using backstrides_type = typename base_type::backstrides_type;
453         using inner_shape_type = typename base_type::inner_shape_type;
454         using inner_strides_type = typename base_type::inner_strides_type;
455         using inner_backstrides_type = typename base_type::inner_backstrides_type;
456         using temporary_type = typename semantic_base::temporary_type;
457         using expression_tag = Tag;
458 
459         constexpr static std::size_t N = S::size();
460 
461         xfixed_adaptor(storage_type&& data);
462         xfixed_adaptor(const storage_type& data);
463 
464         template <class D>
465         xfixed_adaptor(D&& data);
466 
467         ~xfixed_adaptor() = default;
468 
469         xfixed_adaptor(const xfixed_adaptor&) = default;
470         xfixed_adaptor& operator=(const xfixed_adaptor&);
471 
472         xfixed_adaptor(xfixed_adaptor&&) = default;
473         xfixed_adaptor& operator=(xfixed_adaptor&&);
474         xfixed_adaptor& operator=(temporary_type&&);
475 
476         template <class E>
477         xfixed_adaptor& operator=(const xexpression<E>& e);
478 
479         template <class ST = std::array<std::size_t, N>>
480         void resize(ST&& shape, bool force = false) const;
481         template <class ST = shape_type>
482         void resize(ST&& shape, layout_type l) const;
483         template <class ST = shape_type>
484         void resize(ST&& shape, const strides_type& strides) const;
485 
486         template <class ST = std::array<std::size_t, N>>
487         const auto& reshape(ST&& shape, layout_type layout = L) const;
488 
489         template <class ST>
490         bool broadcast_shape(ST& s, bool reuse_cache = false) const;
491 
492         constexpr layout_type layout() const noexcept;
493         bool is_contiguous() const noexcept;
494 
495     private:
496 
497         container_closure_type m_storage;
498 
499         XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S();
500         XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides<L, inner_strides_type>(S());
501         XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides);
502 
503         storage_type& storage_impl() noexcept;
504         const storage_type& storage_impl() const noexcept;
505 
506         XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept;
507         XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept;
508         XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept;
509 
510         friend class xcontainer<xfixed_adaptor<EC, S, L, SH, Tag>>;
511     };
512 
513 #ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED
514     // Out of line definitions to prevent linker errors prior to C++17
515     template <class EC, class S, layout_type L, bool SH, class Tag>
516     constexpr typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_shape_type xfixed_adaptor<EC, S, L, SH, Tag>::m_shape;
517 
518     template <class EC, class S, layout_type L, bool SH, class Tag>
519     constexpr typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_strides_type xfixed_adaptor<EC, S, L, SH, Tag>::m_strides;
520 
521     template <class EC, class S, layout_type L, bool SH, class Tag>
522     constexpr typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_backstrides_type xfixed_adaptor<EC, S, L, SH, Tag>::m_backstrides;
523 #endif
524 
525     /************************************
526      * xfixed_container implementation *
527      ************************************/
528 
529     /**
530      * @name Constructors
531      */
532     //@{
533 
534     /**
535      * Create an uninitialized xfixed_container.
536      * Note this function is only provided for homogenity, and the shape & layout argument is
537      * disregarded (the template shape is always used).
538      *
539      * @param shape the shape of the xfixed_container (unused!)
540      * @param l the layout_type of the xfixed_container (unused!)
541      */
542     template <class ET, class S, layout_type L, bool SH, class Tag>
xfixed_container(const inner_shape_type & shape,layout_type l)543     inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const inner_shape_type& shape, layout_type l)
544     {
545         (void)(shape);
546         (void)(l);
547         XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), m_shape.begin()));
548         XTENSOR_ASSERT(L == l);
549     }
550 
551     template <class ET, class S, layout_type L, bool SH, class Tag>
xfixed_container(const value_type & v)552     inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const value_type& v)
553     {
554         if (this->size() != 1)
555         {
556             XTENSOR_THROW(std::runtime_error,
557                           "wrong shape for scalar assignment (has to be xshape<>).");
558         }
559         m_storage[0] = v;
560     }
561 
562     /**
563      * Create an xfixed_container, and initialize with the value of v.
564      * Note, the shape argument to this function is only provided for homogenity,
565      * and the shape argument is disregarded (the template shape is always used).
566      *
567      * @param shape the shape of the xfixed_container (unused!)
568      * @param v the fill value
569      * @param l the layout_type of the xfixed_container (unused!)
570      */
571     template <class ET, class S, layout_type L, bool SH, class Tag>
xfixed_container(const inner_shape_type & shape,value_type v,layout_type l)572     inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const inner_shape_type& shape, value_type v, layout_type l)
573     {
574         (void)(shape);
575         (void)(l);
576         XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), m_shape.begin()));
577         XTENSOR_ASSERT(L == l);
578         std::fill(m_storage.begin(), m_storage.end(), v);
579     }
580 
581     namespace detail
582     {
583         template <std::size_t X>
584         struct check_initializer_list_shape
585         {
586             template <class T, class S>
runxt::detail::check_initializer_list_shape587             static bool run(const T& t, const S& shape)
588             {
589                 std::size_t IX = shape.size() - X;
590                 bool result = (shape[IX] == t.size());
591                 for (std::size_t i = 0; i < shape[IX]; ++i)
592                 {
593                     result = result && check_initializer_list_shape<X - 1>::run(t.begin()[i], shape);
594                 }
595                 return result;
596             }
597         };
598 
599         template <>
600         struct check_initializer_list_shape<0>
601         {
602             template <class T, class S>
runxt::detail::check_initializer_list_shape603             static bool run(const T& /*t*/, const S& /*shape*/)
604             {
605                 return true;
606             }
607         };
608     }
609 
610     template <class ET, class S, layout_type L, bool SH, class Tag>
611     template <class ST>
from_shape(ST && shape)612     inline xfixed_container<ET, S, L, SH, Tag> xfixed_container<ET, S, L, SH, Tag>::from_shape(ST&& shape)
613     {
614         (void) shape;
615         self_type tmp;
616         XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), tmp.shape().begin()));
617         return tmp;
618     }
619 
620     /**
621      * Allocates an xfixed_container with shape S with values from a C array.
622      * The type returned by get_init_type_t is raw C array ``value_type[X][Y][Z]`` for ``xt::xshape<X, Y, Z>``.
623      * C arrays can be initialized with the initializer list syntax, but the size is checked at compile
624      * time to prevent errors.
625      * Note: for clang < 3.8 this is an initializer_list and the size is not checked at compile-or runtime.
626      */
627     template <class ET, class S, layout_type L, bool SH, class Tag>
628     template <class IX, class EN>
xfixed_container(nested_initializer_list_t<value_type,N> t)629     inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(nested_initializer_list_t<value_type, N> t)
630     {
631         XTENSOR_ASSERT_MSG(detail::check_initializer_list_shape<N>::run(t, this->shape()) == true, "initializer list shape does not match fixed shape");
632         L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<layout_type::row_major>(), t);
633     }
634     //@}
635 
636     /**
637      * @name Extended copy semantic
638      */
639     //@{
640     /**
641      * The extended copy constructor.
642      */
643     template <class ET, class S, layout_type L, bool SH, class Tag>
644     template <class E>
xfixed_container(const xexpression<E> & e)645     inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const xexpression<E>& e)
646     {
647         semantic_base::assign(e);
648     }
649 
650     /**
651      * The extended assignment operator.
652      */
653     template <class ET, class S, layout_type L, bool SH, class Tag>
654     template <class E>
operator =(const xexpression<E> & e)655     inline auto xfixed_container<ET, S, L, SH, Tag>::operator=(const xexpression<E>& e) -> self_type&
656     {
657         return semantic_base::operator=(e);
658     }
659     //@}
660 
661     /**
662      * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different
663      * size throws an assert in debug mode.
664      */
665     template <class ET, class S, layout_type L, bool SH, class Tag>
666     template <class ST>
resize(ST && shape,bool) const667     inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, bool) const
668     {
669         (void)(shape);  // remove unused parameter warning if XTENSOR_ASSERT undefined
670         XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
671     }
672 
673     /**
674      * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different
675      * size throws an assert in debug mode.
676      */
677     template <class ET, class S, layout_type L, bool SH, class Tag>
678     template <class ST>
resize(ST && shape,layout_type l) const679     inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, layout_type l) const
680     {
681         (void)(shape);  // remove unused parameter warning if XTENSOR_ASSERT undefined
682         (void)(l);
683         XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l);
684     }
685 
686     /**
687      * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different
688      * size throws an assert in debug mode.
689      */
690     template <class ET, class S, layout_type L, bool SH, class Tag>
691     template <class ST>
resize(ST && shape,const strides_type & strides) const692     inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, const strides_type& strides) const
693     {
694         (void)(shape);  // remove unused parameter warning if XTENSOR_ASSERT undefined
695         (void)(strides);
696         XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
697         XTENSOR_ASSERT(std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size());
698     }
699 
700     /**
701      * Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``.
702      */
703     template <class ET, class S, layout_type L, bool SH, class Tag>
704     template <class ST>
reshape(ST && shape,layout_type layout) const705     inline auto const& xfixed_container<ET, S, L, SH, Tag>::reshape(ST&& shape, layout_type layout) const
706     {
707         if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && layout == L))
708         {
709             XTENSOR_THROW(std::runtime_error, "Trying to reshape xtensor_fixed with different shape or layout.");
710         }
711         return *this;
712     }
713 
714     template <class ET, class S, layout_type L, bool SH, class Tag>
715     template <class ST>
broadcast_shape(ST & shape,bool) const716     inline bool xfixed_container<ET, S, L, SH, Tag>::broadcast_shape(ST& shape, bool) const
717     {
718         return xt::broadcast_shape(m_shape, shape);
719     }
720 
721     template <class ET, class S, layout_type L, bool SH, class Tag>
layout() const722     constexpr layout_type xfixed_container<ET, S, L, SH, Tag>::layout() const noexcept
723     {
724         return base_type::static_layout;
725     }
726 
727     template <class ET, class S, layout_type L, bool SH, class Tag>
is_contiguous() const728     inline bool xfixed_container<ET, S, L, SH, Tag>::is_contiguous() const noexcept
729     {
730         using str_type = typename inner_strides_type::value_type;
731         return m_strides.empty()
732             || (layout() == layout_type::row_major && m_strides.back() == str_type(1))
733             || (layout() == layout_type::column_major && m_strides.front() == str_type(1));
734     }
735 
736     template <class ET, class S, layout_type L, bool SH, class Tag>
storage_impl()737     inline auto xfixed_container<ET, S, L, SH, Tag>::storage_impl() noexcept -> storage_type&
738     {
739         return m_storage;
740     }
741 
742     template <class ET, class S, layout_type L, bool SH, class Tag>
storage_impl() const743     inline auto xfixed_container<ET, S, L, SH, Tag>::storage_impl() const noexcept -> const storage_type&
744     {
745         return m_storage;
746     }
747 
748     template <class ET, class S, layout_type L, bool SH, class Tag>
shape_impl() const749     XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::shape_impl() const noexcept -> const inner_shape_type&
750     {
751         return m_shape;
752     }
753 
754     template <class ET, class S, layout_type L, bool SH, class Tag>
strides_impl() const755     XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::strides_impl() const noexcept -> const inner_strides_type&
756     {
757         return m_strides;
758     }
759 
760     template <class ET, class S, layout_type L, bool SH, class Tag>
backstrides_impl() const761     XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::backstrides_impl() const noexcept -> const inner_backstrides_type&
762     {
763         return m_backstrides;
764     }
765 
766     /*******************
767      * xfixed_adaptor *
768      *******************/
769 
770     /**
771      * @name Constructors
772      */
773     //@{
774     /**
775      * Constructs an xfixed_adaptor of the given stl-like container.
776      * @param data the container to adapt
777      */
778     template <class EC, class S, layout_type L, bool SH, class Tag>
xfixed_adaptor(storage_type && data)779     inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(storage_type&& data)
780         : base_type(), m_storage(std::move(data))
781     {
782     }
783 
784     /**
785      * Constructs an xfixed_adaptor of the given stl-like container.
786      * @param data the container to adapt
787      */
788     template <class EC, class S, layout_type L, bool SH, class Tag>
xfixed_adaptor(const storage_type & data)789     inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(const storage_type& data)
790         : base_type(), m_storage(data)
791     {
792     }
793 
794     /**
795      * Constructs an xfixed_adaptor of the given stl-like container,
796      * with the specified shape and layout_type.
797      * @param data the container to adapt
798      */
799     template <class EC, class S, layout_type L, bool SH, class Tag>
800     template <class D>
xfixed_adaptor(D && data)801     inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(D&& data)
802         : base_type(), m_storage(std::forward<D>(data))
803     {
804     }
805     //@}
806 
807     template <class EC, class S, layout_type L, bool SH, class Tag>
operator =(const xfixed_adaptor & rhs)808     inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(const xfixed_adaptor& rhs) -> self_type&
809     {
810         base_type::operator=(rhs);
811         m_storage = rhs.m_storage;
812         return *this;
813     }
814 
815     template <class EC, class S, layout_type L, bool SH, class Tag>
operator =(xfixed_adaptor && rhs)816     inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(xfixed_adaptor&& rhs) -> self_type&
817     {
818         base_type::operator=(std::move(rhs));
819         m_storage = rhs.m_storage;
820         return *this;
821     }
822 
823     template <class EC, class S, layout_type L, bool SH, class Tag>
operator =(temporary_type && rhs)824     inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(temporary_type&& rhs) -> self_type&
825     {
826         m_storage.resize(rhs.storage().size());
827         std::copy(rhs.storage().cbegin(), rhs.storage().cend(), m_storage.begin());
828         return *this;
829     }
830 
831     /**
832      * @name Extended copy semantic
833      */
834     //@{
835     /**
836      * The extended assignment operator.
837      */
838     template <class EC, class S, layout_type L, bool SH, class Tag>
839     template <class E>
operator =(const xexpression<E> & e)840     inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(const xexpression<E>& e) -> self_type&
841     {
842         return semantic_base::operator=(e);
843     }
844     //@}
845 
846     /**
847      * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different
848      * size throws an assert in debug mode.
849      */
850     template <class ET, class S, layout_type L, bool SH, class Tag>
851     template <class ST>
resize(ST && shape,bool) const852     inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, bool) const
853     {
854         (void)(shape);  // remove unused parameter warning if XTENSOR_ASSERT undefined
855         XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
856     }
857 
858     /**
859      * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different
860      * size throws an assert in debug mode.
861      */
862     template <class ET, class S, layout_type L, bool SH, class Tag>
863     template <class ST>
resize(ST && shape,layout_type l) const864     inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, layout_type l) const
865     {
866         (void)(shape);  // remove unused parameter warning if XTENSOR_ASSERT undefined
867         (void)(l);
868         XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l);
869     }
870 
871     /**
872      * Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different
873      * size throws an assert in debug mode.
874      */
875     template <class ET, class S, layout_type L, bool SH, class Tag>
876     template <class ST>
resize(ST && shape,const strides_type & strides) const877     inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, const strides_type& strides) const
878     {
879         (void)(shape);  // remove unused parameter warning if XTENSOR_ASSERT undefined
880         (void)(strides);
881         XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
882         XTENSOR_ASSERT(std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size());
883     }
884 
885     /**
886      * Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``.
887      */
888     template <class ET, class S, layout_type L, bool SH, class Tag>
889     template <class ST>
reshape(ST && shape,layout_type layout) const890     inline auto const& xfixed_adaptor<ET, S, L, SH, Tag>::reshape(ST&& shape, layout_type layout) const
891     {
892         if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && layout == L))
893         {
894             XTENSOR_THROW(std::runtime_error, "Trying to reshape xtensor_fixed with different shape or layout.");
895         }
896         return *this;
897     }
898 
899     template <class ET, class S, layout_type L, bool SH, class Tag>
900     template <class ST>
broadcast_shape(ST & shape,bool) const901     inline bool xfixed_adaptor<ET, S, L, SH, Tag>::broadcast_shape(ST& shape, bool) const
902     {
903         return xt::broadcast_shape(m_shape, shape);
904     }
905 
906     template <class EC, class S, layout_type L, bool SH, class Tag>
storage_impl()907     inline auto xfixed_adaptor<EC, S, L, SH, Tag>::storage_impl() noexcept -> storage_type&
908     {
909         return m_storage;
910     }
911 
912     template <class EC, class S, layout_type L, bool SH, class Tag>
storage_impl() const913     inline auto xfixed_adaptor<EC, S, L, SH, Tag>::storage_impl() const noexcept -> const storage_type&
914     {
915         return m_storage;
916     }
917 
918     template <class EC, class S, layout_type L, bool SH, class Tag>
layout() const919     constexpr layout_type xfixed_adaptor<EC, S, L, SH, Tag>::layout() const noexcept
920     {
921         return base_type::static_layout;
922     }
923 
924     template <class EC, class S, layout_type L, bool SH, class Tag>
is_contiguous() const925     inline bool xfixed_adaptor<EC, S, L, SH, Tag>::is_contiguous() const noexcept
926     {
927         using str_type = typename inner_strides_type::value_type;
928         return m_strides.empty()
929             || (layout() == layout_type::row_major && m_strides.back() == str_type(1))
930             || (layout() == layout_type::column_major && m_strides.front() == str_type(1));
931     }
932 
933     template <class EC, class S, layout_type L, bool SH, class Tag>
shape_impl() const934     XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::shape_impl() const noexcept -> const inner_shape_type&
935     {
936         return m_shape;
937     }
938 
939     template <class EC, class S, layout_type L, bool SH, class Tag>
strides_impl() const940     XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::strides_impl() const noexcept -> const inner_strides_type&
941     {
942         return m_strides;
943     }
944 
945     template <class EC, class S, layout_type L, bool SH, class Tag>
backstrides_impl() const946     XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::backstrides_impl() const noexcept -> const inner_backstrides_type&
947     {
948         return m_backstrides;
949     }
950 }
951 
952 #endif
953