cppbind: convert Nasal functions to C++ boost::function.
This commit is contained in:
@@ -4,12 +4,14 @@ set(HEADERS
|
|||||||
Ghost.hxx
|
Ghost.hxx
|
||||||
NasalCallContext.hxx
|
NasalCallContext.hxx
|
||||||
NasalHash.hxx
|
NasalHash.hxx
|
||||||
|
NasalObjectHolder.hxx
|
||||||
NasalString.hxx
|
NasalString.hxx
|
||||||
from_nasal.hxx
|
from_nasal.hxx
|
||||||
to_nasal.hxx
|
to_nasal.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(DETAIL_HEADERS
|
set(DETAIL_HEADERS
|
||||||
|
detail/from_nasal_function_templates.hxx
|
||||||
detail/from_nasal_helper.hxx
|
detail/from_nasal_helper.hxx
|
||||||
detail/functor_templates.hxx
|
detail/functor_templates.hxx
|
||||||
detail/nasal_traits.hxx
|
detail/nasal_traits.hxx
|
||||||
@@ -18,6 +20,7 @@ set(DETAIL_HEADERS
|
|||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
NasalHash.cxx
|
NasalHash.cxx
|
||||||
|
NasalObjectHolder.cxx
|
||||||
NasalString.cxx
|
NasalString.cxx
|
||||||
detail/from_nasal_helper.cxx
|
detail/from_nasal_helper.cxx
|
||||||
detail/to_nasal_helper.cxx
|
detail/to_nasal_helper.cxx
|
||||||
|
|||||||
@@ -86,6 +86,21 @@ namespace nasal
|
|||||||
return from_nasal<T>(_context, get(name));
|
return from_nasal<T>(_context, get(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get member converted to callable object
|
||||||
|
*
|
||||||
|
* @tparam Sig Function signature
|
||||||
|
* @param name Member name
|
||||||
|
*/
|
||||||
|
template<class Sig>
|
||||||
|
typename boost::enable_if< boost::is_function<Sig>,
|
||||||
|
boost::function<Sig>
|
||||||
|
>::type
|
||||||
|
get(const std::string& name)
|
||||||
|
{
|
||||||
|
return from_nasal_helper(_context, get(name), static_cast<Sig*>(0));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new child hash (module)
|
* Create a new child hash (module)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Wrapper class for keeping Nasal objects save from the garbage collector
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#include "NasalObjectHolder.hxx"
|
||||||
|
#include <simgear/nasal/nasal.h>
|
||||||
|
|
||||||
|
namespace nasal
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
ObjectHolder::~ObjectHolder()
|
||||||
|
{
|
||||||
|
naGCRelease(_gc_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
naRef ObjectHolder::get_naRef() const
|
||||||
|
{
|
||||||
|
return _ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGSharedPtr<ObjectHolder> ObjectHolder::makeShared(naRef obj)
|
||||||
|
{
|
||||||
|
return new ObjectHolder(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
ObjectHolder::ObjectHolder(naRef obj):
|
||||||
|
_ref(obj),
|
||||||
|
_gc_key(naGCSave(obj))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nasal
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
///@file Wrapper class for keeping Nasal objects save from the garbage collector
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#ifndef SG_NASAL_OBJECT_HOLDER_HXX_
|
||||||
|
#define SG_NASAL_OBJECT_HOLDER_HXX_
|
||||||
|
|
||||||
|
#include <simgear/nasal/naref.h>
|
||||||
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
|
||||||
|
namespace nasal
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent a Nasal object from being destroyed by the garbage collector during
|
||||||
|
* the lifetime of this object.
|
||||||
|
*/
|
||||||
|
class ObjectHolder:
|
||||||
|
public SGReferenced
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
~ObjectHolder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get captured Nasal object
|
||||||
|
*/
|
||||||
|
naRef get_naRef() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the given object as long as the returned holder exists.
|
||||||
|
*
|
||||||
|
* @param obj Object to save
|
||||||
|
*/
|
||||||
|
static SGSharedPtr<ObjectHolder> makeShared(naRef obj);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
naRef _ref;
|
||||||
|
int _gc_key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param obj Object to save
|
||||||
|
*/
|
||||||
|
ObjectHolder(naRef obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nasal
|
||||||
|
|
||||||
|
#endif /* SG_NASAL_OBJECT_HOLDER_HXX_ */
|
||||||
@@ -80,7 +80,7 @@ naRef f_derivedGetX(naContext c, const Derived& d)
|
|||||||
{
|
{
|
||||||
return nasal::to_nasal(c, d.getX());
|
return nasal::to_nasal(c, d.getX());
|
||||||
}
|
}
|
||||||
naRef f_freeFunction(nasal::CallContext) { return naNil(); }
|
naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
@@ -145,6 +145,26 @@ int main(int argc, char* argv[])
|
|||||||
Hash mod = hash.createHash("mod");
|
Hash mod = hash.createHash("mod");
|
||||||
mod.set("parent", hash);
|
mod.set("parent", hash);
|
||||||
|
|
||||||
|
|
||||||
|
// 'func' is a C++ function registered to Nasal and now converted back to C++
|
||||||
|
boost::function<int (int)> f = hash.get<int (int)>("func");
|
||||||
|
VERIFY( f );
|
||||||
|
VERIFY( f(3) == 3 );
|
||||||
|
|
||||||
|
boost::function<std::string (int)> fs = hash.get<std::string (int)>("func");
|
||||||
|
VERIFY( fs );
|
||||||
|
VERIFY( fs(14) == "14" );
|
||||||
|
|
||||||
|
typedef boost::function<void (int)> FuncVoidInt;
|
||||||
|
FuncVoidInt fvi = hash.get<FuncVoidInt>("func");
|
||||||
|
VERIFY( fvi );
|
||||||
|
fvi(123);
|
||||||
|
|
||||||
|
typedef boost::function<std::string (const std::string&, int, float)> FuncMultiArg;
|
||||||
|
FuncMultiArg fma = hash.get<FuncMultiArg>("func");
|
||||||
|
VERIFY( fma );
|
||||||
|
VERIFY( fma("test", 3, .5) == "test" );
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Test exposing classes to Nasal
|
// Test exposing classes to Nasal
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#ifndef SG_FROM_NASAL_HELPER_HXX_
|
||||||
|
# error Nasal cppbind - do not include this file!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define n BOOST_PP_ITERATION()
|
||||||
|
|
||||||
|
#ifndef SG_BOOST_FUNCTION_FROM_NASAL_FWD
|
||||||
|
# define SG_CALL_TRAITS_PARAM(z, n, dummy)\
|
||||||
|
typename boost::call_traits<A##n>::param_type a##n
|
||||||
|
# define SG_CALL_ARG(z, n, dummy)\
|
||||||
|
to_nasal(ctx, a##n)
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Ret
|
||||||
|
BOOST_PP_COMMA_IF(n)
|
||||||
|
BOOST_PP_ENUM_PARAMS(n, class A)
|
||||||
|
>
|
||||||
|
typename boost::disable_if<boost::is_void<Ret>, Ret>::type
|
||||||
|
callNasalFunction( const ObjectHolder* holder
|
||||||
|
BOOST_PP_COMMA_IF(n)
|
||||||
|
BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
naContext ctx = naNewContext();
|
||||||
|
naRef args[] = {
|
||||||
|
BOOST_PP_ENUM(n, SG_CALL_ARG, 0)
|
||||||
|
};
|
||||||
|
const int num_args = sizeof(args)/sizeof(args[0]);
|
||||||
|
|
||||||
|
naRef result =
|
||||||
|
naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil());
|
||||||
|
|
||||||
|
Ret r = from_nasal_helper(ctx, result, static_cast<Ret*>(0));
|
||||||
|
naFreeContext(ctx);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Ret
|
||||||
|
BOOST_PP_COMMA_IF(n)
|
||||||
|
BOOST_PP_ENUM_PARAMS(n, class A)
|
||||||
|
>
|
||||||
|
typename boost::enable_if<boost::is_void<Ret>, Ret>::type
|
||||||
|
callNasalFunction( const ObjectHolder* holder
|
||||||
|
BOOST_PP_COMMA_IF(n)
|
||||||
|
BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
naContext ctx = naNewContext();
|
||||||
|
naRef args[] = {
|
||||||
|
BOOST_PP_ENUM(n, SG_CALL_ARG, 0)
|
||||||
|
};
|
||||||
|
const int num_args = sizeof(args)/sizeof(args[0]);
|
||||||
|
|
||||||
|
naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil());
|
||||||
|
naFreeContext(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
# undef SG_CALL_TRAITS_PARAM
|
||||||
|
# undef SG_CALL_ARG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Ret
|
||||||
|
BOOST_PP_COMMA_IF(n)
|
||||||
|
BOOST_PP_ENUM_PARAMS(n, class A)
|
||||||
|
>
|
||||||
|
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, A))>
|
||||||
|
boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A)))
|
||||||
|
#ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD
|
||||||
|
;
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
return boost::bind
|
||||||
|
(
|
||||||
|
&callNasalFunction<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, A)>,
|
||||||
|
ObjectHolder::makeShared(code)
|
||||||
|
BOOST_PP_COMMA_IF(n)
|
||||||
|
BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef n
|
||||||
@@ -23,13 +23,20 @@
|
|||||||
#include "nasal_traits.hxx"
|
#include "nasal_traits.hxx"
|
||||||
|
|
||||||
#include <simgear/nasal/nasal.h>
|
#include <simgear/nasal/nasal.h>
|
||||||
|
#include <simgear/nasal/cppbind/NasalObjectHolder.hxx>
|
||||||
|
#include <simgear/nasal/cppbind/to_nasal.hxx>
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/call_traits.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||||
|
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
|
||||||
#include <boost/type_traits.hpp>
|
#include <boost/type_traits.hpp>
|
||||||
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <typeinfo> // std::bad_cast
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class SGPath;
|
class SGPath;
|
||||||
@@ -98,6 +105,42 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
bool from_nasal_helper(naContext c, naRef ref, const bool*);
|
bool from_nasal_helper(naContext c, naRef ref, const bool*);
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
#define SG_BOOST_FUNCTION_FROM_NASAL_FWD
|
||||||
|
#define BOOST_PP_ITERATION_LIMITS (0, 9)
|
||||||
|
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
|
||||||
|
#include BOOST_PP_ITERATE()
|
||||||
|
#undef SG_BOOST_FUNCTION_FROM_NASAL_FWD
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Nasal function to a boost::function with the given signature.
|
||||||
|
*
|
||||||
|
* @tparam Sig Signature of returned function (arguments and return value
|
||||||
|
* are automatically converted using from_nasal/to_nasal)
|
||||||
|
*/
|
||||||
|
template<class Sig>
|
||||||
|
boost::function<Sig>
|
||||||
|
from_nasal_helper(naContext c, naRef ref, boost::function<Sig>*)
|
||||||
|
{
|
||||||
|
if( !naIsCode(ref)
|
||||||
|
&& !naIsCCode(ref)
|
||||||
|
&& !naIsFunc(ref) )
|
||||||
|
throw bad_nasal_cast("not a function");
|
||||||
|
|
||||||
|
return detail::boostFunctionFromNasal(ref, static_cast<Sig*>(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Sig>
|
||||||
|
typename boost::enable_if< boost::is_function<Sig>,
|
||||||
|
boost::function<Sig>
|
||||||
|
>::type
|
||||||
|
from_nasal_helper(naContext c, naRef ref, Sig*)
|
||||||
|
{
|
||||||
|
return from_nasal_helper(c, ref, static_cast<boost::function<Sig>*>(0));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a Nasal number to a C++ numeric type
|
* Convert a Nasal number to a C++ numeric type
|
||||||
*/
|
*/
|
||||||
@@ -147,6 +190,14 @@ namespace nasal
|
|||||||
return Vec2(vec[0], vec[1]);
|
return Vec2(vec[0], vec[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helpers for wrapping calls to Nasal functions into boost::function
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
#define BOOST_PP_ITERATION_LIMITS (0, 9)
|
||||||
|
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
|
||||||
|
#include BOOST_PP_ITERATE()
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace nasal
|
} // namespace nasal
|
||||||
|
|
||||||
#endif /* SG_FROM_NASAL_HELPER_HXX_ */
|
#endif /* SG_FROM_NASAL_HELPER_HXX_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user