mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
992 lines
37 KiB
C++
992 lines
37 KiB
C++
/***************************************************************************
|
|
* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
|
|
* Copyright (c) QuantStack *
|
|
* *
|
|
* Distributed under the terms of the BSD 3-Clause License. *
|
|
* *
|
|
* The full license is in the file LICENSE, distributed with this software. *
|
|
****************************************************************************/
|
|
|
|
#ifndef XTENSOR_FIXED_HPP
|
|
#define XTENSOR_FIXED_HPP
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <xtl/xsequence.hpp>
|
|
|
|
#include "xcontainer.hpp"
|
|
#include "xsemantic.hpp"
|
|
#include "xstorage.hpp"
|
|
#include "xstrides.hpp"
|
|
#include "xtensor_config.hpp"
|
|
|
|
namespace xtl
|
|
{
|
|
namespace detail
|
|
{
|
|
template <class T, std::size_t N>
|
|
struct sequence_builder<xt::const_array<T, N>>
|
|
{
|
|
using sequence_type = xt::const_array<T, N>;
|
|
using value_type = typename sequence_type::value_type;
|
|
using size_type = typename sequence_type::size_type;
|
|
|
|
inline static sequence_type make(size_type /*size*/, value_type /*v*/)
|
|
{
|
|
return sequence_type();
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
namespace xt
|
|
{
|
|
|
|
/**********************
|
|
* xfixed declaration *
|
|
**********************/
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
class xfixed_container;
|
|
|
|
namespace detail
|
|
{
|
|
/**************************************************************************************
|
|
The following is something we can currently only dream about -- for when we drop
|
|
support for a lot of the old compilers (e.g. GCC 4.9, MSVC 2017 ;)
|
|
|
|
template <class T>
|
|
constexpr std::size_t calculate_stride(T& shape, std::size_t idx, layout_type L)
|
|
{
|
|
if (shape[idx] == 1)
|
|
{
|
|
return std::size_t(0);
|
|
}
|
|
|
|
std::size_t data_size = 1;
|
|
std::size_t stride = 1;
|
|
if (L == layout_type::row_major)
|
|
{
|
|
// because we have a integer sequence that counts
|
|
// from 0 to sz - 1, we need to "invert" idx here
|
|
idx = shape.size() - idx;
|
|
for (std::size_t i = idx; i != 0; --i)
|
|
{
|
|
stride = data_size;
|
|
data_size = stride * shape[i - 1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (std::size_t i = 0; i < idx + 1; ++i)
|
|
{
|
|
stride = data_size;
|
|
data_size = stride * shape[i];
|
|
}
|
|
}
|
|
return stride;
|
|
}
|
|
|
|
*****************************************************************************************/
|
|
|
|
template <layout_type L, std::size_t I, std::size_t... X>
|
|
struct calculate_stride;
|
|
|
|
template <std::size_t I, std::size_t Y, std::size_t... X>
|
|
struct calculate_stride<layout_type::column_major, I, Y, X...>
|
|
{
|
|
static constexpr std::ptrdiff_t value = Y
|
|
* calculate_stride<layout_type::column_major, I - 1, X...>::value;
|
|
};
|
|
|
|
template <std::size_t Y, std::size_t... X>
|
|
struct calculate_stride<layout_type::column_major, 0, Y, X...>
|
|
{
|
|
static constexpr std::ptrdiff_t value = 1;
|
|
};
|
|
|
|
template <std::size_t I, std::size_t... X>
|
|
struct calculate_stride_row_major
|
|
{
|
|
static constexpr std::ptrdiff_t value = at<sizeof...(X) - I, X...>::value
|
|
* calculate_stride_row_major<I - 1, X...>::value;
|
|
};
|
|
|
|
template <std::size_t... X>
|
|
struct calculate_stride_row_major<0, X...>
|
|
{
|
|
static constexpr std::ptrdiff_t value = 1;
|
|
};
|
|
|
|
template <std::size_t I, std::size_t... X>
|
|
struct calculate_stride<layout_type::row_major, I, X...>
|
|
{
|
|
static constexpr std::ptrdiff_t value = calculate_stride_row_major<sizeof...(X) - I - 1, X...>::value;
|
|
};
|
|
|
|
namespace workaround
|
|
{
|
|
template <layout_type L, size_t I, class SEQ>
|
|
struct computed_strides;
|
|
|
|
template <layout_type L, size_t I, size_t... X>
|
|
struct computed_strides<L, I, std::index_sequence<X...>>
|
|
{
|
|
static constexpr std::ptrdiff_t value = calculate_stride<L, I, X...>::value;
|
|
};
|
|
|
|
template <layout_type L, size_t I, class SEQ>
|
|
constexpr std::ptrdiff_t get_computed_strides(bool cond)
|
|
{
|
|
return cond ? 0 : computed_strides<L, I, SEQ>::value;
|
|
}
|
|
}
|
|
|
|
template <layout_type L, class R, std::size_t... X, std::size_t... I>
|
|
constexpr R get_strides_impl(const xt::fixed_shape<X...>& shape, std::index_sequence<I...>)
|
|
{
|
|
static_assert(
|
|
(L == layout_type::row_major) || (L == layout_type::column_major),
|
|
"Layout not supported for fixed array"
|
|
);
|
|
#if (_MSC_VER >= 1910)
|
|
using temp_type = std::index_sequence<X...>;
|
|
return R({workaround::get_computed_strides<L, I, temp_type>(shape[I] == 1)...});
|
|
#else
|
|
return R({shape[I] == 1 ? 0 : calculate_stride<L, I, X...>::value...});
|
|
#endif
|
|
}
|
|
|
|
template <class S, class T, std::size_t... I>
|
|
constexpr T get_backstrides_impl(const S& shape, const T& strides, std::index_sequence<I...>)
|
|
{
|
|
return T({(strides[I] * std::ptrdiff_t(shape[I] - 1))...});
|
|
}
|
|
|
|
template <std::size_t... X>
|
|
struct fixed_compute_size_impl;
|
|
|
|
template <std::size_t Y, std::size_t... X>
|
|
struct fixed_compute_size_impl<Y, X...>
|
|
{
|
|
static constexpr std::size_t value = Y * fixed_compute_size_impl<X...>::value;
|
|
};
|
|
|
|
template <std::size_t X>
|
|
struct fixed_compute_size_impl<X>
|
|
{
|
|
static constexpr std::size_t value = X;
|
|
};
|
|
|
|
template <>
|
|
struct fixed_compute_size_impl<>
|
|
{
|
|
// support for 0D xtensor fixed (empty shape = xshape<>)
|
|
static constexpr std::size_t value = 1;
|
|
};
|
|
|
|
// TODO unify with constexpr compute_size when dropping MSVC 2015
|
|
template <class T>
|
|
struct fixed_compute_size;
|
|
|
|
template <std::size_t... X>
|
|
struct fixed_compute_size<xt::fixed_shape<X...>>
|
|
{
|
|
static constexpr std::size_t value = fixed_compute_size_impl<X...>::value;
|
|
};
|
|
|
|
template <class V, std::size_t... X>
|
|
struct get_init_type_impl;
|
|
|
|
template <class V, std::size_t Y>
|
|
struct get_init_type_impl<V, Y>
|
|
{
|
|
using type = V[Y];
|
|
};
|
|
|
|
template <class V>
|
|
struct get_init_type_impl<V>
|
|
{
|
|
using type = V[1];
|
|
};
|
|
|
|
template <class V, std::size_t Y, std::size_t... X>
|
|
struct get_init_type_impl<V, Y, X...>
|
|
{
|
|
using tmp_type = typename get_init_type_impl<V, X...>::type;
|
|
using type = tmp_type[Y];
|
|
};
|
|
}
|
|
|
|
template <layout_type L, class R, std::size_t... X>
|
|
constexpr R get_strides(const fixed_shape<X...>& shape) noexcept
|
|
{
|
|
return detail::get_strides_impl<L, R>(shape, std::make_index_sequence<sizeof...(X)>{});
|
|
}
|
|
|
|
template <class S, class T>
|
|
constexpr T get_backstrides(const S& shape, const T& strides) noexcept
|
|
{
|
|
return detail::get_backstrides_impl(shape, strides, std::make_index_sequence<std::tuple_size<T>::value>{});
|
|
}
|
|
|
|
template <class V, class S>
|
|
struct get_init_type;
|
|
|
|
template <class V, std::size_t... X>
|
|
struct get_init_type<V, fixed_shape<X...>>
|
|
{
|
|
using type = typename detail::get_init_type_impl<V, X...>::type;
|
|
};
|
|
|
|
template <class V, class S>
|
|
using get_init_type_t = typename get_init_type<V, S>::type;
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
struct xcontainer_inner_types<xfixed_container<ET, S, L, SH, Tag>>
|
|
{
|
|
using shape_type = S;
|
|
using inner_shape_type = typename S::cast_type;
|
|
using strides_type = get_strides_t<inner_shape_type>;
|
|
using inner_strides_type = strides_type;
|
|
using backstrides_type = inner_strides_type;
|
|
using inner_backstrides_type = backstrides_type;
|
|
|
|
// NOTE: 0D (S::size() == 0) results in storage for 1 element (scalar)
|
|
#if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(_WIN64)
|
|
// WORKAROUND FOR MSVC 2015 32 bit, fallback to unaligned container for 0D scalar case
|
|
using storage_type = std::array<ET, detail::fixed_compute_size<S>::value>;
|
|
#else
|
|
using storage_type = aligned_array<ET, detail::fixed_compute_size<S>::value>;
|
|
#endif
|
|
|
|
using reference = typename storage_type::reference;
|
|
using const_reference = typename storage_type::const_reference;
|
|
using size_type = typename storage_type::size_type;
|
|
using temporary_type = xfixed_container<ET, S, L, SH, Tag>;
|
|
static constexpr layout_type layout = L;
|
|
};
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
struct xiterable_inner_types<xfixed_container<ET, S, L, SH, Tag>>
|
|
: xcontainer_iterable_types<xfixed_container<ET, S, L, SH, Tag>>
|
|
{
|
|
};
|
|
|
|
/**
|
|
* @class xfixed_container
|
|
* @brief Dense multidimensional container with tensor semantic and fixed
|
|
* dimension.
|
|
*
|
|
* The xfixed_container class implements a dense multidimensional container
|
|
* with tensor semantic and fixed dimension
|
|
*
|
|
* @tparam ET The type of the elements.
|
|
* @tparam S The xshape template paramter of the container.
|
|
* @tparam L The layout_type of the tensor.
|
|
* @tparam SH Wether the tensor can be used as a shared expression.
|
|
* @tparam Tag The expression tag.
|
|
* @sa xtensor_fixed
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
class xfixed_container : public xcontainer<xfixed_container<ET, S, L, SH, Tag>>,
|
|
public xcontainer_semantic<xfixed_container<ET, S, L, SH, Tag>>
|
|
{
|
|
public:
|
|
|
|
using self_type = xfixed_container<ET, S, L, SH, Tag>;
|
|
using base_type = xcontainer<self_type>;
|
|
using semantic_base = xcontainer_semantic<self_type>;
|
|
|
|
using storage_type = typename base_type::storage_type;
|
|
using value_type = typename base_type::value_type;
|
|
using reference = typename base_type::reference;
|
|
using const_reference = typename base_type::const_reference;
|
|
using pointer = typename base_type::pointer;
|
|
using const_pointer = typename base_type::const_pointer;
|
|
using shape_type = typename base_type::shape_type;
|
|
using inner_shape_type = typename base_type::inner_shape_type;
|
|
using strides_type = typename base_type::strides_type;
|
|
using backstrides_type = typename base_type::backstrides_type;
|
|
using inner_backstrides_type = typename base_type::inner_backstrides_type;
|
|
using inner_strides_type = typename base_type::inner_strides_type;
|
|
using temporary_type = typename semantic_base::temporary_type;
|
|
using expression_tag = Tag;
|
|
|
|
static constexpr std::size_t N = std::tuple_size<shape_type>::value;
|
|
static constexpr std::size_t rank = N;
|
|
|
|
xfixed_container() = default;
|
|
xfixed_container(const value_type& v);
|
|
explicit xfixed_container(const inner_shape_type& shape, layout_type l = L);
|
|
explicit xfixed_container(const inner_shape_type& shape, value_type v, layout_type l = L);
|
|
|
|
// remove this enable_if when removing the other value_type constructor
|
|
template <class IX = std::integral_constant<std::size_t, N>, class EN = std::enable_if_t<IX::value != 0, int>>
|
|
xfixed_container(nested_initializer_list_t<value_type, N> t);
|
|
|
|
~xfixed_container() = default;
|
|
|
|
xfixed_container(const xfixed_container&) = default;
|
|
xfixed_container& operator=(const xfixed_container&) = default;
|
|
|
|
xfixed_container(xfixed_container&&) = default;
|
|
xfixed_container& operator=(xfixed_container&&) = default;
|
|
|
|
template <class E>
|
|
xfixed_container(const xexpression<E>& e);
|
|
|
|
template <class E>
|
|
xfixed_container& operator=(const xexpression<E>& e);
|
|
|
|
template <class ST = std::array<std::size_t, N>>
|
|
static xfixed_container from_shape(ST&& /*s*/);
|
|
|
|
template <class ST = std::array<std::size_t, N>>
|
|
void resize(ST&& shape, bool force = false) const;
|
|
template <class ST = shape_type>
|
|
void resize(ST&& shape, layout_type l) const;
|
|
template <class ST = shape_type>
|
|
void resize(ST&& shape, const strides_type& strides) const;
|
|
|
|
template <class ST = std::array<std::size_t, N>>
|
|
const auto& reshape(ST&& shape, layout_type layout = L) const;
|
|
|
|
template <class ST>
|
|
bool broadcast_shape(ST& s, bool reuse_cache = false) const;
|
|
|
|
constexpr layout_type layout() const noexcept;
|
|
bool is_contiguous() const noexcept;
|
|
|
|
private:
|
|
|
|
storage_type m_storage;
|
|
|
|
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S();
|
|
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides<L, inner_strides_type>(S());
|
|
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type
|
|
m_backstrides = get_backstrides(m_shape, m_strides);
|
|
|
|
storage_type& storage_impl() noexcept;
|
|
const storage_type& storage_impl() const noexcept;
|
|
|
|
XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept;
|
|
XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept;
|
|
XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept;
|
|
|
|
friend class xcontainer<xfixed_container<ET, S, L, SH, Tag>>;
|
|
};
|
|
|
|
#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED
|
|
// Out of line definitions to prevent linker errors prior to C++17
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
constexpr
|
|
typename xfixed_container<ET, S, L, SH, Tag>::inner_shape_type xfixed_container<ET, S, L, SH, Tag>::m_shape;
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
constexpr
|
|
typename xfixed_container<ET, S, L, SH, Tag>::inner_strides_type xfixed_container<ET, S, L, SH, Tag>::m_strides;
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
constexpr typename xfixed_container<ET, S, L, SH, Tag>::inner_backstrides_type
|
|
xfixed_container<ET, S, L, SH, Tag>::m_backstrides;
|
|
#endif
|
|
|
|
/****************************************
|
|
* xfixed_container_adaptor declaration *
|
|
****************************************/
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
class xfixed_adaptor;
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
struct xcontainer_inner_types<xfixed_adaptor<EC, S, L, SH, Tag>>
|
|
{
|
|
using storage_type = std::remove_reference_t<EC>;
|
|
using reference = typename storage_type::reference;
|
|
using const_reference = typename storage_type::const_reference;
|
|
using size_type = typename storage_type::size_type;
|
|
using shape_type = S;
|
|
using inner_shape_type = typename S::cast_type;
|
|
using strides_type = get_strides_t<inner_shape_type>;
|
|
using backstrides_type = strides_type;
|
|
using inner_strides_type = strides_type;
|
|
using inner_backstrides_type = backstrides_type;
|
|
using temporary_type = xfixed_container<typename storage_type::value_type, S, L, SH, Tag>;
|
|
static constexpr layout_type layout = L;
|
|
};
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
struct xiterable_inner_types<xfixed_adaptor<EC, S, L, SH, Tag>>
|
|
: xcontainer_iterable_types<xfixed_adaptor<EC, S, L, SH, Tag>>
|
|
{
|
|
};
|
|
|
|
/**
|
|
* @class xfixed_adaptor
|
|
* @brief Dense multidimensional container adaptor with tensor semantic
|
|
* and fixed dimension.
|
|
*
|
|
* The xfixed_adaptor class implements a dense multidimensional
|
|
* container adaptor with tensor semantic and fixed dimension. It
|
|
* is used to provide a multidimensional container semantic and a
|
|
* tensor semantic to stl-like containers.
|
|
*
|
|
* @tparam EC The closure for the container type to adapt.
|
|
* @tparam S The xshape template parameter for the fixed shape of the adaptor
|
|
* @tparam L The layout_type of the adaptor.
|
|
* @tparam SH Wether the adaptor can be used as a shared expression.
|
|
* @tparam Tag The expression tag.
|
|
*/
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
class xfixed_adaptor : public xcontainer<xfixed_adaptor<EC, S, L, SH, Tag>>,
|
|
public xcontainer_semantic<xfixed_adaptor<EC, S, L, SH, Tag>>
|
|
{
|
|
public:
|
|
|
|
using container_closure_type = EC;
|
|
|
|
using self_type = xfixed_adaptor<EC, S, L, SH, Tag>;
|
|
using base_type = xcontainer<self_type>;
|
|
using semantic_base = xcontainer_semantic<self_type>;
|
|
using storage_type = typename base_type::storage_type;
|
|
using shape_type = typename base_type::shape_type;
|
|
using strides_type = typename base_type::strides_type;
|
|
using backstrides_type = typename base_type::backstrides_type;
|
|
using inner_shape_type = typename base_type::inner_shape_type;
|
|
using inner_strides_type = typename base_type::inner_strides_type;
|
|
using inner_backstrides_type = typename base_type::inner_backstrides_type;
|
|
using temporary_type = typename semantic_base::temporary_type;
|
|
using expression_tag = Tag;
|
|
|
|
static constexpr std::size_t N = S::size();
|
|
|
|
xfixed_adaptor(storage_type&& data);
|
|
xfixed_adaptor(const storage_type& data);
|
|
|
|
template <class D>
|
|
xfixed_adaptor(D&& data);
|
|
|
|
~xfixed_adaptor() = default;
|
|
|
|
xfixed_adaptor(const xfixed_adaptor&) = default;
|
|
xfixed_adaptor& operator=(const xfixed_adaptor&);
|
|
|
|
xfixed_adaptor(xfixed_adaptor&&) = default;
|
|
xfixed_adaptor& operator=(xfixed_adaptor&&);
|
|
xfixed_adaptor& operator=(temporary_type&&);
|
|
|
|
template <class E>
|
|
xfixed_adaptor& operator=(const xexpression<E>& e);
|
|
|
|
template <class ST = std::array<std::size_t, N>>
|
|
void resize(ST&& shape, bool force = false) const;
|
|
template <class ST = shape_type>
|
|
void resize(ST&& shape, layout_type l) const;
|
|
template <class ST = shape_type>
|
|
void resize(ST&& shape, const strides_type& strides) const;
|
|
|
|
template <class ST = std::array<std::size_t, N>>
|
|
const auto& reshape(ST&& shape, layout_type layout = L) const;
|
|
|
|
template <class ST>
|
|
bool broadcast_shape(ST& s, bool reuse_cache = false) const;
|
|
|
|
constexpr layout_type layout() const noexcept;
|
|
bool is_contiguous() const noexcept;
|
|
|
|
private:
|
|
|
|
container_closure_type m_storage;
|
|
|
|
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S();
|
|
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides<L, inner_strides_type>(S());
|
|
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type
|
|
m_backstrides = get_backstrides(m_shape, m_strides);
|
|
|
|
storage_type& storage_impl() noexcept;
|
|
const storage_type& storage_impl() const noexcept;
|
|
|
|
XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept;
|
|
XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept;
|
|
XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept;
|
|
|
|
friend class xcontainer<xfixed_adaptor<EC, S, L, SH, Tag>>;
|
|
};
|
|
|
|
#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED
|
|
// Out of line definitions to prevent linker errors prior to C++17
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
constexpr
|
|
typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_shape_type xfixed_adaptor<EC, S, L, SH, Tag>::m_shape;
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
constexpr
|
|
typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_strides_type xfixed_adaptor<EC, S, L, SH, Tag>::m_strides;
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
constexpr typename xfixed_adaptor<EC, S, L, SH, Tag>::inner_backstrides_type
|
|
xfixed_adaptor<EC, S, L, SH, Tag>::m_backstrides;
|
|
#endif
|
|
|
|
/************************************
|
|
* xfixed_container implementation *
|
|
************************************/
|
|
|
|
/**
|
|
* @name Constructors
|
|
*/
|
|
//@{
|
|
|
|
/**
|
|
* Create an uninitialized xfixed_container.
|
|
* Note this function is only provided for homogeneity, and the shape & layout argument is
|
|
* disregarded (the template shape is always used).
|
|
*
|
|
* @param shape the shape of the xfixed_container (unused!)
|
|
* @param l the layout_type of the xfixed_container (unused!)
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const inner_shape_type& shape, layout_type l)
|
|
{
|
|
(void) (shape);
|
|
(void) (l);
|
|
XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), m_shape.begin()));
|
|
XTENSOR_ASSERT(L == l);
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const value_type& v)
|
|
{
|
|
if (this->size() != 1)
|
|
{
|
|
XTENSOR_THROW(std::runtime_error, "wrong shape for scalar assignment (has to be xshape<>).");
|
|
}
|
|
m_storage[0] = v;
|
|
}
|
|
|
|
/**
|
|
* Create an xfixed_container, and initialize with the value of v.
|
|
* Note, the shape argument to this function is only provided for homogeneity,
|
|
* and the shape argument is disregarded (the template shape is always used).
|
|
*
|
|
* @param shape the shape of the xfixed_container (unused!)
|
|
* @param v the fill value
|
|
* @param l the layout_type of the xfixed_container (unused!)
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(
|
|
const inner_shape_type& shape,
|
|
value_type v,
|
|
layout_type l
|
|
)
|
|
{
|
|
(void) (shape);
|
|
(void) (l);
|
|
XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), m_shape.begin()));
|
|
XTENSOR_ASSERT(L == l);
|
|
std::fill(m_storage.begin(), m_storage.end(), v);
|
|
}
|
|
|
|
namespace detail
|
|
{
|
|
template <std::size_t X>
|
|
struct check_initializer_list_shape
|
|
{
|
|
template <class T, class S>
|
|
static bool run(const T& t, const S& shape)
|
|
{
|
|
std::size_t IX = shape.size() - X;
|
|
bool result = (shape[IX] == t.size());
|
|
for (std::size_t i = 0; i < shape[IX]; ++i)
|
|
{
|
|
result = result && check_initializer_list_shape<X - 1>::run(t.begin()[i], shape);
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct check_initializer_list_shape<0>
|
|
{
|
|
template <class T, class S>
|
|
static bool run(const T& /*t*/, const S& /*shape*/)
|
|
{
|
|
return true;
|
|
}
|
|
};
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline xfixed_container<ET, S, L, SH, Tag> xfixed_container<ET, S, L, SH, Tag>::from_shape(ST&& shape)
|
|
{
|
|
(void) shape;
|
|
self_type tmp;
|
|
XTENSOR_ASSERT(shape.size() == N && std::equal(shape.begin(), shape.end(), tmp.shape().begin()));
|
|
return tmp;
|
|
}
|
|
|
|
/**
|
|
* Allocates an xfixed_container with shape S with values from a C array.
|
|
* The type returned by get_init_type_t is raw C array ``value_type[X][Y][Z]`` for
|
|
* ``xt::xshape<X, Y, Z>``. C arrays can be initialized with the initializer list syntax,
|
|
* but the size is checked at compile time to prevent errors.
|
|
* Note: for clang < 3.8 this is an initializer_list and the size is not checked at compile-or runtime.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class IX, class EN>
|
|
inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(nested_initializer_list_t<value_type, N> t)
|
|
{
|
|
XTENSOR_ASSERT_MSG(
|
|
detail::check_initializer_list_shape<N>::run(t, this->shape()) == true,
|
|
"initializer list shape does not match fixed shape"
|
|
);
|
|
constexpr auto tmp = layout_type::row_major;
|
|
L == tmp ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<tmp>(), t);
|
|
}
|
|
|
|
//@}
|
|
|
|
/**
|
|
* @name Extended copy semantic
|
|
*/
|
|
//@{
|
|
/**
|
|
* The extended copy constructor.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class E>
|
|
inline xfixed_container<ET, S, L, SH, Tag>::xfixed_container(const xexpression<E>& e)
|
|
{
|
|
semantic_base::assign(e);
|
|
}
|
|
|
|
/**
|
|
* The extended assignment operator.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class E>
|
|
inline auto xfixed_container<ET, S, L, SH, Tag>::operator=(const xexpression<E>& e) -> self_type&
|
|
{
|
|
return semantic_base::operator=(e);
|
|
}
|
|
|
|
//@}
|
|
|
|
/**
|
|
* Note that the xfixed_container **cannot** be resized. Attempting to resize with a different
|
|
* size throws an assert in debug mode.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, bool) const
|
|
{
|
|
(void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined
|
|
XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
|
|
}
|
|
|
|
/**
|
|
* Note that the xfixed_container **cannot** be resized. Attempting to resize with a different
|
|
* size throws an assert in debug mode.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, layout_type l) const
|
|
{
|
|
(void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined
|
|
(void) (l);
|
|
XTENSOR_ASSERT(
|
|
std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Note that the xfixed_container **cannot** be resized. Attempting to resize with a different
|
|
* size throws an assert in debug mode.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline void xfixed_container<ET, S, L, SH, Tag>::resize(ST&& shape, const strides_type& strides) const
|
|
{
|
|
(void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined
|
|
(void) (strides);
|
|
XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
|
|
XTENSOR_ASSERT(
|
|
std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline const auto& xfixed_container<ET, S, L, SH, Tag>::reshape(ST&& shape, layout_type layout) const
|
|
{
|
|
if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()
|
|
&& layout == L))
|
|
{
|
|
XTENSOR_THROW(std::runtime_error, "Trying to reshape xtensor_fixed with different shape or layout.");
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline bool xfixed_container<ET, S, L, SH, Tag>::broadcast_shape(ST& shape, bool) const
|
|
{
|
|
return xt::broadcast_shape(m_shape, shape);
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
constexpr layout_type xfixed_container<ET, S, L, SH, Tag>::layout() const noexcept
|
|
{
|
|
return base_type::static_layout;
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
inline bool xfixed_container<ET, S, L, SH, Tag>::is_contiguous() const noexcept
|
|
{
|
|
using str_type = typename inner_strides_type::value_type;
|
|
return m_strides.empty() || (layout() == layout_type::row_major && m_strides.back() == str_type(1))
|
|
|| (layout() == layout_type::column_major && m_strides.front() == str_type(1));
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
inline auto xfixed_container<ET, S, L, SH, Tag>::storage_impl() noexcept -> storage_type&
|
|
{
|
|
return m_storage;
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
inline auto xfixed_container<ET, S, L, SH, Tag>::storage_impl() const noexcept -> const storage_type&
|
|
{
|
|
return m_storage;
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::shape_impl() const noexcept
|
|
-> const inner_shape_type&
|
|
{
|
|
return m_shape;
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::strides_impl() const noexcept
|
|
-> const inner_strides_type&
|
|
{
|
|
return m_strides;
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, SH, Tag>::backstrides_impl() const noexcept
|
|
-> const inner_backstrides_type&
|
|
{
|
|
return m_backstrides;
|
|
}
|
|
|
|
/*******************
|
|
* xfixed_adaptor *
|
|
*******************/
|
|
|
|
/**
|
|
* @name Constructors
|
|
*/
|
|
//@{
|
|
/**
|
|
* Constructs an xfixed_adaptor of the given stl-like container.
|
|
* @param data the container to adapt
|
|
*/
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(storage_type&& data)
|
|
: base_type()
|
|
, m_storage(std::move(data))
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Constructs an xfixed_adaptor of the given stl-like container.
|
|
* @param data the container to adapt
|
|
*/
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(const storage_type& data)
|
|
: base_type()
|
|
, m_storage(data)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Constructs an xfixed_adaptor of the given stl-like container,
|
|
* with the specified shape and layout_type.
|
|
* @param data the container to adapt
|
|
*/
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
template <class D>
|
|
inline xfixed_adaptor<EC, S, L, SH, Tag>::xfixed_adaptor(D&& data)
|
|
: base_type()
|
|
, m_storage(std::forward<D>(data))
|
|
{
|
|
}
|
|
|
|
//@}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(const xfixed_adaptor& rhs) -> self_type&
|
|
{
|
|
base_type::operator=(rhs);
|
|
m_storage = rhs.m_storage;
|
|
return *this;
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(xfixed_adaptor&& rhs) -> self_type&
|
|
{
|
|
base_type::operator=(std::move(rhs));
|
|
m_storage = rhs.m_storage;
|
|
return *this;
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(temporary_type&& rhs) -> self_type&
|
|
{
|
|
m_storage.resize(rhs.storage().size());
|
|
std::copy(rhs.storage().cbegin(), rhs.storage().cend(), m_storage.begin());
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @name Extended copy semantic
|
|
*/
|
|
//@{
|
|
/**
|
|
* The extended assignment operator.
|
|
*/
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
template <class E>
|
|
inline auto xfixed_adaptor<EC, S, L, SH, Tag>::operator=(const xexpression<E>& e) -> self_type&
|
|
{
|
|
return semantic_base::operator=(e);
|
|
}
|
|
|
|
//@}
|
|
|
|
/**
|
|
* Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different
|
|
* size throws an assert in debug mode.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, bool) const
|
|
{
|
|
(void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined
|
|
XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
|
|
}
|
|
|
|
/**
|
|
* Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different
|
|
* size throws an assert in debug mode.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, layout_type l) const
|
|
{
|
|
(void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined
|
|
(void) (l);
|
|
XTENSOR_ASSERT(
|
|
std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && L == l
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Note that the xfixed_adaptor **cannot** be resized. Attempting to resize with a different
|
|
* size throws an assert in debug mode.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline void xfixed_adaptor<ET, S, L, SH, Tag>::resize(ST&& shape, const strides_type& strides) const
|
|
{
|
|
(void) (shape); // remove unused parameter warning if XTENSOR_ASSERT undefined
|
|
(void) (strides);
|
|
XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
|
|
XTENSOR_ASSERT(
|
|
std::equal(strides.begin(), strides.end(), m_strides.begin()) && strides.size() == m_strides.size()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``.
|
|
*/
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline const auto& xfixed_adaptor<ET, S, L, SH, Tag>::reshape(ST&& shape, layout_type layout) const
|
|
{
|
|
if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()
|
|
&& layout == L))
|
|
{
|
|
XTENSOR_THROW(std::runtime_error, "Trying to reshape xtensor_fixed with different shape or layout.");
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <class ET, class S, layout_type L, bool SH, class Tag>
|
|
template <class ST>
|
|
inline bool xfixed_adaptor<ET, S, L, SH, Tag>::broadcast_shape(ST& shape, bool) const
|
|
{
|
|
return xt::broadcast_shape(m_shape, shape);
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
inline auto xfixed_adaptor<EC, S, L, SH, Tag>::storage_impl() noexcept -> storage_type&
|
|
{
|
|
return m_storage;
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
inline auto xfixed_adaptor<EC, S, L, SH, Tag>::storage_impl() const noexcept -> const storage_type&
|
|
{
|
|
return m_storage;
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
constexpr layout_type xfixed_adaptor<EC, S, L, SH, Tag>::layout() const noexcept
|
|
{
|
|
return base_type::static_layout;
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
inline bool xfixed_adaptor<EC, S, L, SH, Tag>::is_contiguous() const noexcept
|
|
{
|
|
using str_type = typename inner_strides_type::value_type;
|
|
return m_strides.empty() || (layout() == layout_type::row_major && m_strides.back() == str_type(1))
|
|
|| (layout() == layout_type::column_major && m_strides.front() == str_type(1));
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::shape_impl() const noexcept
|
|
-> const inner_shape_type&
|
|
{
|
|
return m_shape;
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::strides_impl() const noexcept
|
|
-> const inner_strides_type&
|
|
{
|
|
return m_strides;
|
|
}
|
|
|
|
template <class EC, class S, layout_type L, bool SH, class Tag>
|
|
XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, SH, Tag>::backstrides_impl() const noexcept
|
|
-> const inner_backstrides_type&
|
|
{
|
|
return m_backstrides;
|
|
}
|
|
}
|
|
|
|
#endif
|