Skip to content

Commit

Permalink
[WIP] Math: add constexpr to Vector{,2,3,4}
Browse files Browse the repository at this point in the history
  • Loading branch information
sthalik committed Oct 10, 2022
1 parent a55fe9d commit 7388244
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 154 deletions.
33 changes: 33 additions & 0 deletions src/Magnum/Math/Math.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,37 @@ namespace Implementation {

}}

#include <Corrade/Utility/Macros.h>
// TODO remove this once corrade#152 gets merged
#ifndef CORRADE_CONSTEXPR17
#if __cpp_constexpr >= 201304
#define CORRADE_CONSTEXPR14 constexpr
#else
#define CORRADE_CONSTEXPR14
#endif

#if __cpp_constexpr >= 201603
#define CORRADE_CONSTEXPR17 constexpr
#else
#define CORRADE_CONSTEXPR17
#endif

#if __cpp_constexpr >= 202002
#define CORRADE_CONSTEXPR20 constexpr
#else
#define CORRADE_CONSTEXPR20
#endif

#if defined(__clang__) && __clang_major__ >= 9 || defined(__GNUG__) && __GNUG__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1931
#define CORRADE_CONSTEVAL (__builtin_is_constant_evaluated())
#elif CORRADE_CXX_STANDARD >= 202002L
#define CORRADE_CONSTEVAL (std::is_constant_evaluated()) /*include type_traits*/
#elif __cpp_if_constexpr >= 201606
#define CORRADE_CONSTEVAL constexpr(false)
#else
#define CORRADE_NO_CONSTEVAL
#endif

#endif

#endif
10 changes: 10 additions & 0 deletions src/Magnum/Math/Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ corrade_add_test(MathVectorTest VectorTest.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathVector2Test Vector2Test.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathVector3Test Vector3Test.cpp LIBRARIES MagnumMathTestLib)
corrade_add_test(MathVector4Test Vector4Test.cpp LIBRARIES MagnumMathTestLib)
#TODO
#if(MSVC AND MSVC_VERSION GREATER_EQUAL 1931 OR
# CMAKE_CXX_COMPILER_ID MATCHES "Clang$" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 9 OR
# CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 9
# )
corrade_add_test(MathVectorConstexpr14 VectorConstexpr14.cpp LIBRARIES MagnumMathTestLib)
set_target_properties(
MathVectorConstexpr14
PROPERTIES CORRADE_CXX_STANDARD 14)

corrade_add_test(MathColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib)

corrade_add_test(MathRectangularMatrixTest RectangularMatrixTest.cpp LIBRARIES MagnumMathTestLib)
Expand Down
122 changes: 122 additions & 0 deletions src/Magnum/Math/Test/VectorConstexpr14.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022 Vladimír Vondruš <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#include <Corrade/TestSuite/Tester.h>
#include <Magnum/Magnum.h>
#include <Magnum/Math/Vector.h>
#include <Magnum/Math/Vector2.h>

namespace Magnum { namespace Math { namespace Test { namespace {

struct Constexpr14Test: Corrade::TestSuite::Tester {
explicit Constexpr14Test();
#ifndef CORRADE_NO_CONSTEVAL
template<class Vec, typename T> void simple();
template<class Vec, typename T> void integer();
template<class Vec, typename T> void scalar();
template<class Vec, typename T> static constexpr int simpleBody();
template<class Vec, typename T> static constexpr int integerBody();
template<class Vec, typename T> static constexpr int scalarBody();
#else
void no_consteval_on_this_compiler() { CORRADE_COMPARE(0, 0); }
#endif
};

Constexpr14Test::Constexpr14Test() {
addTests<Constexpr14Test>({
#ifndef CORRADE_NO_CONSTEVAL
&Constexpr14Test::simple<Vector2i, int>,
&Constexpr14Test::simple<Vector2ui, unsigned>,
&Constexpr14Test::simple<Vector<2, int>, int>,
&Constexpr14Test::simple<Vector<2, Short>, Short>,
&Constexpr14Test::simple<Vector<2, unsigned>, unsigned>,
&Constexpr14Test::simple<Vector<2, float>, float>,
&Constexpr14Test::simple<Vector<2, double>, double>,
&Constexpr14Test::integer<Vector<2, int>, int>,
&Constexpr14Test::integer<Vector2i, int>,
&Constexpr14Test::integer<Vector2ui, int>,
&Constexpr14Test::integer<Vector<2, int>, int>,
&Constexpr14Test::integer<Vector<2, Short>, Short>,
&Constexpr14Test::integer<Vector<2, unsigned>, unsigned>
#else
&Constexpr14Test::no_consteval_on_this_compiler
#endif
});
}

#ifndef CORRADE_NO_CONSTEVAL
template<class Vec, typename T>
void Constexpr14Test::simple() {
setTestCaseTemplateName(TypeTraits<T>::name());
constexpr int ret = simpleBody<Vec, T>();
static_assert(ret == 0, "");
CORRADE_COMPARE(0, ret);
}

#if CORRADE_CXX_STANDARD >= 201603
#define ASSERT(...) if constexpr(__VA_ARGS__) (void)0; else throw "failed"
#else
#define ASSERT(...) if (!(__VA_ARGS__)) return __LINE__
#endif


template<class Vec, typename T>
constexpr int Constexpr14Test::simpleBody() {
constexpr Vec a{T(1), T(2)}, b{T(2), T(3)};
ASSERT(a[0] == T(1) && a[1] == T(2));
ASSERT(a + b == Vec(T(3), T(5)));
ASSERT(a - b == Vec(T(-1), T(-1)));
ASSERT(a * b == Vec(T(2), T(6)));
ASSERT(b / a == (std::is_integral<T>::value ? (Vec(T(2), T(1))) : (Vec(T(2), T(1.5)))));
ASSERT(b.product() == T(6));
ASSERT(b.sum() == T(5));
return 0;
}

template<class Vec, typename T>
void Constexpr14Test::integer()
{
setTestCaseTemplateName(TypeTraits<T>::name());
constexpr int ret = integerBody<Vec, T>();
static_assert(ret == 0, "");
CORRADE_COMPARE(0, ret);
}

template<class Vec, typename T>
constexpr int Constexpr14Test::integerBody()
{
constexpr Vec a{T(1), T(2)}, b{T(3), T(4)};
ASSERT(a[0] == T(1) && a[1] == T(2));
ASSERT(b % a == Vec(T(0), T(0)));
ASSERT(a % b == Vec(T(1), T(2)));
ASSERT((~a)[0] == ~a[0]);
ASSERT((~b)[0] == ~b[0]);
return 0;
}
#endif

}}}}

CORRADE_TEST_MAIN(Magnum::Math::Test::Constexpr14Test)
24 changes: 13 additions & 11 deletions src/Magnum/Math/TypeTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ Calls @ref TypeTraits<T>::equals() --- using fuzzy compare for floating-point
types and doing equality comparison on integral types. Scalar complement to
@ref equal(const Vector<size, T>& a, const Vector<size, T>&).
*/
template<class T> inline typename std::enable_if<IsScalar<T>::value, bool>::type equal(T a, T b) {
template<class T> constexpr inline typename std::enable_if<IsScalar<T>::value, bool>::type equal(T a, T b) {
return TypeTraits<T>::equals(a, b);
}

Expand All @@ -404,7 +404,7 @@ Calls @ref TypeTraits<T>::equals() --- using fuzzy compare for floating-point
types and doing equality comparison on integral types. Scalar complement to
@ref notEqual(const Vector<size, T>& a, const Vector<size, T>&).
*/
template<class T> inline typename std::enable_if<IsScalar<T>::value, bool>::type notEqual(T a, T b) {
template<class T> constexpr inline typename std::enable_if<IsScalar<T>::value, bool>::type notEqual(T a, T b) {
return !TypeTraits<T>::equals(a, b);
}

Expand Down Expand Up @@ -467,17 +467,19 @@ namespace Implementation {
template<class T> struct TypeTraitsFloatingPoint: TypeTraitsName<T> {
TypeTraitsFloatingPoint() = delete;

static bool equals(T a, T b);
static bool equalsZero(T a, T epsilon);
static constexpr T abs(T x) { return x < 0 ? -x : x; }
static CORRADE_CONSTEXPR14 bool equals(T a, T b);
static CORRADE_CONSTEXPR14 bool equalsZero(T a, T epsilon);
};

template<class T> bool TypeTraitsFloatingPoint<T>::equals(const T a, const T b) {
template<class T> CORRADE_CONSTEXPR14 bool TypeTraitsFloatingPoint<T>::equals(const T a, const T b) {
/* Shortcut for binary equality (also infinites) */
if(a == b) return true;

const T absA = std::abs(a);
const T absB = std::abs(b);
const T difference = std::abs(a - b);
const T absA = abs(a);
const T absB = abs(b);
const T difference = abs(a - b);


/* One of the numbers is zero or both are extremely close to it, relative
error is meaningless */
Expand All @@ -488,11 +490,11 @@ template<class T> bool TypeTraitsFloatingPoint<T>::equals(const T a, const T b)
return difference/(absA + absB) < TypeTraits<T>::epsilon();
}

template<class T> bool TypeTraitsFloatingPoint<T>::equalsZero(const T a, const T magnitude) {
template<class T> CORRADE_CONSTEXPR14 bool TypeTraitsFloatingPoint<T>::equalsZero(const T a, const T magnitude) {
/* Shortcut for binary equality */
if(a == T(0.0)) return true;

const T absA = std::abs(a);
const T absA = abs(a);

/* The value is extremely close to zero, relative error is meaningless */
if(absA < TypeTraits<T>::epsilon())
Expand Down Expand Up @@ -538,7 +540,7 @@ namespace Implementation {
[1 - epsilon, 1 + epsilon] or dot() in range [1 - 2*epsilon + epsilon^2,
1 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off machine precision,
it's omitted. */
template<class T> inline bool isNormalizedSquared(T lengthSquared) {
template<class T> constexpr inline bool isNormalizedSquared(T lengthSquared) {
return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon();
}

Expand Down
Loading

0 comments on commit 7388244

Please sign in to comment.