openPMD-api
Container.hpp
1 /* Copyright 2017-2020 Fabian Koller
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/backend/Attributable.hpp"
24 
25 #include <initializer_list>
26 #include <type_traits>
27 #include <stdexcept>
28 #include <map>
29 #include <string>
30 
31 // expose private and protected members for invasive testing
32 #ifndef OPENPMD_protected
33 # define OPENPMD_protected protected
34 #endif
35 
36 
37 namespace openPMD
38 {
39 namespace traits
40 {
47  template< typename U >
48  struct GenerationPolicy
49  {
50  template< typename T >
51  void operator()(T &)
52  {
53  }
54  };
55 } // traits
56 
65 template<
66  typename T,
67  typename T_key = std::string,
68  typename T_container = std::map< T_key, T >
69 >
70 class Container : public Attributable
71 {
72  static_assert(std::is_base_of< Attributable, T >::value, "Type of container element must be derived from Writable");
73  using InternalContainer = T_container;
74 
75  friend class Iteration;
76  friend class ParticleSpecies;
77  friend class Series;
78 
79 public:
80  using key_type = typename InternalContainer::key_type;
81  using mapped_type = typename InternalContainer::mapped_type;
82  using value_type = typename InternalContainer::value_type;
83  using size_type = typename InternalContainer::size_type;
84  using difference_type = typename InternalContainer::difference_type;
85  using allocator_type = typename InternalContainer::allocator_type;
86  using reference = typename InternalContainer::reference;
87  using const_reference = typename InternalContainer::const_reference;
88  using pointer = typename InternalContainer::pointer;
89  using const_pointer = typename InternalContainer::const_pointer;
90  using iterator = typename InternalContainer::iterator;
91  using const_iterator = typename InternalContainer::const_iterator;
92 
93  Container(Container const&) = default;
94  virtual ~Container() = default;
95 
96  iterator begin() noexcept { return m_container->begin(); }
97  const_iterator begin() const noexcept { return m_container->begin(); }
98  const_iterator cbegin() const noexcept { return m_container->cbegin(); }
99 
100  iterator end() noexcept { return m_container->end(); }
101  const_iterator end() const noexcept { return m_container->end(); }
102  const_iterator cend() const noexcept { return m_container->cend(); }
103 
104  bool empty() const noexcept { return m_container->empty(); }
105 
106  size_type size() const noexcept { return m_container->size(); }
107 
113  void clear()
114  {
115  if(Access::READ_ONLY == IOHandler->m_frontendAccess )
116  throw std::runtime_error("Can not clear a container in a read-only Series.");
117 
118  clear_unchecked();
119  }
120 
121  std::pair< iterator, bool > insert(value_type const& value) { return m_container->insert(value); }
122  template< class P >
123  std::pair< iterator, bool > insert(P&& value) { return m_container->insert(value); }
124  iterator insert(const_iterator hint, value_type const& value) { return m_container->insert(hint, value); }
125  template< class P >
126  iterator insert(const_iterator hint, P&& value) { return m_container->insert(hint, value); }
127  template< class InputIt >
128  void insert(InputIt first, InputIt last) { m_container->insert(first, last); }
129  void insert(std::initializer_list< value_type > ilist) { m_container->insert(ilist); }
130 
131  void swap(Container & other) { m_container->swap(other.m_container); }
132 
133  mapped_type& at(key_type const& key) { return m_container->at(key); }
134  mapped_type const& at(key_type const& key) const { return m_container->at(key); }
135 
142  virtual mapped_type& operator[](key_type const& key)
143  {
144  auto it = m_container->find(key);
145  if( it != m_container->end() )
146  return it->second;
147  else
148  {
149  if(Access::READ_ONLY == IOHandler->m_frontendAccess )
150  {
151  auxiliary::OutOfRangeMsg const out_of_range_msg;
152  throw std::out_of_range(out_of_range_msg(key));
153  }
154 
155  T t = T();
156  t.linkHierarchy(m_writable);
157  auto& ret = m_container->insert({key, std::move(t)}).first->second;
159  gen(ret);
160  return ret;
161  }
162  }
169  virtual mapped_type& operator[](key_type&& key)
170  {
171  auto it = m_container->find(key);
172  if( it != m_container->end() )
173  return it->second;
174  else
175  {
176  if(Access::READ_ONLY == IOHandler->m_frontendAccess )
177  {
178  auxiliary::OutOfRangeMsg out_of_range_msg;
179  throw std::out_of_range(out_of_range_msg(key));
180  }
181 
182  T t = T();
183  t.linkHierarchy(m_writable);
184  auto& ret = m_container->insert({std::move(key), std::move(t)}).first->second;
186  gen(ret);
187  return ret;
188  }
189  }
190 
191  iterator find(key_type const& key) { return m_container->find(key); }
192  const_iterator find(key_type const& key) const { return m_container->find(key); }
193 
199  size_type count(key_type const& key) const { return m_container->count(key); }
200 
206  bool contains(key_type const& key) const { return m_container->find(key) != m_container->end(); }
207 
215  virtual size_type erase(key_type const& key)
216  {
217  if(Access::READ_ONLY == IOHandler->m_frontendAccess )
218  throw std::runtime_error("Can not erase from a container in a read-only Series.");
219 
220  auto res = m_container->find(key);
221  if( res != m_container->end() && res->second.written() )
222  {
224  pDelete.path = ".";
225  IOHandler->enqueue(IOTask(&res->second, pDelete));
226  IOHandler->flush();
227  }
228  return m_container->erase(key);
229  }
230 
232  virtual iterator erase(iterator res)
233  {
234  if(Access::READ_ONLY == IOHandler->m_frontendAccess )
235  throw std::runtime_error("Can not erase from a container in a read-only Series.");
236 
237  if( res != m_container->end() && res->second.written() )
238  {
240  pDelete.path = ".";
241  IOHandler->enqueue(IOTask(&res->second, pDelete));
242  IOHandler->flush();
243  }
244  return m_container->erase(res);
245  }
247  // virtual iterator erase(const_iterator first, const_iterator last)
248 
249  template <class... Args>
250  auto emplace(Args&&... args)
251  -> decltype(InternalContainer().emplace(std::forward<Args>(args)...))
252  {
253  return m_container->emplace(std::forward<Args>(args)...);
254  }
255 
256 OPENPMD_protected:
257  Container()
258  : m_container{std::make_shared< InternalContainer >()}
259  { }
260 
261  void clear_unchecked()
262  {
263  if( written() )
264  throw std::runtime_error("Clearing a written container not (yet) implemented.");
265 
266  m_container->clear();
267  }
268 
269  virtual void flush(std::string const& path)
270  {
271  if( !written() )
272  {
274  pCreate.path = path;
275  IOHandler->enqueue(IOTask(this, pCreate));
276  }
277 
278  flushAttributes();
279  }
280 
281  std::shared_ptr< InternalContainer > m_container;
282 };
283 
284 } // openPMD
Return an error string for read-only access.
Definition: OutOfRangeMsg.hpp:37
Self-contained description of a single IO operation.
Definition: IOTask.hpp:550
virtual 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...
Definition: Container.hpp:142
Container Element Creation Policy.
Definition: Attributable.hpp:46
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:38
bool contains(key_type const &key) const
Checks if there is an element with a key equivalent to an exiting key in the container.
Definition: Container.hpp:206
virtual size_type erase(key_type const &key)
Remove a single element from the container and (if written) from disk.
Definition: Container.hpp:215
Root level of the openPMD hierarchy.
Definition: Series.hpp:64
Public definitions of openPMD-api.
Definition: Date.cpp:29
void clear()
Remove all objects from the container and (if written) from disk.
Definition: Container.hpp:113
auto emplace(Args &&... args) -> decltype(InternalContainer().emplace(std::forward< Args >(args)...))
Definition: Container.hpp:250
size_type count(key_type const &key) const
This returns either 1 if the key is found in the container of 0 if not.
Definition: Container.hpp:199
virtual iterator erase(iterator res)
Definition: Container.hpp:232
Definition: ParticleSpecies.hpp:34
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:70
open series as read-only, fails if series is not found
virtual 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: Container.hpp:169
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:65