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>
48 } // namespace traits
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>
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;
218 
225  std::vector<std::string> group;
226 
228  std::string filePath() const;
229  };
230 
236  MyPath myPath() const;
237 
238  // clang-format off
239 OPENPMD_protected
240  // clang-format on
241 
242  Series retrieveSeries() const;
243 
251  Iteration const &containingIteration() const;
252  Iteration &containingIteration();
255  void seriesFlush(internal::FlushParams);
256 
257  void flushAttributes(internal::FlushParams const &);
259  enum ReadMode
260  {
265  IgnoreExisting,
270  OverrideExisting,
275  FullyReread
276  };
277  void readAttributes(ReadMode);
278 
299  template <typename T>
300  T readFloatingpoint(std::string const &key) const;
322  template <typename T>
323  std::vector<T> readVectorFloatingpoint(std::string const &key) const;
324 
325  /* views into the resources held by m_writable
326  * purely for convenience so code that uses these does not have to go
327  * through m_writable-> */
328  AbstractIOHandler *IOHandler()
329  {
330  return const_cast<AbstractIOHandler *>(
331  static_cast<Attributable const *>(this)->IOHandler());
332  }
333  AbstractIOHandler const *IOHandler() const
334  {
335  auto &opt = m_attri->m_writable.IOHandler;
336  if (!opt || !opt->has_value())
337  {
338  return nullptr;
339  }
340  return &*opt->value();
341  }
342  Writable *&parent()
343  {
344  return m_attri->m_writable.parent;
345  }
346  Writable const *parent() const
347  {
348  return m_attri->m_writable.parent;
349  }
350  Writable &writable()
351  {
352  return m_attri->m_writable;
353  }
354  Writable const &writable() const
355  {
356  return m_attri->m_writable;
357  }
358 
359  inline void setData(std::shared_ptr<internal::AttributableData> attri)
360  {
361  m_attri = std::move(attri);
362  }
363 
364  inline internal::AttributableData &get()
365  {
366  return *m_attri;
367  }
368  inline internal::AttributableData const &get() const
369  {
370  return *m_attri;
371  }
372 
373  bool dirty() const
374  {
375  return writable().dirty;
376  }
377  bool &dirty()
378  {
379  return writable().dirty;
380  }
381  bool written() const
382  {
383  return writable().written;
384  }
385  bool &written()
386  {
387  return writable().written;
388  }
389 
390 private:
396  virtual void linkHierarchy(Writable &w);
397 }; // Attributable
398 
399 // note: we explicitly instantiate Attributable::setAttributeImpl for all T in
400 // Datatype in Attributable.cpp
401 template <typename T>
402 inline bool Attributable::setAttribute(std::string const &key, T value)
403 {
404  auto &attri = get();
405  if (IOHandler() &&
406  IOHandler()->m_seriesStatus == internal::SeriesStatus::Default &&
407  Access::READ_ONLY == IOHandler()->m_frontendAccess)
408  {
409  auxiliary::OutOfRangeMsg const out_of_range_msg(
410  "Attribute", "can not be set (read-only).");
411  error::throwNoSuchAttribute(out_of_range_msg(key));
412  }
413 
414  dirty() = true;
415  auto it = attri.m_attributes.lower_bound(key);
416  if (it != attri.m_attributes.end() &&
417  !attri.m_attributes.key_comp()(key, it->first))
418  {
419  // key already exists in map, just replace the value
420  it->second = Attribute(std::move(value));
421  return true;
422  }
423  else
424  {
425  // emplace a new map element for an unknown key
426  attri.m_attributes.emplace_hint(
427  it, std::make_pair(key, Attribute(std::move(value))));
428  return false;
429  }
430 }
431 
432 inline bool
433 Attributable::setAttribute(std::string const &key, char const value[])
434 {
435  return this->setAttribute(key, std::string(value));
436 }
437 
438 template <typename T>
439 inline T Attributable::readFloatingpoint(std::string const &key) const
440 {
441  static_assert(
442  std::is_floating_point<T>::value,
443  "Type of attribute must be floating point");
444 
445  return getAttribute(key).get<T>();
446 }
447 
448 template <typename T>
449 inline std::vector<T>
450 Attributable::readVectorFloatingpoint(std::string const &key) const
451 {
452  static_assert(
453  std::is_floating_point<T>::value,
454  "Type of attribute must be floating point");
455 
456  return getAttribute(key).get<std::vector<T> >();
457 }
458 } // namespace openPMD
Return an error string for read-only access.
Definition: OutOfRangeMsg.hpp:36
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:439
Definition: Attributable.hpp:85
Container Element Creation Policy.
Definition: Attributable.hpp:47
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:126
ReadMode
Definition: Attributable.hpp:258
String serialization to describe an Attributable.
Definition: Attributable.hpp:212
Definition: WriteIterations.hpp:53
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:450
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:186
Varidic datatype supporting at least all formats for attributes specified in the openPMD standard...
Definition: Attribute.hpp:54
bool setAttribute(std::string const &key, T value)
Populate Attribute of provided name with provided value.
Definition: Attributable.hpp:402
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:179
Writable m_writable
The Writable associated with this Attributable.
Definition: Attributable.hpp:75
Public definitions of openPMD-api.
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:64
Definition: Attributable.hpp:56
Mutability of objects in the openPMD object model is determined by the open mode (Access enum)...
Definition: BaseRecord.hpp:58
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition: AbstractIOHandler.hpp:84
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:131
Definition: AbstractFilePosition.hpp:25
Open Series as read-only, fails if Series is not found.
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:93