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/ThrowError.hpp"
25 #include "openPMD/auxiliary/OutOfRangeMsg.hpp"
26 #include "openPMD/backend/Attribute.hpp"
27 #include "openPMD/backend/Writable.hpp"
28 
29 #include <cstddef>
30 #include <exception>
31 #include <map>
32 #include <memory>
33 #include <string>
34 #include <type_traits>
35 #include <vector>
36 
37 // expose private and protected members for invasive testing
38 #ifndef OPENPMD_protected
39 #define OPENPMD_protected protected:
40 #endif
41 
42 namespace openPMD
43 {
44 namespace traits
45 {
46  template <typename T>
47  struct GenerationPolicy;
48 } // namespace traits
49 class AbstractFilePosition;
50 class Attributable;
51 class Iteration;
52 class Series;
53 
54 namespace internal
55 {
57  {
58  friend class openPMD::Attributable;
59 
60  public:
62  AttributableData(AttributableData const &) = delete;
64  virtual ~AttributableData() = default;
65 
66  AttributableData &operator=(AttributableData const &) = delete;
67  AttributableData &operator=(AttributableData &&) = delete;
68 
69  using A_MAP = std::map<std::string, Attribute>;
76 
77  private:
81  A_MAP m_attributes;
82  };
83 
84  template <typename>
85  class BaseRecordData;
86 } // namespace internal
87 
94 {
95  // @todo remove unnecessary friend (wew that sounds bitter)
96  using A_MAP = std::map<std::string, Attribute>;
97  friend Writable *getWritable(Attributable *);
98  template <typename T_elem>
99  friend class BaseRecord;
100  template <typename T_elem>
101  friend class BaseRecordInterface;
102  template <typename>
103  friend class internal::BaseRecordData;
104  template <typename T, typename T_key, typename T_container>
105  friend class Container;
106  template <typename T>
107  friend struct traits::GenerationPolicy;
108  friend class Iteration;
109  friend class Series;
110  friend class Writable;
111  friend class WriteIterations;
112 
113 protected:
114  std::shared_ptr<internal::AttributableData> m_attri{
116 
117  // Should not be called publicly, only by implementing classes
118  Attributable(std::shared_ptr<internal::AttributableData>);
119 
120 public:
121  Attributable();
122 
123  virtual ~Attributable() = default;
124 
139  template <typename T>
140  bool setAttribute(std::string const &key, T value);
141  bool setAttribute(std::string const &key, char const value[]);
152  Attribute getAttribute(std::string const &key) const;
153 
160  bool deleteAttribute(std::string const &key);
161 
166  std::vector<std::string> attributes() const;
171  size_t numAttributes() const;
177  bool containsAttribute(std::string const &key) const;
178 
184  std::string comment() const;
191  Attributable &setComment(std::string const &comment);
192 
205  void seriesFlush(std::string backendConfig = "{}");
206 
213  struct MyPath
214  {
215  std::string directory;
216  std::string seriesName;
217  std::string seriesExtension;
225  std::vector<std::string> group;
226  Access access;
227 
229  std::string filePath() const;
230  };
231 
237  MyPath myPath() const;
238 
239  // clang-format off
240 OPENPMD_protected
241  // clang-format on
242 
243  Series retrieveSeries() const;
244 
252  Iteration const &containingIteration() const;
257 
258  void flushAttributes(internal::FlushParams const &);
259 
260  enum ReadMode
261  {
277  };
278  void readAttributes(ReadMode);
279 
300  template <typename T>
301  T readFloatingpoint(std::string const &key) const;
323  template <typename T>
324  std::vector<T> readVectorFloatingpoint(std::string const &key) const;
325 
326  /* views into the resources held by m_writable
327  * purely for convenience so code that uses these does not have to go
328  * through m_writable-> */
329  AbstractIOHandler *IOHandler()
330  {
331  return const_cast<AbstractIOHandler *>(
332  static_cast<Attributable const *>(this)->IOHandler());
333  }
334  AbstractIOHandler const *IOHandler() const
335  {
336  auto &opt = m_attri->m_writable.IOHandler;
337  if (!opt || !opt->has_value())
338  {
339  return nullptr;
340  }
341  return &*opt->value();
342  }
343  Writable *&parent()
344  {
345  return m_attri->m_writable.parent;
346  }
347  Writable const *parent() const
348  {
349  return m_attri->m_writable.parent;
350  }
351  Writable &writable()
352  {
353  return m_attri->m_writable;
354  }
355  Writable const &writable() const
356  {
357  return m_attri->m_writable;
358  }
359 
360  inline void setData(std::shared_ptr<internal::AttributableData> attri)
361  {
362  m_attri = std::move(attri);
363  }
364 
365  inline internal::AttributableData &get()
366  {
367  return *m_attri;
368  }
369  inline internal::AttributableData const &get() const
370  {
371  return *m_attri;
372  }
373 
374  bool dirty() const
375  {
376  return writable().dirty;
377  }
378  bool &dirty()
379  {
380  return writable().dirty;
381  }
382  bool written() const
383  {
384  return writable().written;
385  }
386  bool &written()
387  {
388  return writable().written;
389  }
390 
391 private:
397  virtual void linkHierarchy(Writable &w);
398 }; // Attributable
399 
400 // note: we explicitly instantiate Attributable::setAttributeImpl for all T in
401 // Datatype in Attributable.cpp
402 template <typename T>
403 inline bool Attributable::setAttribute(std::string const &key, T value)
404 {
405  auto &attri = get();
406  if (IOHandler() &&
407  IOHandler()->m_seriesStatus == internal::SeriesStatus::Default &&
408  Access::READ_ONLY == IOHandler()->m_frontendAccess)
409  {
410  auxiliary::OutOfRangeMsg const out_of_range_msg(
411  "Attribute", "can not be set (read-only).");
412  error::throwNoSuchAttribute(out_of_range_msg(key));
413  }
414 
415  dirty() = true;
416  auto it = attri.m_attributes.lower_bound(key);
417  if (it != attri.m_attributes.end() &&
418  !attri.m_attributes.key_comp()(key, it->first))
419  {
420  // key already exists in map, just replace the value
421  it->second = Attribute(std::move(value));
422  return true;
423  }
424  else
425  {
426  // emplace a new map element for an unknown key
427  attri.m_attributes.emplace_hint(
428  it, std::make_pair(key, Attribute(std::move(value))));
429  return false;
430  }
431 }
432 
433 inline bool
434 Attributable::setAttribute(std::string const &key, char const value[])
435 {
436  return this->setAttribute(key, std::string(value));
437 }
438 
439 template <typename T>
440 inline T Attributable::readFloatingpoint(std::string const &key) const
441 {
442  static_assert(
443  std::is_floating_point<T>::value,
444  "Type of attribute must be floating point");
445 
446  return getAttribute(key).get<T>();
447 }
448 
449 template <typename T>
450 inline std::vector<T>
451 Attributable::readVectorFloatingpoint(std::string const &key) const
452 {
453  static_assert(
454  std::is_floating_point<T>::value,
455  "Type of attribute must be floating point");
456 
457  return getAttribute(key).get<std::vector<T> >();
458 }
459 } // namespace openPMD
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:180
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:94
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:451
bool containsAttribute(std::string const &key) const
Check whether am Attribute with a given key exists.
Definition: Attributable.cpp:92
MyPath myPath() const
The path to this object within its containing Series.
Definition: Attributable.cpp:180
ReadMode
Definition: Attributable.hpp:261
@ FullyReread
Remove all attributes that have been read previously and read everything that the backend currently h...
Definition: Attributable.hpp:276
@ IgnoreExisting
Don't read an attribute from the backend if it has been previously read.
Definition: Attributable.hpp:266
@ OverrideExisting
Read all the attributes that the backend has to offer and override if it has been read previously.
Definition: Attributable.hpp:271
std::vector< std::string > attributes() const
List all currently stored Attributes' keys.
Definition: Attributable.cpp:76
Attribute getAttribute(std::string const &key) const
Retrieve value of Attribute stored with provided key.
Definition: Attributable.cpp:46
void seriesFlush(std::string backendConfig="{}")
Flush the corresponding Series object.
Definition: Attributable.cpp:109
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:440
size_t numAttributes() const
Count all currently stored Attributes.
Definition: Attributable.cpp:87
bool deleteAttribute(std::string const &key)
Remove Attribute of provided value both logically and physically.
Definition: Attributable.cpp:56
bool setAttribute(std::string const &key, T value)
Populate Attribute of provided name with provided value.
Definition: Attributable.hpp:403
Attributable & setComment(std::string const &comment)
Populate Attribute corresponding to a comment with the user-supplied comment.
Definition: Attributable.cpp:103
std::string comment() const
Retrieve a user-supplied comment associated with the object.
Definition: Attributable.cpp:98
Iteration const & containingIteration() const
Returns the corresponding Iteration.
Definition: Attributable.cpp:126
Varidic datatype supporting at least all formats for attributes specified in the openPMD standard.
Definition: Attribute.hpp:95
U get() const
Retrieve a stored specific Attribute and cast if convertible.
Definition: Attribute.hpp:253
Definition: BaseRecord.hpp:59
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:132
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:127
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:206
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:65
bool written
Whether a Writable has been written to the backend.
Definition: Writable.hpp:159
Writing side of the streaming API.
Definition: WriteIterations.hpp:67
Return an error string for read-only access.
Definition: OutOfRangeMsg.hpp:37
Definition: Attributable.hpp:57
Writable m_writable
The Writable associated with this Attributable.
Definition: Attributable.hpp:75
Definition: BaseRecord.hpp:37
@ Default
Mutability of objects in the openPMD object model is determined by the open mode (Access enum),...
Public definitions of openPMD-api.
Definition: Date.cpp:29
Access
File access mode to use during IO.
Definition: Access.hpp:30
@ READ_ONLY
Open Series as read-only, fails if Series is not found.
String serialization to describe an Attributable.
Definition: Attributable.hpp:214
std::string filePath() const
Reconstructs a path that can be passed to a Series constructor.
Definition: Attributable.cpp:175
std::string seriesName
e.g., samples/git-samples/
Definition: Attributable.hpp:216
std::string seriesExtension
e.g., dataT
Definition: Attributable.hpp:217
std::vector< std::string > group
e.g., .bp, .h5, .json, ...
Definition: Attributable.hpp:225
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition: AbstractIOHandler.hpp:85
Container Element Creation Policy.
Definition: Container.hpp:51