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/auxiliary/OutOfRangeMsg.hpp"
25 #include "openPMD/backend/Attribute.hpp"
26 #include "openPMD/backend/Writable.hpp"
27 
28 #include <cstddef>
29 #include <exception>
30 #include <map>
31 #include <memory>
32 #include <string>
33 #include <type_traits>
34 #include <vector>
35 
36 // expose private and protected members for invasive testing
37 #ifndef OPENPMD_protected
38 #define OPENPMD_protected protected
39 #endif
40 
41 namespace openPMD
42 {
43 namespace traits
44 {
45  template <typename T>
47 } // namespace 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 
66 namespace internal
67 {
69  {
70  friend class openPMD::AttributableInterface;
71 
72  public:
74  AttributableData(AttributableData const &) = 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 
88  enum class SetAttributeMode : char
89  {
90  WhileReadingAttributes,
91  FromPublicAPICall
92  };
93 
98  template <typename T>
99  inline void attr_value_check(
100  std::string const /* key */, T /* value */, SetAttributeMode)
101  {}
102 
103  template <>
104  inline void attr_value_check(
105  std::string const key, std::string const value, SetAttributeMode mode)
106  {
107  switch (mode)
108  {
109  case SetAttributeMode::FromPublicAPICall:
110  if (value.empty())
111  throw std::runtime_error(
112  "[setAttribute] Value for string attribute '" + key +
113  "' must not be empty!");
114  break;
115  case SetAttributeMode::WhileReadingAttributes:
116  // no checks while reading
117  break;
118  }
119  }
120 
121 } // namespace internal
122 
129 {
130  // @todo remove unnecessary friend (wew that sounds bitter)
131  using A_MAP = std::map<std::string, Attribute>;
132  friend Writable *getWritable(AttributableInterface *);
133  template <typename T_elem>
134  friend class BaseRecord;
135  template <typename T, typename T_key, typename T_container>
136  friend class Container;
137  template <typename T>
138  friend struct traits::GenerationPolicy;
139  friend class Iteration;
140  friend class Series;
141  friend class SeriesInterface;
142  friend class Writable;
143  friend class WriteIterations;
144 
145 protected:
146  internal::AttributableData *m_attri = nullptr;
147 
148  // Should not be called publicly, only by implementing classes
150  template <typename T>
151  AttributableInterface(T *attri)
153  static_cast<internal::AttributableData *>(attri)}
154  {}
155 
156 public:
157  virtual ~AttributableInterface() = default;
158 
173  template <typename T>
174  bool setAttribute(std::string const &key, T value);
175  bool setAttribute(std::string const &key, char const value[]);
186  Attribute getAttribute(std::string const &key) const;
187 
194  bool deleteAttribute(std::string const &key);
195 
200  std::vector<std::string> attributes() const;
205  size_t numAttributes() const;
211  bool containsAttribute(std::string const &key) const;
212 
218  std::string comment() const;
225  AttributableInterface &setComment(std::string const &comment);
226 
234  void seriesFlush();
235 
242  struct MyPath
243  {
244  std::string directory;
245  std::string seriesName;
246  std::string seriesExtension;
247 
254  std::vector<std::string> group;
255 
257  std::string filePath() const;
258  };
259 
265  MyPath myPath() const;
266 
267  OPENPMD_protected:
268 
269  internal::SeriesInternal const & retrieveSeries() const;
270  internal::SeriesInternal &retrieveSeries();
271 
279  Iteration const &containingIteration() const;
280  Iteration &containingIteration();
283  void seriesFlush(internal::FlushParams);
284 
285  void flushAttributes(internal::FlushParams const &);
286 
287  template <typename T>
288  bool setAttributeImpl(
289  std::string const &key, T value, internal::SetAttributeMode);
290  bool setAttributeImpl(
291  std::string const &key, char const value[], internal::SetAttributeMode);
293  enum ReadMode
294  {
299  IgnoreExisting,
304  OverrideExisting,
309  FullyReread
310  };
311  void readAttributes(ReadMode);
312 
333  template <typename T>
334  T readFloatingpoint(std::string const &key) const;
356  template <typename T>
357  std::vector<T> readVectorFloatingpoint(std::string const &key) const;
358 
359  /* views into the resources held by m_writable
360  * purely for convenience so code that uses these does not have to go
361  * through m_writable-> */
362  AbstractIOHandler *IOHandler()
363  {
364  return m_attri->m_writable.IOHandler.get();
365  }
366  AbstractIOHandler const *IOHandler() const
367  {
368  return m_attri->m_writable.IOHandler.get();
369  }
370  Writable *&parent()
371  {
372  return m_attri->m_writable.parent;
373  }
374  Writable const *parent() const
375  {
376  return m_attri->m_writable.parent;
377  }
378  Writable &writable()
379  {
380  return m_attri->m_writable;
381  }
382  Writable const &writable() const
383  {
384  return m_attri->m_writable;
385  }
386 
387  inline internal::AttributableData &get()
388  {
389  if (m_attri)
390  {
391  return *m_attri;
392  }
393  else
394  {
395  throw std::runtime_error(
396  "[AttributableInterface] "
397  "Cannot use default-constructed Attributable.");
398  }
399  }
400  inline internal::AttributableData const &get() const
401  {
402  if (m_attri)
403  {
404  return *m_attri;
405  }
406  else
407  {
408  throw std::runtime_error(
409  "[AttributableInterface] "
410  "Cannot use default-constructed Attributable.");
411  }
412  }
413 
414  bool dirty() const
415  {
416  return writable().dirty;
417  }
418  bool &dirty()
419  {
420  return writable().dirty;
421  }
422  bool written() const
423  {
424  return writable().written;
425  }
426  bool &written()
427  {
428  return writable().written;
429  }
430 
431 private:
437  virtual void linkHierarchy(Writable &w);
438 }; // AttributableInterface
439 
440 // Alias this as Attributable since this is a public abstract parent class
441 // for most of the classes in our object model of the openPMD hierarchy
443 
445 {
446 protected:
447  std::shared_ptr<internal::AttributableData> m_attributableData =
448  std::make_shared<internal::AttributableData>();
449 
450 public:
452  {
453  AttributableInterface::m_attri = m_attributableData.get();
454  }
455 };
456 
457 template <typename T>
458 inline bool AttributableInterface::setAttribute(std::string const &key, T value)
459 {
460  return setAttributeImpl(
461  key, std::move(value), internal::SetAttributeMode::FromPublicAPICall);
462 }
463 
464 inline bool
465 Attributable::setAttribute(std::string const &key, char const value[])
466 {
467  return setAttributeImpl(
468  key, value, internal::SetAttributeMode::FromPublicAPICall);
469 }
470 
471 // note: we explicitly instantiate Attributable::setAttributeImpl for all T in
472 // Datatype in Attributable.cpp
473 template <typename T>
474 inline bool Attributable::setAttributeImpl(
475  std::string const &key,
476  T value,
477  internal::SetAttributeMode setAttributeMode)
478 {
479  internal::attr_value_check(key, value, setAttributeMode);
480 
481  auto &attri = get();
482  if (IOHandler() && Access::READ_ONLY == IOHandler()->m_frontendAccess)
483  {
484  auxiliary::OutOfRangeMsg const out_of_range_msg(
485  "Attribute", "can not be set (read-only).");
486  throw no_such_attribute_error(out_of_range_msg(key));
487  }
488 
489  dirty() = true;
490  auto it = attri.m_attributes.lower_bound(key);
491  if (it != attri.m_attributes.end() &&
492  !attri.m_attributes.key_comp()(key, it->first))
493  {
494  // key already exists in map, just replace the value
495 
496  // note: due to a C++17 issue with NVCC 11.0.2 we write the
497  // T value to variant conversion explicitly
498  // https://github.com/openPMD/openPMD-api/pull/1103
499  // it->second = Attribute(std::move(value));
500  it->second = Attribute(Attribute::resource(std::move(value)));
501  return true;
502  }
503  else
504  {
505  // emplace a new map element for an unknown key
506  attri.m_attributes.emplace_hint(
507  it, std::make_pair(key, Attribute(std::move(value))));
508  return false;
509  }
510 }
511 
512 inline bool Attributable::setAttributeImpl(
513  std::string const &key,
514  char const value[],
515  internal::SetAttributeMode setAttributeMode)
516 {
517  return this->setAttributeImpl(key, std::string(value), setAttributeMode);
518 }
519 
520 template <typename T>
521 inline T AttributableInterface::readFloatingpoint(std::string const &key) const
522 {
523  static_assert(
524  std::is_floating_point<T>::value,
525  "Type of attribute must be floating point");
526 
527  return getAttribute(key).get<T>();
528 }
529 
530 template <typename T>
531 inline std::vector<T>
533 {
534  static_assert(
535  std::is_floating_point<T>::value,
536  "Type of attribute must be floating point");
537 
538  return getAttribute(key).get<std::vector<T> >();
539 }
540 } // namespace openPMD
Return an error string for read-only access.
Definition: OutOfRangeMsg.hpp:36
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:532
Definition: Attributable.hpp:56
Definition: Series.hpp:498
Container Element Creation Policy.
Definition: Attributable.hpp:46
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:40
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:521
Writing side of the streaming API.
Definition: WriteIterations.hpp:46
Root level of the openPMD hierarchy.
Definition: Series.hpp:537
Varidic datatype supporting at least all formats for attributes specified in the openPMD standard...
Definition: Attribute.hpp:51
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:122
Public definitions of openPMD-api.
Definition: Date.cpp:28
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:63
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:128
Definition: Attributable.hpp:68
bool setAttribute(std::string const &key, T value)
Populate Attribute of provided name with provided value.
Definition: Attributable.hpp:458
Definition: BaseRecord.hpp:35
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition: AbstractIOHandler.hpp:103
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:110
ReadMode
Definition: Attributable.hpp:292
String serialization to describe an Attributable.
Definition: Attributable.hpp:241
Map-like container that enforces openPMD requirements and handles IO.
Definition: Container.hpp:105
Definition: AbstractFilePosition.hpp:25
Definition: Attributable.hpp:444
open series as read-only, fails if series is not found