File indexing completed on 2025-09-17 08:54:10
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <cassert>
0010 #include <cstring>
0011 #include <memory>
0012 #include <utility>
0013
0014 #include <covfie/core/concepts.hpp>
0015 #include <covfie/core/parameter_pack.hpp>
0016 #include <covfie/core/qualifiers.hpp>
0017 #include <covfie/core/utility/binary_io.hpp>
0018 #include <covfie/core/utility/nd_size.hpp>
0019 #include <covfie/core/vector.hpp>
0020
0021 namespace covfie::backend {
0022 template <
0023 concepts::vector_descriptor _output_vector_t,
0024 typename _index_t = std::size_t>
0025 struct array {
0026 using this_t = array<_output_vector_t, _index_t>;
0027 static constexpr bool is_initial = true;
0028
0029 using contravariant_input_t =
0030 covfie::vector::scalar_d<covfie::vector::vector_d<_index_t, 1>>;
0031 using covariant_output_t =
0032 covfie::vector::array_reference_vector_d<_output_vector_t>;
0033
0034 using vector_t = std::decay_t<typename covariant_output_t::vector_t>;
0035
0036 using configuration_t = utility::nd_size<contravariant_input_t::dimensions>;
0037
0038 static constexpr uint32_t IO_MAGIC_HEADER = 0xAB010000;
0039
0040 struct owning_data_t {
0041 using parent_t = this_t;
0042
0043 owning_data_t()
0044 : m_size(0)
0045 , m_ptr({})
0046 {
0047 }
0048
0049 owning_data_t(owning_data_t &&) = default;
0050 owning_data_t & operator=(owning_data_t &&) = default;
0051
0052 explicit owning_data_t(std::size_t n)
0053 : m_size(n)
0054 , m_ptr(std::make_unique<vector_t[]>(n))
0055 {
0056 }
0057
0058 explicit owning_data_t(configuration_t conf)
0059 : owning_data_t(conf[0])
0060 {
0061 }
0062
0063 explicit owning_data_t(parameter_pack<owning_data_t> && conf)
0064 : owning_data_t(std::move(conf.x))
0065 {
0066 }
0067
0068 explicit owning_data_t(parameter_pack<configuration_t> && conf)
0069 : owning_data_t(conf.x[0])
0070 {
0071 }
0072
0073 explicit owning_data_t(
0074 std::size_t size, std::unique_ptr<vector_t[]> && ptr
0075 )
0076 : m_size(size)
0077 , m_ptr(std::move(ptr))
0078 {
0079 }
0080
0081 owning_data_t(const owning_data_t & o)
0082 : m_size(o.m_size)
0083 , m_ptr(std::make_unique<vector_t[]>(m_size))
0084 {
0085 assert(m_size == 0 || m_ptr);
0086
0087 if (o.m_ptr && m_size > 0) {
0088 std::memcpy(
0089 m_ptr.get(), o.m_ptr.get(), m_size * sizeof(vector_t)
0090 );
0091 }
0092 }
0093
0094 owning_data_t & operator=(const owning_data_t & o)
0095 {
0096 m_size = o.m_size;
0097 m_ptr = std::make_unique<vector_t[]>(m_size);
0098
0099 assert(m_size == 0 || m_ptr);
0100
0101 if (o.m_ptr && m_size > 0) {
0102 std::memcpy(
0103 m_ptr.get(), o.m_ptr.get(), m_size * sizeof(vector_t)
0104 );
0105 }
0106 }
0107
0108 configuration_t get_configuration() const
0109 {
0110 return {m_size};
0111 }
0112
0113 static owning_data_t read_binary(std::istream & fs)
0114 {
0115 utility::read_io_header(fs, IO_MAGIC_HEADER);
0116
0117 uint32_t float_width = utility::read_binary<uint32_t>(fs);
0118
0119 if (float_width != 4 && float_width != 8) {
0120 throw std::runtime_error(
0121 "Float type is neither IEEE 754 single- nor "
0122 "double-precision, binary input is not supported."
0123 );
0124 }
0125
0126 auto size =
0127 utility::read_binary<std::decay_t<decltype(m_size)>>(fs);
0128 std::unique_ptr<vector_t[]> ptr =
0129 std::make_unique<vector_t[]>(size);
0130
0131 for (std::size_t i = 0; i < size; ++i) {
0132 for (std::size_t j = 0; j < _output_vector_t::size; ++j) {
0133 using scalar_t = typename _output_vector_t::type;
0134 if (float_width == 4) {
0135 ptr[i][j] =
0136 static_cast<scalar_t>(utility::read_binary<float>(fs
0137 ));
0138 } else if (float_width == 8) {
0139 ptr[i][j] = static_cast<scalar_t>(
0140 utility::read_binary<double>(fs)
0141 );
0142 } else {
0143 throw std::logic_error("Float width is unexpected.");
0144 }
0145 }
0146 }
0147
0148 utility::read_io_footer(fs, IO_MAGIC_HEADER);
0149
0150 return owning_data_t(size, std::move(ptr));
0151 }
0152
0153 static void write_binary(std::ostream & fs, const owning_data_t & o)
0154 {
0155 utility::write_io_header(fs, IO_MAGIC_HEADER);
0156
0157 uint32_t float_width;
0158
0159 if constexpr (std::
0160 is_same_v<typename _output_vector_t::type, float>)
0161 {
0162 float_width = 4;
0163 } else if constexpr (std::is_same_v<
0164 typename _output_vector_t::type,
0165 double>)
0166 {
0167 float_width = 8;
0168 } else {
0169 throw std::logic_error(
0170 "Float type is neither IEEE 754 single- nor "
0171 "double-precision, binary output is not supported."
0172 );
0173 }
0174
0175 fs.write(
0176 reinterpret_cast<const char *>(&float_width),
0177 sizeof(std::decay_t<decltype(float_width)>)
0178 );
0179
0180 fs.write(
0181 reinterpret_cast<const char *>(&o.m_size),
0182 sizeof(std::decay_t<decltype(o.m_size)>)
0183 );
0184
0185 for (std::size_t i = 0; i < o.m_size; ++i) {
0186 for (std::size_t j = 0; j < _output_vector_t::size; ++j) {
0187 fs.write(
0188 reinterpret_cast<const char *>(&o.m_ptr[i][j]),
0189 sizeof(typename _output_vector_t::type)
0190 );
0191 }
0192 }
0193
0194 utility::write_io_footer(fs, IO_MAGIC_HEADER);
0195 }
0196
0197 uint64_t get_size() const
0198 {
0199 return m_size;
0200 }
0201
0202 std::unique_ptr<vector_t[]> get_host_array() const
0203 {
0204 std::unique_ptr<vector_t[]> rv =
0205 std::make_unique<vector_t[]>(m_size);
0206 std::memcpy(rv.get(), m_ptr.get(), m_size * sizeof(vector_t));
0207 return rv;
0208 }
0209
0210 uint64_t m_size;
0211 std::unique_ptr<vector_t[]> m_ptr;
0212 };
0213
0214 struct non_owning_data_t {
0215 using parent_t = this_t;
0216
0217 non_owning_data_t(const owning_data_t & o)
0218 : m_size(o.m_size)
0219 , m_ptr(o.m_ptr.get())
0220 {
0221 }
0222
0223 COVFIE_HOST_DEVICE typename covariant_output_t::vector_t
0224 at(typename contravariant_input_t::vector_t i) const
0225 {
0226 assert(i < m_size);
0227 return m_ptr[i];
0228 }
0229
0230 uint64_t m_size;
0231 typename decltype(owning_data_t::m_ptr)::pointer m_ptr;
0232 };
0233 };
0234 }