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/backend/Attributable.hpp"
26 
27 #include <initializer_list>
28 #include <map>
29 #include <set>
30 #include <stdexcept>
31 #include <string>
32 #include <type_traits>
33 #include <utility>
34 
35 // expose private and protected members for invasive testing
36 #ifndef OPENPMD_protected
37 #define OPENPMD_protected protected:
38 #endif
39 
40 namespace openPMD
41 {
42 namespace traits
43 {
50  template <typename U>
52  {
53  constexpr static bool is_noop = true;
54  template <typename T>
55  void operator()(T &)
56  {}
57  };
58 } // namespace traits
59 
60 namespace internal
61 {
62  class SeriesData;
63  template <typename>
64  class EraseStaleEntries;
65 
66  template <
67  typename T,
68  typename T_key = std::string,
69  typename T_container = std::map<T_key, T>>
70  class ContainerData : virtual public AttributableData
71  {
72  public:
73  using InternalContainer = T_container;
74 
78  InternalContainer m_container;
79 
80  ContainerData() = default;
81 
82  ContainerData(ContainerData const &) = delete;
83  ContainerData(ContainerData &&) = delete;
84 
85  ContainerData &operator=(ContainerData const &) = delete;
86  ContainerData &operator=(ContainerData &&) = delete;
87  };
88 } // namespace internal
89 
99 template <
100  typename T,
101  typename T_key = std::string,
102  typename T_container = std::map<T_key, T>>
103 class Container : virtual public Attributable
104 {
105  static_assert(
106  std::is_base_of<Attributable, T>::value,
107  "Type of container element must be derived from Writable");
108 
109  friend class Iteration;
110  friend class ParticleSpecies;
111  friend class ParticlePatches;
112  friend class internal::SeriesData;
113  friend class Series;
114  template <typename>
115  friend class internal::EraseStaleEntries;
116  friend class StatefulIterator;
117 
118 protected:
120  using InternalContainer = T_container;
121 
122  std::shared_ptr<ContainerData> m_containerData;
123 
124  inline void setData(std::shared_ptr<ContainerData> containerData)
125  {
126  m_containerData = std::move(containerData);
127  Attributable::setData(m_containerData);
128  }
129 
130  inline InternalContainer const &container() const
131  {
132  return m_containerData->m_container;
133  }
134 
135  inline InternalContainer &container()
136  {
137  return m_containerData->m_container;
138  }
139 
140 public:
141  using key_type = typename InternalContainer::key_type;
142  using mapped_type = typename InternalContainer::mapped_type;
143  using value_type = typename InternalContainer::value_type;
144  using size_type = typename InternalContainer::size_type;
145  using difference_type = typename InternalContainer::difference_type;
146  using allocator_type = typename InternalContainer::allocator_type;
147  using reference = typename InternalContainer::reference;
148  using const_reference = typename InternalContainer::const_reference;
149  using pointer = typename InternalContainer::pointer;
150  using const_pointer = typename InternalContainer::const_pointer;
151  using iterator = typename InternalContainer::iterator;
152  using const_iterator = typename InternalContainer::const_iterator;
153  using reverse_iterator = typename InternalContainer::reverse_iterator;
154  using const_reverse_iterator =
155  typename InternalContainer::const_reverse_iterator;
156 
157  iterator begin() noexcept;
158  const_iterator begin() const noexcept;
159  const_iterator cbegin() const noexcept;
160 
161  iterator end() noexcept;
162  const_iterator end() const noexcept;
163  const_iterator cend() const noexcept;
164 
165  reverse_iterator rbegin() noexcept;
166  const_reverse_iterator rbegin() const noexcept;
167  const_reverse_iterator crbegin() const noexcept;
168 
169  reverse_iterator rend() noexcept;
170  const_reverse_iterator rend() const noexcept;
171  const_reverse_iterator crend() const noexcept;
172 
173  bool empty() const noexcept;
174 
175  size_type size() const noexcept;
176 
183  void clear();
184 
185  std::pair<iterator, bool> insert(value_type const &value);
186  std::pair<iterator, bool> insert(value_type &&value);
187  iterator insert(const_iterator hint, value_type const &value);
188  iterator insert(const_iterator hint, value_type &&value);
189  template <class InputIt>
190  void insert(InputIt first, InputIt last)
191  {
192  container().insert(first, last);
193  }
194  void insert(std::initializer_list<value_type> ilist);
195 
196  void swap(Container &other);
197 
198  mapped_type &at(key_type const &key);
199  mapped_type const &at(key_type const &key) const;
200 
211  mapped_type &operator[](key_type const &key);
222  mapped_type &operator[](key_type &&key);
223 
224  iterator find(key_type const &key);
225  const_iterator find(key_type const &key) const;
226 
232  size_type count(key_type const &key) const;
233 
240  bool contains(key_type const &key) const;
241 
250  size_type erase(key_type const &key);
251 
253  iterator erase(iterator res);
255  // virtual iterator erase(const_iterator first, const_iterator last)
256 
257  template <class... Args>
258  auto emplace(Args &&...args)
259  -> decltype(InternalContainer().emplace(std::forward<Args>(args)...))
260  {
261  return container().emplace(std::forward<Args>(args)...);
262  }
263 
264  // clang-format off
265 OPENPMD_protected
266  // clang-format on
267 
268  void clear_unchecked();
269 
270  virtual void
271  flush(std::string const &path, internal::FlushParams const &flushParams);
272 
273  Container();
274 
275  Container(NoInit);
276 
277 public:
278  /*
279  * Need to define these manually due to the virtual inheritance from
280  * Attributable.
281  * Otherwise, they would only run from the most derived class
282  * if explicitly called.
283  * If not defining these, a user could destroy copy/move constructors/
284  * assignment operators by deriving from any class that has a virtual
285  * Attributable somewhere.
286  * Care must be taken in move constructors/assignment operators to not move
287  * multiple times (which could happen in diamond inheritance situations).
288  */
289 
290  Container(Container const &other);
291 
292  Container(Container &&other) noexcept;
293 
294  Container &operator=(Container const &other);
295 
296  Container &operator=(Container &&other) noexcept;
297 };
298 
299 namespace internal
300 {
310  template <typename Container_t>
312  {
313  static_assert(
314  std::is_same_v<Container_t, std::remove_reference_t<Container_t>>);
315  using key_type = typename Container_t::key_type;
316  using mapped_type = typename Container_t::mapped_type;
317  std::set<key_type> m_accessedKeys;
318  /*
319  * Note: Putting a copy here leads to weird bugs due to destructors
320  * being called too eagerly upon destruction.
321  * Should be avoidable by extending the frontend redesign to the
322  * Container class template
323  * (https://github.com/openPMD/openPMD-api/pull/886)
324  */
325  Container_t &m_originalContainer;
326 
327  public:
328  explicit EraseStaleEntries(Container_t &container_in);
329 
331  EraseStaleEntries &operator=(EraseStaleEntries &&) = delete;
332 
333  mapped_type &operator[](typename Container_t::key_type const &k);
334 
335  mapped_type &at(typename Container_t::key_type const &k);
336 
342  void forget(typename Container_t::key_type const &k);
343 
345  };
346 } // namespace internal
347 } // namespace openPMD
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:222
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:104
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:258
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...
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:146
Definition: ParticlePatches.hpp:32
Definition: ParticleSpecies.hpp:34
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:107
Definition: Container.hpp:71
InternalContainer m_container
The wrapped container holding all the actual data, e.g.
Definition: Container.hpp:78
This class wraps a Container and forwards operator[]() and at() to it.
Definition: Container.hpp:312
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
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition: AbstractIOHandler.hpp:106
Container Element Creation Policy.
Definition: Container.hpp:52