8#ifndef GRIDFORMAT_COMMON_FIELD_HPP_
9#define GRIDFORMAT_COMMON_FIELD_HPP_
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>
40 static constexpr struct DisableResize {} no_resize{};
42 virtual ~Field() =
default;
67 auto result = _serialized();
69 throw SizeError(
"Serialized size does not match expected number of bytes");
74 template<
typename Visitor>
76 return precision().visit([&] <
typename T> (
const Precision<T>&) {
78 return visitor(serialization.template as_span_of<T>());
83 template<std::ranges::range R>
requires(Concepts::Scalar<MDRangeValueType<R>>)
85 return _export_to<true>(std::forward<R>(output_range));
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));
95 template<Concepts::Scalar S>
97 const auto my_layout =
layout();
99 if (my_layout.number_of_entries() != 1)
100 throw TypeError(
"Field cannot be exported into a scalar");
102 out =
static_cast<S
>(data[0]);
107 template<Concepts::Scalar S>
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>>)
123 DynamicPrecision _prec;
125 virtual MDLayout _layout()
const = 0;
126 virtual DynamicPrecision _precision()
const = 0;
127 virtual Serialization _serialized()
const = 0;
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();
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)
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."
145 num_scalars/num_sub_scalars,
146 DefaultValue<std::ranges::range_value_t<R>>::get()
149 const auto output_range_layout = get_md_layout(output_range);
150 if (output_range_layout.number_of_entries() < my_layout.number_of_entries())
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()) +
"'"
158 std::size_t offset = 0;
160 _export_to(output_range, data, offset);
163 return std::forward<R>(output_range);
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);
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++]);
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));
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