diff options
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llcommon/always_return.h | 124 | ||||
| -rw-r--r-- | indra/llcommon/function_types.h | 49 | ||||
| -rw-r--r-- | indra/llcommon/lleventdispatcher.cpp | 7 | ||||
| -rw-r--r-- | indra/llcommon/lleventdispatcher.h | 326 | ||||
| -rw-r--r-- | indra/llcommon/llsdutil.h | 4 | ||||
| -rw-r--r-- | indra/llcommon/tests/lleventdispatcher_test.cpp | 62 | 
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;  | 
