Skip to content

Commit

Permalink
Pointer to ContainerData solution for Iteration.meshes
Browse files Browse the repository at this point in the history
  • Loading branch information
franzpoeschel committed Jun 28, 2023
1 parent fd65afd commit 8c28fab
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 75 deletions.
15 changes: 11 additions & 4 deletions include/openPMD/CustomHierarchy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@ class CustomHierarchy : public Container<CustomHierarchy>
std::vector<std::string> currentPath);

template <typename T>
static void
synchronizeContainers(Container<T> &target, Container<T> &source);
static void synchronizeContainers(
Container<T> &target,
Container<T, std::string, std::shared_ptr<internal::ContainerData<T>>>
&source);

protected:
CustomHierarchy();
Expand Down Expand Up @@ -158,7 +160,12 @@ class CustomHierarchy : public Container<CustomHierarchy>
template <typename ContainedType>
auto asContainerOf() -> Container<ContainedType> &;

Container<Mesh> meshes{};
Container<ParticleSpecies> particles{};
Container<Mesh, std::string, std::shared_ptr<internal::ContainerData<Mesh>>>
meshes{};
Container<
ParticleSpecies,
std::string,
std::shared_ptr<internal::ContainerData<ParticleSpecies>>>
particles{};
};
} // namespace openPMD
9 changes: 7 additions & 2 deletions include/openPMD/Mesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <array>
Expand All @@ -40,6 +41,10 @@ namespace openPMD
class Mesh : public BaseRecord<MeshRecordComponent>
{
friend class Container<Mesh>;
friend class Container<
Mesh,
std::string,
std::shared_ptr<internal::ContainerData<Mesh>>>;
friend class Iteration;
friend class CustomHierarchy;

Expand Down Expand Up @@ -156,7 +161,7 @@ class Mesh : public BaseRecord<MeshRecordComponent>
*/
template <
typename T,
typename = std::enable_if_t<std::is_floating_point<T>::value> >
typename = std::enable_if_t<std::is_floating_point<T>::value>>
Mesh &setGridSpacing(std::vector<T> const &gridSpacing);

/**
Expand Down Expand Up @@ -223,7 +228,7 @@ class Mesh : public BaseRecord<MeshRecordComponent>
*/
template <
typename T,
typename = std::enable_if_t<std::is_floating_point<T>::value> >
typename = std::enable_if_t<std::is_floating_point<T>::value>>
Mesh &setTimeOffset(T timeOffset);

private:
Expand Down
4 changes: 4 additions & 0 deletions include/openPMD/ParticleSpecies.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ namespace openPMD
class ParticleSpecies : public Container<Record>
{
friend class Container<ParticleSpecies>;
friend class Container<
ParticleSpecies,
std::string,
std::shared_ptr<internal::ContainerData<ParticleSpecies>>>;
friend class Container<Record>;
friend class Iteration;
friend class CustomHierarchy;
Expand Down
10 changes: 10 additions & 0 deletions include/openPMD/backend/Attributable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ namespace internal

AttributableData &operator=(AttributableData const &) = delete;
AttributableData &operator=(AttributableData &&) = delete;

inline std::shared_ptr<SharedAttributableData> &asSharedPtr()
{
return *this;
}
inline std::shared_ptr<SharedAttributableData> const &
asSharedPtr() const
{
return *this;
}
};

template <typename, typename>
Expand Down
75 changes: 69 additions & 6 deletions include/openPMD/backend/Container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,28 @@ namespace internal
class EraseStaleEntries;
struct CustomHierarchyData;

template <typename T_Container>
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<T_key, T> >
typename T_container = std::map<T_key, T>>
class ContainerData : virtual public AttributableData
{
public:
Expand All @@ -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<T_container>::construct();

ContainerData() = default;

Expand All @@ -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 <typename T, typename T_key, typename T_Container>
struct AccessContainer<
std::shared_ptr<ContainerData<T, T_key, T_Container>>>
{
using T_Wrapper = std::shared_ptr<ContainerData<T, T_key, T_Container>>;
using T_ActualContainer = T_Container;
static T_Wrapper construct()
{
return std::make_shared<ContainerData<T, T_key, T_Container>>();
}
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.
Expand All @@ -99,7 +160,7 @@ namespace internal
template <
typename T,
typename T_key = std::string,
typename T_container = std::map<T_key, T> >
typename T_container = std::map<T_key, T>>
class Container : virtual public Attributable
{
friend class Iteration;
Expand All @@ -113,9 +174,11 @@ class Container : virtual public Attributable
friend struct internal::CustomHierarchyData;
friend class CustomHierarchy;

using AccessContainer = internal::AccessContainer<T_container>;

protected:
using ContainerData = internal::ContainerData<T, T_key, T_container>;
using InternalContainer = T_container;
using InternalContainer = typename AccessContainer::T_ActualContainer;

std::shared_ptr<ContainerData> m_containerData;

Expand All @@ -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:
Expand Down
26 changes: 16 additions & 10 deletions src/CustomHierarchy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,8 @@ namespace internal
for (auto p : std::initializer_list<Attributable *>{
&m_embeddedDatasets, &m_embeddedMeshes, &m_embeddedParticles})
{
static_cast<std::shared_ptr<internal::SharedAttributableData> &>(
*p->m_attri) =
static_cast<
std::shared_ptr<internal::SharedAttributableData> &>(*this);

p->m_attri->asSharedPtr() = this->asSharedPtr();
}
}
} // namespace internal
Expand Down Expand Up @@ -403,9 +401,12 @@ void CustomHierarchy::read(

template <typename T>
void CustomHierarchy::synchronizeContainers(
Container<T> &target, Container<T> &source)
Container<T> &target,
Container<T, std::string, std::shared_ptr<internal::ContainerData<T>>>
&source)
{
if (target.m_containerData.get() == source.m_containerData.get())
if (target.m_containerData.get() ==
source.m_containerData->m_container.get())
{
return;
}
Expand All @@ -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(
Expand All @@ -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())
Expand Down
Loading

0 comments on commit 8c28fab

Please sign in to comment.