Skip to content

Commit 8c28fab

Browse files
committed
Pointer to ContainerData solution for Iteration.meshes
1 parent fd65afd commit 8c28fab

File tree

7 files changed

+169
-75
lines changed

7 files changed

+169
-75
lines changed

include/openPMD/CustomHierarchy.hpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,10 @@ class CustomHierarchy : public Container<CustomHierarchy>
114114
std::vector<std::string> currentPath);
115115

116116
template <typename T>
117-
static void
118-
synchronizeContainers(Container<T> &target, Container<T> &source);
117+
static void synchronizeContainers(
118+
Container<T> &target,
119+
Container<T, std::string, std::shared_ptr<internal::ContainerData<T>>>
120+
&source);
119121

120122
protected:
121123
CustomHierarchy();
@@ -158,7 +160,12 @@ class CustomHierarchy : public Container<CustomHierarchy>
158160
template <typename ContainedType>
159161
auto asContainerOf() -> Container<ContainedType> &;
160162

161-
Container<Mesh> meshes{};
162-
Container<ParticleSpecies> particles{};
163+
Container<Mesh, std::string, std::shared_ptr<internal::ContainerData<Mesh>>>
164+
meshes{};
165+
Container<
166+
ParticleSpecies,
167+
std::string,
168+
std::shared_ptr<internal::ContainerData<ParticleSpecies>>>
169+
particles{};
163170
};
164171
} // namespace openPMD

include/openPMD/Mesh.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "openPMD/backend/Attributable.hpp"
2424
#include "openPMD/backend/BaseRecord.hpp"
25+
#include "openPMD/backend/Container.hpp"
2526
#include "openPMD/backend/MeshRecordComponent.hpp"
2627

2728
#include <array>
@@ -40,6 +41,10 @@ namespace openPMD
4041
class Mesh : public BaseRecord<MeshRecordComponent>
4142
{
4243
friend class Container<Mesh>;
44+
friend class Container<
45+
Mesh,
46+
std::string,
47+
std::shared_ptr<internal::ContainerData<Mesh>>>;
4348
friend class Iteration;
4449
friend class CustomHierarchy;
4550

@@ -156,7 +161,7 @@ class Mesh : public BaseRecord<MeshRecordComponent>
156161
*/
157162
template <
158163
typename T,
159-
typename = std::enable_if_t<std::is_floating_point<T>::value> >
164+
typename = std::enable_if_t<std::is_floating_point<T>::value>>
160165
Mesh &setGridSpacing(std::vector<T> const &gridSpacing);
161166

162167
/**
@@ -223,7 +228,7 @@ class Mesh : public BaseRecord<MeshRecordComponent>
223228
*/
224229
template <
225230
typename T,
226-
typename = std::enable_if_t<std::is_floating_point<T>::value> >
231+
typename = std::enable_if_t<std::is_floating_point<T>::value>>
227232
Mesh &setTimeOffset(T timeOffset);
228233

229234
private:

include/openPMD/ParticleSpecies.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ namespace openPMD
3333
class ParticleSpecies : public Container<Record>
3434
{
3535
friend class Container<ParticleSpecies>;
36+
friend class Container<
37+
ParticleSpecies,
38+
std::string,
39+
std::shared_ptr<internal::ContainerData<ParticleSpecies>>>;
3640
friend class Container<Record>;
3741
friend class Iteration;
3842
friend class CustomHierarchy;

include/openPMD/backend/Attributable.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,16 @@ namespace internal
117117

118118
AttributableData &operator=(AttributableData const &) = delete;
119119
AttributableData &operator=(AttributableData &&) = delete;
120+
121+
inline std::shared_ptr<SharedAttributableData> &asSharedPtr()
122+
{
123+
return *this;
124+
}
125+
inline std::shared_ptr<SharedAttributableData> const &
126+
asSharedPtr() const
127+
{
128+
return *this;
129+
}
120130
};
121131

122132
template <typename, typename>

include/openPMD/backend/Container.hpp

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,28 @@ namespace internal
6363
class EraseStaleEntries;
6464
struct CustomHierarchyData;
6565

66+
template <typename T_Container>
67+
struct AccessContainer
68+
{
69+
using T_ActualContainer = T_Container;
70+
static T_Container construct()
71+
{
72+
return T_Container();
73+
}
74+
static T_ActualContainer &access(T_Container &cont)
75+
{
76+
return cont;
77+
}
78+
static T_ActualContainer const &access(T_Container const &cont)
79+
{
80+
return cont;
81+
}
82+
};
83+
6684
template <
6785
typename T,
6886
typename T_key = std::string,
69-
typename T_container = std::map<T_key, T> >
87+
typename T_container = std::map<T_key, T>>
7088
class ContainerData : virtual public AttributableData
7189
{
7290
public:
@@ -75,7 +93,8 @@ namespace internal
7593
/**
7694
* The wrapped container holding all the actual data, e.g. std::map.
7795
*/
78-
InternalContainer m_container;
96+
InternalContainer m_container =
97+
AccessContainer<T_container>::construct();
7998

8099
ContainerData() = default;
81100

@@ -85,6 +104,48 @@ namespace internal
85104
ContainerData &operator=(ContainerData const &) = delete;
86105
ContainerData &operator=(ContainerData &&) = delete;
87106
};
107+
108+
/*
109+
* This allows to have a Container which references another Container's
110+
* data.
111+
* Reason: Unfortunately, Iteration::meshes and Iteration::particles are
112+
* public members and not methods. This makes it impossible to modify their
113+
* behavior when doing an internal refactoring.
114+
* We would need this now: We want to keep these members for legady and
115+
* shortcut access, but the actual data is now stored as a further group
116+
* in the CustomHierarchy structure. E.g. `iteration.meshes` points to
117+
* the same thing as `iteration["meshes"].
118+
* If we had a method `Iteration::meshes()`, we could simply find that group
119+
* at call time and hand it out to the user.
120+
* Instead, we need to synchronize both objects. At first flush, **if**
121+
* there are meshes defined, all data is moved from `Iteration.meshes` to
122+
* `Iteration["meshes"]. Then, `Iteration.meshes` is set to point at
123+
* `Iteration["meshes"]`, making them go synchronous.
124+
* This is made possible by allowing the use of `internal::ContainerData`
125+
* as internal container type.
126+
* We cannot create them synchronously at construction time since the key
127+
* "meshes" might not be created after all, and `setMeshesPath()` has not
128+
* been called yet, so would not even know the proper key.
129+
*/
130+
template <typename T, typename T_key, typename T_Container>
131+
struct AccessContainer<
132+
std::shared_ptr<ContainerData<T, T_key, T_Container>>>
133+
{
134+
using T_Wrapper = std::shared_ptr<ContainerData<T, T_key, T_Container>>;
135+
using T_ActualContainer = T_Container;
136+
static T_Wrapper construct()
137+
{
138+
return std::make_shared<ContainerData<T, T_key, T_Container>>();
139+
}
140+
static T_ActualContainer &access(T_Wrapper &cont)
141+
{
142+
return cont->m_container;
143+
}
144+
static T_ActualContainer const &access(T_Wrapper const &cont)
145+
{
146+
return cont->m_container;
147+
}
148+
};
88149
} // namespace internal
89150

90151
/** @brief Map-like container that enforces openPMD requirements and handles IO.
@@ -99,7 +160,7 @@ namespace internal
99160
template <
100161
typename T,
101162
typename T_key = std::string,
102-
typename T_container = std::map<T_key, T> >
163+
typename T_container = std::map<T_key, T>>
103164
class Container : virtual public Attributable
104165
{
105166
friend class Iteration;
@@ -113,9 +174,11 @@ class Container : virtual public Attributable
113174
friend struct internal::CustomHierarchyData;
114175
friend class CustomHierarchy;
115176

177+
using AccessContainer = internal::AccessContainer<T_container>;
178+
116179
protected:
117180
using ContainerData = internal::ContainerData<T, T_key, T_container>;
118-
using InternalContainer = T_container;
181+
using InternalContainer = typename AccessContainer::T_ActualContainer;
119182

120183
std::shared_ptr<ContainerData> m_containerData;
121184

@@ -127,12 +190,12 @@ class Container : virtual public Attributable
127190

128191
inline InternalContainer const &container() const
129192
{
130-
return m_containerData->m_container;
193+
return AccessContainer::access(m_containerData->m_container);
131194
}
132195

133196
inline InternalContainer &container()
134197
{
135-
return m_containerData->m_container;
198+
return AccessContainer::access(m_containerData->m_container);
136199
}
137200

138201
public:

src/CustomHierarchy.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,8 @@ namespace internal
150150
for (auto p : std::initializer_list<Attributable *>{
151151
&m_embeddedDatasets, &m_embeddedMeshes, &m_embeddedParticles})
152152
{
153-
static_cast<std::shared_ptr<internal::SharedAttributableData> &>(
154-
*p->m_attri) =
155-
static_cast<
156-
std::shared_ptr<internal::SharedAttributableData> &>(*this);
153+
154+
p->m_attri->asSharedPtr() = this->asSharedPtr();
157155
}
158156
}
159157
} // namespace internal
@@ -403,9 +401,12 @@ void CustomHierarchy::read(
403401

404402
template <typename T>
405403
void CustomHierarchy::synchronizeContainers(
406-
Container<T> &target, Container<T> &source)
404+
Container<T> &target,
405+
Container<T, std::string, std::shared_ptr<internal::ContainerData<T>>>
406+
&source)
407407
{
408-
if (target.m_containerData.get() == source.m_containerData.get())
408+
if (target.m_containerData.get() ==
409+
source.m_containerData->m_container.get())
409410
{
410411
return;
411412
}
@@ -422,10 +423,9 @@ void CustomHierarchy::synchronizeContainers(
422423
target_attributes.emplace(std::move(pair));
423424
}
424425
source.get().m_attributes.clear();
425-
source.setData(target.m_containerData);
426-
// We need to do this since we redirect the Attributable pointers for some
427-
// members:
428-
source.Attributable::setData(target.m_attri);
426+
source.m_containerData->m_container = target.m_containerData;
427+
428+
source.m_attri->asSharedPtr() = target.m_attri->asSharedPtr();
429429
}
430430

431431
void CustomHierarchy::flush_internal(
@@ -441,6 +441,12 @@ void CustomHierarchy::flush_internal(
441441

442442
// No need to do anything in access::readOnly since meshes and particles
443443
// are initialized as aliases for subgroups at parsing time
444+
/*
445+
* @todo
446+
* This will not update Iteration::meshes and Iteration::particles in
447+
* instances that the user copied
448+
* Need to create them synchronously from the beginning
449+
*/
444450
if (access::write(IOHandler()->m_frontendAccess))
445451
{
446452
if (!meshes.empty())

0 commit comments

Comments
 (0)