1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
#ifndef DUNE_COMMON_STD_LAYOUT_STRIDE_HH
#define DUNE_COMMON_STD_LAYOUT_STRIDE_HH
#include <array>
#include <type_traits>
#include <dune/common/indices.hh>
#include <dune/common/std/impl/fwd_layouts.hh>
namespace Dune::Std {
/// \brief A layout mapping where the strides are user-defined.
template <class Extents>
class layout_stride::mapping
{
template <class> friend class mapping;
static constexpr typename Extents::rank_type rank_ = Extents::rank();
public:
using extents_type = Extents;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using layout_type = layout_stride;
private:
using strides_type = std::array<index_type,rank_>;
public:
/// \brief The default construction initializes the strides from layout_right
constexpr mapping () noexcept
: mapping(layout_right::template mapping<extents_type>{})
{}
/// \brief Copy constructor for the mapping
constexpr mapping (const mapping&) noexcept = default;
/// \brief Construct the mapping from given extents and strides
template <class OtherIndexType,
std::enable_if_t<std::is_convertible_v<const OtherIndexType&, index_type>, int> = 0,
std::enable_if_t<std::is_nothrow_constructible_v<index_type, const OtherIndexType&>, int> = 0>
constexpr mapping (const extents_type& e, const std::array<OtherIndexType,rank_>& s) noexcept
: extents_(e)
, strides_{}
{
for (rank_type r = 0; r < rank_; ++r)
strides_[r] = s[r];
}
/// \brief Construct the mapping from given extents and strides
template <class OtherIndexType,
std::enable_if_t<std::is_convertible_v<const OtherIndexType&, index_type>, int> = 0,
std::enable_if_t<std::is_nothrow_constructible_v<index_type, const OtherIndexType&>, int> = 0>
constexpr mapping (const extents_type& e, const span<OtherIndexType,rank_>& s) noexcept
: extents_(e)
, strides_{}
{
for (rank_type r = 0; r < rank_; ++r)
strides_[r] = s[r];
}
/// \brief Construct the mapping from another mapping with different extents and different strides
template <class M,
std::enable_if_t<(M::extents_type::rank() == extents_type::rank()), int> = 0,
std::enable_if_t<(M::is_always_unique()), int> = 0,
std::enable_if_t<(M::is_always_strided()), int> = 0,
decltype(std::declval<M>().extents(), bool{}) = true,
decltype(std::declval<M>().stride(std::declval<rank_type>()), bool{}) = true>
constexpr mapping (const M& m) noexcept
: extents_(m.extents())
, strides_{}
{
for (rank_type r = 0; r < rank_; ++r)
strides_[r] = m.stride(r);
}
/// \brief Copy-assignment for the mapping
constexpr mapping& operator= (const mapping&) noexcept = default;
constexpr const extents_type& extents () const noexcept { return extents_; }
/// \brief Return the sum `1 + (E(0)-1)*S(0) + (E(1)-1)*S(1) + ...`
constexpr index_type required_span_size () const noexcept
{
return size(extents_,strides_);
}
/// \brief Compute the offset by folding with index-array with the strides array
template <class... Indices,
std::enable_if_t<(sizeof...(Indices) == rank_), int> = 0,
std::enable_if_t<(std::is_convertible_v<Indices, index_type> && ...), int> = 0,
std::enable_if_t<(std::is_nothrow_constructible_v<index_type, Indices> && ...), int> = 0>
constexpr index_type operator() (Indices... ii) const noexcept
{
return unpackIntegerSequence([&](auto... r) {
return ((static_cast<index_type>(ii)*strides_[r]) + ... + 0); },
std::make_index_sequence<rank_>{});
}
/// \brief The default offset for rank-0 tensors is 0
constexpr index_type operator() () const noexcept
{
return 0;
}
static constexpr bool is_always_unique () noexcept { return true; }
static constexpr bool is_always_exhaustive () noexcept { return false; }
static constexpr bool is_always_strided () noexcept { return true; }
static constexpr bool is_unique () noexcept { return true; }
static constexpr bool is_strided () noexcept { return true; }
constexpr bool is_exhaustive () const noexcept
{
// Actually this could be improved. A strided layout can still be exhaustive.
// This test is more complicated to implement, though. See §24.7.3.4.7.4 line (5.2)
// in the C++ standard document N4971
return extents_type::rank() == 0 || (required_span_size() > 0 && required_span_size() == extents().product());
}
/// \brief Get the array of all strides
constexpr const strides_type& strides () const noexcept
{
return strides_;
}
/// \brief Get the single stride `i`
template <class E = extents_type,
std::enable_if_t<(E::rank() > 0), int> = 0>
constexpr index_type stride (rank_type i) const noexcept
{
return strides_[i];
}
template <class OtherMapping,
std::enable_if_t<(OtherMapping::extents_type::rank() == extents_type::rank()), int> = 0,
std::enable_if_t<(OtherMapping::is_always_strided()), int> = 0>
friend constexpr bool operator== (const mapping& a, const OtherMapping& b) noexcept
{
if (offset(b))
return false;
if constexpr(extents_type::rank() == 0)
return true;
return a.extents_ == b.extents_ && a.strides_ == b.strides_;
}
private:
template <class E, class S>
static constexpr index_type size (const E& extents, const S& strides) noexcept
{
if constexpr (E::rank() == 0)
return 1;
else {
if (extents.product() == 0)
return 0;
else {
index_type result = 1;
for (rank_type r = 0; r < E::rank(); ++r)
result += (extents.extent(r)-1) * strides[r];
return result;
}
}
}
template <class M>
static constexpr size_type offset (const M& m) noexcept
{
if constexpr (M::extents_type::rank() == 0)
return m();
else {
if (m.required_span_size() == 0)
return 0;
else {
return unpackIntegerSequence([&](auto... r) {
return m((r,0)...); }, // map the index tuple (0,0...)
std::make_index_sequence<M::extents_type::rank()>{});
}
}
}
private:
[[no_unique_address]] extents_type extents_;
strides_type strides_;
};
} // end namespace Dune::Std
#endif // DUNE_COMMON_STD_LAYOUT_STRIDE_HH
|