GridFormat 0.4.0
I/O-Library for grid-like data structures
Loading...
Searching...
No Matches
field.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2// SPDX-License-Identifier: MIT
8#ifndef GRIDFORMAT_COMMON_FIELD_HPP_
9#define GRIDFORMAT_COMMON_FIELD_HPP_
10
11#include <memory>
12#include <cstddef>
13#include <concepts>
14#include <type_traits>
15#include <utility>
16#include <ranges>
17#include <cmath>
18
19#include <gridformat/common/md_layout.hpp>
20#include <gridformat/common/precision.hpp>
21#include <gridformat/common/serialization.hpp>
22#include <gridformat/common/type_traits.hpp>
23#include <gridformat/common/exceptions.hpp>
24#include <gridformat/common/concepts.hpp>
25#include <gridformat/common/ranges.hpp>
26
27namespace GridFormat {
28
31
37class Field {
38 public:
40 static constexpr struct DisableResize {} no_resize{};
41
42 virtual ~Field() = default;
43
44 Field() = default;
45 Field(Field&&) = default;
46 Field(const Field&) = delete;
47 Field& operator=(Field&&) = default;
48 Field& operator=(const Field&) = delete;
49
51 MDLayout layout() const {
52 return _layout();
53 }
54
56 DynamicPrecision precision() const {
57 return _precision();
58 }
59
61 std::size_t size_in_bytes() const {
62 return layout().number_of_entries()*precision().size_in_bytes();
63 }
64
66 Serialization serialized() const {
67 auto result = _serialized();
68 if (result.size() != size_in_bytes())
69 throw SizeError("Serialized size does not match expected number of bytes");
70 return result;
71 }
72
74 template<typename Visitor>
75 decltype(auto) visit_field_values(Visitor&& visitor) const {
76 return precision().visit([&] <typename T> (const Precision<T>&) {
77 const auto serialization = serialized();
78 return visitor(serialization.template as_span_of<T>());
79 });
80 }
81
83 template<std::ranges::range R> requires(Concepts::Scalar<MDRangeValueType<R>>)
84 decltype(auto) export_to(R&& output_range) const {
85 return _export_to<true>(std::forward<R>(output_range));
86 }
87
89 template<std::ranges::range R> requires(Concepts::Scalar<MDRangeValueType<R>>)
90 decltype(auto) export_to(R&& output_range, DisableResize) const {
91 return _export_to<false>(std::forward<R>(output_range));
92 }
93
95 template<Concepts::Scalar S>
96 void export_to(S& out) const {
97 const auto my_layout = layout();
98 const auto serialization = serialized();
99 if (my_layout.number_of_entries() != 1)
100 throw TypeError("Field cannot be exported into a scalar");
101 visit_field_values([&] <typename T> (std::span<const T> data) {
102 out = static_cast<S>(data[0]);
103 });
104 }
105
107 template<Concepts::Scalar S>
108 S export_to() const {
109 S out;
110 export_to(out);
111 return out;
112 }
113
115 template<Concepts::ResizableMDRange R>
116 requires(Concepts::StaticallySizedMDRange<std::ranges::range_value_t<R>> or
117 Concepts::Scalar<std::ranges::range_value_t<R>>)
118 R export_to() const {
119 return export_to(R{});
120 }
121
122 private:
123 DynamicPrecision _prec;
124
125 virtual MDLayout _layout() const = 0;
126 virtual DynamicPrecision _precision() const = 0;
127 virtual Serialization _serialized() const = 0;
128
130 template<bool enable_resize, std::ranges::range R> requires(Concepts::Scalar<MDRangeValueType<R>>)
131 decltype(auto) _export_to(R&& output_range) const {
132 const auto my_layout = layout();
133
134 if constexpr (Concepts::ResizableMDRange<R> && enable_resize) {
135 const auto num_scalars = my_layout.number_of_entries();
136 const auto num_sub_scalars = get_md_layout<std::ranges::range_value_t<R>>().number_of_entries();
137 if (num_scalars%num_sub_scalars != 0)
138 throw TypeError(
139 "Cannot export the field into the given range type. "
140 "Number of entries in the field is not divisible by the "
141 "number of entries in the value_type of the provided range."
142 );
143
144 output_range.resize(
145 num_scalars/num_sub_scalars,
146 DefaultValue<std::ranges::range_value_t<R>>::get()
147 );
148 } else {
149 const auto output_range_layout = get_md_layout(output_range);
150 if (output_range_layout.number_of_entries() < my_layout.number_of_entries())
151 throw SizeError(
152 std::string{"Cannot fill the given range. Too few entries. "} +
153 "Number of field entries: '" + std::to_string(my_layout.number_of_entries()) + "'; " +
154 "Number of range entries: '" + std::to_string(output_range_layout.number_of_entries()) + "'"
155 );
156 }
157
158 std::size_t offset = 0;
159 visit_field_values([&] <typename T> (std::span<const T> data) {
160 _export_to(output_range, data, offset);
161 });
162
163 return std::forward<R>(output_range);
164 }
165
166 template<std::ranges::range R, Concepts::Scalar T>
167 void _export_to(R& range,
168 std::span<const T> data,
169 std::size_t& offset) const {
170 if constexpr (mdrange_dimension<R> > 1)
171 std::ranges::for_each(range, [&] (std::ranges::range auto& sub_range) {
172 _export_to(sub_range, data, offset);
173 });
174 else
175 std::ranges::for_each_n(
176 std::ranges::begin(range),
177 std::min(Ranges::size(range), data.size() - offset),
178 [&] <typename V> (V& value) {
179 value = static_cast<V>(data[offset++]);
180 }
181 );
182 }
183};
184
186using FieldPtr = std::shared_ptr<const Field>;
187
189template<typename F> requires(
190 std::derived_from<std::remove_cvref_t<F>, Field> and
191 !std::is_lvalue_reference_v<F>)
193 return std::make_shared<std::add_const_t<F>>(std::forward<F>(f));
194}
195
197
198} // namespace GridFormat
199
200#endif // GRIDFORMAT_COMMON_FIELD_HPP_
Abstract interface for fields of values that is used by writers/readers to store fields.
Definition: field.hpp:37
std::size_t size_in_bytes() const
Return the size of all field values in serialized form.
Definition: field.hpp:61
decltype(auto) export_to(R &&output_range) const
Export the field values into the provided range, resize if necessary, and return it.
Definition: field.hpp:84
S export_to() const
Export the field as a scalar (works only if the field is a scalar field)
Definition: field.hpp:108
Serialization serialized() const
Return the field values in serialized form.
Definition: field.hpp:66
R export_to() const
Export the field into a resizable range (e.g. std::vector)
Definition: field.hpp:118
void export_to(S &out) const
Export the field as a scalar (works only if the field is a scalar field)
Definition: field.hpp:96
decltype(auto) visit_field_values(Visitor &&visitor) const
Visit the scalar values of the field in the form of an std::span.
Definition: field.hpp:75
decltype(auto) export_to(R &&output_range, DisableResize) const
Export the field values into the provided range without resizing (given range must be large enough)
Definition: field.hpp:90
DynamicPrecision precision() const
Return the precision of the scalar field values.
Definition: field.hpp:56
MDLayout layout() const
Return the layout of this field.
Definition: field.hpp:51
std::shared_ptr< const Field > FieldPtr
Pointer type used by writers/readers for fields.
Definition: field.hpp:186
FieldPtr make_field_ptr(F &&f)
Factory function for field pointers.
Definition: field.hpp:192