openPMD-api
AbstractIOHandlerImplCommon.hpp
1 /* Copyright 2018-2021 Franz Poeschel
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 
22 #pragma once
23 
24 #include "openPMD/IO/AbstractFilePosition.hpp"
25 #include "openPMD/IO/AbstractIOHandler.hpp"
26 #include "openPMD/IO/AbstractIOHandlerImpl.hpp"
27 #include "openPMD/IO/InvalidatableFile.hpp"
28 #include "openPMD/auxiliary/StringManip.hpp"
29 #include "openPMD/backend/Writable.hpp"
30 
31 #include <unordered_map>
32 #include <unordered_set>
33 
34 namespace openPMD
35 {
36 template <typename FilePositionType = AbstractFilePosition>
37 class AbstractIOHandlerImplCommon : public AbstractIOHandlerImpl
38 {
39  // friend struct detail::BufferedActions;
40 public:
41  explicit AbstractIOHandlerImplCommon(AbstractIOHandler *handler);
42 
43  ~AbstractIOHandlerImplCommon() override;
44 
45 protected:
50  std::unordered_map<Writable *, InvalidatableFile> m_files;
51  std::unordered_set<InvalidatableFile> m_dirty;
52 
53  enum PossiblyExisting
54  {
55  PE_InvalidatableFile = 0,
56  PE_Iterator,
57  PE_NewlyCreated,
58  };
59 
60  std::tuple<
62  std::unordered_map<Writable *, InvalidatableFile>::iterator,
63  bool>
64  getPossiblyExisting(std::string file);
65 
66  void associateWithFile(Writable *writable, InvalidatableFile file);
67 
72  std::string fullPath(InvalidatableFile);
73 
74  std::string fullPath(std::string);
75 
87  InvalidatableFile
88  refreshFileFromParent(Writable *writable, bool preferParentFile);
89 
97  std::shared_ptr<FilePositionType>
98  setAndGetFilePosition(Writable *writable, bool write = true);
99 
106  virtual std::shared_ptr<FilePositionType>
107  setAndGetFilePosition(Writable *writable, std::string extend);
108 
112  virtual std::string
113  filePositionToString(std::shared_ptr<FilePositionType>) = 0;
114 
118  virtual std::shared_ptr<FilePositionType> extendFilePosition(
119  std::shared_ptr<FilePositionType> const &, std::string) = 0;
120 };
121 
122 template <typename FilePositionType>
124  AbstractIOHandler *handler)
125  : AbstractIOHandlerImpl{handler}
126 {}
127 
128 template <typename FilePositionType>
130  default;
131 
132 template <typename FilePositionType>
133 std::tuple<
135  std::unordered_map<Writable *, InvalidatableFile>::iterator,
136  bool>
138  std::string file)
139 {
140 
141  auto it = std::find_if(
142  m_files.begin(),
143  m_files.end(),
144  [file](
145  std::unordered_map<Writable *, InvalidatableFile>::value_type const
146  &entry) {
147  return *entry.second == file && entry.second.valid();
148  });
149 
150  bool newlyCreated;
151  InvalidatableFile name;
152  if (it == m_files.end())
153  {
154  name = file;
155  newlyCreated = true;
156  }
157  else
158  {
159  name = it->second;
160  newlyCreated = false;
161  }
162  return std::tuple<
163  InvalidatableFile,
164  std::unordered_map<Writable *, InvalidatableFile>::iterator,
165  bool>(std::move(name), it, newlyCreated);
166 }
167 
168 template <typename FilePositionType>
170  Writable *writable, InvalidatableFile file)
171 {
172  // make sure to overwrite
173  m_files[writable] = std::move(file);
174 }
175 
176 template <typename FilePositionType>
178  InvalidatableFile fileName)
179 {
180  return fullPath(*fileName);
181 }
182 
183 template <typename FilePositionType>
184 std::string
186 {
187  if (auxiliary::ends_with(m_handler->directory, "/"))
188  {
189  return m_handler->directory + fileName;
190  }
191  else
192  {
193  return m_handler->directory + "/" + fileName;
194  }
195 }
196 
197 template <typename FilePositionType>
198 InvalidatableFile
200  Writable *writable, bool preferParentFile)
201 {
202  auto getFileFromParent = [writable, this]() {
203  auto file = m_files.find(writable->parent)->second;
204  associateWithFile(writable, file);
205  return file;
206  };
207  if (preferParentFile && writable->parent)
208  {
209  return getFileFromParent();
210  }
211  else
212  {
213  auto it = m_files.find(writable);
214  if (it != m_files.end())
215  {
216  return m_files.find(writable)->second;
217  }
218  else if (writable->parent)
219  {
220  return getFileFromParent();
221  }
222  else
223  {
224  throw std::runtime_error(
225  "Internal error: Root object must be opened explicitly.");
226  }
227  }
228 }
229 
230 template <typename FilePositionType>
231 std::shared_ptr<FilePositionType>
233  Writable *writable, bool write)
234 {
235  std::shared_ptr<AbstractFilePosition> res;
236 
237  if (writable->abstractFilePosition)
238  {
239  res = writable->abstractFilePosition;
240  }
241  else if (writable->parent)
242  {
243  res = writable->parent->abstractFilePosition;
244  }
245  else
246  { // we are root
247  res = std::make_shared<FilePositionType>();
248  }
249  if (write)
250  {
251  writable->abstractFilePosition = res;
252  }
253  return std::dynamic_pointer_cast<FilePositionType>(res);
254 }
255 
256 template <typename FilePositionType>
257 std::shared_ptr<FilePositionType>
259  Writable *writable, std::string extend)
260 {
261  if (!auxiliary::starts_with(extend, '/'))
262  {
263  extend = "/" + extend;
264  }
265  auto oldPos = setAndGetFilePosition(writable, false);
266  auto res = extendFilePosition(oldPos, extend);
267 
268  writable->abstractFilePosition = res;
269  return res;
270 }
271 } // namespace openPMD
std::shared_ptr< FilePositionType > setAndGetFilePosition(Writable *writable, bool write=true)
Figure out the file position of the writable.
Definition: AbstractIOHandlerImplCommon.hpp:232
Wrapper around a shared pointer to:
Definition: InvalidatableFile.hpp:43
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:179
virtual std::shared_ptr< FilePositionType > extendFilePosition(std::shared_ptr< FilePositionType > const &, std::string)=0
Public definitions of openPMD-api.
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:64
Definition: Writable.hpp:44
virtual std::string filePositionToString(std::shared_ptr< FilePositionType >)=0
InvalidatableFile refreshFileFromParent(Writable *writable, bool preferParentFile)
Get the writable&#39;s containing file.
Definition: AbstractIOHandlerImplCommon.hpp:199
Definition: AbstractIOHandlerImpl.hpp:35
std::string fullPath(InvalidatableFile)
Definition: AbstractIOHandlerImplCommon.hpp:177
std::unordered_map< Writable *, InvalidatableFile > m_files
map each Writable to its associated file contains only the filename, without the OS path ...
Definition: AbstractIOHandlerImplCommon.hpp:50