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