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 /* Assuming the second dimension is contiguous so we can calculate the
hashes easily */ hashes easily */
CORRADE_ASSERT(data.empty()[0] || data.isContiguous<1>(), 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]; 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. /* Table containing index of first occurence for each unique entry.
Reserving more buckets than necessary (i.e. as if each entry was Reserving more buckets than necessary (i.e. as if each entry was
unique). */ unique). */
std::unordered_map<Containers::ArrayView<const char>, UnsignedInt, ArrayHash, ArrayEqual> table{dataSize}; std::unordered_map<Containers::ArrayView<const char>, UnsignedInt, ArrayHash, ArrayEqual> table{dataSize};
Containers::Array<UnsignedInt> remapping{Containers::NoInit, dataSize};
/* Go through all entries */ /* Go through all entries */
for(std::size_t i = 0; i != dataSize; ++i) { for(std::size_t i = 0; i != dataSize; ++i) {
/* Try to insert new entry into the table */ /* 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()); const auto result = table.emplace(entry, table.size());
/* Add the (either new or already existing) index into the array */ /* 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) /* If this is a new combination, copy the data to new (earlier)
position in the array. Data in [table.size()-1, i) are already 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()); 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 { 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); 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 @brief Remove duplicates from indexed data in-place
@param[in,out] indices Index array, which will get remapped to list just @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 removeDuplicatesInPlace();
void removeDuplicatesInPlaceNonContiguous(); void removeDuplicatesInPlaceNonContiguous();
void removeDuplicatesInPlaceIntoWrongOutputSize();
template<class T> void removeDuplicatesIndexedInPlace(); template<class T> void removeDuplicatesIndexedInPlace();
void removeDuplicatesIndexedInPlaceSmallType(); void removeDuplicatesIndexedInPlaceSmallType();
void removeDuplicatesIndexedInPlaceEmptyIndices(); void removeDuplicatesIndexedInPlaceEmptyIndices();
@ -56,6 +57,7 @@ struct RemoveDuplicatesTest: TestSuite::Tester {
RemoveDuplicatesTest::RemoveDuplicatesTest() { RemoveDuplicatesTest::RemoveDuplicatesTest() {
addTests({&RemoveDuplicatesTest::removeDuplicatesInPlace, addTests({&RemoveDuplicatesTest::removeDuplicatesInPlace,
&RemoveDuplicatesTest::removeDuplicatesInPlaceNonContiguous, &RemoveDuplicatesTest::removeDuplicatesInPlaceNonContiguous,
&RemoveDuplicatesTest::removeDuplicatesInPlaceIntoWrongOutputSize,
&RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedByte>, &RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedByte>,
&RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedShort>, &RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedShort>,
&RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedInt>, &RemoveDuplicatesTest::removeDuplicatesIndexedInPlace<UnsignedInt>,
@ -92,7 +94,19 @@ void RemoveDuplicatesTest::removeDuplicatesInPlaceNonContiguous() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
MeshTools::removeDuplicatesInPlace(Containers::arrayCast<2, char>(Containers::arrayView(data)).every({1, 2})); 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() { template<class T> void RemoveDuplicatesTest::removeDuplicatesIndexedInPlace() {

Loading…
Cancel
Save