diff --git a/doc/changelog.dox b/doc/changelog.dox index 8d00867c8..8c52a4a5a 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -133,6 +133,11 @@ See also: @ref Math::UnderlyingTypeOf utility - Added batch versions of @ref Math::isInf() and @ref Math::isNan() +@subsubsection changelog-latest-new-meshtools MeshTools library + +- @ref MeshTools::duplicateInto() alternative to @ref MeshTools::duplicate() + that writes the output to an existing location + @subsubsection changelog-latest-new-platform Platform libraries - @ref Platform::Sdl2Application and @ref Platform::GlfwApplication are now diff --git a/src/Magnum/MeshTools/Duplicate.h b/src/Magnum/MeshTools/Duplicate.h index 8360ac2d4..786304b5f 100644 --- a/src/Magnum/MeshTools/Duplicate.h +++ b/src/Magnum/MeshTools/Duplicate.h @@ -26,30 +26,70 @@ */ /** @file - * @brief Function @ref Magnum::MeshTools::duplicate() + * @brief Function @ref Magnum::MeshTools::duplicate(), @ref Magnum::MeshTools::duplicateInto() */ #include +#include +#include +#include #include -#include "Magnum/Types.h" +#include "Magnum/Magnum.h" namespace Magnum { namespace MeshTools { +#ifndef DOXYGEN_GENERATING_OUTPUT +/* Fwdecl so we can have duplicateInto() ordered after duplicate() */ +template void duplicateInto(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&); +#endif + /** -@brief Duplicate data using index array +@brief Duplicate data using given index array Converts indexed array to non-indexed, for example data `{a, b, c, d}` with index array `{1, 1, 0, 3, 2, 2}` will be converted to `{b, b, a, d, c, c}`. +The resulting array size is the same as size of @p indices, expects that all +indices are in range for the @p data array. + +If you want to fill an existing memory (or, for example a @ref std::vector), +use @ref duplicateInto(). @see @ref removeDuplicates(), @ref combineIndexedArrays() */ -template std::vector duplicate(const std::vector& indices, const std::vector& data) { - std::vector out; - out.reserve(indices.size()); - for(const UnsignedInt index: indices) { - CORRADE_ASSERT(index < data.size(), "MeshTools::duplicate(): index out of range", out); - out.push_back(data[index]); +template Containers::Array duplicate(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& data) { + Containers::Array out{Containers::NoInit, indices.size()}; + duplicateInto(indices, data, out); + return out; +} + +/** +@brief Duplicate data using an index array into given output array +@param[in] indices Index array to use +@param[in] data Input data +@param[out] out Where to store the output + +A variant of @ref duplicate() that fills existing memory instead of allocating +a new array. +*/ +template void duplicateInto(const Containers::StridedArrayView1D& indices, const Containers::StridedArrayView1D& data, const Containers::StridedArrayView1D& out) { + CORRADE_ASSERT(out.size() == indices.size(), + "MeshTools::duplicateInto(): bad output size, expected" << indices.size() << "but got" << out.size(), ); + for(std::size_t i = 0; i != indices.size(); ++i) { + const std::size_t index = indices[i]; + CORRADE_ASSERT(index < data.size(), "MeshTools::duplicateInto(): index" << index << "out of bounds for" << data.size() << "elements", ); + out[i] = data[index]; } +} + +/** +@brief Duplicate data using given index array + +Like @ref duplicate(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&), +but putting the result into a @ref std::vector. +*/ +template std::vector duplicate(const std::vector& indices, const std::vector& data) { + std::vector out(indices.size()); + duplicateInto(indices, data, out); return out; } diff --git a/src/Magnum/MeshTools/Test/CMakeLists.txt b/src/Magnum/MeshTools/Test/CMakeLists.txt index 103552150..e5ffaa63a 100644 --- a/src/Magnum/MeshTools/Test/CMakeLists.txt +++ b/src/Magnum/MeshTools/Test/CMakeLists.txt @@ -37,6 +37,7 @@ corrade_add_test(MeshToolsTransformTest TransformTest.cpp LIBRARIES MagnumMeshTo # Graceful assert for testing set_property(TARGET MeshToolsCombineIndexedArraysTest + MeshToolsDuplicateTest MeshToolsInterleaveTest MeshToolsSubdivideTest APPEND PROPERTY COMPILE_DEFINITIONS "CORRADE_GRACEFUL_ASSERT") diff --git a/src/Magnum/MeshTools/Test/DuplicateTest.cpp b/src/Magnum/MeshTools/Test/DuplicateTest.cpp index 0f28775c9..a4ccce295 100644 --- a/src/Magnum/MeshTools/Test/DuplicateTest.cpp +++ b/src/Magnum/MeshTools/Test/DuplicateTest.cpp @@ -23,7 +23,10 @@ DEALINGS IN THE SOFTWARE. */ +#include #include +#include +#include #include "Magnum/Magnum.h" #include "Magnum/MeshTools/Duplicate.h" @@ -34,15 +37,72 @@ struct DuplicateTest: TestSuite::Tester { explicit DuplicateTest(); void duplicate(); + void duplicateOutOfBounds(); + void duplicateStl(); + + void duplicateInto(); + void duplicateIntoWrongSize(); }; DuplicateTest::DuplicateTest() { - addTests({&DuplicateTest::duplicate}); + addTests({&DuplicateTest::duplicate, + &DuplicateTest::duplicateOutOfBounds, + &DuplicateTest::duplicateStl, + + &DuplicateTest::duplicateInto, + &DuplicateTest::duplicateIntoWrongSize}); } void DuplicateTest::duplicate() { + constexpr UnsignedByte indices[]{1, 1, 0, 3, 2, 2}; + constexpr Int data[]{-7, 35, 12, -18}; + + CORRADE_COMPARE_AS((MeshTools::duplicate(indices, data)), + (Containers::Array{Containers::InPlaceInit, { + 35, 35, -7, -18, 12, 12 + }}), TestSuite::Compare::Container); +} + +void DuplicateTest::duplicateOutOfBounds() { + constexpr UnsignedByte indices[]{1, 1, 0, 4, 2, 2}; + constexpr Int data[]{-7, 35, 12, -18}; + + std::ostringstream out; + Error redirectError{&out}; + + MeshTools::duplicate(indices, data); + CORRADE_COMPARE(out.str(), + "MeshTools::duplicateInto(): index 4 out of bounds for 4 elements\n"); +} + +void DuplicateTest::duplicateStl() { CORRADE_COMPARE(MeshTools::duplicate({1, 1, 0, 3, 2, 2}, std::vector{-7, 35, 12, -18}), - (std::vector{35, 35, -7, -18, 12, 12})); + (std::vector{35, 35, -7, -18, 12, 12})); +} + +void DuplicateTest::duplicateInto() { + constexpr UnsignedByte indices[]{1, 1, 0, 3, 2, 2}; + constexpr Int data[]{-7, 35, 12, -18}; + Int output[6]; + + MeshTools::duplicateInto(indices, data, output); + CORRADE_COMPARE_AS(Containers::arrayView(output), + (Containers::Array{Containers::InPlaceInit, { + 35, 35, -7, -18, 12, 12 + }}), TestSuite::Compare::Container); +} + +void DuplicateTest::duplicateIntoWrongSize() { + constexpr UnsignedByte indices[]{1, 1, 0, 3, 2, 2}; + constexpr Int data[]{-7, 35, 12, -18}; + Int output[5]; + + std::ostringstream out; + Error redirectError{&out}; + + MeshTools::duplicateInto(indices, data, output); + CORRADE_COMPARE(out.str(), + "MeshTools::duplicateInto(): bad output size, expected 6 but got 5\n"); } }}}}