diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/apply.h | 68 | ||||
-rw-r--r-- | indra/llcommon/tests/llleap_test.cpp | 14 |
2 files changed, 71 insertions, 11 deletions
diff --git a/indra/llcommon/apply.h b/indra/llcommon/apply.h index ef4a8fd68b..7c58d63bc0 100644 --- a/indra/llcommon/apply.h +++ b/indra/llcommon/apply.h @@ -12,11 +12,48 @@ #if ! defined(LL_APPLY_H) #define LL_APPLY_H +#include <boost/type_traits/function_traits.hpp> #include <tuple> namespace LL { +/** + * USAGE NOTE: + * https://stackoverflow.com/a/40523474/5533635 + * + * If you're trying to pass apply() a variadic function, the compiler + * complains that it can't deduce the callable type, presumably because it + * doesn't know which arity to reify to pass. + * + * But it works to wrap the variadic function in a generic lambda, e.g.: + * + * @CODE + * LL::apply( + * [](auto&&... args) + * { + * return variadic(std::forward<decltype(args)>(args)...); + * }, + * args); + * @ENDCODE + * + * Presumably this is because there's only one instance of the generic lambda + * @em type, with a variadic <tt>operator()()</tt>. + * + * It's pointless to provide a wrapper @em function that implicitly supplies + * the generic lambda. You couldn't pass your variadic function to our wrapper + * function, for the same original reason! + * + * Instead we provide a wrapper @em macro. Sorry, Dr. Stroustrup. + */ +#define VAPPLY(FUNC, ARGS) \ + LL::apply( \ + [](auto&&... args) \ + { \ + return (FUNC)(std::forward<decltype(args)>(args)...); \ + }, \ + (ARGS)) + #if __cplusplus >= 201703L // C++17 implementation @@ -34,16 +71,43 @@ auto apply_impl(CALLABLE&& func, TUPLE&& args, std::index_sequence<I...>) } template <typename CALLABLE, typename... ARGS> -auto apply(CALLABLE&& func, std::tuple<ARGS...>&& args) +auto apply(CALLABLE&& func, const std::tuple<ARGS...>& args) { // std::index_sequence_for is the magic sauce here, generating an argument // pack of indexes for each entry in args. apply_impl() can then pass // those to std::get() to unpack args into individual arguments. return apply_impl(std::forward<CALLABLE>(func), - std::forward<std::tuple<ARGS...>>(args), + args, std::index_sequence_for<ARGS...>{}); } +// per https://stackoverflow.com/a/57510428/5533635 +template <typename CALLABLE, typename T, size_t SIZE> +auto apply(CALLABLE&& func, const std::array<T, SIZE>& args) +{ + return apply(std::forward<CALLABLE>(func), std::tuple_cat(args)); +} + +// per https://stackoverflow.com/a/28411055/5533635 +template <typename CALLABLE, typename T, std::size_t... I> +auto apply_impl(CALLABLE&& func, const std::vector<T>& args, std::index_sequence<I...>) +{ + return apply_impl(std::forward<CALLABLE>(func), + std::make_tuple(std::forward<T>(args[I])...), + I...); +} + +// this goes beyond C++17 std::apply() +template <typename CALLABLE, typename T> +auto apply(CALLABLE&& func, const std::vector<T>& args) +{ + constexpr auto arity = boost::function_traits<CALLABLE>::arity; + assert(args.size() == arity); + return apply_impl(std::forward<CALLABLE>(func), + args, + std::make_index_sequence<arity>()); +} + #endif // C++14 } // namespace LL diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 9754353ab0..25db4b6542 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -15,10 +15,11 @@ #include "llleap.h" // STL headers // std headers +#include <functional> // external library headers +//#include <boost/algorithm/string/join.hpp> #include <boost/assign/list_of.hpp> #include <boost/phoenix/core/argument.hpp> -#include <boost/foreach.hpp> // other Linden headers #include "../test/lltut.h" #include "../test/namedtempfile.h" @@ -29,7 +30,6 @@ #include "llstring.h" #include "stringize.h" #include "StringVec.h" -#include <functional> using boost::assign::list_of; @@ -110,11 +110,6 @@ namespace tut "import os\n" "import sys\n" "\n" - // Don't forget that this Python script is written to some - // temp directory somewhere! Its __file__ is useless in - // finding indra/lib/python. Use our __FILE__, with - // raw-string syntax to deal with Windows pathnames. - "mydir = os.path.dirname(r'" << __FILE__ << "')\n" "from llbase import llsd\n" "\n" "class ProtocolError(Exception):\n" @@ -241,9 +236,10 @@ namespace tut "import sys\n" "sys.stderr.write('''Hello from Python!\n" "note partial line''')\n"); + StringVec vcommand{ PYTHON, script.getName() }; +// std::string command{ boost::algorithm::join(vcommand, " ") }; CaptureLog log(LLError::LEVEL_INFO); - waitfor(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + waitfor(LLLeap::create(get_test_name(), vcommand)); log.messageWith("Hello from Python!"); log.messageWith("note partial line"); } |