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 #include <type_traits>
35 
36 // expose private and protected members for invasive testing
37 #ifndef OPENPMD_protected
38 # define OPENPMD_protected protected
39 #endif
40 
41 
42 namespace openPMD
43 {
44 namespace traits
45 {
46  template< typename T >
48 } // traits
51 class Iteration;
52 namespace internal
53 {
54  class SeriesInternal;
55 }
56 
57 class no_such_attribute_error : public std::runtime_error
58 {
59 public:
60  no_such_attribute_error(std::string const& what_arg)
61  : std::runtime_error(what_arg)
62  { }
63  virtual ~no_such_attribute_error() { }
64 };
65 
66 namespace internal
67 {
69 {
70  friend class openPMD::AttributableInterface;
71 
72 public:
74  AttributableData( AttributableData const & ) = delete;
75  AttributableData( AttributableData && ) = delete;
76  virtual ~AttributableData() = default;
77 
78  AttributableData & operator=( AttributableData const & ) = delete;
79  AttributableData & operator=( AttributableData && ) = delete;
80 
81  using A_MAP = std::map< std::string, Attribute >;
82  Writable m_writable;
83 
84 private:
85  A_MAP m_attributes;
86 };
87 
92 template< typename T >
93 inline void
94 attr_value_check( std::string const /* key */, T /* value */ )
95 {
96 }
97 
98 template< >
99 inline void
100 attr_value_check( std::string const key, std::string const value )
101 {
102  if( value.empty() )
103  throw std::runtime_error(
104  "[setAttribute] Value for string attribute '" + key +
105  "' must not be empty!" );
106 }
107 
108 } // namespace internal
109 
116 {
117  // @todo remove unnecessary friend (wew that sounds bitter)
118  using A_MAP = std::map< std::string, Attribute >;
119  friend Writable* getWritable(AttributableInterface*);
120  template< typename T_elem >
121  friend class BaseRecord;
122  template<
123  typename T,
124  typename T_key,
125  typename T_container
126  >
127  friend class Container;
128  template< typename T >
129  friend struct traits::GenerationPolicy;
130  friend class Iteration;
131  friend class Series;
132  friend class SeriesInterface;
133  friend class Writable;
134  friend class WriteIterations;
135 
136 protected:
137  internal::AttributableData * m_attri = nullptr;
138 
139  // Should not be called publicly, only by implementing classes
141  template< typename T >
142  AttributableInterface( T * attri )
144  static_cast< internal::AttributableData * >( attri ) }
145  {
146  }
147 
148 public:
149  virtual ~AttributableInterface() = default;
150 
165  template< typename T >
166  bool setAttribute(std::string const& key, T value);
167  bool setAttribute(std::string const& key, char const value[]);
177  Attribute getAttribute(std::string const& key) const;
178 
184  bool deleteAttribute(std::string const& key);
185 
190  std::vector< std::string > attributes() const;
195  size_t numAttributes() const;
201  bool containsAttribute(std::string const& key) const;
202 
208  std::string comment() const;
214  AttributableInterface& setComment(std::string const& comment);
215 
223  void seriesFlush();
224 
231  struct MyPath
232  {
233  std::string directory;
234  std::string seriesName;
235  std::string seriesExtension;
236 
243  std::vector< std::string > group;
244 
246  std::string filePath() const;
247  };
248 
254  MyPath myPath() const;
255 
256 OPENPMD_protected:
257 
258  internal::SeriesInternal const & retrieveSeries() const;
259  internal::SeriesInternal & retrieveSeries();
260 
268  Iteration const & containingIteration() const;
272  void seriesFlush( FlushLevel );
273 
274  void flushAttributes();
275  enum ReadMode {
291  };
292  void readAttributes( ReadMode );
293 
308  template< typename T >
309  T readFloatingpoint(std::string const& key) const;
324  template< typename T >
325  std::vector< T > readVectorFloatingpoint(std::string const& key) const;
326 
327  /* views into the resources held by m_writable
328  * purely for convenience so code that uses these does not have to go through m_writable-> */
329  AbstractIOHandler * IOHandler()
330  {
331  return m_attri->m_writable.IOHandler.get();
332  }
333  AbstractIOHandler const * IOHandler() const
334  {
335  return m_attri->m_writable.IOHandler.get();
336  }
337  Writable *& parent()
338  {
339  return m_attri->m_writable.parent;
340  }
341  Writable const * parent() const
342  {
343  return m_attri->m_writable.parent;
344  }
345  Writable & writable()
346  {
347  return m_attri->m_writable;
348  }
349  Writable const & writable() const
350  {
351  return m_attri->m_writable;
352  }
353 
354  inline
355  internal::AttributableData & get()
356  {
357  if( m_attri )
358  {
359  return *m_attri;
360  }
361  else
362  {
363  throw std::runtime_error(
364  "[AttributableInterface] "
365  "Cannot use default-constructed Attributable." );
366  }
367  }
368  inline
369  internal::AttributableData const & get() const
370  {
371  if( m_attri )
372  {
373  return *m_attri;
374  }
375  else
376  {
377  throw std::runtime_error(
378  "[AttributableInterface] "
379  "Cannot use default-constructed Attributable." );
380  }
381  }
382 
383  bool dirty() const { return writable().dirty; }
384  bool& dirty() { return writable().dirty; }
385  bool written() const { return writable().written; }
386  bool& written() { return writable().written; }
387 
388 private:
394  virtual void linkHierarchy(Writable& w);
395 }; // AttributableInterface
396 
397 // Alias this as Attributable since this is a public abstract parent class
398 // for most of the classes in our object model of the openPMD hierarchy
399 using Attributable = AttributableInterface;
400 
402 {
403 protected:
404  std::shared_ptr< internal::AttributableData > m_attributableData =
405  std::make_shared< internal::AttributableData >();
406 
407 public:
409  {
410  AttributableInterface::m_attri = m_attributableData.get();
411  }
412 };
413 
414 //TODO explicitly instantiate Attributable::setAttribute for all T in Datatype
415 template< typename T >
416 inline bool
417 AttributableInterface::setAttribute( std::string const & key, T value )
418 {
419  internal::attr_value_check( key, value );
420 
421  auto & attri = get();
422  if(IOHandler() && Access::READ_ONLY == IOHandler()->m_frontendAccess )
423  {
424  auxiliary::OutOfRangeMsg const out_of_range_msg(
425  "Attribute",
426  "can not be set (read-only)."
427  );
428  throw no_such_attribute_error(out_of_range_msg(key));
429  }
430 
431  dirty() = true;
432  auto it = attri.m_attributes.lower_bound(key);
433  if( it != attri.m_attributes.end()
434  && !attri.m_attributes.key_comp()(key, it->first) )
435  {
436  // key already exists in map, just replace the value
437  it->second = Attribute(value);
438  return true;
439  } else
440  {
441  // emplace a new map element for an unknown key
442  attri.m_attributes.emplace_hint(
443  it, std::make_pair(key, Attribute(std::move(value))));
444  return false;
445  }
446 }
447 
448 inline bool
449 AttributableInterface::setAttribute( std::string const & key, char const value[] )
450 {
451  return this->setAttribute(key, std::string(value));
452 }
453 
454 template< typename T >
455 inline T AttributableInterface::readFloatingpoint( std::string const & key ) const
456 {
457  static_assert(std::is_floating_point< T >::value, "Type of attribute must be floating point");
458 
459  return getAttribute(key).get< T >();
460 }
461 
462 template< typename T >
463 inline std::vector< T >
464 AttributableInterface::readVectorFloatingpoint( std::string const & key ) const
465 {
466  static_assert(std::is_floating_point< T >::value, "Type of attribute must be floating point");
467 
468  return getAttribute(key).get< std::vector< T > >();
469 }
470 } // namespace openPMD
openPMD::Access::READ_ONLY
@ READ_ONLY
open series as read-only, fails if series is not found
openPMD::AttributableInterface::myPath
MyPath myPath() const
The path to this object within its containing Series.
Definition: Attributable.cpp:192
openPMD::AttributableInterface::OverrideExisting
@ OverrideExisting
Read all the attributes that the backend has to offer and override if it has been read previously.
Definition: Attributable.hpp:285
openPMD::Writable
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:64
openPMD::AttributableInterface::FullyReread
@ FullyReread
Remove all attributes that have been read previously and read everything that the backend currently h...
Definition: Attributable.hpp:290
openPMD::AttributableInterface::setAttribute
bool setAttribute(std::string const &key, T value)
Populate Attribute of provided name with provided value.
Definition: Attributable.hpp:417
openPMD::internal::AttributableData
Definition: Attributable.hpp:68
openPMD::BaseRecord
Definition: BaseRecord.hpp:36
openPMD::LegacyAttributable
Definition: Attributable.hpp:401
openPMD::AttributableInterface::containingIteration
const Iteration & containingIteration() const
Returns the corresponding Iteration.
Definition: Attributable.cpp:138
openPMD::AttributableInterface::deleteAttribute
bool deleteAttribute(std::string const &key)
Remove Attribute of provided value both logically and physically.
Definition: Attributable.cpp:58
openPMD::AttributableInterface::MyPath
String serialization to describe an Attributable.
Definition: Attributable.hpp:231
openPMD::AbstractFilePosition
Definition: AbstractFilePosition.hpp:26
openPMD::AttributableInterface::seriesFlush
void seriesFlush()
Flush the corresponding Series object.
Definition: Attributable.cpp:116
openPMD::Attribute
Varidic datatype supporting at least all formats for attributes specified in the openPMD standard.
Definition: Attribute.hpp:50
openPMD::UnitDimension::T
@ T
time
openPMD::WriteIterations
Writing side of the streaming API.
Definition: WriteIterations.hpp:47
openPMD::internal::SeriesInternal
Definition: Series.hpp:443
openPMD::AbstractIOHandler
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:98
openPMD::AttributableInterface::MyPath::seriesName
std::string seriesName
e.g., samples/git-samples/
Definition: Attributable.hpp:234
openPMD::AttributableInterface::attributes
std::vector< std::string > attributes() const
List all currently stored Attributes' keys.
Definition: Attributable.cpp:78
openPMD::Series
Root level of the openPMD hierarchy.
Definition: Series.hpp:478
openPMD::auxiliary::OutOfRangeMsg
Return an error string for read-only access.
Definition: OutOfRangeMsg.hpp:37
openPMD::AttributableInterface::containsAttribute
bool containsAttribute(std::string const &key) const
Check whether am Attribute with a given key exists.
Definition: Attributable.cpp:96
openPMD::SeriesInterface
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:112
openPMD::Iteration
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:39
openPMD::AttributableInterface::comment
std::string comment() const
Retrieve a user-supplied comment associated with the object.
Definition: Attributable.cpp:103
openPMD::AttributableInterface::MyPath::group
std::vector< std::string > group
e.g., .bp, .h5, .json, ...
Definition: Attributable.hpp:243
openPMD::AttributableInterface::getAttribute
Attribute getAttribute(std::string const &key) const
Retrieve value of Attribute stored with provided key.
Definition: Attributable.cpp:47
openPMD
Public definitions of openPMD-api.
Definition: Date.cpp:29
openPMD::AttributableInterface::MyPath::filePath
std::string filePath() const
Reconstructs a path that can be passed to a Series constructor.
Definition: Attributable.cpp:187
openPMD::AttributableInterface::readFloatingpoint
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:455
openPMD::Container
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:106
openPMD::Attribute::get
U get() const
Retrieve a stored specific Attribute and cast if convertible.
Definition: Attribute.hpp:332
openPMD::no_such_attribute_error
Definition: Attributable.hpp:57
openPMD::AttributableInterface
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:115
openPMD::traits::GenerationPolicy
Container Element Creation Policy.
Definition: Attributable.hpp:47
openPMD::AttributableInterface::setComment
AttributableInterface & setComment(std::string const &comment)
Populate Attribute corresponding to a comment with the user-supplied comment.
Definition: Attributable.cpp:109
openPMD::AttributableInterface::IgnoreExisting
@ IgnoreExisting
Don't read an attribute from the backend if it has been previously read.
Definition: Attributable.hpp:280
openPMD::AttributableInterface::ReadMode
ReadMode
Definition: Attributable.hpp:275
openPMD::FlushLevel
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition: AbstractIOHandler.hpp:63
openPMD::AttributableInterface::readVectorFloatingpoint
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:464
openPMD::AttributableInterface::MyPath::seriesExtension
std::string seriesExtension
e.g., dataT
Definition: Attributable.hpp:235
openPMD::AttributableInterface::numAttributes
size_t numAttributes() const
Count all currently stored Attributes.
Definition: Attributable.cpp:90