Browse Source

MeshTools: make a version of duplicate() not dependent on std::vector.

Provide a version taking StridedArrayView instead, taking an arbitrary
view and also arbitrary index type. Also introduce duplicateInto() which
doesn't even allocate, but rather writes the output to pre-existing
location.
pull/229/head
Vladimír Vondruš 7 years ago
parent
commit
61397afc31
  1. 5
      doc/changelog.dox
  2. 58
      src/Magnum/MeshTools/Duplicate.h
  3. 1
      src/Magnum/MeshTools/Test/CMakeLists.txt
  4. 62
      src/Magnum/MeshTools/Test/DuplicateTest.cpp

5
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

58
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 <vector>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Utility/Assert.h>
#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<class IndexType, class T> void duplicateInto(const Containers::StridedArrayView1D<const IndexType>&, const Containers::StridedArrayView1D<const T>&, const Containers::StridedArrayView1D<T>&);
#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<class T> std::vector<T> duplicate(const std::vector<UnsignedInt>& indices, const std::vector<T>& data) {
std::vector<T> 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<class IndexType, class T> Containers::Array<T> duplicate(const Containers::StridedArrayView1D<const IndexType>& indices, const Containers::StridedArrayView1D<const T>& data) {
Containers::Array<T> out{Containers::NoInit, indices.size()};
duplicateInto<IndexType, T>(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<class IndexType, class T> void duplicateInto(const Containers::StridedArrayView1D<const IndexType>& indices, const Containers::StridedArrayView1D<const T>& data, const Containers::StridedArrayView1D<T>& 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 IndexType>&, const Containers::StridedArrayView1D<const T>&),
but putting the result into a @ref std::vector.
*/
template<class T> std::vector<T> duplicate(const std::vector<UnsignedInt>& indices, const std::vector<T>& data) {
std::vector<T> out(indices.size());
duplicateInto<UnsignedInt, T>(indices, data, out);
return out;
}

1
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")

62
src/Magnum/MeshTools/Test/DuplicateTest.cpp

@ -23,7 +23,10 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Magnum.h"
#include "Magnum/MeshTools/Duplicate.h"
@ -34,17 +37,74 @@ 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<UnsignedByte, Int>(indices, data)),
(Containers::Array<Int>{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<UnsignedByte, Int>(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<int>{-7, 35, 12, -18}),
(std::vector<Int>{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<UnsignedByte, Int>(indices, data, output);
CORRADE_COMPARE_AS(Containers::arrayView<const Int>(output),
(Containers::Array<Int>{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<UnsignedByte, Int>(indices, data, output);
CORRADE_COMPARE(out.str(),
"MeshTools::duplicateInto(): bad output size, expected 6 but got 5\n");
}
}}}}
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::DuplicateTest)

Loading…
Cancel
Save