Browse Source

Math: make batch functions actually usable.

No longer it's needed to add ugly explicit template types or casts.
mousecapture
Vladimír Vondruš 6 years ago
parent
commit
a6dd63af0f
  1. 3
      doc/changelog.dox
  2. 91
      src/Magnum/Math/FunctionsBatch.h
  3. 36
      src/Magnum/Math/Test/FunctionsBatchTest.cpp
  4. 4
      src/Magnum/MeshTools/CompressIndices.cpp
  5. 4
      src/Magnum/MeshTools/Test/GenerateNormalsTest.cpp

3
doc/changelog.dox

@ -132,6 +132,9 @@ See also:
- @ref Math::Matrix3::scaling() const and @ref Math::Matrix4::scaling() const
now return a signed scaling vector, taking into account negative scaling as
well
- Functions in @ref Magnum/Math/FunctionsBatch.h now accept any type that's
convertible to a @ref Corrade::Containers::StridedArrayView without having
to add explicit casts or template parameters
@subsubsection changelog-latest-changes-meshtools MeshTools library

91
src/Magnum/Math/FunctionsBatch.h

@ -36,6 +36,16 @@
namespace Magnum { namespace Math {
namespace Implementation {
/** @todo Utility/Algorithms.h has a similar (but different) variant of this,
maybe turn that into some public utility once we have one more use case? */
template<class T, class View = decltype(Corrade::Containers::Implementation::ErasedArrayViewConverter<typename std::remove_reference<T&&>::type>::from(std::declval<T&&>()))> static auto stridedArrayViewTypeFor(T&&) -> typename View::Type;
template<class T> static T stridedArrayViewTypeFor(const Corrade::Containers::ArrayView<T>&);
template<class T> static T stridedArrayViewTypeFor(const Corrade::Containers::StridedArrayView1D<T>&);
}
/**
@{ @name Batch functions
@ -67,14 +77,26 @@ template<class T> auto isInf(Corrade::Containers::StridedArrayView1D<const T> ra
return out;
}
/**
@overload
@m_since_latest
Converts @p range to @ref Corrade::Containers::StridedArrayView1D and calls the
above overload. Works with any type that's convertible to
@ref Corrade::Containers::StridedArrayView.
*/
template<class Iterable, class T = decltype(Implementation::stridedArrayViewTypeFor(std::declval<Iterable&&>()))> inline auto isInf(Iterable&& range) -> decltype(isInf(std::declval<T>())) {
return isInf(Corrade::Containers::StridedArrayView1D<const T>{range});
}
/** @overload */
template<class T> inline auto isInf(std::initializer_list<T> list) -> decltype(isInf(std::declval<T>())) {
return isInf<T>(Corrade::Containers::arrayView(list.begin(), list.size()));
return isInf(Corrade::Containers::stridedArrayView(list));
}
/** @overload */
template<class T, std::size_t size> inline auto isInf(const T(&array)[size]) -> decltype(isInf(std::declval<T>())) {
return isInf<T>(Corrade::Containers::arrayView(array));
return isInf(Corrade::Containers::StridedArrayView1D<const T>{array});
}
/**
@ -101,14 +123,27 @@ template<class T> inline auto isNan(Corrade::Containers::StridedArrayView1D<cons
return out;
}
/**
@overload
@m_since_latest
Converts @p range to @ref Corrade::Containers::StridedArrayView1D and calls the
above overload. Works with any type that's convertible to
@ref Corrade::Containers::StridedArrayView.
*/
/* See isInf() for why arrayView() and not stridedArrayView() */
template<class Iterable, class T = decltype(Implementation::stridedArrayViewTypeFor(std::declval<Iterable&&>()))> inline auto isNan(Iterable&& range) -> decltype(isNan(std::declval<T>())) {
return isNan(Corrade::Containers::StridedArrayView1D<const T>{range});
}
/** @overload */
template<class T> inline auto isNan(std::initializer_list<T> list) -> decltype(isNan(std::declval<T>())) {
return isNan<T>(Corrade::Containers::arrayView(list.begin(), list.size()));
return isNan(Corrade::Containers::stridedArrayView(list));
}
/** @overload */
template<class T, std::size_t size> inline auto isNan(const T(&array)[size]) -> decltype(isNan(std::declval<T>())) {
return isNan<T>(Corrade::Containers::arrayView(array));
return isNan(Corrade::Containers::StridedArrayView1D<const T>{array});
}
namespace Implementation {
@ -162,14 +197,26 @@ template<class T> inline T min(Corrade::Containers::StridedArrayView1D<const T>
return iOut.second;
}
/**
@overload
@m_since_latest
Converts @p range to @ref Corrade::Containers::StridedArrayView1D and calls the
above overload. Works with any type that's convertible to
@ref Corrade::Containers::StridedArrayView.
*/
template<class Iterable, class T = decltype(Implementation::stridedArrayViewTypeFor(std::declval<Iterable&&>()))> inline T min(Iterable&& range) {
return min(Corrade::Containers::StridedArrayView1D<const T>{range});
}
/** @overload */
template<class T> inline T min(std::initializer_list<T> list) {
return min<T>(Corrade::Containers::arrayView(list.begin(), list.size()));
return min(Corrade::Containers::stridedArrayView(list));
}
/** @overload */
template<class T, std::size_t size> inline T min(const T(&array)[size]) {
return min<T>(Corrade::Containers::arrayView(array));
return min(Corrade::Containers::StridedArrayView1D<const T>{array});
}
/**
@ -189,14 +236,26 @@ template<class T> inline T max(Corrade::Containers::StridedArrayView1D<const T>
return iOut.second;
}
/**
@overload
@m_since_latest
Converts @p range to @ref Corrade::Containers::StridedArrayView1D and calls the
above overload. Works with any type that's convertible to
@ref Corrade::Containers::StridedArrayView.
*/
template<class Iterable, class T = decltype(Implementation::stridedArrayViewTypeFor(std::declval<Iterable&&>()))> inline T max(Iterable&& range) {
return max(Corrade::Containers::StridedArrayView1D<const T>{range});
}
/** @overload */
template<class T> inline T max(std::initializer_list<T> list) {
return max<T>(Corrade::Containers::arrayView(list.begin(), list.size()));
return max(Corrade::Containers::stridedArrayView(list));
}
/** @overload */
template<class T, std::size_t size> inline T max(const T(&array)[size]) {
return max<T>(Corrade::Containers::arrayView(array));
return max(Corrade::Containers::StridedArrayView1D<const T>{array});
}
namespace Implementation {
@ -232,14 +291,26 @@ template<class T> inline std::pair<T, T> minmax(Corrade::Containers::StridedArra
return {min, max};
}
/**
@overload
@m_since_latest
Converts @p range to @ref Corrade::Containers::StridedArrayView1D and calls the
above overload. Works with any type that's convertible to
@ref Corrade::Containers::StridedArrayView.
*/
template<class Iterable, class T = decltype(Implementation::stridedArrayViewTypeFor(std::declval<Iterable&&>()))> inline std::pair<T, T> minmax(Iterable&& range) {
return minmax(Corrade::Containers::StridedArrayView1D<const T>{range});
}
/** @overload */
template<class T> inline std::pair<T, T> minmax(std::initializer_list<T> list) {
return minmax<T>(Corrade::Containers::arrayView(list.begin(), list.size()));
return minmax(Corrade::Containers::stridedArrayView(list));
}
/** @overload */
template<class T, std::size_t size> inline std::pair<T, T> minmax(const T(&array)[size]) {
return minmax<T>(Corrade::Containers::arrayView(array));
return minmax(Corrade::Containers::StridedArrayView1D<const T>{array});
}
/*@}*/

36
src/Magnum/Math/Test/FunctionsBatchTest.cpp

@ -23,6 +23,8 @@
DEALINGS IN THE SOFTWARE.
*/
#include <vector>
#include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Math/FunctionsBatch.h"
@ -85,6 +87,14 @@ void FunctionsBatchTest::isInf() {
Vector2 c[]{{5.0f, -3.0f}, {-2.0f, 14.0f}, {Constants::inf(), -5.0f}};
CORRADE_COMPARE(Math::isInf(c), BoolVector<2>{1});
/* Mutable view */
CORRADE_COMPARE(Math::isInf(Corrade::Containers::StridedArrayView1D<Vector2>{c}), BoolVector<2>{1});
/* This should work without explicit casts or types */
CORRADE_VERIFY(!Math::isInf(std::vector<Float>{5.0f, -2.0f, -1.0f}));
CORRADE_COMPARE(Math::isInf(std::vector<Vector2>{
{5.0f, -3.0f}, {-2.0f, 14.0f}, {Constants::inf(), -5.0f}
}), BoolVector<2>{1});
}
void FunctionsBatchTest::isNan() {
@ -109,6 +119,14 @@ void FunctionsBatchTest::isNan() {
Vector2 c[]{{5.0f, -3.0f}, {14.0f, Constants::nan()}, {-2.0f, -5.0f}};
CORRADE_COMPARE(Math::isNan(c), BoolVector<2>{2});
/* Mutable view */
CORRADE_COMPARE(Math::isNan(Corrade::Containers::StridedArrayView1D<Vector2>{c}), BoolVector<2>{2});
/* This should work without explicit casts or types */
CORRADE_VERIFY(!Math::isNan(std::vector<Float>{5.0f, -2.0f, -1.0f}));
CORRADE_COMPARE(Math::isNan(std::vector<Vector2>{
{5.0f, -3.0f}, {14.0f, Constants::nan()}, {-2.0f, -5.0f}
}), BoolVector<2>{2});
}
void FunctionsBatchTest::min() {
@ -121,6 +139,12 @@ void FunctionsBatchTest::min() {
const Int array[]{5, -2, 9};
CORRADE_COMPARE(Math::min(array), -2);
/* Mutable view */
Int marray[]{5, -2, 9};
CORRADE_COMPARE(Math::min(Corrade::Containers::StridedArrayView1D<Int>{marray}), -2);
/* This should work without explicit casts or types */
CORRADE_COMPARE(Math::min(std::vector<Int>{5, -2, 9}), -2);
/* Wrapped types */
CORRADE_COMPARE(Math::min({5.0_degf, 2.0_degf, 9.0_degf}), 2.0_degf);
@ -136,6 +160,12 @@ void FunctionsBatchTest::max() {
const Int array[]{5, -2, 9};
CORRADE_COMPARE(Math::max(array), 9);
/* Mutable view */
Int marray[]{5, -2, 9};
CORRADE_COMPARE(Math::max(Corrade::Containers::StridedArrayView1D<Int>{marray}), 9);
/* This should work without explicit casts or types */
CORRADE_COMPARE(Math::max(std::vector<Int>{5, -2, 9}), 9);
/* Wrapped types */
CORRADE_COMPARE(Math::max({5.0_degf, 2.0_degf, 9.0_degf}), 9.0_degf);
@ -160,6 +190,12 @@ void FunctionsBatchTest::minmax() {
const Float array[]{-1.0f, 2.0f, -3.0f};
CORRADE_COMPARE(Math::minmax(array), expected);
/* Mutable view */
Float marray[]{-1.0f, 2.0f, -3.0f};
CORRADE_COMPARE(Math::minmax(Corrade::Containers::StridedArrayView1D<Float>{marray}), expected);
/* This should work without explicit casts or types */
CORRADE_COMPARE(Math::minmax(std::vector<Float>{-1.0f, 2.0f, -3.0f}), expected);
/* Wrapped types */
CORRADE_COMPARE(Math::minmax({1.0_radf, 2.0_radf, 3.0_radf}), std::make_pair(1.0_radf, 3.0_radf));

4
src/Magnum/MeshTools/CompressIndices.cpp

@ -49,7 +49,7 @@ template<class T> inline Containers::Array<char> compress(const std::vector<Unsi
std::tuple<Containers::Array<char>, MeshIndexType, UnsignedInt, UnsignedInt> compressIndices(const std::vector<UnsignedInt>& indices) {
/** @todo Performance hint when range can be represented by smaller value? */
const auto minmax = Math::minmax<UnsignedInt>(indices);
const auto minmax = Math::minmax(indices);
Containers::Array<char> data;
MeshIndexType type;
switch(Math::log(256, minmax.second)) {
@ -76,7 +76,7 @@ std::tuple<Containers::Array<char>, MeshIndexType, UnsignedInt, UnsignedInt> com
template<class T> Containers::Array<T> compressIndicesAs(const std::vector<UnsignedInt>& indices) {
#if !defined(CORRADE_NO_ASSERT) || defined(CORRADE_GRACEFUL_ASSERT)
const auto max = Math::max<UnsignedInt>(indices);
const auto max = Math::max(indices);
CORRADE_ASSERT(Math::log(256, max) < sizeof(T), "MeshTools::compressIndicesAs(): type too small to represent value" << max, {});
#endif

4
src/Magnum/MeshTools/Test/GenerateNormalsTest.cpp

@ -406,7 +406,7 @@ void GenerateNormalsTest::benchmarkFlat() {
generateFlatNormalsInto(positions, normals);
}
CORRADE_COMPARE(Math::min<Vector3>(normals), (Vector3{-1.0f, -1.0f, -1.0f}));
CORRADE_COMPARE(Math::min(normals), (Vector3{-1.0f, -1.0f, -1.0f}));
}
void GenerateNormalsTest::benchmarkSmooth() {
@ -417,7 +417,7 @@ void GenerateNormalsTest::benchmarkSmooth() {
BeveledCubePositions, normals);
}
CORRADE_COMPARE(Math::min<Vector3>(normals), (Vector3{-0.996072f, -0.997808f, -0.996072f}));
CORRADE_COMPARE(Math::min(normals), (Vector3{-0.996072f, -0.997808f, -0.996072f}));
}
}}}}

Loading…
Cancel
Save