openPMD-api
Attributable.hpp
1 /* Copyright 2017-2021 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/IO/AbstractIOHandler.hpp"
24 #include "openPMD/backend/Attribute.hpp"
25 #include "openPMD/backend/Writable.hpp"
26 #include "openPMD/auxiliary/OutOfRangeMsg.hpp"
27 
28 #include <exception>
29 #include <map>
30 #include <memory>
31 #include <vector>
32 #include <string>
33 #include <cstddef>
34 
35 // expose private and protected members for invasive testing
36 #ifndef OPENPMD_protected
37 # define OPENPMD_protected protected
38 #endif
39 
40 
41 namespace openPMD
42 {
43 namespace traits
44 {
45  template< typename T >
47 } // traits
50 class Iteration;
51 namespace internal
52 {
53  class SeriesInternal;
54 }
55 
56 class no_such_attribute_error : public std::runtime_error
57 {
58 public:
59  no_such_attribute_error(std::string const& what_arg)
60  : std::runtime_error(what_arg)
61  { }
62  virtual ~no_such_attribute_error() { }
63 };
64 
65 namespace internal
66 {
68 {
69  friend class openPMD::AttributableInterface;
70 
71 public:
73  AttributableData( AttributableData const & ) = delete;
74  AttributableData( AttributableData && ) = delete;
75  virtual ~AttributableData() = default;
76 
77  AttributableData & operator=( AttributableData const & ) = delete;
78  AttributableData & operator=( AttributableData && ) = delete;
79 
80  using A_MAP = std::map< std::string, Attribute >;
81  Writable m_writable;
82 
83 private:
84  A_MAP m_attributes;
85 };
86 }
87 
94 {
95  // @todo remove unnecessary friend (wew that sounds bitter)
96  using A_MAP = std::map< std::string, Attribute >;
97  friend Writable* getWritable(AttributableInterface*);
98  template< typename T_elem >
99  friend class BaseRecord;
100  template<
101  typename T,
102  typename T_key,
103  typename T_container
104  >
105  friend class Container;
106  template< typename T >
107  friend struct traits::GenerationPolicy;
108  friend class Iteration;
109  friend class Series;
110  friend class SeriesInterface;
111  friend class Writable;
112  friend class WriteIterations;
113 
114 protected:
115  internal::AttributableData * m_attri = nullptr;
116 
117  // Should not be called publicly, only by implementing classes
119  template< typename T >
120  AttributableInterface( T * attri )
122  static_cast< internal::AttributableData * >( attri ) }
123  {
124  }
125 
126 public:
127  virtual ~AttributableInterface() = default;
128 
143  template< typename T >
144  bool setAttribute(std::string const& key, T value);
145  bool setAttribute(std::string const& key, char const value[]);
155  Attribute getAttribute(std::string const& key) const;
156 
162  bool deleteAttribute(std::string const& key);
163 
168  std::vector< std::string > attributes() const;
173  size_t numAttributes() const;
179  bool containsAttribute(std::string const& key) const;
180 
186  std::string comment() const;
192  AttributableInterface& setComment(std::string const& comment);
193 
201  void seriesFlush();
202 
209  struct MyPath
210  {
211  std::string directory;
212  std::string seriesName;
213  std::string seriesExtension;
214 
221  std::vector< std::string > group;
222 
224  std::string filePath() const;
225  };
226 
232  MyPath myPath() const;
233 
234 OPENPMD_protected:
235 
236  internal::SeriesInternal const & retrieveSeries() const;
237  internal::SeriesInternal & retrieveSeries();
238 
246  Iteration const & containingIteration() const;
247  Iteration & containingIteration();
250  void seriesFlush( FlushLevel );
251 
252  void flushAttributes();
253  enum ReadMode {
258  IgnoreExisting,
263  OverrideExisting,
268  FullyReread
269  };
270  void readAttributes( ReadMode );
271 
286  template< typename T >
287  T readFloatingpoint(std::string const& key) const;
302  template< typename T >
303  std::vector< T > readVectorFloatingpoint(std::string const& key) const;
304 
305  /* views into the resources held by m_writable
306  * purely for convenience so code that uses these does not have to go through m_writable-> */
307  AbstractIOHandler * IOHandler()
308  {
309  return m_attri->m_writable.IOHandler.get();
310  }
311  AbstractIOHandler const * IOHandler() const
312  {
313  return m_attri->m_writable.IOHandler.get();
314  }
315  Writable *& parent()
316  {
317  return m_attri->m_writable.parent;
318  }
319  Writable const * parent() const
320  {
321  return m_attri->m_writable.parent;
322  }
323  Writable & writable()
324  {
325  return m_attri->m_writable;
326  }
327  Writable const & writable() const
328  {
329  return m_attri->m_writable;
330  }
331 
332  inline
334  {
335  if( m_attri )
336  {
337  return *m_attri;
338  }
339  else
340  {
341  throw std::runtime_error(
342  "[AttributableInterface] "
343  "Cannot use default-constructed Attributable." );
344  }
345  }
346  inline
347  internal::AttributableData const & get() const
348  {
349  if( m_attri )
350  {
351  return *m_attri;
352  }
353  else
354  {
355  throw std::runtime_error(
356  "[AttributableInterface] "
357  "Cannot use default-constructed Attributable." );
358  }
359  }
360 
361  bool dirty() const { return writable().dirty; }
362  bool& dirty() { return writable().dirty; }
363  bool written() const { return writable().written; }
364  bool& written() { return writable().written; }
365 
366 private:
372  virtual void linkHierarchy(Writable& w);
373 }; // AttributableInterface
374 
375 // Alias this as Attributable since this is a public abstract parent class
376 // for most of the classes in our object model of the openPMD hierarchy
378 
380 {
381 protected:
382  std::shared_ptr< internal::AttributableData > m_attributableData =
383  std::make_shared< internal::AttributableData >();
384 
385 public:
387  {
388  AttributableInterface::m_attri = m_attributableData.get();
389  }
390 };
391 
392 //TODO explicitly instantiate Attributable::setAttribute for all T in Datatype
393 template< typename T >
394 inline bool
395 AttributableInterface::setAttribute( std::string const & key, T value )
396 {
397  auto & attri = get();
398  if(IOHandler() && Access::READ_ONLY == IOHandler()->m_frontendAccess )
399  {
400  auxiliary::OutOfRangeMsg const out_of_range_msg(
401  "Attribute",
402  "can not be set (read-only)."
403  );
404  throw no_such_attribute_error(out_of_range_msg(key));
405  }
406 
407  dirty() = true;
408  auto it = attri.m_attributes.lower_bound(key);
409  if( it != attri.m_attributes.end()
410  && !attri.m_attributes.key_comp()(key, it->first) )
411  {
412  // key already exists in map, just replace the value
413  it->second = Attribute(value);
414  return true;
415  } else
416  {
417  // emplace a new map element for an unknown key
418  attri.m_attributes.emplace_hint(
419  it, std::make_pair(key, Attribute(std::move(value))));
420  return false;
421  }
422 }
423 inline bool
424 AttributableInterface::setAttribute( std::string const & key, char const value[] )
425 {
426  return this->setAttribute(key, std::string(value));
427 }
428 
429 template< typename T >
430 inline T AttributableInterface::readFloatingpoint( std::string const & key ) const
431 {
432  static_assert(std::is_floating_point< T >::value, "Type of attribute must be floating point");
433 
434  return getAttribute(key).get< T >();
435 }
436 
437 template< typename T >
438 inline std::vector< T >
439 AttributableInterface::readVectorFloatingpoint( std::string const & key ) const
440 {
441  static_assert(std::is_floating_point< T >::value, "Type of attribute must be floating point");
442 
443  return getAttribute(key).get< std::vector< T > >();
444 }
445 } // namespace openPMD
Return an error string for read-only access.
Definition: OutOfRangeMsg.hpp:37
std::vector< T > readVectorFloatingpoint(std::string const &key) const
Retrieve a vector of values of a floating point Attributes of user-defined precision with ensured typ...
Definition: Attributable.hpp:439
Definition: Attributable.hpp:56
U get() const
Retrieve a stored specific Attribute and cast if convertible.
Definition: Attribute.hpp:232
Definition: Series.hpp:441
Container Element Creation Policy.
Definition: Attributable.hpp:46
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:39
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition: AbstractIOHandler.hpp:63
T readFloatingpoint(std::string const &key) const
Retrieve the value of a floating point Attribute of user-defined precision with ensured type-safety...
Definition: Attributable.hpp:430
Writing side of the streaming API.
Definition: WriteIterations.hpp:47
Root level of the openPMD hierarchy.
Definition: Series.hpp:476
Varidic datatype supporting at least all formats for attributes specified in the openPMD standard...
Definition: Attribute.hpp:50
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
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:93
Definition: Attributable.hpp:67
bool setAttribute(std::string const &key, T value)
Populate Attribute of provided name with provided value.
Definition: Attributable.hpp:395
Definition: BaseRecord.hpp:36
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:112
ReadMode
Definition: Attributable.hpp:252
String serialization to describe an Attributable.
Definition: Attributable.hpp:208
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:106
Definition: AbstractFilePosition.hpp:26
Definition: Attributable.hpp:379
open series as read-only, fails if series is not found