diff --git a/config/ImathConfig.h.in b/config/ImathConfig.h.in index 132f6235..6e1ddab4 100644 --- a/config/ImathConfig.h.in +++ b/config/ImathConfig.h.in @@ -174,4 +174,9 @@ # endif #endif +// Whether the copy and move constructors of Vec2, Vec3 and Vec4 are default or not. +#ifndef IMATH_VEC_BE_TRIVIALLY_RELOCATABLE +# define IMATH_VEC_BE_TRIVIALLY_RELOCATABLE 0 +#endif + #endif // INCLUDED_IMATH_CONFIG_H diff --git a/src/Imath/ImathBoxAlgo.h b/src/Imath/ImathBoxAlgo.h index 3ad5e127..00545e34 100644 --- a/src/Imath/ImathBoxAlgo.h +++ b/src/Imath/ImathBoxAlgo.h @@ -49,7 +49,7 @@ clip (const T& p, const Box& box) IMATH_NOEXCEPT /// template -IMATH_HOSTDEVICE constexpr inline T +IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T closestPointInBox (const T& p, const Box& box) IMATH_NOEXCEPT { return clip (p, box); diff --git a/src/Imath/ImathVec.h b/src/Imath/ImathVec.h index 49d69256..c8a3013c 100644 --- a/src/Imath/ImathVec.h +++ b/src/Imath/ImathVec.h @@ -72,18 +72,27 @@ template class IMATH_EXPORT_TEMPLATE_TYPE Vec2 IMATH_HOSTDEVICE constexpr Vec2 (T a, T b) IMATH_NOEXCEPT; /// Copy constructor +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE != 0 + IMATH_HOSTDEVICE Vec2 (const Vec2&) = default; +#else IMATH_HOSTDEVICE constexpr Vec2 (const Vec2& v) IMATH_NOEXCEPT; +#endif /// Construct from Vec2 of another base type template IMATH_HOSTDEVICE constexpr Vec2 (const Vec2& v) IMATH_NOEXCEPT; - /// Assignment + /// Copy assignment +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE != 0 + IMATH_HOSTDEVICE Vec2& + operator= (const Vec2&) = default; +#else IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator= (const Vec2& v) IMATH_NOEXCEPT; +#endif /// Destructor - ~Vec2 () IMATH_NOEXCEPT = default; + ~Vec2 () = default; /// @} @@ -369,7 +378,11 @@ template class IMATH_EXPORT_TEMPLATE_TYPE Vec3 IMATH_HOSTDEVICE constexpr Vec3 (T a, T b, T c) IMATH_NOEXCEPT; /// Copy constructor +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE != 0 + IMATH_HOSTDEVICE constexpr Vec3 (const Vec3& v) IMATH_NOEXCEPT = default; +#else IMATH_HOSTDEVICE constexpr Vec3 (const Vec3& v) IMATH_NOEXCEPT; +#endif /// Construct from Vec3 of another base type template @@ -387,9 +400,14 @@ template class IMATH_EXPORT_TEMPLATE_TYPE Vec3 explicit IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3 (const Vec4& v, InfException); - /// Assignment + /// Copy assignment +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE != 0 + IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3& + operator= (const Vec3& v) IMATH_NOEXCEPT = default; +#else IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator= (const Vec3& v) IMATH_NOEXCEPT; +#endif /// Destructor ~Vec3 () IMATH_NOEXCEPT = default; @@ -690,7 +708,11 @@ template class IMATH_EXPORT_TEMPLATE_TYPE Vec4 IMATH_HOSTDEVICE constexpr Vec4 (T a, T b, T c, T d) IMATH_NOEXCEPT; /// Copy constructor +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE != 0 + IMATH_HOSTDEVICE constexpr Vec4 (const Vec4& v) IMATH_NOEXCEPT = default; +#else IMATH_HOSTDEVICE constexpr Vec4 (const Vec4& v) IMATH_NOEXCEPT; +#endif /// Construct from Vec4 of another base type template @@ -700,9 +722,14 @@ template class IMATH_EXPORT_TEMPLATE_TYPE Vec4 template IMATH_HOSTDEVICE explicit constexpr Vec4 (const Vec3& v) IMATH_NOEXCEPT; - /// Assignment + /// Copy assignment +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE != 0 + IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec4& + operator= (const Vec4& v) IMATH_NOEXCEPT = default; +#else IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator= (const Vec4& v) IMATH_NOEXCEPT; +#endif /// Destructor ~Vec4 () IMATH_NOEXCEPT = default; @@ -1212,11 +1239,13 @@ IMATH_HOSTDEVICE constexpr inline Vec2::Vec2 (T a, T b) IMATH_NOEXCEPT y (b) {} +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE == 0 template IMATH_HOSTDEVICE constexpr inline Vec2::Vec2 (const Vec2& v) IMATH_NOEXCEPT : x (v.x), y (v.y) {} +#endif template template @@ -1225,6 +1254,7 @@ IMATH_HOSTDEVICE constexpr inline Vec2::Vec2 (const Vec2& v) y (T (v.y)) {} +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE == 0 template IMATH_CONSTEXPR14 IMATH_HOSTDEVICE inline const Vec2& Vec2::operator= (const Vec2& v) IMATH_NOEXCEPT @@ -1233,6 +1263,7 @@ Vec2::operator= (const Vec2& v) IMATH_NOEXCEPT y = v.y; return *this; } +#endif template template @@ -1618,12 +1649,14 @@ IMATH_HOSTDEVICE constexpr inline Vec3::Vec3 (T a, T b, T c) IMATH_NOEXCEPT z (c) {} +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE == 0 template IMATH_HOSTDEVICE constexpr inline Vec3::Vec3 (const Vec3& v) IMATH_NOEXCEPT : x (v.x), y (v.y), z (v.z) {} +#endif template template @@ -1633,6 +1666,7 @@ IMATH_HOSTDEVICE constexpr inline Vec3::Vec3 (const Vec3& v) z (T (v.z)) {} +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE == 0 template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3& Vec3::operator= (const Vec3& v) IMATH_NOEXCEPT @@ -1642,6 +1676,7 @@ Vec3::operator= (const Vec3& v) IMATH_NOEXCEPT z = v.z; return *this; } +#endif template template @@ -2093,6 +2128,7 @@ IMATH_HOSTDEVICE constexpr inline Vec4::Vec4 (T a, T b, T c, T d) w (d) {} +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE == 0 template IMATH_HOSTDEVICE constexpr inline Vec4::Vec4 (const Vec4& v) IMATH_NOEXCEPT : x (v.x), @@ -2100,6 +2136,7 @@ IMATH_HOSTDEVICE constexpr inline Vec4::Vec4 (const Vec4& v) IMATH_NOEXCEPT z (v.z), w (v.w) {} +#endif template template @@ -2110,6 +2147,7 @@ IMATH_HOSTDEVICE constexpr inline Vec4::Vec4 (const Vec4& v) w (T (v.w)) {} +#if IMATH_VEC_BE_TRIVIALLY_RELOCATABLE == 0 template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4& Vec4::operator= (const Vec4& v) IMATH_NOEXCEPT @@ -2120,6 +2158,7 @@ Vec4::operator= (const Vec4& v) IMATH_NOEXCEPT w = v.w; return *this; } +#endif template template diff --git a/src/ImathTest/CMakeLists.txt b/src/ImathTest/CMakeLists.txt index 58820316..c135240d 100644 --- a/src/ImathTest/CMakeLists.txt +++ b/src/ImathTest/CMakeLists.txt @@ -78,6 +78,13 @@ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" target_link_libraries(ImathHalfPerfTest Imath::Imath) add_test(NAME Imath.half_perf_test COMMAND $) +add_executable(ImathVecTriviallyRelocatableTest vec_trivially_relocatable_main.cpp testVecTriviallyRelocatable.cpp) +set_target_properties(ImathVecTriviallyRelocatableTest PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" +) +target_link_libraries(ImathVecTriviallyRelocatableTest Imath::Imath) +add_test(NAME Imath.vec_trivially_relocatable_test COMMAND $) + function(DEFINE_IMATH_TESTS) foreach(curtest IN LISTS ARGN) add_test(NAME Imath.${curtest} COMMAND $ ${curtest}) diff --git a/src/ImathTest/testVecTriviallyRelocatable.cpp b/src/ImathTest/testVecTriviallyRelocatable.cpp new file mode 100644 index 00000000..a5ed6415 --- /dev/null +++ b/src/ImathTest/testVecTriviallyRelocatable.cpp @@ -0,0 +1,268 @@ +// +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenEXR Project. +// + +#ifdef NDEBUG +# undef NDEBUG +#endif + +#define IMATH_VEC_BE_TRIVIALLY_RELOCATABLE 1 + +#include "testVecTriviallyRelocatable.h" +#include +#include +#include +#include +#include + +// Include ImathForward *after* other headers to validate forward declarations +#include + +using namespace std; +using namespace IMATH_INTERNAL_NAMESPACE; + +namespace +{ + +template +void +testLength2T () +{ + const T s = std::sqrt (std::numeric_limits::min ()); + const T e = 4 * std::numeric_limits::epsilon (); + + Vec2 v; + + v = Vec2 (0, 0); + assert (v.length () == 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 0, e)); + + v = Vec2 (3, 4); + assert (v.length () == 5); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + v = Vec2 (3000, 4000); + assert (v.length () == 5000); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + T t = s * (1 << 4); + + v = Vec2 (t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec2 (0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec2 (-t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal ( + v.length (), t * std::sqrt (2), t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + t = s / (1 << 4); + + v = Vec2 (t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec2 (0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec2 (-t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal ( + v.length (), t * std::sqrt (2), t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + t = s / (1 << 20); + + v = Vec2 (t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec2 (0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec2 (-t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal ( + v.length (), t * std::sqrt (2), t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); +} + +template +void +testLength3T () +{ + const T s = std::sqrt (std::numeric_limits::min ()); + const T e = 4 * std::numeric_limits::epsilon (); + + Vec3 v; + + v = Vec3 (0, 0, 0); + assert (v.length () == 0); + assert (v.normalized ().length () == 0); + + v = Vec3 (3, 4, 0); + assert (v.length () == 5); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + v = Vec3 (3000, 4000, 0); + assert (v.length () == 5000); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + v = Vec3 (1, -1, 1); + assert ( + IMATH_INTERNAL_NAMESPACE::equal (v.length (), 1 * std::sqrt (3), e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + v = Vec3 (1000, -1000, 1000); + assert (IMATH_INTERNAL_NAMESPACE::equal ( + v.length (), 1000 * std::sqrt (3), 1000 * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + T t = s * (1 << 4); + + v = Vec3 (t, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (0, t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (0, 0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (-t, -t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal ( + v.length (), t * std::sqrt (3), t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + t = s / (1 << 4); + + v = Vec3 (t, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (0, t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (0, 0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (-t, -t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal ( + v.length (), t * std::sqrt (3), t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + t = s / (1 << 20); + + v = Vec3 (t, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (0, t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (0, 0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec3 (-t, -t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal ( + v.length (), t * std::sqrt (3), t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); +} + +template +void +testLength4T () +{ + const T s = std::sqrt (std::numeric_limits::min ()); + const T e = 4 * std::numeric_limits::epsilon (); + + Vec4 v; + + v = Vec4 (0, 0, 0, 0); + assert (v.length () == 0); + assert (v.normalized ().length () == 0); + + v = Vec4 (3, 4, 0, 0); + assert (v.length () == 5); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + v = Vec4 (3000, 4000, 0, 0); + assert (v.length () == 5000); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + v = Vec4 (1, -1, 1, 1); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), 2, e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + v = Vec4 (1000, -1000, 1000, 1000); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), 2000, 1000 * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + T t = s * (1 << 4); + + v = Vec4 (t, 0, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, t, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, 0, t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, 0, 0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (-t, -t, -t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t * 2, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + t = s / (1 << 4); + + v = Vec4 (t, 0, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, t, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, 0, t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, 0, 0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (-t, -t, -t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t * 2, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + + t = s / (1 << 20); + + v = Vec4 (t, 0, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, t, 0, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, 0, t, 0); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (0, 0, 0, t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); + v = Vec4 (-t, -t, -t, -t); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.length (), t * 2, t * e)); + assert (IMATH_INTERNAL_NAMESPACE::equal (v.normalized ().length (), 1, e)); +} + +} // namespace + +void +testVecTriviallyRelocatable () +{ + cout << "Testing some basic vector operations when vectors are trivially relocatable." << endl; + + testLength2T (); + testLength2T (); + testLength3T (); + testLength3T (); + testLength4T (); + testLength4T (); + + cout << "ok\n" << endl; +} diff --git a/src/ImathTest/testVecTriviallyRelocatable.h b/src/ImathTest/testVecTriviallyRelocatable.h new file mode 100644 index 00000000..62bdd641 --- /dev/null +++ b/src/ImathTest/testVecTriviallyRelocatable.h @@ -0,0 +1,6 @@ +// +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenEXR Project. +// + +void testVecTriviallyRelocatable (); diff --git a/src/ImathTest/vec_trivially_relocatable_main.cpp b/src/ImathTest/vec_trivially_relocatable_main.cpp new file mode 100644 index 00000000..e2e17b0a --- /dev/null +++ b/src/ImathTest/vec_trivially_relocatable_main.cpp @@ -0,0 +1,28 @@ +// +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenEXR Project. +// + +#ifdef NDEBUG +# undef NDEBUG +#endif + +#include "testVecTriviallyRelocatable.h" + +#include +#include + +#define TEST(x) \ + if (argc < 2 || !strcmp (argv[1], #x)) x (); + +int +main (int argc, char* argv[]) +{ + // NB: If you add a test here, make sure to enumerate it in the + // CMakeLists.txt so it runs as part of the test suite + TEST (testVecTriviallyRelocatable) + // NB: If you add a test here, make sure to enumerate it in the + // CMakeLists.txt so it runs as part of the test suite + + return 0; +}