diff --git a/include/openPMD/CustomHierarchy.hpp b/include/openPMD/CustomHierarchy.hpp index f99bbcb897..1f34dc9d7a 100644 --- a/include/openPMD/CustomHierarchy.hpp +++ b/include/openPMD/CustomHierarchy.hpp @@ -114,8 +114,10 @@ class CustomHierarchy : public Container std::vector currentPath); template - static void - synchronizeContainers(Container &target, Container &source); + static void synchronizeContainers( + Container &target, + Container>> + &source); protected: CustomHierarchy(); @@ -158,7 +160,12 @@ class CustomHierarchy : public Container template auto asContainerOf() -> Container &; - Container meshes{}; - Container particles{}; + Container>> + meshes{}; + Container< + ParticleSpecies, + std::string, + std::shared_ptr>> + particles{}; }; } // namespace openPMD diff --git a/include/openPMD/Mesh.hpp b/include/openPMD/Mesh.hpp index 38db4df2e9..dd198e75d4 100644 --- a/include/openPMD/Mesh.hpp +++ b/include/openPMD/Mesh.hpp @@ -22,6 +22,7 @@ #include "openPMD/backend/Attributable.hpp" #include "openPMD/backend/BaseRecord.hpp" +#include "openPMD/backend/Container.hpp" #include "openPMD/backend/MeshRecordComponent.hpp" #include @@ -40,6 +41,10 @@ namespace openPMD class Mesh : public BaseRecord { friend class Container; + friend class Container< + Mesh, + std::string, + std::shared_ptr>>; friend class Iteration; friend class CustomHierarchy; @@ -156,7 +161,7 @@ class Mesh : public BaseRecord */ template < typename T, - typename = std::enable_if_t::value> > + typename = std::enable_if_t::value>> Mesh &setGridSpacing(std::vector const &gridSpacing); /** @@ -223,7 +228,7 @@ class Mesh : public BaseRecord */ template < typename T, - typename = std::enable_if_t::value> > + typename = std::enable_if_t::value>> Mesh &setTimeOffset(T timeOffset); private: diff --git a/include/openPMD/ParticleSpecies.hpp b/include/openPMD/ParticleSpecies.hpp index a0c474a391..0e14883154 100644 --- a/include/openPMD/ParticleSpecies.hpp +++ b/include/openPMD/ParticleSpecies.hpp @@ -33,6 +33,10 @@ namespace openPMD class ParticleSpecies : public Container { friend class Container; + friend class Container< + ParticleSpecies, + std::string, + std::shared_ptr>>; friend class Container; friend class Iteration; friend class CustomHierarchy; diff --git a/include/openPMD/backend/Attributable.hpp b/include/openPMD/backend/Attributable.hpp index 63161d638d..c4b27204ff 100644 --- a/include/openPMD/backend/Attributable.hpp +++ b/include/openPMD/backend/Attributable.hpp @@ -117,6 +117,16 @@ namespace internal AttributableData &operator=(AttributableData const &) = delete; AttributableData &operator=(AttributableData &&) = delete; + + inline std::shared_ptr &asSharedPtr() + { + return *this; + } + inline std::shared_ptr const & + asSharedPtr() const + { + return *this; + } }; template diff --git a/include/openPMD/backend/Container.hpp b/include/openPMD/backend/Container.hpp index fbfef046a6..4b75545ac8 100644 --- a/include/openPMD/backend/Container.hpp +++ b/include/openPMD/backend/Container.hpp @@ -63,10 +63,28 @@ namespace internal class EraseStaleEntries; struct CustomHierarchyData; + template + struct AccessContainer + { + using T_ActualContainer = T_Container; + static T_Container construct() + { + return T_Container(); + } + static T_ActualContainer &access(T_Container &cont) + { + return cont; + } + static T_ActualContainer const &access(T_Container const &cont) + { + return cont; + } + }; + template < typename T, typename T_key = std::string, - typename T_container = std::map > + typename T_container = std::map> class ContainerData : virtual public AttributableData { public: @@ -75,7 +93,8 @@ namespace internal /** * The wrapped container holding all the actual data, e.g. std::map. */ - InternalContainer m_container; + InternalContainer m_container = + AccessContainer::construct(); ContainerData() = default; @@ -85,6 +104,48 @@ namespace internal ContainerData &operator=(ContainerData const &) = delete; ContainerData &operator=(ContainerData &&) = delete; }; + + /* + * This allows to have a Container which references another Container's + * data. + * Reason: Unfortunately, Iteration::meshes and Iteration::particles are + * public members and not methods. This makes it impossible to modify their + * behavior when doing an internal refactoring. + * We would need this now: We want to keep these members for legady and + * shortcut access, but the actual data is now stored as a further group + * in the CustomHierarchy structure. E.g. `iteration.meshes` points to + * the same thing as `iteration["meshes"]. + * If we had a method `Iteration::meshes()`, we could simply find that group + * at call time and hand it out to the user. + * Instead, we need to synchronize both objects. At first flush, **if** + * there are meshes defined, all data is moved from `Iteration.meshes` to + * `Iteration["meshes"]. Then, `Iteration.meshes` is set to point at + * `Iteration["meshes"]`, making them go synchronous. + * This is made possible by allowing the use of `internal::ContainerData` + * as internal container type. + * We cannot create them synchronously at construction time since the key + * "meshes" might not be created after all, and `setMeshesPath()` has not + * been called yet, so would not even know the proper key. + */ + template + struct AccessContainer< + std::shared_ptr>> + { + using T_Wrapper = std::shared_ptr>; + using T_ActualContainer = T_Container; + static T_Wrapper construct() + { + return std::make_shared>(); + } + static T_ActualContainer &access(T_Wrapper &cont) + { + return cont->m_container; + } + static T_ActualContainer const &access(T_Wrapper const &cont) + { + return cont->m_container; + } + }; } // namespace internal /** @brief Map-like container that enforces openPMD requirements and handles IO. @@ -99,7 +160,7 @@ namespace internal template < typename T, typename T_key = std::string, - typename T_container = std::map > + typename T_container = std::map> class Container : virtual public Attributable { friend class Iteration; @@ -113,9 +174,11 @@ class Container : virtual public Attributable friend struct internal::CustomHierarchyData; friend class CustomHierarchy; + using AccessContainer = internal::AccessContainer; + protected: using ContainerData = internal::ContainerData; - using InternalContainer = T_container; + using InternalContainer = typename AccessContainer::T_ActualContainer; std::shared_ptr m_containerData; @@ -127,12 +190,12 @@ class Container : virtual public Attributable inline InternalContainer const &container() const { - return m_containerData->m_container; + return AccessContainer::access(m_containerData->m_container); } inline InternalContainer &container() { - return m_containerData->m_container; + return AccessContainer::access(m_containerData->m_container); } public: diff --git a/src/CustomHierarchy.cpp b/src/CustomHierarchy.cpp index c1a9f2b826..fcabfbbca8 100644 --- a/src/CustomHierarchy.cpp +++ b/src/CustomHierarchy.cpp @@ -150,10 +150,8 @@ namespace internal for (auto p : std::initializer_list{ &m_embeddedDatasets, &m_embeddedMeshes, &m_embeddedParticles}) { - static_cast &>( - *p->m_attri) = - static_cast< - std::shared_ptr &>(*this); + + p->m_attri->asSharedPtr() = this->asSharedPtr(); } } } // namespace internal @@ -403,9 +401,12 @@ void CustomHierarchy::read( template void CustomHierarchy::synchronizeContainers( - Container &target, Container &source) + Container &target, + Container>> + &source) { - if (target.m_containerData.get() == source.m_containerData.get()) + if (target.m_containerData.get() == + source.m_containerData->m_container.get()) { return; } @@ -422,10 +423,9 @@ void CustomHierarchy::synchronizeContainers( target_attributes.emplace(std::move(pair)); } source.get().m_attributes.clear(); - source.setData(target.m_containerData); - // We need to do this since we redirect the Attributable pointers for some - // members: - source.Attributable::setData(target.m_attri); + source.m_containerData->m_container = target.m_containerData; + + source.m_attri->asSharedPtr() = target.m_attri->asSharedPtr(); } void CustomHierarchy::flush_internal( @@ -441,6 +441,12 @@ void CustomHierarchy::flush_internal( // No need to do anything in access::readOnly since meshes and particles // are initialized as aliases for subgroups at parsing time + /* + * @todo + * This will not update Iteration::meshes and Iteration::particles in + * instances that the user copied + * Need to create them synchronously from the beginning + */ if (access::write(IOHandler()->m_frontendAccess)) { if (!meshes.empty()) diff --git a/src/IO/AbstractIOHandlerImpl.cpp b/src/IO/AbstractIOHandlerImpl.cpp index c572efd310..c1bba44417 100644 --- a/src/IO/AbstractIOHandlerImpl.cpp +++ b/src/IO/AbstractIOHandlerImpl.cpp @@ -20,26 +20,24 @@ std::future AbstractIOHandlerImpl::flush() case O::CREATE_FILE: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] CREATE_FILE" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] CREATE_FILE" << std::endl; createFile(i.writable, parameter); break; } case O::CHECK_FILE: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] CHECK_FILE" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] CHECK_FILE" << std::endl; checkFile(i.writable, parameter); break; } case O::CREATE_PATH: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - // << i.writable - // << "] CREATE_PATH: " << parameter.path - //<< std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] CREATE_PATH: " << parameter.path << std::endl; createPath(i.writable, parameter); break; } @@ -47,8 +45,8 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] CREATE_DATASET" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] CREATE_DATASET" << std::endl; createDataset(i.writable, parameter); break; } @@ -56,40 +54,40 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] EXTEND_DATASET" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] EXTEND_DATASET" << std::endl; extendDataset(i.writable, parameter); break; } case O::OPEN_FILE: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] OPEN_FILE" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] OPEN_FILE" << std::endl; openFile(i.writable, parameter); break; } case O::CLOSE_FILE: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] CLOSE_FILE" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] CLOSE_FILE" << std::endl; closeFile(i.writable, parameter); break; } case O::OPEN_PATH: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] OPEN_PATH" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] OPEN_PATH" << std::endl; openPath(i.writable, parameter); break; } case O::CLOSE_PATH: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] CLOSE_PATH" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] CLOSE_PATH" << std::endl; closePath(i.writable, parameter); break; } @@ -97,24 +95,24 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] OPEN_DATASET" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] OPEN_DATASET" << std::endl; openDataset(i.writable, parameter); break; } case O::DELETE_FILE: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] DELETE_FILE" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] DELETE_FILE" << std::endl; deleteFile(i.writable, parameter); break; } case O::DELETE_PATH: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] DELETE_PATH" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] DELETE_PATH" << std::endl; deletePath(i.writable, parameter); break; } @@ -122,16 +120,16 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] DELETE_DATASET" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] DELETE_DATASET" << std::endl; deleteDataset(i.writable, parameter); break; } case O::DELETE_ATT: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] DELETE_ATT" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] DELETE_ATT" << std::endl; deleteAttribute(i.writable, parameter); break; } @@ -139,16 +137,16 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] WRITE_DATASET" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] WRITE_DATASET" << std::endl; writeDataset(i.writable, parameter); break; } case O::WRITE_ATT: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] WRITE_ATT" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] WRITE_ATT" << std::endl; writeAttribute(i.writable, parameter); break; } @@ -156,8 +154,8 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] READ_DATASET" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] READ_DATASET" << std::endl; readDataset(i.writable, parameter); break; } @@ -165,24 +163,24 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] GET_BUFFER_VIEW" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] GET_BUFFER_VIEW" << std::endl; getBufferView(i.writable, parameter); break; } case O::READ_ATT: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] READ_ATT" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] READ_ATT" << std::endl; readAttribute(i.writable, parameter); break; } case O::LIST_PATHS: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] LIST_PATHS" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] LIST_PATHS" << std::endl; listPaths(i.writable, parameter); break; } @@ -190,24 +188,24 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] LIST_DATASETS" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] LIST_DATASETS" << std::endl; listDatasets(i.writable, parameter); break; } case O::LIST_ATTS: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] LIST_ATTS" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] LIST_ATTS" << std::endl; listAttributes(i.writable, parameter); break; } case O::ADVANCE: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] ADVANCE" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] ADVANCE" << std::endl; advance(i.writable, parameter); break; } @@ -215,17 +213,18 @@ std::future AbstractIOHandlerImpl::flush() auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] AVAILABLE_CHUNKS" - //<< std::endl; + std::cout << "[" << i.writable->parent + << "->" + //<< i.writable << "] AVAILABLE_CHUNKS" + << std::endl; availableChunks(i.writable, parameter); break; } case O::DEREGISTER: { auto ¶meter = deref_dynamic_cast>( i.parameter.get()); - // std::cout << "[" << i.writable->parent << "->" - //<< i.writable << "] DEREGISTER" << std::endl; + std::cout << "[" << i.writable->parent << "->" << i.writable + << "] DEREGISTER" << std::endl; deregister(i.writable, parameter); break; }