Browse Source

MeshTools: added removeDuplicatesInPlaceInto().

I need to put the resulting index array into a pre-existing allocation.
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
8f5639e385
  1. 19
      src/Magnum/MeshTools/RemoveDuplicates.cpp
  2. 13
      src/Magnum/MeshTools/RemoveDuplicates.h
  3. 16
      src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp

19
src/Magnum/MeshTools/RemoveDuplicates.cpp

@ -44,20 +44,21 @@ struct ArrayHash {
}
};
std::pair<Containers::Array<UnsignedInt>, std::size_t> removeDuplicatesInPlace(const Containers::StridedArrayView2D<char>& data) {
std::size_t removeDuplicatesInPlaceInto(const Containers::StridedArrayView2D<char>& data, const Containers::StridedArrayView1D<UnsignedInt>& indices) {
/* Assuming the second dimension is contiguous so we can calculate the
hashes easily */
CORRADE_ASSERT(data.empty()[0] || data.isContiguous<1>(),
"MeshTools::removeDuplicatesInPlace(): second data view dimension is not contiguous", {});
"MeshTools::removeDuplicatesInPlaceInto(): second data view dimension is not contiguous", {});
const std::size_t dataSize = data.size()[0];
CORRADE_ASSERT(indices.size() == dataSize,
"MeshTools::removeDuplicatesInPlaceInto(): output index array has" << indices.size() << "elements but expected" << dataSize, {});
/* Table containing index of first occurence for each unique entry.
Reserving more buckets than necessary (i.e. as if each entry was
unique). */
std::unordered_map<Containers::ArrayView<const char>, UnsignedInt, ArrayHash, ArrayEqual> table{dataSize};
Containers::Array<UnsignedInt> remapping{Containers::NoInit, dataSize};
/* Go through all entries */
for(std::size_t i = 0; i != dataSize; ++i) {
/* Try to insert new entry into the table */
@ -65,7 +66,7 @@ std::pair<Containers::Array<UnsignedInt>, std::size_t> removeDuplicatesInPlace(c
const auto result = table.emplace(entry, table.size());
/* Add the (either new or already existing) index into the array */
remapping[i] = result.first->second;
indices[i] = result.first->second;
/* If this is a new combination, copy the data to new (earlier)
position in the array. Data in [table.size()-1, i) are already
@ -76,7 +77,13 @@ std::pair<Containers::Array<UnsignedInt>, std::size_t> removeDuplicatesInPlace(c
}
CORRADE_INTERNAL_ASSERT(dataSize >= table.size());
return {std::move(remapping), table.size()};
return table.size();
}
std::pair<Containers::Array<UnsignedInt>, std::size_t> removeDuplicatesInPlace(const Containers::StridedArrayView2D<char>& data) {
Containers::Array<UnsignedInt> indices{Containers::NoInit, data.size()[0]};
const std::size_t size = removeDuplicatesInPlaceInto(data, indices);
return {std::move(indices), size};
}
namespace {

13
src/Magnum/MeshTools/RemoveDuplicates.h

@ -74,6 +74,19 @@ instead. Usage example:
*/
MAGNUM_MESHTOOLS_EXPORT std::pair<Containers::Array<UnsignedInt>, std::size_t> removeDuplicatesInPlace(const Containers::StridedArrayView2D<char>& data);
/**
@brief Remove duplicate data from given array in-place
@param[in,out] data Data array, duplicate items will be cut away with order
preserved
@param[out] indices Where to put the resulting index array
@return Size of unique prefix in the cleaned up @p data array
@m_since_latest
Same as above, except that the index array is not allocated but put into
@p indices instead. Expects that @p indices has the same size as @p data.
*/
MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesInPlaceInto(const Containers::StridedArrayView2D<char>& data, const Containers::StridedArrayView1D<UnsignedInt>& indices);
/**
@brief Remove duplicates from indexed data in-place
@param[in,out] indices Index array, which will get remapped to list just

16
src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp

@ -38,6 +38,7 @@ struct RemoveDuplicatesTest: TestSuite::Tester {
void removeDuplicatesInPlace();
void removeDuplicatesInPlaceNonContiguous();
void removeDuplicatesInPlaceIntoWrongOutputSize();
template<class T> void removeDuplicatesIndexedInPlace();
void removeDuplicatesIndexedInPlaceSmallType();
void removeDuplicatesIndexedInPlaceEmptyIndices();
@ -56,6 +57,7 @@ struct RemoveDuplicatesTest: TestSuite::Tester {
RemoveDuplicatesTest::RemoveDuplicatesTest() {
addTests({&RemoveDuplicatesTest::removeDuplicatesInPlace,
&RemoveDuplicatesTest::removeDuplicatesInPlaceNonContiguous,
&RemoveDuplicatesTest::removeDuplicatesInPlaceIntoWrongOutputSize,
&RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedByte>,
&RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedShort>,
&RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedInt>,
@ -92,7 +94,19 @@ void RemoveDuplicatesTest::removeDuplicatesInPlaceNonContiguous() {
std::ostringstream out;
Error redirectError{&out};
MeshTools::removeDuplicatesInPlace(Containers::arrayCast<2, char>(Containers::arrayView(data)).every({1, 2}));
CORRADE_COMPARE(out.str(), "MeshTools::removeDuplicatesInPlace(): second data view dimension is not contiguous\n");
CORRADE_COMPARE(out.str(), "MeshTools::removeDuplicatesInPlaceInto(): second data view dimension is not contiguous\n");
}
void RemoveDuplicatesTest::removeDuplicatesInPlaceIntoWrongOutputSize() {
Int data[8]{};
UnsignedInt output[7];
std::ostringstream out;
Error redirectError{&out};
MeshTools::removeDuplicatesInPlaceInto(
Containers::arrayCast<2, char>(Containers::arrayView(data)),
output);
CORRADE_COMPARE(out.str(), "MeshTools::removeDuplicatesInPlaceInto(): output index array has 7 elements but expected 8\n");
}
template<class T> void RemoveDuplicatesTest::removeDuplicatesIndexedInPlace() {

Loading…
Cancel
Save