Skip to content

Commit 3de2176

Browse files
committed
Make mergeChunks function public
1 parent 679b08c commit 3de2176

4 files changed

Lines changed: 118 additions & 105 deletions

File tree

include/openPMD/ChunkInfo.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ namespace chunk_assignment
9191

9292
using Assignment = std::map<unsigned int, std::vector<WrittenChunkInfo>>;
9393

94+
template <typename Chunk_t>
95+
void mergeChunks(std::vector<Chunk_t> &);
96+
9497
struct PartialAssignment
9598
{
9699
ChunkTable notAssigned;

src/ChunkInfo.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <iostream>
2828
#include <list>
2929
#include <map>
30+
#include <optional>
3031
#include <utility>
3132

3233
#ifdef _WIN32
@@ -68,6 +69,115 @@ bool WrittenChunkInfo::operator==(WrittenChunkInfo const &other) const
6869

6970
namespace chunk_assignment
7071
{
72+
namespace
73+
{
74+
/*
75+
* Check whether two chunks can be merged to form a large one
76+
* and optionally return that larger chunk
77+
*/
78+
template <typename Chunk_t>
79+
std::optional<Chunk_t>
80+
mergeChunks(Chunk_t const &chunk1, Chunk_t const &chunk2)
81+
{
82+
/*
83+
* Idea:
84+
* If two chunks can be merged into one, they agree on offsets and
85+
* extents in all but exactly one dimension dim.
86+
* At dimension dim, the offset of chunk 2 is equal to the offset
87+
* of chunk 1 plus its extent -- or vice versa.
88+
*/
89+
unsigned dimensionality = chunk1.extent.size();
90+
for (unsigned dim = 0; dim < dimensionality; ++dim)
91+
{
92+
Chunk_t const *c1(&chunk1), *c2(&chunk2);
93+
// check if one chunk is the extension of the other at
94+
// dimension dim
95+
// first, let's put things in order
96+
if (c1->offset[dim] > c2->offset[dim])
97+
{
98+
std::swap(c1, c2);
99+
}
100+
// now, c1 begins at the lower of both offsets
101+
// next check, that both chunks border one another exactly
102+
if (c2->offset[dim] != c1->offset[dim] + c1->extent[dim])
103+
{
104+
continue;
105+
}
106+
// we've got a candidate
107+
// verify that all other dimensions have equal values
108+
auto equalValues = [dimensionality, dim, c1, c2]() {
109+
for (unsigned j = 0; j < dimensionality; ++j)
110+
{
111+
if (j == dim)
112+
{
113+
continue;
114+
}
115+
if (c1->offset[j] != c2->offset[j] ||
116+
c1->extent[j] != c2->extent[j])
117+
{
118+
return false;
119+
}
120+
}
121+
return true;
122+
};
123+
if (!equalValues())
124+
{
125+
continue;
126+
}
127+
// we can merge the chunks
128+
Offset offset(c1->offset);
129+
Extent extent(c1->extent);
130+
extent[dim] += c2->extent[dim];
131+
return std::make_optional(Chunk_t(offset, extent));
132+
}
133+
return std::optional<Chunk_t>();
134+
}
135+
} // namespace
136+
137+
/*
138+
* Merge chunks in the chunktable until no chunks are left that can be
139+
* merged.
140+
*/
141+
template <typename Chunk_t>
142+
void mergeChunks(std::vector<Chunk_t> &table)
143+
{
144+
bool stillChanging;
145+
do
146+
{
147+
stillChanging = false;
148+
auto innerLoops = [&table]() {
149+
/*
150+
* Iterate over pairs of chunks in the table.
151+
* When a pair that can be merged is found, merge it,
152+
* delete the original two chunks from the table,
153+
* put the new one in and return.
154+
*/
155+
for (auto i = table.begin(); i < table.end(); ++i)
156+
{
157+
for (auto j = i + 1; j < table.end(); ++j)
158+
{
159+
std::optional<Chunk_t> merged = mergeChunks(*i, *j);
160+
if (merged)
161+
{
162+
// erase order is important due to iterator
163+
// invalidation
164+
table.erase(j);
165+
table.erase(i);
166+
table.emplace_back(std::move(merged.value()));
167+
return true;
168+
}
169+
}
170+
}
171+
return false;
172+
};
173+
stillChanging = innerLoops();
174+
} while (stillChanging);
175+
}
176+
177+
template void mergeChunks<ChunkInfo>(std::vector<ChunkInfo> &);
178+
template void
179+
mergeChunks<WrittenChunkInfo>(std::vector<WrittenChunkInfo> &);
180+
71181
namespace
72182
{
73183
std::map<std::string, std::list<unsigned int> >

src/IO/JSON/JSONIOHandlerImpl.cpp

Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -875,107 +875,6 @@ namespace
875875
}
876876
return res;
877877
}
878-
879-
/*
880-
* Check whether two chunks can be merged to form a large one
881-
* and optionally return that larger chunk
882-
*/
883-
std::optional<WrittenChunkInfo>
884-
mergeChunks(WrittenChunkInfo const &chunk1, WrittenChunkInfo const &chunk2)
885-
{
886-
/*
887-
* Idea:
888-
* If two chunks can be merged into one, they agree on offsets and
889-
* extents in all but exactly one dimension dim.
890-
* At dimension dim, the offset of chunk 2 is equal to the offset
891-
* of chunk 1 plus its extent -- or vice versa.
892-
*/
893-
unsigned dimensionality = chunk1.extent.size();
894-
for (unsigned dim = 0; dim < dimensionality; ++dim)
895-
{
896-
WrittenChunkInfo const *c1(&chunk1), *c2(&chunk2);
897-
// check if one chunk is the extension of the other at
898-
// dimension dim
899-
// first, let's put things in order
900-
if (c1->offset[dim] > c2->offset[dim])
901-
{
902-
std::swap(c1, c2);
903-
}
904-
// now, c1 begins at the lower of both offsets
905-
// next check, that both chunks border one another exactly
906-
if (c2->offset[dim] != c1->offset[dim] + c1->extent[dim])
907-
{
908-
continue;
909-
}
910-
// we've got a candidate
911-
// verify that all other dimensions have equal values
912-
auto equalValues = [dimensionality, dim, c1, c2]() {
913-
for (unsigned j = 0; j < dimensionality; ++j)
914-
{
915-
if (j == dim)
916-
{
917-
continue;
918-
}
919-
if (c1->offset[j] != c2->offset[j] ||
920-
c1->extent[j] != c2->extent[j])
921-
{
922-
return false;
923-
}
924-
}
925-
return true;
926-
};
927-
if (!equalValues())
928-
{
929-
continue;
930-
}
931-
// we can merge the chunks
932-
Offset offset(c1->offset);
933-
Extent extent(c1->extent);
934-
extent[dim] += c2->extent[dim];
935-
return std::make_optional(WrittenChunkInfo(offset, extent));
936-
}
937-
return std::optional<WrittenChunkInfo>();
938-
}
939-
940-
/*
941-
* Merge chunks in the chunktable until no chunks are left that can be
942-
* merged.
943-
*/
944-
void mergeChunks(ChunkTable &table)
945-
{
946-
bool stillChanging;
947-
do
948-
{
949-
stillChanging = false;
950-
auto innerLoops = [&table]() {
951-
/*
952-
* Iterate over pairs of chunks in the table.
953-
* When a pair that can be merged is found, merge it,
954-
* delete the original two chunks from the table,
955-
* put the new one in and return.
956-
*/
957-
for (auto i = table.begin(); i < table.end(); ++i)
958-
{
959-
for (auto j = i + 1; j < table.end(); ++j)
960-
{
961-
std::optional<WrittenChunkInfo> merged =
962-
mergeChunks(*i, *j);
963-
if (merged)
964-
{
965-
// erase order is important due to iterator
966-
// invalidation
967-
table.erase(j);
968-
table.erase(i);
969-
table.emplace_back(std::move(merged.value()));
970-
return true;
971-
}
972-
}
973-
}
974-
return false;
975-
};
976-
stillChanging = innerLoops();
977-
} while (stillChanging);
978-
}
979878
} // namespace
980879

981880
void JSONIOHandlerImpl::availableChunks(
@@ -985,7 +884,7 @@ void JSONIOHandlerImpl::availableChunks(
985884
auto filePosition = setAndGetFilePosition(writable);
986885
auto &j = obtainJsonContents(writable)["data"];
987886
*parameters.chunks = chunksInJSON(j);
988-
mergeChunks(*parameters.chunks);
887+
chunk_assignment::mergeChunks(*parameters.chunks);
989888
}
990889

991890
void JSONIOHandlerImpl::openFile(

src/binding/python/ChunkInfo.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ void init_Chunk(py::module &m)
171171
})
172172
.def_readwrite("offset", &ChunkInfo::offset)
173173
.def_readwrite("extent", &ChunkInfo::extent);
174-
py::bind_vector<PyVecChunkInfo>(m, "VectorChunkInfo");
175-
py::implicitly_convertible<py::list, std::vector<ChunkInfo>>();
174+
py::bind_vector<PyVecChunkInfo>(m, "VectorChunkInfo")
175+
.def("merge_chunks", &chunk_assignment::mergeChunks<ChunkInfo>);
176176
py::class_<WrittenChunkInfo, ChunkInfo>(m, "WrittenChunkInfo")
177177
.def(py::init<Offset, Extent>(), py::arg("offset"), py::arg("extent"))
178178
.def(
@@ -238,7 +238,8 @@ void init_Chunk(py::module &m)
238238
})
239239
.def("available", &host_info::methodAvailable);
240240

241-
py::bind_vector<ChunkTable>(m, "ChunkTable");
241+
py::bind_vector<ChunkTable>(m, "ChunkTable")
242+
.def("merge_chunks", &chunk_assignment::mergeChunks<WrittenChunkInfo>);
242243

243244
using namespace chunk_assignment;
244245

0 commit comments

Comments
 (0)