summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/always_return.h124
-rw-r--r--indra/llcommon/function_types.h49
-rw-r--r--indra/llcommon/lleventdispatcher.cpp7
-rw-r--r--indra/llcommon/lleventdispatcher.h326
-rw-r--r--indra/llcommon/llsdutil.h4
-rw-r--r--indra/llcommon/tests/lleventdispatcher_test.cpp62
7 files changed, 460 insertions, 114 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 33e8301e12..64751926d0 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -117,11 +117,13 @@ set(llcommon_SOURCE_FILES
set(llcommon_HEADER_FILES
CMakeLists.txt
+ always_return.h
apply.h
chrono.h
classic_callback.h
ctype_workaround.h
fix_macros.h
+ function_types.h
indra_constants.h
lazyeventapi.h
linden_common.h
diff --git a/indra/llcommon/always_return.h b/indra/llcommon/always_return.h
new file mode 100644
index 0000000000..6b9f1fdeaf
--- /dev/null
+++ b/indra/llcommon/always_return.h
@@ -0,0 +1,124 @@
+/**
+ * @file always_return.h
+ * @author Nat Goodspeed
+ * @date 2023-01-20
+ * @brief Call specified callable with arbitrary arguments, but always return
+ * specified type.
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Copyright (c) 2023, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_ALWAYS_RETURN_H)
+#define LL_ALWAYS_RETURN_H
+
+#include <type_traits> // std::enable_if, std::is_convertible
+
+namespace LL
+{
+
+#if __cpp_lib_is_invocable >= 201703L // C++17
+ template <typename CALLABLE, typename... ARGS>
+ using invoke_result = std::invoke_result<CALLABLE, ARGS...>;
+#else // C++14
+ template <typename CALLABLE, typename... ARGS>
+ using invoke_result = std::result_of<CALLABLE(ARGS...)>;
+#endif // C++14
+
+ /**
+ * AlwaysReturn<T>()(some_function, some_args...) calls
+ * some_function(some_args...). It is guaranteed to return a value of type
+ * T, regardless of the return type of some_function(). If some_function()
+ * returns a type convertible to T, it will convert and return that value.
+ * Otherwise (notably if some_function() is void), AlwaysReturn returns
+ * T().
+ *
+ * When some_function() returns a type not convertible to T, if
+ * you want AlwaysReturn to return some T value other than
+ * default-constructed T(), pass that value to AlwaysReturn's constructor.
+ */
+ template <typename DESIRED>
+ class AlwaysReturn
+ {
+ public:
+ /// pass explicit default value if other than default-constructed type
+ AlwaysReturn(const DESIRED& dft=DESIRED()): mDefault(dft) {}
+
+ // callable returns a type not convertible to DESIRED, return default
+ template <typename CALLABLE, typename... ARGS,
+ typename std::enable_if<
+ ! std::is_convertible<
+ typename invoke_result<CALLABLE, ARGS...>::type,
+ DESIRED
+ >::value,
+ bool
+ >::type=true>
+ DESIRED operator()(CALLABLE&& callable, ARGS&&... args)
+ {
+ // discard whatever callable(args) returns
+ std::forward<CALLABLE>(callable)(std::forward<ARGS>(args)...);
+ return mDefault;
+ }
+
+ // callable returns a type convertible to DESIRED
+ template <typename CALLABLE, typename... ARGS,
+ typename std::enable_if<
+ std::is_convertible<
+ typename invoke_result<CALLABLE, ARGS...>::type,
+ DESIRED
+ >::value,
+ bool
+ >::type=true>
+ DESIRED operator()(CALLABLE&& callable, ARGS&&... args)
+ {
+ return { std::forward<CALLABLE>(callable)(std::forward<ARGS>(args)...) };
+ }
+
+ private:
+ DESIRED mDefault;
+ };
+
+ /**
+ * always_return<T>(some_function, some_args...) calls
+ * some_function(some_args...). It is guaranteed to return a value of type
+ * T, regardless of the return type of some_function(). If some_function()
+ * returns a type convertible to T, it will convert and return that value.
+ * Otherwise (notably if some_function() is void), always_return() returns
+ * T().
+ */
+ template <typename DESIRED, typename CALLABLE, typename... ARGS>
+ DESIRED always_return(CALLABLE&& callable, ARGS&&... args)
+ {
+ return AlwaysReturn<DESIRED>()(std::forward<CALLABLE>(callable),
+ std::forward<ARGS>(args)...);
+ }
+
+ /**
+ * make_always_return<T>(some_function) returns a callable which, when
+ * called with appropriate some_function() arguments, always returns a
+ * value of type T, regardless of the return type of some_function(). If
+ * some_function() returns a type convertible to T, the returned callable
+ * will convert and return that value. Otherwise (notably if
+ * some_function() is void), the returned callable returns T().
+ *
+ * When some_function() returns a type not convertible to T, if
+ * you want the returned callable to return some T value other than
+ * default-constructed T(), pass that value to make_always_return() as its
+ * optional second argument.
+ */
+ template <typename DESIRED, typename CALLABLE>
+ auto make_always_return(CALLABLE&& callable, const DESIRED& dft=DESIRED())
+ {
+ return
+ [dft, callable = std::forward<CALLABLE>(callable)]
+ (auto&&... args)
+ {
+ return AlwaysReturn<DESIRED>(dft)(callable,
+ std::forward<decltype(args)>(args)...);
+ };
+ }
+
+} // namespace LL
+
+#endif /* ! defined(LL_ALWAYS_RETURN_H) */
diff --git a/indra/llcommon/function_types.h b/indra/llcommon/function_types.h
new file mode 100644
index 0000000000..3f42f6d640
--- /dev/null
+++ b/indra/llcommon/function_types.h
@@ -0,0 +1,49 @@
+/**
+ * @file function_types.h
+ * @author Nat Goodspeed
+ * @date 2023-01-20
+ * @brief Extend boost::function_types to examine boost::function and
+ * std::function
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Copyright (c) 2023, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_FUNCTION_TYPES_H)
+#define LL_FUNCTION_TYPES_H
+
+#include <boost/function.hpp>
+#include <boost/function_types/function_arity.hpp>
+#include <functional>
+
+namespace LL
+{
+
+ template <typename F>
+ struct function_arity_impl
+ {
+ static constexpr auto value = boost::function_types::function_arity<F>::value;
+ };
+
+ template <typename F>
+ struct function_arity_impl<std::function<F>>
+ {
+ static constexpr auto value = function_arity_impl<F>::value;
+ };
+
+ template <typename F>
+ struct function_arity_impl<boost::function<F>>
+ {
+ static constexpr auto value = function_arity_impl<F>::value;
+ };
+
+ template <typename F>
+ struct function_arity
+ {
+ static constexpr auto value = function_arity_impl<typename std::decay<F>::type>::value;
+ };
+
+} // namespace LL
+
+#endif /* ! defined(LL_FUNCTION_TYPES_H) */
diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp
index d10cf16b88..caff854753 100644
--- a/indra/llcommon/lleventdispatcher.cpp
+++ b/indra/llcommon/lleventdispatcher.cpp
@@ -384,8 +384,7 @@ struct LLEventDispatcher::LLSDDispatchEntry: public LLEventDispatcher::DispatchE
(desc, ": bad request: ", mismatch);
}
// Event syntax looks good, go for it!
- mFunc(event);
- return {};
+ return mFunc(event);
}
LLSD addMetadata(LLSD meta) const override
@@ -603,8 +602,8 @@ void LLEventDispatcher::addMapParamsDispatchEntry(const std::string& name,
}
/// Register a callable by name
-void LLEventDispatcher::add(const std::string& name, const std::string& desc,
- const Callable& callable, const LLSD& required)
+void LLEventDispatcher::addLLSD(const std::string& name, const std::string& desc,
+ const Callable& callable, const LLSD& required)
{
mDispatch.emplace(name, new LLSDDispatchEntry(desc, callable, required));
}
diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h
index 5ab860b6dd..789a59459c 100644
--- a/indra/llcommon/lleventdispatcher.h
+++ b/indra/llcommon/lleventdispatcher.h
@@ -32,17 +32,18 @@
#if ! defined(LL_LLEVENTDISPATCHER_H)
#define LL_LLEVENTDISPATCHER_H
-#include <boost/iterator/transform_iterator.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
#include <boost/function_types/is_nonmember_callable_builtin.hpp>
-#include <boost/function_types/function_arity.hpp>
-#include <boost/function_types/result_type.hpp>
+#include <boost/hof/is_invocable.hpp> // until C++17, when we get std::is_invocable
+#include <boost/iterator/transform_iterator.hpp>
#include <functional> // std::function
#include <memory> // std::unique_ptr
#include <string>
#include <typeinfo>
#include <type_traits>
#include <utility> // std::pair
+#include "always_return.h"
+#include "function_types.h" // LL::function_arity
#include "llevents.h"
#include "llptrto.h"
#include "llsdutil.h"
@@ -78,7 +79,7 @@ public:
//@{
/// Accept any C++ callable with the right signature
- typedef std::function<void(const LLSD&)> Callable;
+ typedef std::function<LLSD(const LLSD&)> Callable;
/**
* Register a @a callable by @a name. The passed @a callable accepts a
@@ -90,19 +91,25 @@ public:
void add(const std::string& name,
const std::string& desc,
const Callable& callable,
- const LLSD& required=LLSD());
+ const LLSD& required=LLSD())
+ {
+ addLLSD(name, desc, callable, required);
+ }
- /**
- * The case of a free function (or static method) accepting(const LLSD&)
- * could also be intercepted by the arbitrary-args overload below. Ensure
- * that it's directed to the Callable overload above instead.
- */
+ template <typename CALLABLE,
+ typename=typename std::enable_if<
+ boost::hof::is_invocable<CALLABLE, LLSD>::value
+ >::type>
void add(const std::string& name,
const std::string& desc,
- void (*f)(const LLSD&),
+ CALLABLE&& callable,
const LLSD& required=LLSD())
{
- add(name, desc, Callable(f), required);
+ addLLSD(
+ name,
+ desc,
+ Callable(LL::make_always_return<LLSD>(std::forward<CALLABLE>(callable))),
+ required);
}
/**
@@ -111,6 +118,27 @@ public:
* specifying a <tt>std::bind()</tt> expression. The passed @a method
* accepts a single LLSD value, presumably containing other parameters.
*/
+ template <typename R, class CLASS>
+ void add(const std::string& name,
+ const std::string& desc,
+ R (CLASS::*method)(const LLSD&),
+ const LLSD& required=LLSD())
+ {
+ addMethod<CLASS>(name, desc, method, required);
+ }
+
+ /// Overload for both const and non-const methods. The passed @a method
+ /// accepts a single LLSD value, presumably containing other parameters.
+ template <typename R, class CLASS>
+ void add(const std::string& name,
+ const std::string& desc,
+ R (CLASS::*method)(const LLSD&) const,
+ const LLSD& required=LLSD())
+ {
+ addMethod<CLASS>(name, desc, method, required);
+ }
+
+ // because the compiler can't match a method returning void to the above
template <class CLASS>
void add(const std::string& name,
const std::string& desc,
@@ -131,6 +159,128 @@ public:
addMethod<CLASS>(name, desc, method, required);
}
+ // non-const nullary method
+ template <typename R, class CLASS>
+ void add(const std::string& name,
+ const std::string& desc,
+ R (CLASS::*method)())
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // const nullary method
+ template <typename R, class CLASS>
+ void add(const std::string& name,
+ const std::string& desc,
+ R (CLASS::*method)() const)
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // non-const nullary method returning void
+ template <class CLASS>
+ void add(const std::string& name,
+ const std::string& desc,
+ void (CLASS::*method)())
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // const nullary method returning void
+ template <class CLASS>
+ void add(const std::string& name,
+ const std::string& desc,
+ void (CLASS::*method)() const)
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // non-const unary method (but method accepting LLSD should use the other add())
+ // enable_if usage per https://stackoverflow.com/a/39913395/5533635
+ template <typename R, class CLASS, typename ARG,
+ typename = typename std::enable_if<
+ ! std::is_same<typename std::decay<ARG>::type, LLSD>::value
+ >::type>
+ void add(const std::string& name,
+ const std::string& desc,
+ R (CLASS::*method)(ARG))
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // const unary method (but method accepting LLSD should use the other add())
+ template <typename R, class CLASS, typename ARG,
+ typename = typename std::enable_if<
+ ! std::is_same<typename std::decay<ARG>::type, LLSD>::value
+ >::type>
+ void add(const std::string& name,
+ const std::string& desc,
+ R (CLASS::*method)(ARG) const)
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // non-const unary method returning void
+ // enable_if usage per https://stackoverflow.com/a/39913395/5533635
+ template <class CLASS, typename ARG,
+ typename = typename std::enable_if<
+ ! std::is_same<typename std::decay<ARG>::type, LLSD>::value
+ >::type>
+ void add(const std::string& name,
+ const std::string& desc,
+ void (CLASS::*method)(ARG))
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // const unary method returning void
+ template <class CLASS, typename ARG,
+ typename = typename std::enable_if<
+ ! std::is_same<typename std::decay<ARG>::type, LLSD>::value
+ >::type>
+ void add(const std::string& name,
+ const std::string& desc,
+ void (CLASS::*method)(ARG) const)
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // non-const binary (or more) method
+ template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS>
+ void add(const std::string& name,
+ const std::string& desc,
+ R (CLASS::*method)(ARG0, ARG1, ARGS...))
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // const binary (or more) method
+ template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS>
+ void add(const std::string& name,
+ const std::string& desc,
+ R (CLASS::*method)(ARG0, ARG1, ARGS...) const)
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // non-const binary (or more) method returning void
+ template <class CLASS, typename ARG0, typename ARG1, typename... ARGS>
+ void add(const std::string& name,
+ const std::string& desc,
+ void (CLASS::*method)(ARG0, ARG1, ARGS...))
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
+ // const binary (or more) method returning void
+ template <class CLASS, typename ARG0, typename ARG1, typename... ARGS>
+ void add(const std::string& name,
+ const std::string& desc,
+ void (CLASS::*method)(ARG0, ARG1, ARGS...) const)
+ {
+ addVMethod<CLASS>(name, desc, method);
+ }
+
//@}
/// @name Register functions with arbitrary param lists
@@ -143,12 +293,16 @@ public:
* When calling this name, pass an LLSD::Array. Each entry in turn will be
* converted to the corresponding parameter type using LLSDParam.
*/
- // enable_if usage per https://stackoverflow.com/a/39913395/5533635
- template<typename Function,
- typename = typename std::enable_if<
- boost::function_types::is_nonmember_callable_builtin<Function>::value
+ template <typename CALLABLE,
+ typename=typename std::enable_if<
+ ! boost::hof::is_invocable<CALLABLE, LLSD>()
>::type>
- void add(const std::string& name, const std::string& desc, Function f);
+ void add(const std::string& name,
+ const std::string& desc,
+ CALLABLE&& f)
+ {
+ addV(name, desc, f);
+ }
/**
* Register a nonstatic class method with arbitrary parameters.
@@ -156,11 +310,7 @@ public:
* To cover cases such as a method on an LLSingleton we don't yet want to
* instantiate, instead of directly storing an instance pointer, accept a
* nullary callable returning a pointer/reference to the desired class
- * instance. If you already have an instance in hand,
- * boost::lambda::var(instance) or boost::lambda::constant(instance_ptr)
- * produce suitable callables.
- *
- * TODO: variant accepting a method of the containing class, no getter.
+ * instance.
*
* When calling this name, pass an LLSD::Array. Each entry in turn will be
* converted to the corresponding parameter type using LLSDParam.
@@ -186,7 +336,8 @@ public:
*/
template<typename Function,
typename = typename std::enable_if<
- boost::function_types::is_nonmember_callable_builtin<Function>::value
+ boost::function_types::is_nonmember_callable_builtin<Function>::value &&
+ ! boost::hof::is_invocable<Function, LLSD>::value
>::type>
void add(const std::string& name, const std::string& desc, Function f,
const LLSD& params, const LLSD& defaults=LLSD());
@@ -348,6 +499,11 @@ public:
friend std::ostream& operator<<(std::ostream&, const LLEventDispatcher&);
private:
+ void addLLSD(const std::string& name,
+ const std::string& desc,
+ const Callable& callable,
+ const LLSD& required);
+
template <class CLASS, typename METHOD>
void addMethod(const std::string& name, const std::string& desc,
const METHOD& method, const LLSD& required)
@@ -359,9 +515,40 @@ private:
}
else
{
- add(name, desc, std::bind(method, downcast, std::placeholders::_1), required);
+ add(name,
+ desc,
+ Callable(LL::make_always_return<LLSD>(
+ [downcast, method]
+ (const LLSD& args)
+ {
+ return (downcast->*method)(args);
+ })),
+ required);
}
}
+
+ template <class CLASS, typename METHOD>
+ void addVMethod(const std::string& name, const std::string& desc,
+ const METHOD& method)
+ {
+ CLASS* downcast = dynamic_cast<CLASS*>(this);
+ if (! downcast)
+ {
+ addFail(name, typeid(CLASS).name());
+ }
+ else
+ {
+ // add() arbitrary method plus InstanceGetter, where the
+ // InstanceGetter in this case returns 'this'. We don't need to
+ // worry about binding 'this' because, once this LLEventDispatcher
+ // is destroyed, the DispatchEntry goes away too.
+ add(name, desc, method, [downcast](){ return downcast; });
+ }
+ }
+
+ template <typename Function>
+ void addV(const std::string& name, const std::string& desc, Function f);
+
void addFail(const std::string& name, const std::string& classname) const;
LLSD try_call(const std::string& key, const std::string& name,
const LLSD& event) const;
@@ -405,21 +592,19 @@ private:
const invoker_function& invoker,
const LLSD& params,
const LLSD& defaults);
- template <typename RETURNTYPE>
- struct ReturnLLSD;
};
/*****************************************************************************
* LLEventDispatcher template implementation details
*****************************************************************************/
-template<typename Function, typename>
-void LLEventDispatcher::add(const std::string& name, const std::string& desc, Function f)
+template <typename Function>
+void LLEventDispatcher::addV(const std::string& name, const std::string& desc, Function f)
{
// Construct an invoker_function, a callable accepting const LLSD&.
// Add to DispatchMap an ArrayParamsDispatchEntry that will handle the
// caller's LLSD::Array.
addArrayParamsDispatchEntry(name, desc, make_invoker(f),
- boost::function_types::function_arity<Function>::value);
+ LL::function_arity<Function>::value);
}
template<typename Method, typename InstanceGetter, typename>
@@ -429,7 +614,7 @@ void LLEventDispatcher::add(const std::string& name, const std::string& desc, Me
// Subtract 1 from the compile-time arity because the getter takes care of
// the first parameter. We only need (arity - 1) additional arguments.
addArrayParamsDispatchEntry(name, desc, make_invoker(f, getter),
- boost::function_types::function_arity<Method>::value - 1);
+ LL::function_arity<Method>::value - 1);
}
template<typename Function, typename>
@@ -448,64 +633,23 @@ void LLEventDispatcher::add(const std::string& name, const std::string& desc, Me
addMapParamsDispatchEntry(name, desc, make_invoker(f, getter), params, defaults);
}
-// general case, when f() has a non-void return type
-template <typename RETURNTYPE>
-struct LLEventDispatcher::ReturnLLSD
-{
- template <typename Function>
- LLSD operator()(Function f, const LLSD& args)
- {
- return { LL::apply(f, args) };
- }
-
- template <typename Method, typename InstanceGetter>
- LLSD operator()(Method f, const InstanceGetter& getter, const LLSD& args)
- {
- constexpr auto arity = boost::function_types::function_arity<
- typename std::remove_reference<Method>::type>::value - 1;
-
- // Use bind_front() to bind the method to (a pointer to) the object
- // returned by getter(). It's okay to capture and bind a pointer
- // because this bind_front() object will last only as long as this
- // operator() call.
- return { LL::apply_n<arity>(LL::bind_front(f, LL::get_ptr(getter())), args) };
- }
-};
-
-// specialize for void return type
-template <>
-struct LLEventDispatcher::ReturnLLSD<void>
-{
- template <typename Function>
- LLSD operator()(Function f, const LLSD& args)
- {
- LL::apply(f, args);
- return {};
- }
-
- template <typename Method, typename InstanceGetter>
- LLSD operator()(Method f, const InstanceGetter& getter, const LLSD& args)
- {
- constexpr auto arity = boost::function_types::function_arity<
- typename std::remove_reference<Method>::type>::value - 1;
-
- // Use bind_front() to bind the method to (a pointer to) the object
- // returned by getter(). It's okay to capture and bind a pointer
- // because this bind_front() object will last only as long as this
- // operator() call.
- LL::apply_n<arity>(LL::bind_front(f, LL::get_ptr(getter())), args);
- return {};
- }
-};
-
template <typename Function>
LLEventDispatcher::invoker_function
LLEventDispatcher::make_invoker(Function f)
{
+ // Return an invoker_function that accepts (const LLSD& args).
return [f](const LLSD& args)
{
- return ReturnLLSD<typename boost::function_types::result_type<Function>::type>()
- (f, args);
+ // When called, call always_return<LLSD>, directing it to call
+ // f(expanded args). always_return<LLSD> guarantees we'll get an LLSD
+ // value back, even if it's undefined because 'f' doesn't return a
+ // type convertible to LLSD.
+ return LL::always_return<LLSD>(
+ [f, args]
+ ()
+ {
+ return LL::apply(f, args);
+ });
};
}
@@ -513,10 +657,24 @@ template <typename Method, typename InstanceGetter>
LLEventDispatcher::invoker_function
LLEventDispatcher::make_invoker(Method f, const InstanceGetter& getter)
{
+ // function_arity<member function> includes its implicit 'this' pointer
+ constexpr auto arity = LL::function_arity<
+ typename std::remove_reference<Method>::type>::value - 1;
+
return [f, getter](const LLSD& args)
{
- return ReturnLLSD<typename boost::function_types::result_type<Method>::type>()
- (f, getter, args);
+ // always_return<LLSD>() immediately calls the lambda we pass, and
+ // returns LLSD whether our passed lambda returns void or non-void.
+ return LL::always_return<LLSD>(
+ [f, getter, args]
+ ()
+ {
+ // Use bind_front() to bind the method to (a pointer to) the object
+ // returned by getter(). It's okay to capture and bind a pointer
+ // because this bind_front() object will last only as long as this
+ // lambda call.
+ return LL::apply_n<arity>(LL::bind_front(f, LL::get_ptr(getter())), args);
+ });
};
}
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index baf4400768..a6fd2fdac2 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -30,9 +30,9 @@
#define LL_LLSDUTIL_H
#include "apply.h" // LL::invoke()
+#include "function_types.h" // LL::function_arity
#include "llsd.h"
#include <boost/functional/hash.hpp>
-#include <boost/function_types/function_arity.hpp>
#include <cassert>
#include <type_traits>
@@ -628,7 +628,7 @@ template <typename CALLABLE>
auto apply(CALLABLE&& func, const LLSD& args)
{
// infer arity from the definition of func
- constexpr auto arity = boost::function_types::function_arity<
+ constexpr auto arity = function_arity<
typename std::remove_reference<CALLABLE>::type>::value;
// now that we have a compile-time arity, apply_n() works
return apply_n<arity>(std::forward<CALLABLE>(func), args);
diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp
index 8e84a9e038..2a3644e2e1 100644
--- a/indra/llcommon/tests/lleventdispatcher_test.cpp
+++ b/indra/llcommon/tests/lleventdispatcher_test.cpp
@@ -423,9 +423,9 @@ namespace tut
work.add(name, desc, &Dispatcher::cmethod1, required);
// Non-subclass method with/out required params
addf("method1", "method1", &v);
- work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1));
+ work.add(name, desc, [this](const LLSD& args){ return v.method1(args); });
addf("method1_req", "method1", &v);
- work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1), required);
+ work.add(name, desc, [this](const LLSD& args){ return v.method1(args); }, required);
/*--------------- Arbitrary params, array style ----------------*/
@@ -609,6 +609,7 @@ namespace tut
void addf(const std::string& n, const std::string& d, Vars* v)
{
+ debug("addf('", n, "', '", d, "')");
// This method is to capture in our own DescMap the name and
// description of every registered function, for metadata query
// testing.
@@ -1339,22 +1340,25 @@ namespace tut
DispatchResult(): LLDispatchListener("results", "op")
{
- // As of 2022-12-22, LLEventDispatcher's shorthand add() methods
- // for pointer-to-method of same instance only support methods
- // with signature void(const LLSD&). The generic add(pointer-to-
- // method) requires an instance getter.
- add("strfunc", "return string", &DR::strfunc, [this](){ return this; });
- add("voidfunc", "void function", &DR::voidfunc, [this](){ return this; });
- add("emptyfunc", "return empty LLSD", &DR::emptyfunc, [this](){ return this; });
- add("intfunc", "return Integer LLSD", &DR::intfunc, [this](){ return this; });
- add("mapfunc", "return map LLSD", &DR::mapfunc, [this](){ return this; });
- add("arrayfunc", "return array LLSD", &DR::arrayfunc, [this](){ return this; });
+ add("strfunc", "return string", &DR::strfunc);
+ add("voidfunc", "void function", &DR::voidfunc);
+ add("emptyfunc", "return empty LLSD", &DR::emptyfunc);
+ add("intfunc", "return Integer LLSD", &DR::intfunc);
+ add("llsdfunc", "return passed LLSD", &DR::llsdfunc);
+ add("mapfunc", "return map LLSD", &DR::mapfunc);
+ add("arrayfunc", "return array LLSD", &DR::arrayfunc);
}
std::string strfunc(const std::string& str) const { return "got " + str; }
void voidfunc() const {}
LLSD emptyfunc() const { return {}; }
int intfunc(int i) const { return -i; }
+ LLSD llsdfunc(const LLSD& event) const
+ {
+ LLSD result{ event };
+ result["with"] = "string";
+ return result;
+ }
LLSD mapfunc(int i, const std::string& str) const
{
return llsd::map("i", intfunc(i), "str", strfunc(str));
@@ -1395,6 +1399,16 @@ namespace tut
template<> template<>
void object::test<26>()
{
+ set_test_name("LLSD echo");
+ DispatchResult service;
+ LLSD result{ service("llsdfunc", llsd::map("op", "llsdfunc", "reqid", 17)) };
+ ensure_equals("llsdfunc() mismatch", result,
+ llsd::map("op", "llsdfunc", "reqid", 17, "with", "string"));
+ }
+
+ template<> template<>
+ void object::test<27>()
+ {
set_test_name("map LLSD result");
DispatchResult service;
LLSD result{ service("mapfunc", llsd::array(-12, "value")) };
@@ -1402,7 +1416,7 @@ namespace tut
}
template<> template<>
- void object::test<27>()
+ void object::test<28>()
{
set_test_name("array LLSD result");
DispatchResult service;
@@ -1411,7 +1425,7 @@ namespace tut
}
template<> template<>
- void object::test<28>()
+ void object::test<29>()
{
set_test_name("listener error, no reply");
DispatchResult service;
@@ -1422,7 +1436,7 @@ namespace tut
}
template<> template<>
- void object::test<29>()
+ void object::test<30>()
{
set_test_name("listener error with reply");
DispatchResult service;
@@ -1435,7 +1449,7 @@ namespace tut
}
template<> template<>
- void object::test<30>()
+ void object::test<31>()
{
set_test_name("listener call to void function");
DispatchResult service;
@@ -1452,7 +1466,7 @@ namespace tut
}
template<> template<>
- void object::test<31>()
+ void object::test<32>()
{
set_test_name("listener call to string function");
DispatchResult service;
@@ -1468,7 +1482,7 @@ namespace tut
}
template<> template<>
- void object::test<32>()
+ void object::test<33>()
{
set_test_name("listener call to map function");
DispatchResult service;
@@ -1485,7 +1499,7 @@ namespace tut
}
template<> template<>
- void object::test<33>()
+ void object::test<34>()
{
set_test_name("batched map success");
DispatchResult service;
@@ -1512,7 +1526,7 @@ namespace tut
}
template<> template<>
- void object::test<34>()
+ void object::test<35>()
{
set_test_name("batched map error");
DispatchResult service;
@@ -1545,7 +1559,7 @@ namespace tut
}
template<> template<>
- void object::test<35>()
+ void object::test<36>()
{
set_test_name("batched map exception");
DispatchResult service;
@@ -1568,7 +1582,7 @@ namespace tut
}
template<> template<>
- void object::test<36>()
+ void object::test<37>()
{
set_test_name("batched array success");
DispatchResult service;
@@ -1602,7 +1616,7 @@ namespace tut
}
template<> template<>
- void object::test<37>()
+ void object::test<38>()
{
set_test_name("batched array error");
DispatchResult service;
@@ -1633,7 +1647,7 @@ namespace tut
}
template<> template<>
- void object::test<38>()
+ void object::test<39>()
{
set_test_name("batched array exception");
DispatchResult service;