openPMD-api
 
Loading...
Searching...
No Matches
BaseRecord.hpp
1/* Copyright 2017-2025 Fabian Koller, Franz Poeschel, Axel Huebl
2 *
3 * This file is part of openPMD-api.
4 *
5 * openPMD-api is free software: you can redistribute it and/or modify
6 * it under the terms of of either the GNU General Public License or
7 * the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * openPMD-api is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License and the GNU Lesser General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * and the GNU Lesser General Public License along with openPMD-api.
19 * If not, see <http://www.gnu.org/licenses/>.
20 */
21#pragma once
22
23#include "openPMD/Error.hpp"
24#include "openPMD/RecordComponent.hpp"
25#include "openPMD/UnitDimension.hpp"
26#include "openPMD/auxiliary/Variant.hpp"
27#include "openPMD/backend/BaseRecordComponent.hpp"
28#include "openPMD/backend/Container.hpp"
29
30#include <array>
31#include <stdexcept>
32#include <string>
33#include <type_traits> // std::remove_reference_t
34#include <utility> // std::declval
35
36namespace openPMD
37{
38template <typename>
39class BaseRecord;
40namespace internal
41{
42 template <
43 typename T_elem, // = T_RecordComponent
44 /*
45 * Technically not necessary, but some old compilers ignore friend
46 * declarations at this place, so we specify the data class explicitly
47 */
48 typename T_RecordComponentData = typename T_elem::Data_t>
49 class BaseRecordData final
50 : public ContainerData<T_elem>
51 , public T_RecordComponentData
52 {
53 using T_RecordComponent = T_elem;
54
55 public:
56 BaseRecordData();
57
58 BaseRecordData(BaseRecordData const &) = delete;
59 BaseRecordData(BaseRecordData &&) = delete;
60
61 BaseRecordData &operator=(BaseRecordData const &) = delete;
62 BaseRecordData &operator=(BaseRecordData &&) = delete;
63 };
64
65 // @todo change T_InternalContainer to direct iterator type
66 template <
67 typename T_BaseRecord_,
68 typename T_BaseRecordData_,
69 typename T_BaseIterator>
70 class ScalarIterator
71 {
72 /*
73 * Allow other template instantiations of ScalarIterators member access.
74 */
75 template <typename, typename, typename>
76 friend class ScalarIterator;
77
78 using T_BaseRecord = T_BaseRecord_;
79 using T_BaseRecordData = T_BaseRecordData_;
80 using T_RecordComponent = typename T_BaseRecord::T_RecordComponent;
81 using T_Container = typename T_BaseRecord::T_Container;
82 using T_Value =
83 std::remove_reference_t<decltype(*std::declval<T_BaseIterator>())>;
84 using Left = T_BaseIterator;
85 struct Right
86 { /*Empty*/
87 constexpr bool operator==(Right const &) const noexcept
88 {
89 return true;
90 }
91 constexpr bool operator!=(Right const &) const noexcept
92 {
93 return false;
94 }
95 };
96
97 template <typename>
98 friend class openPMD::BaseRecord;
99
100 T_BaseRecordData *m_baseRecordData = nullptr;
101 using ScalarTuple =
102 std::optional<std::pair<std::string const, T_RecordComponent>>;
103 ScalarTuple m_scalarTuple;
104 std::variant<Left, Right> m_iterator;
105
106 explicit ScalarIterator();
107
108 ScalarIterator(T_BaseRecord *baseRecord, bool is_end);
109 ScalarIterator(T_BaseRecord *baseRecord, Left iterator);
110
111 public:
124 template <
125 typename Other,
126 /*
127 * We need this in order to not accidentally register this as a copy
128 * constructor.
129 */
130 typename SFINAE = std::enable_if_t<
131 !std::is_same_v<T_BaseRecord, typename Other::T_BaseRecord>>>
132 ScalarIterator(Other const &other)
133 : m_baseRecordData(other.m_baseRecordData)
134 , m_scalarTuple(
135 other.m_scalarTuple.has_value()
136 ? ScalarTuple(
137 std::make_pair(
138 RecordComponent::SCALAR,
139 T_RecordComponent(
140 other.m_scalarTuple.value().second)))
141 : ScalarTuple(std::nullopt))
142 , m_iterator(
143 std::visit(
144 auxiliary::overloaded{
145 [](typename Other::Left const &left) {
146 // This converts the STL iterator to an
147 // STL const_iterator
148 return std::variant<Left, Right>(left);
149 },
150 [](typename Other::Right const &) {
151 return std::variant<Left, Right>(Right());
152 }},
153 other.m_iterator))
154 {}
155
156 ScalarIterator &operator++();
157
158 T_Value *operator->();
159
160 T_Value &operator*();
161
162 bool operator==(ScalarIterator const &other) const;
163
164 bool operator!=(ScalarIterator const &other) const;
165 };
166} // namespace internal
167
178template <typename T_elem>
179class BaseRecord
180 : public Container<T_elem>
181 , public T_elem // T_RecordComponent
182{
183public:
184 using T_RecordComponent = T_elem;
185 using T_Container = Container<T_elem>;
186
187private:
188 using T_Self = BaseRecord<T_elem>;
189 friend class Iteration;
190 friend class ParticleSpecies;
191 friend class PatchRecord;
192 friend class Record;
193 friend class Mesh;
194 template <typename, typename>
195 friend class internal::BaseRecordData;
196 template <typename, typename, typename>
197 friend class internal::ScalarIterator;
198 template <typename T>
199 friend T &internal::makeOwning(T &self, Series);
200
201 using Data_t =
203 std::shared_ptr<Data_t> m_baseRecordData;
204
205 static_assert(
206 traits::GenerationPolicy<T_RecordComponent>::is_noop,
207 "Internal error: Scalar components cannot have generation policies.");
208
209 inline Data_t const &get() const
210 {
211 return *m_baseRecordData;
212 }
213
214 inline Data_t &get()
215 {
216 return *m_baseRecordData;
217 }
218
219 inline std::shared_ptr<Data_t> getShared()
220 {
221 return m_baseRecordData;
222 }
223
224 BaseRecord();
225
226protected:
227 inline void setData(std::shared_ptr<Data_t> data)
228 {
229 m_baseRecordData = std::move(data);
230 T_Container::setData(m_baseRecordData);
231 T_RecordComponent::setData(m_baseRecordData);
232 }
233
234public:
235 using key_type = typename Container<T_elem>::key_type;
236 using mapped_type = typename Container<T_elem>::mapped_type;
237 using value_type = typename Container<T_elem>::value_type;
238 using size_type = typename Container<T_elem>::size_type;
239 using difference_type = typename Container<T_elem>::difference_type;
240 using allocator_type = typename Container<T_elem>::allocator_type;
241 using reference = typename Container<T_elem>::reference;
242 using const_reference = typename Container<T_elem>::const_reference;
243 using pointer = typename Container<T_elem>::pointer;
244 using const_pointer = typename Container<T_elem>::const_pointer;
245
246 using iterator = internal::ScalarIterator<
247 T_Self,
248 Data_t,
249 typename T_Container::InternalContainer::iterator>;
250 using const_iterator = internal::ScalarIterator<
251 T_Self const,
252 Data_t const,
253 typename T_Container::InternalContainer::const_iterator>;
254 using reverse_iterator = internal::ScalarIterator<
255 T_Self,
256 Data_t,
257 typename T_Container::InternalContainer::reverse_iterator>;
258 using const_reverse_iterator = internal::ScalarIterator<
259 T_Self const,
260 Data_t const,
261 typename T_Container::InternalContainer::const_reverse_iterator>;
262
263private:
264 template <typename... Arg>
265 iterator makeIterator(Arg &&...arg)
266 {
267 return iterator{this, std::forward<Arg>(arg)...};
268 }
269 template <typename... Arg>
270 const_iterator makeIterator(Arg &&...arg) const
271 {
272 return const_iterator{this, std::forward<Arg>(arg)...};
273 }
274 template <typename... Arg>
275 reverse_iterator makeReverseIterator(Arg &&...arg)
276 {
277 return reverse_iterator{this, std::forward<Arg>(arg)...};
278 }
279 template <typename... Arg>
280 const_reverse_iterator makeReverseIterator(Arg &&...arg) const
281 {
282 return const_reverse_iterator{this, std::forward<Arg>(arg)...};
283 }
284
285public:
286 iterator begin();
287 const_iterator begin() const;
288 const_iterator cbegin() const;
289 iterator end();
290 const_iterator end() const;
291 const_iterator cend() const;
292 reverse_iterator rbegin();
293 const_reverse_iterator rbegin() const;
294 const_reverse_iterator crbegin() const;
295 reverse_iterator rend();
296 const_reverse_iterator rend() const;
297 const_reverse_iterator crend() const;
298
299 virtual ~BaseRecord();
300
301 mapped_type &operator[](key_type const &key);
302 mapped_type &operator[](key_type &&key);
303 mapped_type &at(key_type const &key);
304 mapped_type const &at(key_type const &key) const;
305 size_type erase(key_type const &key);
306 iterator erase(iterator res);
307 bool empty() const noexcept;
308 iterator find(key_type const &key);
309 const_iterator find(key_type const &key) const;
310 size_type count(key_type const &key) const;
311 size_type size() const;
312 void clear();
313 std::pair<iterator, bool> insert(value_type const &value);
314 std::pair<iterator, bool> insert(value_type &&value);
315 iterator insert(const_iterator hint, value_type const &value);
316 iterator insert(const_iterator hint, value_type &&value);
317 template <class InputIt>
318 void insert(InputIt first, InputIt last);
319 void insert(std::initializer_list<value_type> ilist);
320 void swap(BaseRecord &other) noexcept;
321 bool contains(key_type const &key) const;
322 template <class... Args>
323 auto emplace(Args &&...args) -> std::pair<iterator, bool>;
324
326 // iterator erase(const_iterator first, const_iterator last) override;
327
346 unit_representations::AsArray unitDimension() const;
347
348 void setDatasetDefined(BaseRecordComponent::Data_t &data) override
349 {
350 if (!T_Container::empty())
351 {
353 "A scalar component can not be contained at the same time as "
354 "one or more regular components.");
355 }
356 T_RecordComponent::setDatasetDefined(data);
357 }
358
363 bool scalar() const;
364
365protected:
366 void readBase();
367
368private:
369 void flush(std::string const &, internal::FlushParams const &) final;
370 virtual void
371 flush_impl(std::string const &, internal::FlushParams const &) = 0;
372
373 void eraseScalar();
374}; // BaseRecord
375
376namespace detail
377{
378 constexpr char const *const NO_SCALAR_INSERT =
379 "[BaseRecord] emplace()/insert()/swap() API invalid for scalar "
380 "records. Use the Record directly as a RecordComponent.";
381
382 template <typename BaseRecord>
383 void verifyNonscalar(BaseRecord *self);
384} // namespace detail
385
386template <typename T_elem>
387template <typename... Args>
388auto BaseRecord<T_elem>::emplace(Args &&...args) -> std::pair<iterator, bool>
389{
390 detail::verifyNonscalar(this);
391 auto res = this->container().emplace(std::forward<Args>(args)...);
392 if (res.first->first == RecordComponent::SCALAR)
393 {
394 this->container().erase(res.first);
395 throw error::WrongAPIUsage(detail::NO_SCALAR_INSERT);
396 }
397 return {makeIterator(std::move(res.first)), res.second};
398}
399
400} // namespace openPMD
Base class for any type of record (e.g.
Definition BaseRecord.hpp:182
bool scalar() const
Returns true if this record only contains a single component.
Definition BaseRecord.cpp:770
unit_representations::AsArray unitDimension() const
Return the physical dimension (quantity) of a record.
Definition BaseRecord.cpp:763
Definition RecordComponent.hpp:114
The API was used in an illegal way.
Definition Error.hpp:84
Definition BaseRecord.hpp:52
Definition BaseRecord.hpp:71
ScalarIterator(Other const &other)
Auto-convert normal to const iterator.
Definition BaseRecord.hpp:132
Public definitions of openPMD-api.
Definition Date.cpp:29
@ T
time
Definition UnitDimension.hpp:41
STL namespace.
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition AbstractIOHandler.hpp:106