File indexing completed on 2025-09-17 08:54:11
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <iostream>
0010 #include <memory>
0011 #include <numeric>
0012 #include <type_traits>
0013
0014 #include <covfie/core/backend/primitive/array.hpp>
0015 #include <covfie/core/concepts.hpp>
0016 #include <covfie/core/parameter_pack.hpp>
0017 #include <covfie/core/qualifiers.hpp>
0018 #include <covfie/core/utility/binary_io.hpp>
0019 #include <covfie/core/utility/nd_map.hpp>
0020 #include <covfie/core/utility/nd_size.hpp>
0021 #include <covfie/core/vector.hpp>
0022
0023 namespace covfie::backend {
0024 template <
0025 concepts::vector_descriptor _input_vector_t,
0026 concepts::field_backend _storage_t>
0027 struct strided {
0028 using this_t = strided<_input_vector_t, _storage_t>;
0029 static constexpr bool is_initial = false;
0030
0031 using backend_t = _storage_t;
0032
0033 using contravariant_input_t =
0034 covfie::vector::array_vector_d<_input_vector_t>;
0035 using contravariant_output_t = typename backend_t::contravariant_input_t;
0036 using covariant_input_t = typename backend_t::covariant_output_t;
0037 using covariant_output_t = covariant_input_t;
0038
0039 using coordinate_t = typename contravariant_input_t::vector_t;
0040 using array_t = backend_t;
0041
0042 using configuration_t = utility::nd_size<contravariant_input_t::dimensions>;
0043
0044 static constexpr uint32_t IO_MAGIC_HEADER = 0xAB020010;
0045
0046 template <typename T>
0047 static std::unique_ptr<
0048 std::decay_t<typename backend_t::covariant_output_t::vector_t>[]>
0049 make_strided_copy(const T & other)
0050 {
0051 configuration_t sizes = other.get_configuration();
0052 std::unique_ptr<
0053 std::decay_t<typename backend_t::covariant_output_t::vector_t>[]>
0054 res = std::make_unique<std::decay_t<
0055 typename backend_t::covariant_output_t::vector_t>[]>(
0056 std::accumulate(
0057 std::begin(sizes),
0058 std::end(sizes),
0059 1ul,
0060 std::multiplies<std::size_t>()
0061 )
0062 );
0063 typename T::parent_t::non_owning_data_t nother(other);
0064
0065 utility::nd_map<decltype(sizes)>(
0066 [&sizes, ¬her, &res](decltype(sizes) t) {
0067 typename contravariant_input_t::scalar_t idx = 0;
0068
0069 for (std::size_t k = 0; k < contravariant_input_t::dimensions;
0070 ++k) {
0071 typename contravariant_input_t::scalar_t tmp = t[k];
0072
0073 for (std::size_t l = k + 1;
0074 l < contravariant_input_t::dimensions;
0075 ++l)
0076 {
0077 tmp *= sizes[l];
0078 }
0079
0080 idx += tmp;
0081 }
0082
0083 for (std::size_t i = 0; i < covariant_output_t::dimensions; ++i)
0084 {
0085 if constexpr (covariant_output_t::dimensions == 1 && !std::unsigned_integral<std::decay_t<decltype(t)>>)
0086 {
0087 res[idx][i] = nother.at(t[0])[i];
0088 } else {
0089 res[idx][i] = nother.at(t)[i];
0090 }
0091 }
0092 },
0093 sizes
0094 );
0095
0096 return res;
0097 }
0098
0099 struct owning_data_t {
0100 using parent_t = this_t;
0101
0102 owning_data_t()
0103 : owning_data_t(configuration_t{})
0104 {
0105 }
0106
0107 owning_data_t(const owning_data_t &) = default;
0108 owning_data_t(owning_data_t &&) = default;
0109 owning_data_t & operator=(const owning_data_t &) = default;
0110 owning_data_t & operator=(owning_data_t &&) = default;
0111
0112 template <typename T>
0113 requires(std::same_as<
0114 typename T::parent_t::configuration_t,
0115 configuration_t> &&
0116 std::constructible_from<
0117 typename backend_t::owning_data_t,
0118 std::size_t,
0119 std::add_rvalue_reference_t<std::unique_ptr<std::decay_t<
0120 typename backend_t::covariant_output_t::
0121 vector_t>[]>>>) explicit owning_data_t(const T &
0122 o)
0123 : m_sizes(o.get_configuration())
0124 , m_storage(
0125 std::accumulate(
0126 std::begin(m_sizes),
0127 std::end(m_sizes),
0128 1ul,
0129 std::multiplies<std::size_t>()
0130 ),
0131 make_strided_copy(o)
0132 )
0133 {
0134 }
0135
0136 explicit owning_data_t(configuration_t conf
0137 ) requires(std::constructible_from<typename backend_t::owning_data_t, std::size_t> && !std::constructible_from<typename backend_t::owning_data_t, utility::nd_size<1>>)
0138 : m_sizes(conf)
0139 , m_storage(std::accumulate(
0140 std::begin(m_sizes),
0141 std::end(m_sizes),
0142 static_cast<std::size_t>(1),
0143 std::multiplies<std::size_t>()
0144 ))
0145 {
0146 }
0147
0148 explicit owning_data_t(configuration_t conf)
0149 requires(std::constructible_from<
0150 typename backend_t::owning_data_t,
0151 utility::nd_size<1>>)
0152 : m_sizes(conf)
0153 , m_storage(utility::nd_size<1>{std::accumulate(
0154 std::begin(m_sizes),
0155 std::end(m_sizes),
0156 static_cast<std::size_t>(1),
0157 std::multiplies<std::size_t>()
0158 )})
0159 {
0160 }
0161
0162 template <typename... Args>
0163 requires(sizeof...(Args) > 0) explicit owning_data_t(
0164 parameter_pack<configuration_t, Args...> && args
0165 )
0166 : m_sizes(args.x)
0167 , m_storage(std::move(args.xs))
0168 {
0169 }
0170
0171 template <typename T>
0172 requires(std::constructible_from<
0173 owning_data_t,
0174 T>) explicit owning_data_t(parameter_pack<T> && args)
0175 : owning_data_t(args.x)
0176 {
0177 }
0178
0179 explicit owning_data_t(
0180 const configuration_t & c, typename backend_t::owning_data_t && b
0181 )
0182 : m_sizes(c)
0183 , m_storage(std::forward<typename backend_t::owning_data_t>(b))
0184 {
0185 }
0186
0187 typename backend_t::owning_data_t & get_backend(void)
0188 {
0189 return m_storage;
0190 }
0191
0192 const typename backend_t::owning_data_t & get_backend(void) const
0193 {
0194 return m_storage;
0195 }
0196
0197 configuration_t get_configuration(void) const
0198 {
0199 return m_sizes;
0200 }
0201
0202 static owning_data_t read_binary(std::istream & fs)
0203 {
0204 utility::read_io_header(fs, IO_MAGIC_HEADER);
0205
0206 auto sizes = utility::read_binary<decltype(m_sizes)>(fs);
0207 auto be = backend_t::owning_data_t::read_binary(fs);
0208
0209 utility::read_io_footer(fs, IO_MAGIC_HEADER);
0210
0211 return owning_data_t(sizes, std::move(be));
0212 }
0213
0214 static void write_binary(std::ostream & fs, const owning_data_t & o)
0215 {
0216 utility::write_io_header(fs, IO_MAGIC_HEADER);
0217
0218 fs.write(
0219 reinterpret_cast<const char *>(&o.m_sizes),
0220 sizeof(decltype(o.m_sizes))
0221 );
0222
0223 backend_t::owning_data_t::write_binary(fs, o.m_storage);
0224
0225 utility::write_io_footer(fs, IO_MAGIC_HEADER);
0226 }
0227
0228 configuration_t m_sizes;
0229 typename backend_t::owning_data_t m_storage;
0230 };
0231
0232 struct non_owning_data_t {
0233 using parent_t = this_t;
0234
0235 non_owning_data_t(const owning_data_t & o)
0236 : m_sizes(o.m_sizes)
0237 , m_storage(o.m_storage)
0238 {
0239 }
0240
0241 COVFIE_HOST_DEVICE typename covariant_output_t::vector_t
0242 at(coordinate_t c) const
0243 {
0244 typename contravariant_input_t::scalar_t idx = 0;
0245
0246 #ifndef NDEBUG
0247 for (std::size_t i = 0; i < contravariant_input_t::dimensions; ++i)
0248 {
0249 assert(c[i] < m_sizes[i]);
0250 }
0251 #endif
0252
0253 for (std::size_t k = 0; k < contravariant_input_t::dimensions; ++k)
0254 {
0255 typename contravariant_input_t::scalar_t tmp = c[k];
0256
0257 for (std::size_t l = k + 1;
0258 l < contravariant_input_t::dimensions;
0259 ++l)
0260 {
0261 tmp *=
0262 static_cast<typename contravariant_input_t::scalar_t>(
0263 m_sizes[l]
0264 );
0265 }
0266
0267 idx += tmp;
0268 }
0269
0270 return m_storage.at({idx});
0271 }
0272
0273 typename backend_t::non_owning_data_t & get_backend(void)
0274 {
0275 return m_storage;
0276 }
0277
0278 const typename backend_t::non_owning_data_t & get_backend(void) const
0279 {
0280 return m_storage;
0281 }
0282
0283 configuration_t m_sizes;
0284 typename backend_t::non_owning_data_t m_storage;
0285 };
0286 };
0287 }