From 9548c6c4023c94f2b44ea595d8e17f595bad50f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20P=C3=B6schel?= Date: Wed, 28 Jun 2023 14:47:30 +0200 Subject: [PATCH] Introduce SharedAttributableData --- include/openPMD/backend/Attributable.hpp | 79 +++++++++++++++++------- include/openPMD/backend/Writable.hpp | 7 +++ src/Iteration.cpp | 6 +- src/Series.cpp | 10 +-- src/backend/Attributable.cpp | 11 +++- src/backend/Writable.cpp | 1 + 6 files changed, 84 insertions(+), 30 deletions(-) diff --git a/include/openPMD/backend/Attributable.hpp b/include/openPMD/backend/Attributable.hpp index 0f7b722ae5..05b140de32 100644 --- a/include/openPMD/backend/Attributable.hpp +++ b/include/openPMD/backend/Attributable.hpp @@ -56,18 +56,19 @@ namespace internal class IterationData; class SeriesData; - class AttributableData + class SharedAttributableData { friend class openPMD::Attributable; public: - AttributableData(); - AttributableData(AttributableData const &) = delete; - AttributableData(AttributableData &&) = delete; - virtual ~AttributableData() = default; + SharedAttributableData(AttributableData *); + SharedAttributableData(SharedAttributableData const &) = delete; + SharedAttributableData(SharedAttributableData &&) = delete; + virtual ~SharedAttributableData() = default; - AttributableData &operator=(AttributableData const &) = delete; - AttributableData &operator=(AttributableData &&) = delete; + SharedAttributableData & + operator=(SharedAttributableData const &) = delete; + SharedAttributableData &operator=(SharedAttributableData &&) = delete; using A_MAP = std::map; /** @@ -77,6 +78,46 @@ namespace internal */ Writable m_writable; + private: + /** + * The attributes defined by this Attributable. + */ + A_MAP m_attributes; + }; + + /* + * This is essentially a two-level pointer. + * + * 1. level: Our public API hands out handles to users that are (shared) + * pointers to an internal object (PIMPL). + * 2. level: Multiple internal objects might refer to the same item in an + * openPMD file, e.g. to the same backend object. + * So, the internal object for an Attributable is a shared pointer to the + * unique object identifying this item. + * + * Such sharing occurs in the CustomHierarchy class where multiple + * containers refer to the same group in the openPMD hierarchy + * (container of groups, of meshes, of particle species, of datasets). + * This might also become relevant for links as in HDF5 if we choose to + * implement them. + */ + + class AttributableData : public std::shared_ptr + { + friend class openPMD::Attributable; + + using SharedData_t = std::shared_ptr; + + public: + AttributableData(); + AttributableData(SharedAttributableData *); + AttributableData(AttributableData const &) = delete; + AttributableData(AttributableData &&) = delete; + virtual ~AttributableData() = default; + + AttributableData &operator=(AttributableData const &) = delete; + AttributableData &operator=(AttributableData &&) = delete; + template T asInternalCopyOf() { @@ -112,12 +153,6 @@ namespace internal std::shared_ptr(self, [](auto const *) {})); return res; } - - private: - /** - * The attributes defined by this Attributable. - */ - A_MAP m_attributes; }; template @@ -410,7 +445,7 @@ OPENPMD_protected } AbstractIOHandler const *IOHandler() const { - auto &opt = m_attri->m_writable.IOHandler; + auto &opt = writable().IOHandler; if (!opt || !opt->has_value()) { return nullptr; @@ -419,19 +454,19 @@ OPENPMD_protected } Writable *&parent() { - return m_attri->m_writable.parent; + return writable().parent; } Writable const *parent() const { - return m_attri->m_writable.parent; + return writable().parent; } Writable &writable() { - return m_attri->m_writable; + return (*m_attri)->m_writable; } Writable const &writable() const { - return m_attri->m_writable; + return (*m_attri)->m_writable; } inline void setData(std::shared_ptr attri) @@ -439,13 +474,13 @@ OPENPMD_protected m_attri = std::move(attri); } - inline internal::AttributableData &get() + inline internal::SharedAttributableData &get() { - return *m_attri; + return **m_attri; } - inline internal::AttributableData const &get() const + inline internal::SharedAttributableData const &get() const { - return *m_attri; + return **m_attri; } bool dirty() const diff --git a/include/openPMD/backend/Writable.hpp b/include/openPMD/backend/Writable.hpp index d0b8b4f3c7..7ca9f4c3bd 100644 --- a/include/openPMD/backend/Writable.hpp +++ b/include/openPMD/backend/Writable.hpp @@ -48,6 +48,7 @@ class Series; namespace internal { + class SharedAttributableData; class AttributableData; class SeriesData; } // namespace internal @@ -73,6 +74,7 @@ namespace debug */ class Writable final { + friend class internal::SharedAttributableData; friend class internal::AttributableData; friend class internal::SeriesData; friend class Attributable; @@ -140,6 +142,11 @@ OPENPMD_private */ std::shared_ptr>> IOHandler = nullptr; + /* + * Link to the containing Attributable. + * If multiple Attributables share the same Writable, then the creating one. + * (See SharedAttributableData) + */ internal::AttributableData *attributable = nullptr; Writable *parent = nullptr; diff --git a/src/Iteration.cpp b/src/Iteration.cpp index 366fea0de1..93318fdeb0 100644 --- a/src/Iteration.cpp +++ b/src/Iteration.cpp @@ -27,6 +27,7 @@ #include "openPMD/auxiliary/DerefDynamicCast.hpp" #include "openPMD/auxiliary/Filesystem.hpp" #include "openPMD/auxiliary/StringManip.hpp" +#include "openPMD/backend/Attributable.hpp" #include "openPMD/backend/Writable.hpp" #include @@ -708,7 +709,8 @@ auto Iteration::beginStep( case IE::fileBased: if (thisObject.has_value()) { - file = &static_cast(*thisObject).get(); + file = static_cast( + thisObject.value().m_attri.get()); } else { @@ -790,7 +792,7 @@ void Iteration::endStep() switch (series.iterationEncoding()) { case IE::fileBased: - file = &Attributable::get(); + file = m_attri.get(); break; case IE::groupBased: case IE::variableBased: diff --git a/src/Series.cpp b/src/Series.cpp index d587575b44..8202523367 100644 --- a/src/Series.cpp +++ b/src/Series.cpp @@ -1060,7 +1060,7 @@ void Series::initSeries( std::unique_ptr input) { auto &series = get(); - auto &writable = series.m_writable; + auto &writable = series->m_writable; /* * In Access modes READ_LINEAR and APPEND, the Series constructor might have @@ -2419,7 +2419,7 @@ AdvanceStatus Series::advance( // If the backend does not support steps, we cannot continue here param.isThisStepMandatory = true; } - IOTask task(&file.m_writable, param); + IOTask task(&file->m_writable, param); IOHandler()->enqueue(task); } @@ -2516,7 +2516,7 @@ AdvanceStatus Series::advance(AdvanceMode mode) // If the backend does not support steps, we cannot continue here param.isThisStepMandatory = true; } - IOTask task(&series.m_writable, param); + IOTask task(&series->m_writable, param); IOHandler()->enqueue(task); // We cannot call Series::flush now, since the IO handler is still filled @@ -2880,9 +2880,9 @@ namespace internal // This releases the openPMD hierarchy iterations.container().clear(); // Release the IO Handler - if (m_writable.IOHandler) + if (operator*().m_writable.IOHandler) { - *m_writable.IOHandler = std::nullopt; + *operator*().m_writable.IOHandler = std::nullopt; } } } // namespace internal diff --git a/src/backend/Attributable.cpp b/src/backend/Attributable.cpp index d5ff005389..5d296a28f5 100644 --- a/src/backend/Attributable.cpp +++ b/src/backend/Attributable.cpp @@ -38,7 +38,16 @@ namespace openPMD { namespace internal { - AttributableData::AttributableData() : m_writable{this} + SharedAttributableData::SharedAttributableData(AttributableData *attr) + : m_writable{attr} + {} + + AttributableData::AttributableData() + : SharedData_t(std::make_shared(this)) + {} + + AttributableData::AttributableData(SharedAttributableData *raw_ptr) + : SharedData_t({raw_ptr, [](auto const *) {}}) {} } // namespace internal diff --git a/src/backend/Writable.cpp b/src/backend/Writable.cpp index 0e399a3a81..c012051d9e 100644 --- a/src/backend/Writable.cpp +++ b/src/backend/Writable.cpp @@ -21,6 +21,7 @@ #include "openPMD/backend/Writable.hpp" #include "openPMD/Series.hpp" #include "openPMD/auxiliary/DerefDynamicCast.hpp" +#include "openPMD/backend/Attributable.hpp" namespace openPMD {