From 8f5639e3859b69461bd3e50bc83536b042e5a603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 27 Feb 2020 01:24:14 +0100 Subject: [PATCH] MeshTools: added removeDuplicatesInPlaceInto(). I need to put the resulting index array into a pre-existing allocation. --- src/Magnum/MeshTools/RemoveDuplicates.cpp | 19 +++++++++++++------ src/Magnum/MeshTools/RemoveDuplicates.h | 13 +++++++++++++ .../MeshTools/Test/RemoveDuplicatesTest.cpp | 16 +++++++++++++++- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/Magnum/MeshTools/RemoveDuplicates.cpp b/src/Magnum/MeshTools/RemoveDuplicates.cpp index 6f7a526a6..52f30afcb 100644 --- a/src/Magnum/MeshTools/RemoveDuplicates.cpp +++ b/src/Magnum/MeshTools/RemoveDuplicates.cpp @@ -44,20 +44,21 @@ struct ArrayHash { } }; -std::pair, std::size_t> removeDuplicatesInPlace(const Containers::StridedArrayView2D& data) { +std::size_t removeDuplicatesInPlaceInto(const Containers::StridedArrayView2D& data, const Containers::StridedArrayView1D& 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, UnsignedInt, ArrayHash, ArrayEqual> table{dataSize}; - Containers::Array 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, 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, std::size_t> removeDuplicatesInPlace(c } CORRADE_INTERNAL_ASSERT(dataSize >= table.size()); - return {std::move(remapping), table.size()}; + return table.size(); +} + +std::pair, std::size_t> removeDuplicatesInPlace(const Containers::StridedArrayView2D& data) { + Containers::Array indices{Containers::NoInit, data.size()[0]}; + const std::size_t size = removeDuplicatesInPlaceInto(data, indices); + return {std::move(indices), size}; } namespace { diff --git a/src/Magnum/MeshTools/RemoveDuplicates.h b/src/Magnum/MeshTools/RemoveDuplicates.h index 504b992a3..a259c1e80 100644 --- a/src/Magnum/MeshTools/RemoveDuplicates.h +++ b/src/Magnum/MeshTools/RemoveDuplicates.h @@ -74,6 +74,19 @@ instead. Usage example: */ MAGNUM_MESHTOOLS_EXPORT std::pair, std::size_t> removeDuplicatesInPlace(const Containers::StridedArrayView2D& 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& data, const Containers::StridedArrayView1D& indices); + /** @brief Remove duplicates from indexed data in-place @param[in,out] indices Index array, which will get remapped to list just diff --git a/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp b/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp index 1891083f3..59109cf7d 100644 --- a/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp +++ b/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp @@ -38,6 +38,7 @@ struct RemoveDuplicatesTest: TestSuite::Tester { void removeDuplicatesInPlace(); void removeDuplicatesInPlaceNonContiguous(); + void removeDuplicatesInPlaceIntoWrongOutputSize(); template 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, &RemoveDuplicatesTest::removeDuplicatesIndexedInPlace, &RemoveDuplicatesTest::removeDuplicatesIndexedInPlace, @@ -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 void RemoveDuplicatesTest::removeDuplicatesIndexedInPlace() {