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 | 90 | 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 | 1348 | void copy_field_names(const GridReader& reader, FieldNameStorage& names) { | |
65 |
2/4✓ Branch 2 taken 1348 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1348 times.
✗ Branch 6 not taken.
|
1348 | std::ranges::copy(cell_field_names(reader), std::back_inserter(names.cell_fields)); |
66 |
2/4✓ Branch 2 taken 1348 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1348 times.
✗ Branch 6 not taken.
|
1348 | std::ranges::copy(point_field_names(reader), std::back_inserter(names.point_fields)); |
67 |
2/4✓ Branch 2 taken 1348 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1348 times.
✗ Branch 6 not taken.
|
1348 | std::ranges::copy(meta_data_field_names(reader), std::back_inserter(names.meta_data_fields)); |
68 | 1348 | } | |
69 | |||
70 | using ReaderFactoryFunctor = std::function<std::unique_ptr<GridReader>(const std::string&)>; | ||
71 | |||
72 | template<Concepts::Communicator C = NullCommunicator> | ||
73 | 469 | ReaderFactoryFunctor default_reader_factory(const C& c = {}) { | |
74 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 239 times.
|
469 | if (!std::same_as<C, NullCommunicator>) |
75 | 144 | return [fac = AnyReaderFactory<C>{c}] (const std::string& f) { return fac.make_for(f); }; | |
76 | 618 | return [fac = AnyReaderFactory<>{}] (const std::string& f) { return fac.make_for(f); }; | |
77 | } | ||
78 | |||
79 | } // namespace ReaderDetail | ||
80 | #endif // DOXYGEN | ||
81 | |||
82 | /*! | ||
83 | * \ingroup API | ||
84 | * \brief Interface to the readers for all supported file formats. | ||
85 | * \details Typically you would construct this class with one of the predefined | ||
86 | * file format instances. For example, with the .vtu file format: | ||
87 | * \code{.cpp} | ||
88 | * GridFormat::Reader reader{GridFormat::vtu}; | ||
89 | * \endcode | ||
90 | * \note Unless you pass in a custom ReaderFactoryFunctor, this class requires the | ||
91 | * AnyReaderFactory to be defined. Thus, this header cannot be included | ||
92 | * without the general API header gridformat.hpp which defines all formats. | ||
93 | */ | ||
94 | class Reader : public GridReader { | ||
95 | public: | ||
96 | using ReaderFactoryFunctor = ReaderDetail::ReaderFactoryFunctor; | ||
97 | |||
98 | 293 | Reader(ReaderFactoryFunctor f = ReaderDetail::default_reader_factory()) | |
99 |
1/2✓ Branch 3 taken 293 times.
✗ Branch 4 not taken.
|
293 | : _reader_factory{f} |
100 | 293 | {} | |
101 | |||
102 | 228 | explicit Reader(const FileFormat::Any&, ReaderFactoryFunctor f = ReaderDetail::default_reader_factory()) | |
103 |
2/4✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 228 times.
✗ Branch 5 not taken.
|
228 | : Reader(f) |
104 | 228 | {} | |
105 | |||
106 | template<Concepts::Communicator C> | ||
107 | 62 | explicit Reader(const FileFormat::Any&, const C& c) | |
108 |
2/4✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
|
62 | : Reader(ReaderDetail::default_reader_factory(c)) |
109 | 62 | {} | |
110 | |||
111 | template<ReaderDetail::SequentiallyConstructible FileFormat> | ||
112 | 544 | explicit Reader(const FileFormat& f) | |
113 |
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))} |
114 | 544 | {} | |
115 | |||
116 | template<typename FileFormat, | ||
117 | Concepts::Communicator Communicator> | ||
118 | requires(ReaderDetail::ParallelConstructible<FileFormat, Communicator>) | ||
119 | 100 | explicit Reader(const FileFormat& f, const Communicator& c) | |
120 |
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))} |
121 | 100 | {} | |
122 | |||
123 | //! Construct a reader instance from the given arguments, while directly opening the given file | ||
124 | template<typename... ConstructorArgs> | ||
125 | 528 | static Reader from(const std::string& filename, ConstructorArgs&&... args) { | |
126 |
5/8✓ Branch 2 taken 220 times.
✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 220 times.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 110 times.
✗ Branch 9 not taken.
|
528 | return Reader{std::forward<ConstructorArgs>(args)...}.with_opened(filename); |
127 | } | ||
128 | |||
129 | //! Read the data from the given file and return this reader | ||
130 | Reader& with_opened(const std::string& filename) & { | ||
131 | this->open(filename); | ||
132 | return *this; | ||
133 | } | ||
134 | |||
135 | //! Read the data from the given file and return this reader (lvalue references overload) | ||
136 | 306 | Reader&& with_opened(const std::string& filename) && { | |
137 | 306 | this->open(filename); | |
138 | 306 | return std::move(*this); | |
139 | } | ||
140 | |||
141 | private: | ||
142 | template<typename ReaderImpl> | ||
143 | 652 | auto _make_unique(ReaderImpl&& reader) const { | |
144 | 652 | return std::make_unique<std::remove_cvref_t<ReaderImpl>>(std::move(reader)); | |
145 | } | ||
146 | |||
147 | 42 | std::string _name() const override { | |
148 |
1/2✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
|
42 | if (_reader_is_set()) |
149 | 42 | return _access_reader().name(); | |
150 | ✗ | return "undefined"; | |
151 | } | ||
152 | |||
153 | 622 | void _open(const std::string& filename, typename GridReader::FieldNames& names) override { | |
154 |
2/2✓ Branch 1 taken 293 times.
✓ Branch 2 taken 329 times.
|
622 | if (_reader_factory) |
155 |
1/2✓ Branch 2 taken 293 times.
✗ Branch 3 not taken.
|
293 | _reader = (*_reader_factory)(filename); |
156 | 622 | _access_reader().close(); | |
157 | 622 | _access_reader().open(filename); | |
158 | 619 | ReaderDetail::copy_field_names(_access_reader(), names); | |
159 | 619 | }; | |
160 | |||
161 | ✗ | void _close() override { | |
162 | ✗ | _access_reader().close(); | |
163 | ✗ | } | |
164 | |||
165 | 1949 | std::size_t _number_of_cells() const override { | |
166 | 1949 | return _access_reader().number_of_cells(); | |
167 | } | ||
168 | |||
169 | 1826 | std::size_t _number_of_points() const override { | |
170 | 1826 | return _access_reader().number_of_points(); | |
171 | } | ||
172 | |||
173 | 34 | std::size_t _number_of_pieces() const override { | |
174 | 34 | return _access_reader().number_of_pieces(); | |
175 | } | ||
176 | |||
177 | 3130 | FieldPtr _cell_field(std::string_view name) const override { | |
178 | 3130 | return _access_reader().cell_field(name); | |
179 | } | ||
180 | |||
181 | 3160 | FieldPtr _point_field(std::string_view name) const override { | |
182 | 3160 | return _access_reader().point_field(name); | |
183 | } | ||
184 | |||
185 | ✗ | FieldPtr _meta_data_field(std::string_view name) const override { | |
186 | ✗ | return _access_reader().meta_data_field(name); | |
187 | } | ||
188 | |||
189 | 1371 | void _visit_cells(const CellVisitor& v) const override { | |
190 | 1371 | _access_reader().visit_cells(v); | |
191 | 1371 | } | |
192 | |||
193 | 591 | FieldPtr _points() const override { | |
194 | 591 | return _access_reader().points(); | |
195 | } | ||
196 | |||
197 | 18 | typename GridReader::PieceLocation _location() const override { | |
198 | 18 | return _access_reader().location(); | |
199 | } | ||
200 | |||
201 | 6 | std::vector<double> _ordinates(unsigned int dir) const override { | |
202 | 6 | return _access_reader().ordinates(dir); | |
203 | } | ||
204 | |||
205 | 6 | std::array<double, 3> _spacing() const override { | |
206 | 6 | return _access_reader().spacing(); | |
207 | } | ||
208 | |||
209 | 6 | std::array<double, 3> _origin() const override { | |
210 | 6 | return _access_reader().origin(); | |
211 | } | ||
212 | |||
213 | ✗ | std::array<double, 3> _basis_vector(unsigned int dir) const override { | |
214 | ✗ | return _access_reader().basis_vector(dir); | |
215 | } | ||
216 | |||
217 | 560 | bool _is_sequence() const override { | |
218 | 560 | return _access_reader().is_sequence(); | |
219 | } | ||
220 | |||
221 | 138 | std::size_t _number_of_steps() const override { | |
222 | 138 | return _access_reader().number_of_steps(); | |
223 | } | ||
224 | |||
225 | 465 | double _time_at_step(std::size_t step) const override { | |
226 | 465 | return _access_reader().time_at_step(step); | |
227 | } | ||
228 | |||
229 | 465 | void _set_step(std::size_t step, typename GridReader::FieldNames& field_names) override { | |
230 | 465 | _access_reader().set_step(step); | |
231 | 465 | field_names.clear(); | |
232 | 465 | ReaderDetail::copy_field_names(_access_reader(), field_names); | |
233 | 465 | } | |
234 | |||
235 | 13302 | const GridReader& _access_reader() const { | |
236 | 13302 | _check_reader_access(); | |
237 | 13302 | return *_reader; | |
238 | } | ||
239 | |||
240 | 2793 | GridReader& _access_reader() { | |
241 | 2793 | _check_reader_access(); | |
242 | 2793 | return *_reader; | |
243 | } | ||
244 | |||
245 | 16095 | void _check_reader_access() const { | |
246 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16095 times.
|
16095 | if (!_reader_is_set()) |
247 | ✗ | throw InvalidState("No file has been read"); | |
248 | 16095 | } | |
249 | |||
250 | 16137 | bool _reader_is_set() const { | |
251 | 16137 | return static_cast<bool>(_reader); | |
252 | } | ||
253 | |||
254 | std::unique_ptr<GridReader> _reader; | ||
255 | std::optional<ReaderFactoryFunctor> _reader_factory; | ||
256 | }; | ||
257 | |||
258 | } // namespace GridFormat | ||
259 | |||
260 | #endif // GRIDFORMAT_WRITER_HPP_ | ||
261 |