Commit 0e8ab17b authored by Jan Möbius's avatar Jan Möbius
Browse files

Merge branch 'cpp11' into 'master'

Cpp11



See merge request !23
parents 59c6c56c de46a56b
Pipeline #76 passed with stage
.project
CMakeLists.txt.user
......@@ -88,6 +88,12 @@ add_subdirectory (src/OpenMesh/Core)
add_subdirectory (src/OpenMesh/Tools)
add_subdirectory (src/OpenMesh/Apps)
set(OPENMESH_BENCHMARK_DIR CACHE PATH "Source path of benchmark (https://github.com/google/benchmark).")
if (OPENMESH_BENCHMARK_DIR)
add_subdirectory(${OPENMESH_BENCHMARK_DIR} benchmark)
add_subdirectory(src/Benchmark)
endif()
# Do not build unit tests when build as external library
if(${PROJECT_NAME} MATCHES "OpenMesh")
add_subdirectory (src/Unittests)
......
set (SOURCES "")
list (APPEND SOURCES
main.cpp
VectorT_new.cpp
VectorT_legacy.cpp
VectorT_dummy_data.cpp
)
add_executable(OMBenchmark ${SOURCES})
set_target_properties(OMBenchmark PROPERTIES
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(OMBenchmark benchmark OpenMeshCore)
\ No newline at end of file
/*
* VectorT.cpp
*
* Created on: Nov 19, 2015
* Author: ebke
*/
#ifndef BMPOSTFIX
#error "Do not compile directly."
#endif
#include <type_traits>
#define ASSEMBLE_(POSTFIX, PREFIX) PREFIX ## POSTFIX
#define ASSEMBLE(POSTFIX, PREFIX) ASSEMBLE_(POSTFIX, PREFIX)
#define MYBENCHMARK(NAME) BENCHMARK(NAME)
#define MYBENCHMARK_TEMPLATE(NAME, TYPE) BENCHMARK_TEMPLATE(NAME, TYPE)
template<class Vec>
static inline
typename std::enable_if<Vec::size_ == 3, Vec>::type
testVec() {
return Vec(1.1, 1.2, 1.3);
}
template<class Vec>
static inline
typename std::enable_if<Vec::size_ == 4, Vec>::type
testVec() {
return Vec(1.1, 1.2, 1.3, 1.4);
}
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_add_compare)(benchmark::State& state) {
Vec v1(0.0);
Vec v2(1000.0);
while (state.KeepRunning()) {
v1 += testVec<Vec>();
v2 -= testVec<Vec>();
if (v1 == v2) {
v1 -= v2;
v2 += v1;
}
}
// Just so nothing gets optimized away.
static double dummy;
dummy = v1.norm() + v2.norm();
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec3f);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec4d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec4f);
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_cross_product)(benchmark::State& state) {
Vec v1(0.0);
Vec v2(1000.0);
while (state.KeepRunning()) {
v1 += testVec<Vec>();
v2 -= testVec<Vec>();
v1 = (v1 % v2);
}
// Just so nothing gets optimized away.
static double dummy;
dummy = v1.norm() + v2.norm();
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3f);
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_scalar_product)(benchmark::State& state) {
Vec v1(0.0);
Vec v2(1000.0);
double acc = 0;
while (state.KeepRunning()) {
v1 += testVec<Vec>();
v2 -= testVec<Vec>();
acc += (v1 | v2);
}
// Otherwise GCC will optimize everything away.
static double dummy;
dummy = acc;
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec3f);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec4d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec4f);
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_norm)(benchmark::State& state) {
Vec v1(0.0);
double acc = 0;
while (state.KeepRunning()) {
v1 += testVec<Vec>();
acc += v1.norm();
}
// Otherwise GCC will optimize everything away.
static double dummy;
dummy = acc;
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec3f);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec4d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec4f);
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_times_scalar)(benchmark::State& state) {
Vec v1(0.0);
while (state.KeepRunning()) {
v1 += testVec<Vec>();
v1 *= static_cast<decltype(v1.norm())>(1.0)/v1[0];
v1 *= v1[1];
}
// Otherwise GCC will optimize everything away.
static double dummy;
dummy = v1.norm();
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec3f);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec4d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec4f);
#include "VectorT_dummy_data.hpp"
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_add_in_place)(benchmark::State& state) {
auto v = make_dummy_vector<Vec>();
while (state.KeepRunning()) {
v += v;
}
// Otherwise GCC will optimize everything away.
static double dummy = observe_dummy_vector(v);
static_cast<void>(dummy);
}
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_add_temporary)(benchmark::State& state) {
auto v = make_dummy_vector<Vec>();
while (state.KeepRunning()) {
v = v + v;
}
// Otherwise GCC will optimize everything away.
static double dummy = observe_dummy_vector(v);
static_cast<void>(dummy);
}
typedef OpenMesh::VectorT<std::valarray<double>, 3> Vec3VAd;
typedef OpenMesh::VectorT<std::complex<double>, 3> Vec3Cd;
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_in_place), Vec3VAd);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_temporary), Vec3VAd);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_in_place), Vec3Cd);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_temporary), Vec3Cd);
#include "VectorT_dummy_data.hpp"
template<> std::valarray<double> make_dummy_component() {
return std::valarray<double>(128);
}
#pragma once
#include <valarray>
#include <complex>
template<typename T>
T make_dummy_component() {
return T();
}
template<> std::valarray<double> make_dummy_component();
template<typename Vec>
Vec make_dummy_vector() {
return Vec(make_dummy_component<typename Vec::value_type>());
}
template<typename Scalar>
double observe_dummy_component(const Scalar& _s) {
return _s;
}
template<typename T>
double observe_dummy_component(const std::valarray<T>& _s) {
return _s.sum();
}
template<typename T>
double observe_dummy_component(const std::complex<T>& _s) {
return _s.real() + _s.imag();
}
template<typename Vec>
double observe_dummy_vector(const Vec& _vec) {
double result = 0.0;
for (int dim = 0; dim < _vec.dim(); ++dim) {
result += observe_dummy_component(_vec[dim]);
}
return result;
}
/*
* VectorT_legacy.cpp
*
* Created on: Nov 19, 2015
* Author: ebke
*/
#include <benchmark/benchmark_api.h>
#define OPENMESH_VECTOR_LEGACY
#include <OpenMesh/Core/Geometry/VectorT.hh>
#define BMPOSTFIX _Legacy
#include "VectorT.cpp"
/*
* VectorT_new.cpp
*
* Created on: Nov 19, 2015
* Author: ebke
*/
#include <benchmark/benchmark_api.h>
#include <OpenMesh/Core/Geometry/VectorT.hh>
#define BMPOSTFIX _CPP11
#include "VectorT.cpp"
/*
* main.cpp
*
* Created on: Nov 19, 2015
* Author: ebke
*/
#include <benchmark/benchmark_api.h>
BENCHMARK_MAIN();
This diff is collapsed.
......@@ -59,6 +59,10 @@
// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182)
// macro expansion and preprocessor defines
// don't work properly.
#if (__cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY)
#include "Vector11T.hh"
#else
#ifndef DOXYGEN
#ifndef OPENMESH_VECTOR_HH
......@@ -77,12 +81,6 @@
#include <xmmintrin.h>
#endif
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#include <array>
#include <initializer_list>
#include <type_traits>
#endif
//== NAMESPACES ===============================================================
......@@ -92,24 +90,6 @@ namespace OpenMesh {
//== CLASS DEFINITION =========================================================
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
/*
* Helpers for VectorT
*/
namespace {
template<typename... Ts>
struct are_convertible_to;
template<typename To, typename From, typename... Froms>
struct are_convertible_to<To, From, Froms...> {
static constexpr bool value = std::is_convertible<From, To>::value && are_convertible_to<To, Froms...>::value;
};
template<typename To, typename From>
struct are_convertible_to<To, From> : public std::is_convertible<From, To> {};
}
#endif
/** The N values of the template Scalar type are the only data members
of the class VectorT<Scalar,N>. This guarantees 100% compatibility
with arrays of type Scalar and size N, allowing us to define the
......@@ -121,18 +101,7 @@ struct are_convertible_to<To, From> : public std::is_convertible<From, To> {};
*/
template<typename Scalar, int N> class VectorDataT {
public:
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
VectorDataT() {}
template<typename... T>
constexpr VectorDataT(T... vs) : values_ {{vs...}} {
static_assert(sizeof...(vs) == N,
"Incorrect number of vector components supplied.");
}
std::array<Scalar, N> values_;
#else
Scalar values_[N];
#endif
};
......@@ -141,22 +110,9 @@ template<typename Scalar, int N> class VectorDataT {
/// This specialization enables us to use aligned SSE instructions.
template<> class VectorDataT<float, 4> {
public:
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
VectorDataT() {}
template<typename... T>
constexpr VectorDataT(T... vs) : values_ {{vs...}} {
static_assert(sizeof...(vs) == 4,
"Incorrect number of vector components supplied.");
}
#endif
union {
__m128 m128;
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
std::array<float, 4> values_;
#else
float values_[4];
#endif
};
};
......@@ -432,24 +388,7 @@ typedef VectorT<double,6> Vec6d;
//=============================================================================
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
/**
* Literal operator for inline specification of colors in HTML syntax.
*
* Example:
* \code{.cpp}
* OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
* \endcode
*/
constexpr OpenMesh::Vec4f operator"" _htmlColor(unsigned long long raw_color) {
return OpenMesh::Vec4f(
((raw_color >> 24) & 0xFF) / 255.0f,
((raw_color >> 16) & 0xFF) / 255.0f,
((raw_color >> 8) & 0xFF) / 255.0f,
((raw_color >> 0) & 0xFF) / 255.0f);
}
#endif
#endif // OPENMESH_VECTOR_HH defined
//=============================================================================
#endif // DOXYGEN
#endif // C++11
......@@ -97,28 +97,6 @@ public:
/// default constructor creates uninitialized values.
inline VectorT() {}
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
explicit inline VectorT(const Scalar &v) {
vectorize(v);
}
template<typename... T,
typename = typename std::enable_if<sizeof...(T) == DIM>::type,
typename = typename std::enable_if<are_convertible_to<Scalar, T...>::value>::type>
constexpr VectorT(T... vs) : Base { static_cast<Scalar>(vs)...}
{ }
template<int D = DIM, typename = typename std::enable_if<D == DIM>::type>
typename std::enable_if<D==4, VectorT>::type
homogenized() const {
return VectorT(
Base::values_[0]/Base::values_[3],
Base::values_[1]/Base::values_[3],
Base::values_[2]/Base::values_[3],
1);
}
#else
/// special constructor for 1D vectors
explicit inline VectorT(const Scalar& v) {
// assert(DIM==1);
......@@ -165,7 +143,6 @@ public:
Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2;
Base::values_[3]=v3; Base::values_[4]=v4; Base::values_[5]=v5;
}
#endif
#endif
/// construct from a value array (explicit)
......@@ -210,21 +187,11 @@ public:
// /// cast to const Scalar array
// inline operator const Scalar*() const { return Base::values_; }
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
/// access to Scalar array
inline Scalar* data() { return Base::values_.data(); }
/// access to const Scalar array
inline const Scalar*data() const { return Base::values_.data(); }
#else
/// access to Scalar array
inline Scalar* data() { return Base::values_; }
/// access to const Scalar array
inline const Scalar*data() const { return Base::values_; }
#endif
//----------------------------------------------------------- element access
......
......@@ -38,6 +38,71 @@ Scalar get_item(Vector& _vec, int _index) {
return 0.0;
}
namespace {
template<class Scalar>
struct Factory {
typedef OpenMesh::VectorT<Scalar, 2> Vector2;
typedef OpenMesh::VectorT<Scalar, 3> Vector3;
typedef OpenMesh::VectorT<Scalar, 4> Vector4;
static Vector2 *vec2_default() {
return new Vector2(Scalar(), Scalar());
}
static Vector2 *vec2_user_defined(const Scalar& _v0, const Scalar& _v1) {
return new Vector2(_v0, _v1);
}
static Vector3 *vec3_default() {
return new Vector3(Scalar(), Scalar(), Scalar());
}
static Vector3 *vec3_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2) {
return new Vector3(_v0, _v1, _v2);
}
static Vector4 *vec4_default() {
return new Vector4(Scalar(), Scalar(), Scalar(), Scalar());
}
static Vector4 *vec4_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2, const Scalar& _v3) {
return new Vector4(_v0, _v1, _v2, _v3);
}
};
}
template<class Scalar, int N>
void defInitMod(class_<OpenMesh::VectorT<Scalar, N>> &classVector);
template<class Scalar>
void defInitMod(class_<OpenMesh::VectorT<Scalar, 2>> &classVector) {
classVector
.def("__init__", make_constructor(&Factory<Scalar>::vec2_default))
.def("__init__", make_constructor(&Factory<Scalar>::vec2_user_defined))
;
typedef OpenMesh::VectorT<Scalar, 2> Vector;
def("dot", &Vector::operator|);
}
template<class Scalar>
void defInitMod(class_<OpenMesh::VectorT<Scalar, 3>> &classVector) {
classVector
.def("__init__", make_constructor(&Factory<Scalar>::vec3_default))
.def("__init__", make_constructor(&Factory<Scalar>::vec3_user_defined))
.def("__mod__", &Factory<Scalar>::Vector3::operator%)
;
def("cross", &Factory<Scalar>::Vector3::operator%);
typedef OpenMesh::VectorT<Scalar, 3> Vector;
def("dot", &Vector::operator|);
}
template<class Scalar>
void defInitMod(class_<OpenMesh::VectorT<Scalar, 4>> &classVector) {
classVector
.def("__init__", make_constructor(&Factory<Scalar>::vec4_default))
.def("__init__", make_constructor(&Factory<Scalar>::vec4_user_defined))
;
typedef OpenMesh::VectorT<Scalar, 4> Vector;
def("dot", &Vector::operator|);
}
/**
* Expose a vector type to %Python.
*
......@@ -86,12 +151,12 @@ void expose_vec(const char *_name) {
.def("vectorize", &Vector::vectorize, return_internal_reference<>())
.def(self < self)
.def("norm", &Vector::norm)
.def("length", &Vector::length)
.def("sqrnorm", &Vector::sqrnorm)
.def("normalize", &Vector::normalize, return_internal_reference<>())
.def("normalized", &Vector::normalized)
.def("normalize_cond", &Vector::normalize_cond, return_internal_reference<>())
.def("norm", &Vector::template norm<Scalar>)
.def("length", &Vector::template length<Scalar>)
.def("sqrnorm", &Vector::template sqrnorm<Scalar>)
.def("normalize", &Vector::template normalize<Scalar>, return_internal_reference<>())
.def("normalized", &Vector::template normalized<Scalar>)
.def("normalize_cond", &Vector::template normalize_cond<Scalar>, return_internal_reference<>())
.def("l1_norm", &Vector::l1_norm)
.def("l8_norm", &Vector::l8_norm)
......@@ -115,56 +180,7 @@ void expose_vec(const char *_name) {
.staticmethod("vectorized")
;
typedef OpenMesh::VectorT<Scalar, 2> Vector2;
typedef OpenMesh::VectorT<Scalar, 3> Vector3;
typedef OpenMesh::VectorT<Scalar, 4> Vector4;
struct Factory {
static Vector2 *vec2_default() {
return new Vector2(Scalar(), Scalar());
}
static Vector2 *vec2_user_defined(const Scalar& _v0, const Scalar& _v1) {
return new Vector2(_v0, _v1);
}
static Vector3 *vec3_default() {
return new Vector3(Scalar(), Scalar(), Scalar());
}
static Vector3 *vec3_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2) {
return new Vector3(_v0, _v1, _v2);
}
static Vector4 *vec4_default() {
return new Vector4(Scalar(), Scalar(), Scalar(), Scalar());
}
static Vector4 *vec4_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2, const Scalar& _v3) {
return new Vector4(_v0, _v1, _v2, _v3);
}
};
if (N == 2) {
classVector
.def("__init__", make_constructor(&Factory::vec2_default))
.def("__init__", make_constructor(&Factory::vec2_user_defined))
;
}
if (N == 3) {
classVector
.def("__init__", make_constructor(&Factory::vec3_default))
.def("__init__", make_constructor(&Factory::vec3_user_defined))
.def("__mod__", &Vector3::operator%)
;
def("cross", &Vector3::operator%);
}
if (N == 4) {
classVector
.def("__init__", make_constructor(&Factory::vec4_default))
.def("__init__", make_constructor(&Factory::vec4_user_defined))
;
}
def("dot", &Vector::operator|);
defInitMod<Scalar, N>(classVector);
}
} // namespace OpenMesh
......