openPMD-api
Container.hpp
1 /* Copyright 2017-2025 Fabian Koller and 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/IO/Access.hpp"
25 #include "openPMD/auxiliary/TypeTraits.hpp"
26 #include "openPMD/backend/Attributable.hpp"
27 #include "openPMD/backend/HierarchyVisitor.hpp"
28 
29 #include <initializer_list>
30 #include <map>
31 #include <set>
32 #include <stdexcept>
33 #include <string>
34 #include <type_traits>
35 #include <utility>
36 
37 // expose private and protected members for invasive testing
38 #ifndef OPENPMD_protected
39 #define OPENPMD_protected protected:
40 #endif
41 
42 namespace openPMD
43 {
44 namespace traits
45 {
52  template <typename U>
54  {
55  constexpr static bool is_noop = true;
56  template <typename T>
57  void operator()(T &)
58  {}
59  };
60 } // namespace traits
61 
62 namespace internal
63 {
64  class SeriesData;
65  template <typename>
66  class EraseStaleEntries;
67 
68  template <
69  typename T,
70  typename T_key = std::string,
71  typename T_container = std::map<T_key, T>>
72  class ContainerData : virtual public AttributableData
73  {
74  public:
75  using InternalContainer = T_container;
76 
80  InternalContainer m_container;
81 
82  ContainerData() = default;
83 
84  ContainerData(ContainerData const &) = delete;
85  ContainerData(ContainerData &&) = delete;
86 
87  ContainerData &operator=(ContainerData const &) = delete;
88  ContainerData &operator=(ContainerData &&) = delete;
89  };
90 } // namespace internal
91 
101 template <
102  typename T,
103  typename T_key = std::string,
104  typename T_container = std::map<T_key, T>>
105 class Container : virtual public Attributable
106 {
107  static_assert(
108  std::is_base_of<Attributable, T>::value,
109  "Type of container element must be derived from Writable");
110 
111  friend class Iteration;
112  friend class ParticleSpecies;
113  friend class ParticlePatches;
114  friend class internal::SeriesData;
115  friend class Series;
116  template <typename>
117  friend class internal::EraseStaleEntries;
118  friend class StatefulIterator;
119 
120 protected:
122  using InternalContainer = T_container;
123 
124  std::shared_ptr<ContainerData> m_containerData;
125 
126  inline void setData(std::shared_ptr<ContainerData> containerData)
127  {
128  m_containerData = std::move(containerData);
129  Attributable::setData(m_containerData);
130  }
131 
132  inline InternalContainer const &container() const
133  {
134  return m_containerData->m_container;
135  }
136 
137  inline InternalContainer &container()
138  {
139  return m_containerData->m_container;
140  }
141 
142 public:
143  using key_type = typename InternalContainer::key_type;
144  using mapped_type = typename InternalContainer::mapped_type;
145  using value_type = typename InternalContainer::value_type;
146  using size_type = typename InternalContainer::size_type;
147  using difference_type = typename InternalContainer::difference_type;
148  using allocator_type = typename InternalContainer::allocator_type;
149  using reference = typename InternalContainer::reference;
150  using const_reference = typename InternalContainer::const_reference;
151  using pointer = typename InternalContainer::pointer;
152  using const_pointer = typename InternalContainer::const_pointer;
153  using iterator = typename InternalContainer::iterator;
154  using const_iterator = typename InternalContainer::const_iterator;
155  using reverse_iterator = typename InternalContainer::reverse_iterator;
156  using const_reverse_iterator =
157  typename InternalContainer::const_reverse_iterator;
158 
159  iterator begin() noexcept;
160  const_iterator begin() const noexcept;
161  const_iterator cbegin() const noexcept;
162 
163  iterator end() noexcept;
164  const_iterator end() const noexcept;
165  const_iterator cend() const noexcept;
166 
167  reverse_iterator rbegin() noexcept;
168  const_reverse_iterator rbegin() const noexcept;
169  const_reverse_iterator crbegin() const noexcept;
170 
171  reverse_iterator rend() noexcept;
172  const_reverse_iterator rend() const noexcept;
173  const_reverse_iterator crend() const noexcept;
174 
175  bool empty() const noexcept;
176 
177  size_type size() const noexcept;
178 
185  void clear();
186 
187  std::pair<iterator, bool> insert(value_type const &value);
188  std::pair<iterator, bool> insert(value_type &&value);
189  iterator insert(const_iterator hint, value_type const &value);
190  iterator insert(const_iterator hint, value_type &&value);
191  template <class InputIt>
192  void insert(InputIt first, InputIt last)
193  {
194  container().insert(first, last);
195  }
196  void insert(std::initializer_list<value_type> ilist);
197 
198  void swap(Container &other);
199 
200  mapped_type &at(key_type const &key);
201  mapped_type const &at(key_type const &key) const;
202 
213  mapped_type &operator[](key_type const &key);
224  mapped_type &operator[](key_type &&key);
225 
226  iterator find(key_type const &key);
227  const_iterator find(key_type const &key) const;
228 
234  size_type count(key_type const &key) const;
235 
242  bool contains(key_type const &key) const;
243 
252  size_type erase(key_type const &key);
253 
255  iterator erase(iterator res);
257  // virtual iterator erase(const_iterator first, const_iterator last)
258 
259  template <class... Args>
260  auto emplace(Args &&...args)
261  -> decltype(InternalContainer().emplace(std::forward<Args>(args)...))
262  {
263  return container().emplace(std::forward<Args>(args)...);
264  }
265 
266  template <typename ChildClass>
267  void visitHierarchyImpl(HierarchyVisitor &v, bool recursive)
268  {
269  if (recursive)
270  {
271  for (auto &p : *this)
272  {
273  p.second.visitHierarchy(v, recursive);
274  }
275  }
276  v(*static_cast<ChildClass *>(this));
277  }
278 
279  // clang-format off
280 OPENPMD_protected
281  // clang-format on
282 
283  void clear_unchecked();
284 
285  virtual void
286  flush(std::string const &path, internal::FlushParams const &flushParams);
287 
288  Container();
289 
290  Container(NoInit);
291 
292 public:
293  /*
294  * Need to define these manually due to the virtual inheritance from
295  * Attributable.
296  * Otherwise, they would only run from the most derived class
297  * if explicitly called.
298  * If not defining these, a user could destroy copy/move constructors/
299  * assignment operators by deriving from any class that has a virtual
300  * Attributable somewhere.
301  * Care must be taken in move constructors/assignment operators to not move
302  * multiple times (which could happen in diamond inheritance situations).
303  */
304 
305  Container(Container const &other);
306 
307  Container(Container &&other) noexcept;
308 
309  Container &operator=(Container const &other);
310 
311  Container &operator=(Container &&other) noexcept;
312 };
313 
314 namespace internal
315 {
325  template <typename Container_t>
327  {
328  static_assert(
329  std::is_same_v<Container_t, std::remove_reference_t<Container_t>>);
330  using key_type = typename Container_t::key_type;
331  using mapped_type = typename Container_t::mapped_type;
332  std::set<key_type> m_accessedKeys;
333  /*
334  * Note: Putting a copy here leads to weird bugs due to destructors
335  * being called too eagerly upon destruction.
336  * Should be avoidable by extending the frontend redesign to the
337  * Container class template
338  * (https://github.com/openPMD/openPMD-api/pull/886)
339  */
340  Container_t &m_originalContainer;
341 
342  public:
343  explicit EraseStaleEntries(Container_t &container_in);
344 
346  EraseStaleEntries &operator=(EraseStaleEntries &&) = delete;
347 
348  mapped_type &operator[](typename Container_t::key_type const &k);
349 
350  mapped_type &at(typename Container_t::key_type const &k);
351 
357  void forget(typename Container_t::key_type const &k);
358 
360  };
361 } // namespace internal
362 } // namespace openPMD
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:225
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:106
mapped_type & operator[](key_type const &key)
Access the value that is mapped to a key equivalent to key, creating it if such key does not exist al...
void clear()
Remove all objects from the container and (if written) from disk.
size_type erase(key_type const &key)
Remove a single element from the container and (if written) from disk.
size_type count(key_type const &key) const
This returns either 1 if the key is found in the container of 0 if not.
bool contains(key_type const &key) const
Checks if there is an element with a key equivalent to an exiting key in the container.
iterator erase(iterator res)
auto emplace(Args &&...args) -> decltype(InternalContainer().emplace(std::forward< Args >(args)...))
Definition: Container.hpp:260
mapped_type & operator[](key_type &&key)
Access the value that is mapped to a key equivalent to key, creating it if such key does not exist al...
Definition: HierarchyVisitor.hpp:20
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:172
Definition: ParticlePatches.hpp:32
Definition: ParticleSpecies.hpp:39
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:288
Based on the logic of the former class ReadIterations, integrating into itself the logic of former Wr...
Definition: StatefulIterator.hpp:204
Definition: Attributable.hpp:110
Definition: Container.hpp:73
InternalContainer m_container
The wrapped container holding all the actual data, e.g.
Definition: Container.hpp:80
This class wraps a Container and forwards operator[]() and at() to it.
Definition: Container.hpp:327
void forget(typename Container_t::key_type const &k)
Remove key from the list of accessed keys.
Data members for Series.
Definition: Series.hpp:90
Public definitions of openPMD-api.
Definition: Date.cpp:29
Container Element Creation Policy.
Definition: Container.hpp:54