GCC Code Coverage Report


Directory: gridformat/
File: gridformat/reader.hpp
Date: 2026-10-18 00:09:19
Exec Total Coverage
Lines: 89 98 90.8%
Functions: 67 70 95.7%
Branches: 25 49 51.0%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2 // SPDX-License-Identifier: MIT
3 /*!
4 * \file
5 * \ingroup API
6 * \brief A generic reader providing access to the readers for all supported formats.
7 */
8 #ifndef GRIDFORMAT_READER_HPP_
9 #define GRIDFORMAT_READER_HPP_
10
11 #include <array>
12 #include <vector>
13 #include <memory>
14 #include <utility>
15 #include <concepts>
16 #include <functional>
17 #include <optional>
18 #include <algorithm>
19 #include <iterator>
20 #include <string>
21
22 #include <gridformat/common/type_traits.hpp>
23 #include <gridformat/parallel/concepts.hpp>
24 #include <gridformat/parallel/communication.hpp>
25 #include <gridformat/grid/reader.hpp>
26
27 namespace GridFormat {
28
29 namespace FileFormat { struct Any; }
30
31 template<typename FileFormat>
32 struct ReaderFactory;
33
34 // Forward declaration, implementation in main API header.
35 template<Concepts::Communicator C = NullCommunicator>
36 class AnyReaderFactory {
37 public:
38 AnyReaderFactory() requires(std::same_as<C, NullCommunicator>) = default;
39 54 explicit AnyReaderFactory(const C& comm) : _comm{comm} {}
40 std::unique_ptr<GridReader> make_for(const std::string& filename) const;
41 private:
42 C _comm;
43 };
44
45 #ifndef DOXYGEN
46 namespace ReaderDetail {
47
48 template<typename FileFormat>
49 concept SequentiallyConstructible
50 = is_complete<ReaderFactory<FileFormat>>
51 and requires(const FileFormat& f) {
52 { ReaderFactory<FileFormat>::make(f) } -> std::derived_from<GridReader>;
53 };
54
55 template<typename FileFormat, typename Communicator>
56 concept ParallelConstructible
57 = is_complete<ReaderFactory<FileFormat>>
58 and Concepts::Communicator<Communicator>
59 and requires(const FileFormat& f, const Communicator& comm) {
60 { ReaderFactory<FileFormat>::make(f, comm) } -> std::derived_from<GridReader>;
61 };
62
63 template<typename FieldNameStorage>
64 1353 void copy_field_names(const GridReader& reader, FieldNameStorage& names) {
65
2/4
✓ Branch 2 taken 1353 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1353 times.
✗ Branch 6 not taken.
1353 std::ranges::copy(cell_field_names(reader), std::back_inserter(names.cell_fields));
66
2/4
✓ Branch 2 taken 1353 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1353 times.
✗ Branch 6 not taken.
1353 std::ranges::copy(point_field_names(reader), std::back_inserter(names.point_fields));
67
2/4
✓ Branch 2 taken 1353 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1353 times.
✗ Branch 6 not taken.
1353 std::ranges::copy(meta_data_field_names(reader), std::back_inserter(names.meta_data_fields));
68 1353 }
69
70 using ReaderFactoryFunctor = std::function<std::unique_ptr<GridReader>(const std::string&)>;
71
72 template<Concepts::Communicator C = NullCommunicator>
73 473 ReaderFactoryFunctor default_reader_factory(const C& c = {}) {
74 if constexpr (!std::same_as<C, NullCommunicator>)
75 144 return [fac = AnyReaderFactory<C>{c}] (const std::string& f) { return fac.make_for(f); };
76 else
77 627 return [fac = AnyReaderFactory<>{}] (const std::string& f) { return fac.make_for(f); };
78 }
79
80 } // namespace ReaderDetail
81 #endif // DOXYGEN
82
83 /*!
84 * \ingroup API
85 * \brief Interface to the readers for all supported file formats.
86 * \details Typically you would construct this class with one of the predefined
87 * file format instances. For example, with the .vtu file format:
88 * \code{.cpp}
89 * GridFormat::Reader reader{GridFormat::vtu};
90 * \endcode
91 * \note Unless you pass in a custom ReaderFactoryFunctor, this class requires the
92 * AnyReaderFactory to be defined. Thus, this header cannot be included
93 * without the general API header gridformat.hpp which defines all formats.
94 */
95 class Reader : public GridReader {
96 public:
97 using ReaderFactoryFunctor = ReaderDetail::ReaderFactoryFunctor;
98
99 7 Reader()
100
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 : Reader(ReaderDetail::default_reader_factory())
101 7 {}
102
103 297 explicit Reader(ReaderFactoryFunctor f)
104 297 : _reader_factory{std::move(f)}
105 297 {}
106
107 228 explicit Reader(const FileFormat::Any&, ReaderFactoryFunctor f = ReaderDetail::default_reader_factory())
108
2/4
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 228 times.
✗ Branch 5 not taken.
228 : Reader(f)
109 228 {}
110
111 template<Concepts::Communicator C>
112 62 explicit Reader(const FileFormat::Any&, const C& c)
113
3/5
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
62 : Reader(ReaderDetail::default_reader_factory(c))
114 62 {}
115
116 template<ReaderDetail::SequentiallyConstructible FileFormat>
117 544 explicit Reader(const FileFormat& f)
118
2/4
✓ Branch 2 taken 272 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 272 times.
✗ Branch 6 not taken.
544 : _reader{_make_unique(ReaderFactory<FileFormat>::make(f))}
119 544 {}
120
121 template<typename FileFormat,
122 Concepts::Communicator Communicator>
123 requires(ReaderDetail::ParallelConstructible<FileFormat, Communicator>)
124 100 explicit Reader(const FileFormat& f, const Communicator& c)
125
2/4
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 54 times.
✗ Branch 6 not taken.
100 : _reader{_make_unique(ReaderFactory<FileFormat>::make(f, c))}
126 100 {}
127
128 //! Construct a reader instance from the given arguments, while directly opening the given file
129 template<typename... ConstructorArgs>
130 528 static Reader from(const std::string& filename, ConstructorArgs&&... args) {
131
4/6
✓ Branch 2 taken 110 times.
✓ Branch 3 taken 154 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 110 times.
✓ Branch 6 taken 154 times.
✗ Branch 7 not taken.
528 return Reader{std::forward<ConstructorArgs>(args)...}.with_opened(filename);
132 }
133
134 //! Read the data from the given file and return this reader
135 Reader& with_opened(const std::string& filename) & {
136 this->open(filename);
137 return *this;
138 }
139
140 //! Read the data from the given file and return this reader (lvalue references overload)
141 306 Reader&& with_opened(const std::string& filename) && {
142 306 this->open(filename);
143 306 return std::move(*this);
144 }
145
146 private:
147 template<typename ReaderImpl>
148 652 auto _make_unique(ReaderImpl&& reader) const {
149 652 return std::make_unique<std::remove_cvref_t<ReaderImpl>>(std::move(reader));
150 }
151
152 42 std::string _name() const override {
153
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 if (_reader_is_set())
154 42 return _access_reader().name();
155 ✗ return "undefined";
156 }
157
158 627 void _open(const std::string& filename, typename GridReader::FieldNames& names) override {
159
2/2
✓ Branch 1 taken 298 times.
✓ Branch 2 taken 329 times.
627 if (_reader_factory)
160
1/2
✓ Branch 2 taken 298 times.
✗ Branch 3 not taken.
298 _reader = (*_reader_factory)(filename);
161 627 _access_reader().close();
162 627 _access_reader().open(filename);
163 624 ReaderDetail::copy_field_names(_access_reader(), names);
164 624 };
165
166 ✗ void _close() override {
167 ✗ _access_reader().close();
168 ✗ }
169
170 2078 std::size_t _number_of_cells() const override {
171 2078 return _access_reader().number_of_cells();
172 }
173
174 1826 std::size_t _number_of_points() const override {
175 1826 return _access_reader().number_of_points();
176 }
177
178 34 std::size_t _number_of_pieces() const override {
179 34 return _access_reader().number_of_pieces();
180 }
181
182 3130 FieldPtr _cell_field(std::string_view name) const override {
183 3130 return _access_reader().cell_field(name);
184 }
185
186 3160 FieldPtr _point_field(std::string_view name) const override {
187 3160 return _access_reader().point_field(name);
188 }
189
190 ✗ FieldPtr _meta_data_field(std::string_view name) const override {
191 ✗ return _access_reader().meta_data_field(name);
192 }
193
194 1371 void _visit_cells(const CellVisitor& v) const override {
195 1371 _access_reader().visit_cells(v);
196 1371 }
197
198 591 FieldPtr _points() const override {
199 591 return _access_reader().points();
200 }
201
202 18 typename GridReader::PieceLocation _location() const override {
203 18 return _access_reader().location();
204 }
205
206 6 std::vector<double> _ordinates(unsigned int dir) const override {
207 6 return _access_reader().ordinates(dir);
208 }
209
210 6 std::array<double, 3> _spacing() const override {
211 6 return _access_reader().spacing();
212 }
213
214 6 std::array<double, 3> _origin() const override {
215 6 return _access_reader().origin();
216 }
217
218 ✗ std::array<double, 3> _basis_vector(unsigned int dir) const override {
219 ✗ return _access_reader().basis_vector(dir);
220 }
221
222 560 bool _is_sequence() const override {
223 560 return _access_reader().is_sequence();
224 }
225
226 141 std::size_t _number_of_steps() const override {
227 141 return _access_reader().number_of_steps();
228 }
229
230 465 double _time_at_step(std::size_t step) const override {
231 465 return _access_reader().time_at_step(step);
232 }
233
234 465 void _set_step(std::size_t step, typename GridReader::FieldNames& field_names) override {
235 465 _access_reader().set_step(step);
236 465 field_names.clear();
237 465 ReaderDetail::copy_field_names(_access_reader(), field_names);
238 465 }
239
240 13434 const GridReader& _access_reader() const {
241 13434 _check_reader_access();
242 13434 return *_reader;
243 }
244
245 2808 GridReader& _access_reader() {
246 2808 _check_reader_access();
247 2808 return *_reader;
248 }
249
250 16242 void _check_reader_access() const {
251
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16242 times.
16242 if (!_reader_is_set())
252 ✗ throw InvalidState("No file has been read");
253 16242 }
254
255 16284 bool _reader_is_set() const {
256 16284 return static_cast<bool>(_reader);
257 }
258
259 std::unique_ptr<GridReader> _reader;
260 std::optional<ReaderFactoryFunctor> _reader_factory;
261 };
262
263 } // namespace GridFormat
264
265 #endif // GRIDFORMAT_WRITER_HPP_
266