From 8e0c15e32e4a6e7f0cc21cf10456875b1c332164 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Wed, 6 Mar 2013 17:00:38 +0100 Subject: [PATCH] cppbind: allow adding free functions accepting nasal::CallContext and do some cleanup --- simgear/nasal/cppbind/CMakeLists.txt | 1 + simgear/nasal/cppbind/Ghost.hxx | 137 ++++-------------- simgear/nasal/cppbind/NasalCallContext.hxx | 135 +++++++++++++++++ simgear/nasal/cppbind/cppbind_test.cxx | 9 +- .../nasal/cppbind/detail/to_nasal_helper.cxx | 50 ++++++- .../nasal/cppbind/detail/to_nasal_helper.hxx | 16 +- 6 files changed, 221 insertions(+), 127 deletions(-) create mode 100644 simgear/nasal/cppbind/NasalCallContext.hxx diff --git a/simgear/nasal/cppbind/CMakeLists.txt b/simgear/nasal/cppbind/CMakeLists.txt index 0439e6ed..32a08904 100644 --- a/simgear/nasal/cppbind/CMakeLists.txt +++ b/simgear/nasal/cppbind/CMakeLists.txt @@ -2,6 +2,7 @@ include (SimGearComponent) set(HEADERS Ghost.hxx + NasalCallContext.hxx NasalHash.hxx NasalString.hxx from_nasal.hxx diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index 4c185a2c..7354644a 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -20,8 +20,7 @@ #ifndef SG_NASAL_GHOST_HXX_ #define SG_NASAL_GHOST_HXX_ -#include "from_nasal.hxx" -#include "to_nasal.hxx" +#include "NasalCallContext.hxx" #include @@ -122,120 +121,20 @@ namespace nasal BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type) + template + struct reduced_type + { + typedef typename boost::remove_cv< + typename boost::remove_reference::type + >::type type; + }; + template struct reduced_is_same: - public boost::is_same< - typename boost::remove_cv< - typename boost::remove_reference::type - >::type, - T2 - > + public boost::is_same::type, T2> {}; } - /** - * Context passed to a function/method being called from Nasal - */ - struct CallContext - { - CallContext(naContext c, size_t argc, naRef* args): - c(c), - argc(argc), - args(args) - {} - - bool isNumeric(size_t index) const - { - return (index < argc && naIsNum(args[index])); - } - - bool isString(size_t index) const - { - return (index < argc && naIsString(args[index])); - } - - bool isHash(size_t index) const - { - return (index < argc && naIsHash(args[index])); - } - - bool isVector(size_t index) const - { - return (index < argc && naIsVector(args[index])); - } - - bool isGhost(size_t index) const - { - return (index < argc && naIsGhost(args[index])); - } - - void popFront(size_t num = 1) - { - if( argc < num ) - return; - - args += num; - argc -= num; - } - - void popBack(size_t num = 1) - { - if( argc < num ) - return; - - argc -= num; - } - - /** - * Get the argument with given index if it exists. Otherwise returns the - * passed default value. - * - * @tparam T Type of argument (converted using ::from_nasal) - * @param index Index of requested argument - * @param def Default value returned if too few arguments available - */ - template - typename from_nasal_ptr::return_type - getArg(size_t index, const T& def = T()) const - { - if( index >= argc ) - return def; - - return from_nasal(args[index]); - } - - /** - * Get the argument with given index. Raises a Nasal runtime error if there - * are to few arguments available. - */ - template - typename from_nasal_ptr::return_type - requireArg(size_t index) const - { - if( index >= argc ) - naRuntimeError(c, "Missing required arg #%d", index); - - return from_nasal(args[index]); - } - - template - naRef to_nasal(T arg) const - { - return nasal::to_nasal(c, arg); - } - - template - typename from_nasal_ptr::return_type - from_nasal(naRef ref) const - { - return (*from_nasal_ptr::get())(c, ref); - } - - naContext c; - size_t argc; - naRef *args; - }; - /** * Class for exposing C++ objects to Nasal * @@ -972,4 +871,20 @@ namespace nasal } // namespace nasal +/** + * Convert every shared pointer to a ghost. + */ +// Needs to be outside any namespace to mark ADL work +template +typename boost::enable_if< + nasal::internal::has_element_type< + typename nasal::internal::reduced_type::type + >, + naRef +>::type +to_nasal_helper(naContext c, T ptr) +{ + return nasal::Ghost::create(c, ptr); +} + #endif /* SG_NASAL_GHOST_HXX_ */ diff --git a/simgear/nasal/cppbind/NasalCallContext.hxx b/simgear/nasal/cppbind/NasalCallContext.hxx new file mode 100644 index 00000000..235f619d --- /dev/null +++ b/simgear/nasal/cppbind/NasalCallContext.hxx @@ -0,0 +1,135 @@ +///@file +/// Call context for Nasal extension functions +/// +// Copyright (C) 2012 Thomas Geymayer +// +// 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_CALL_CONTEXT_HXX_ +#define SG_NASAL_CALL_CONTEXT_HXX_ + +#include "from_nasal.hxx" +#include "to_nasal.hxx" + +namespace nasal +{ + + /** + * Context passed to a function/method being called from Nasal + */ + struct CallContext + { + CallContext(naContext c, size_t argc, naRef* args): + c(c), + argc(argc), + args(args) + {} + + bool isNumeric(size_t index) const + { + return (index < argc && naIsNum(args[index])); + } + + bool isString(size_t index) const + { + return (index < argc && naIsString(args[index])); + } + + bool isHash(size_t index) const + { + return (index < argc && naIsHash(args[index])); + } + + bool isVector(size_t index) const + { + return (index < argc && naIsVector(args[index])); + } + + bool isGhost(size_t index) const + { + return (index < argc && naIsGhost(args[index])); + } + + void popFront(size_t num = 1) + { + if( argc < num ) + return; + + args += num; + argc -= num; + } + + void popBack(size_t num = 1) + { + if( argc < num ) + return; + + argc -= num; + } + + /** + * Get the argument with given index if it exists. Otherwise returns the + * passed default value. + * + * @tparam T Type of argument (converted using ::from_nasal) + * @param index Index of requested argument + * @param def Default value returned if too few arguments available + */ + template + typename from_nasal_ptr::return_type + getArg(size_t index, const T& def = T()) const + { + if( index >= argc ) + return def; + + return from_nasal(args[index]); + } + + /** + * Get the argument with given index. Raises a Nasal runtime error if there + * are to few arguments available. + */ + template + typename from_nasal_ptr::return_type + requireArg(size_t index) const + { + if( index >= argc ) + naRuntimeError(c, "Missing required arg #%d", index); + + return from_nasal(args[index]); + } + + template + naRef to_nasal(T arg) const + { + return nasal::to_nasal(c, arg); + } + + template + typename from_nasal_ptr::return_type + from_nasal(naRef ref) const + { + return (*from_nasal_ptr::get())(c, ref); + } + + naContext c; + size_t argc; + naRef *args; + }; + +} // namespace nasal + + +#endif /* SG_NASAL_CALL_CONTEXT_HXX_ */ diff --git a/simgear/nasal/cppbind/cppbind_test.cxx b/simgear/nasal/cppbind/cppbind_test.cxx index 23e5e33f..876f3c45 100644 --- a/simgear/nasal/cppbind/cppbind_test.cxx +++ b/simgear/nasal/cppbind/cppbind_test.cxx @@ -64,16 +64,12 @@ typedef boost::shared_ptr DerivedPtr; typedef boost::shared_ptr DoubleDerivedPtr; typedef boost::shared_ptr DoubleDerived2Ptr; -naRef to_nasal_helper(naContext c, const BasePtr& base) -{ - return nasal::Ghost::create(c, base); -} - naRef derivedFreeMember(Derived&, const nasal::CallContext&) { return naNil(); } naRef f_derivedGetX(naContext c, const Derived& d) { return nasal::to_nasal(c, d.getX()); } +naRef f_freeFunction(nasal::CallContext) { return naNil(); } int main(int argc, char* argv[]) { @@ -124,6 +120,7 @@ int main(int argc, char* argv[]) hash.set("vec2", vec); hash.set("name", "my-name"); hash.set("string", std::string("blub")); + hash.set("func", &f_freeFunction); r = to_nasal(c, hash); VERIFY( naIsHash(r) ); @@ -165,6 +162,8 @@ int main(int argc, char* argv[]) .bases< Ghost >() .member("base", &DoubleDerived2::getBase); + nasal::to_nasal(c, DoubleDerived2Ptr()); + BasePtr d( new Derived ); naRef derived = Ghost::create(c, d); VERIFY( naIsGhost(derived) ); diff --git a/simgear/nasal/cppbind/detail/to_nasal_helper.cxx b/simgear/nasal/cppbind/detail/to_nasal_helper.cxx index bc1f25e2..fd744fde 100644 --- a/simgear/nasal/cppbind/detail/to_nasal_helper.cxx +++ b/simgear/nasal/cppbind/detail/to_nasal_helper.cxx @@ -18,9 +18,12 @@ #include "to_nasal_helper.hxx" #include +#include #include +#include + namespace nasal { //---------------------------------------------------------------------------- @@ -37,12 +40,6 @@ namespace nasal return to_nasal_helper(c, std::string(str)); } - //---------------------------------------------------------------------------- - naRef to_nasal_helper(naContext c, naCFunction func) - { - return naNewFunc(c, naNewCCode(c, func)); - } - //---------------------------------------------------------------------------- naRef to_nasal_helper(naContext c, const Hash& hash) { @@ -60,4 +57,45 @@ namespace nasal { return to_nasal_helper(c, path.str()); } + + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, naCFunction func) + { + return naNewFunc(c, naNewCCode(c, func)); + } + + //---------------------------------------------------------------------------- + static naRef free_function_invoker( naContext c, + naRef me, + int argc, + naRef* args, + void* user_data ) + { + free_function_t* func = static_cast(user_data); + assert(func); + return (*func)(nasal::CallContext(c, argc, args)); + } + + //---------------------------------------------------------------------------- + static void free_function_destroy(void* func) + { + delete static_cast(func); + } + + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, const free_function_t& func) + { + return naNewFunc + ( + c, + naNewCCodeUD + ( + c, + &free_function_invoker, + new free_function_t(func), + &free_function_destroy + ) + ); + } + } // namespace nasal diff --git a/simgear/nasal/cppbind/detail/to_nasal_helper.hxx b/simgear/nasal/cppbind/detail/to_nasal_helper.hxx index 237366a9..c74282ef 100644 --- a/simgear/nasal/cppbind/detail/to_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/to_nasal_helper.hxx @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -36,8 +37,11 @@ class SGPath; namespace nasal { + class CallContext; class Hash; + typedef boost::function free_function_t; + /** * Convert std::string to Nasal string */ @@ -49,11 +53,6 @@ namespace nasal // We need this to prevent the array overload of to_nasal being called naRef to_nasal_helper(naContext c, const char* str); - /** - * Convert function pointer to Nasal function - */ - naRef to_nasal_helper(naContext c, naCFunction func); - /** * Convert a nasal::Hash to a Nasal hash */ @@ -66,6 +65,13 @@ namespace nasal naRef to_nasal_helper(naContext c, const SGPath& path); + /** + * Convert function pointer to Nasal function + */ + naRef to_nasal_helper(naContext c, naCFunction func); + + naRef to_nasal_helper(naContext c, const free_function_t& func); + /** * Convert a numeric type to Nasal number */ -- 2.39.5