cppbind: Opimize convert fixed size arrays and more type_traits

This commit is contained in:
Thomas Geymayer 2018-01-23 08:41:44 +01:00
parent 7df4f32de6
commit e81597a176
3 changed files with 162 additions and 82 deletions

View File

@ -28,14 +28,13 @@
#include <simgear/nasal/cppbind/NasalMe.hxx>
#include <simgear/nasal/cppbind/NasalMethodHolder.hxx>
#include <simgear/nasal/cppbind/NasalObjectHolder.hxx>
#include <simgear/std/type_traits.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
#include <array>
#include <string>
#include <vector>
@ -143,9 +142,7 @@ namespace nasal
* Convert a Nasal number to a C++ numeric type
*/
template<class T>
typename boost::enable_if< boost::is_arithmetic<T>,
T
>::type
std::enable_if_t<std::is_arithmetic<T>::value, T>
from_nasal_helper(naContext c, naRef ref, const T*)
{
naRef num = naNumValue(ref);
@ -174,17 +171,39 @@ namespace nasal
return vec;
}
/**
* Convert a Nasal vector to a std::array
*/
template<class T, std::size_t N>
std::array<T, N>
from_nasal_helper(naContext c, naRef ref, const std::array<T, N>*)
{
if( !naIsVector(ref) )
throw bad_nasal_cast("Not a vector");
if( naVec_size(ref) != N )
throw bad_nasal_cast(
"Expected vector with " + std::to_string(N) + " elements"
);
std::array<T, N> arr;
for(std::size_t i = 0; i < N; ++i)
arr[i] = from_nasal_helper(c, naVec_get(ref, i), static_cast<T*>(0));
return arr;
}
/**
* Convert a Nasal vector of 2 elements to a 2d vector
*/
template<class Vec2>
typename boost::enable_if<is_vec2<Vec2>, Vec2>::type
std::enable_if_t<is_vec2<Vec2>::value, Vec2>
from_nasal_helper(naContext c, naRef ref, const Vec2*)
{
std::vector<double> vec =
from_nasal_helper(c, ref, static_cast<std::vector<double>*>(0));
if( vec.size() != 2 )
throw bad_nasal_cast("Expected vector with two elements");
auto vec =
from_nasal_helper(c, ref, static_cast<std::array<double, 2>*>(0));
return Vec2(vec[0], vec[1]);
}
@ -194,10 +213,8 @@ namespace nasal
template<class T>
SGRect<T> from_nasal_helper(naContext c, naRef ref, const SGRect<T>*)
{
std::vector<double> vec =
from_nasal_helper(c, ref, static_cast<std::vector<double>*>(0));
if( vec.size() != 4 )
throw bad_nasal_cast("Expected vector with four elements");
auto vec =
from_nasal_helper(c, ref, static_cast<std::array<double, 4>*>(0));
return SGRect<T>(vec[0], vec[1], vec[2], vec[3]);
}

View File

@ -25,12 +25,13 @@
#include <simgear/math/SGMath.hxx>
#include <simgear/math/SGRect.hxx>
#include <simgear/nasal/cppbind/cppbind_fwd.hxx>
#include <simgear/std/type_traits.hxx>
#include <boost/function/function_fwd.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/call_traits.hpp>
#include <boost/type_traits.hpp>
#include <array>
#include <initializer_list>
#include <map>
#include <string>
#include <vector>
@ -75,11 +76,66 @@ namespace nasal
naRef to_nasal_helper(naContext c, const free_function_t& func);
namespace detail
{
template<class T>
naRef array_to_nasal(naContext c, const T* arr, size_t size);
}
/**
* Convert a fixed size array to a Nasal vector
*/
template<class T, size_t N>
naRef to_nasal_helper(naContext c, const T(&array)[N])
{
return detail::array_to_nasal(c, array, N);
}
/**
* Convert a fixed size C++ array to a Nasal vector
*/
template<class T, size_t N>
naRef to_nasal_helper(naContext c, const std::array<T, N>& array)
{
return detail::array_to_nasal(c, array.data(), N);
}
/**
* Convert a std::initializer_list to a Nasal vector
*/
template<class T>
naRef to_nasal_helper(naContext c, std::initializer_list<T> list)
{
return detail::array_to_nasal(c, list.begin(), list.size());
}
/**
* Convert std::vector to a Nasal vector
*/
template< template<class T, class Alloc> class Vector,
class T,
class Alloc
>
std::enable_if_t<
std::is_same<Vector<T,Alloc>, std::vector<T,Alloc>>::value,
naRef
>
to_nasal_helper(naContext c, const Vector<T, Alloc>& vec)
{
return detail::array_to_nasal(c, vec.data(), vec.size());
}
/**
* Convert a std::map to a Nasal Hash
*/
template<class Value>
naRef to_nasal_helper(naContext c, const std::map<std::string, Value>& map);
/**
* Convert an enum value to the according numeric value
*/
template<class T>
typename boost::enable_if< boost::is_enum<T>, naRef >::type
std::enable_if_t<std::is_enum<T>::value, naRef>
to_nasal_helper(naContext c, T val)
{
return naNum(val);
@ -89,7 +145,7 @@ namespace nasal
* Convert a numeric type to Nasal number
*/
template<class T>
typename boost::enable_if< boost::is_arithmetic<T>, naRef >::type
std::enable_if_t<std::is_arithmetic<T>::value, naRef>
to_nasal_helper(naContext c, T num)
{
return naNum(num);
@ -99,67 +155,40 @@ namespace nasal
* Convert a 2d vector to Nasal vector with 2 elements
*/
template<class Vec2>
typename boost::enable_if<is_vec2<Vec2>, naRef>::type
to_nasal_helper(naContext c, const Vec2& vec);
/**
* Convert a std::map to a Nasal Hash
*/
template<class Value>
naRef to_nasal_helper(naContext c, const std::map<std::string, Value>& map);
/**
* Convert a fixed size array to a Nasal vector
*/
template<class T, size_t N>
naRef to_nasal_helper(naContext c, const T(&array)[N]);
/**
* Convert std::vector to Nasal vector
*/
template< template<class T, class Alloc> class Vector,
class T,
class Alloc
>
typename boost::enable_if< boost::is_same< Vector<T,Alloc>,
std::vector<T,Alloc>
>,
naRef
>::type
to_nasal_helper(naContext c, const Vector<T, Alloc>& vec)
{
naRef ret = naNewVector(c);
naVec_setsize(c, ret, static_cast<int>(vec.size()));
for(int i = 0; i < static_cast<int>(vec.size()); ++i)
naVec_set(ret, i, to_nasal_helper(c, vec[i]));
return ret;
}
//----------------------------------------------------------------------------
template<class Vec2>
typename boost::enable_if<is_vec2<Vec2>, naRef>::type
std::enable_if_t<is_vec2<Vec2>::value, naRef>
to_nasal_helper(naContext c, const Vec2& vec)
{
// We take just double because in Nasal every number is represented as
// double
double nasal_vec[2] = {
return to_nasal_helper(c, {
// We take just double because in Nasal every number is represented as
// double
static_cast<double>(vec[0]),
static_cast<double>(vec[1])
};
return to_nasal_helper(c, nasal_vec);
});
}
/**
* Convert a SGRect to a Nasal vector with position and size of the rect
*/
template<class T>
naRef to_nasal_helper(naContext c, const SGRect<T>& rect)
{
return to_nasal_helper(c, {
static_cast<double>(rect.x()),
static_cast<double>(rect.y()),
static_cast<double>(rect.width()),
static_cast<double>(rect.height())
});
}
//----------------------------------------------------------------------------
template<class T>
naRef to_nasal_helper(naContext c, const SGRect<T>& rect)
naRef detail::array_to_nasal(naContext c, const T* arr, size_t size)
{
std::vector<double> vec(4);
vec[0] = rect.x();
vec[1] = rect.y();
vec[2] = rect.width();
vec[3] = rect.height();
return to_nasal_helper(c, vec);
naRef ret = naNewVector(c);
naVec_setsize(c, ret, static_cast<int>(size));
for(int i = 0; i < static_cast<int>(size); ++i)
naVec_set(ret, i, to_nasal_helper(c, arr[i]));
return ret;
}
//----------------------------------------------------------------------------
@ -182,17 +211,6 @@ namespace nasal
return hash;
}
//----------------------------------------------------------------------------
template<class T, size_t N>
naRef to_nasal_helper(naContext c, const T(&array)[N])
{
naRef ret = naNewVector(c);
naVec_setsize(c, ret, static_cast<int>(N));
for(int i = 0; i < static_cast<int>(N); ++i)
naVec_set(ret, i, to_nasal_helper(c, array[i]));
return ret;
}
} // namespace nasal
#endif /* SG_TO_NASAL_HELPER_HXX_ */

View File

@ -117,6 +117,51 @@ naRef f_derivedGetX(const Derived& d, naContext c)
}
naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
namespace std
{
template<class T, std::size_t N>
ostream& operator<<(ostream& strm, const array<T, N>& vec)
{
for(auto const& v: vec)
strm << "'" << v << "',";
return strm;
}
}
BOOST_AUTO_TEST_CASE( cppbind_arrays )
{
TestContext ctx;
naRef na_vec = ctx.to_nasal({1., 2., 3.42});
BOOST_REQUIRE( naIsVector(na_vec) );
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(na_vec, 2)), 3.42);
na_vec = ctx.to_nasal(std::initializer_list<double>({1., 2., 3.42}));
BOOST_REQUIRE( naIsVector(na_vec) );
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(na_vec, 2)), 3.42);
using arr_d3_t = std::array<double, 3>;
arr_d3_t std_arr = {1., 2., 3.42};
na_vec = ctx.to_nasal(std_arr);
BOOST_REQUIRE( naIsVector(na_vec) );
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(na_vec, 2)), 3.42);
double d_arr[] = {1., 2., 3.42};
na_vec = ctx.to_nasal(d_arr);
BOOST_REQUIRE( naIsVector(na_vec) );
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(na_vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(na_vec, 2)), 3.42);
BOOST_CHECK_EQUAL(std_arr, ctx.from_nasal<arr_d3_t>(na_vec));
}
BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
{
TestContext c;