diff options
| -rw-r--r-- | indra/llcommon/apply.h | 6 | ||||
| -rw-r--r-- | indra/llcommon/llsdutil.h | 6 | ||||
| -rw-r--r-- | indra/llcommon/tests/apply_test.cpp | 52 | 
3 files changed, 62 insertions, 2 deletions
diff --git a/indra/llcommon/apply.h b/indra/llcommon/apply.h index 26753f5017..9f4c268895 100644 --- a/indra/llcommon/apply.h +++ b/indra/llcommon/apply.h @@ -108,7 +108,11 @@ auto apply_impl(CALLABLE&& func, const std::vector<T>& args, std::index_sequence                   std::make_tuple(args[I]...));  } -// this goes beyond C++17 std::apply() +/** + * apply(function, std::vector) goes beyond C++17 std::apply(). For this case + * @a function @emph cannot be variadic: the compiler must know at compile + * time how many arguments to pass. This isn't Python. + */  template <typename CALLABLE, typename T>  auto apply(CALLABLE&& func, const std::vector<T>& args)  { diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index eaf8825791..eddaa64bd2 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -31,6 +31,7 @@  #include "llsd.h"  #include <boost/functional/hash.hpp> +#include <boost/type_traits.hpp>  #include <cassert>  // U32 @@ -601,6 +602,11 @@ auto apply_impl(CALLABLE&& func, const LLSD& array, std::index_sequence<I...>)      return std::forward<CALLABLE>(func)(LLSDParam<LLSD>(array[I])...);  } +/** + * apply(function, LLSD) goes beyond C++17 std::apply(). For this case + * @a function @emph cannot be variadic: the compiler must know at compile + * time how many arguments to pass. This isn't Python. + */  template <typename CALLABLE>  auto apply(CALLABLE&& func, const LLSD& args)  { diff --git a/indra/llcommon/tests/apply_test.cpp b/indra/llcommon/tests/apply_test.cpp index 1f1085a702..28ee3f9c81 100644 --- a/indra/llcommon/tests/apply_test.cpp +++ b/indra/llcommon/tests/apply_test.cpp @@ -15,12 +15,27 @@  #include "apply.h"  // STL headers  // std headers +#include <iomanip>  // external library headers  // other Linden headers -#include "../test/lltut.h"  #include "llsd.h"  #include "llsdutil.h" +// for ensure_equals +std::ostream& operator<<(std::ostream& out, const std::vector<std::string>& stringvec) +{ +    const char* delim = "["; +    for (const auto& str : stringvec) +    { +        out << delim << std::quoted(str); +        delim = ", "; +    } +    return out << ']'; +} + +// the above must be declared BEFORE ensure_equals(std::vector<std::string>) +#include "../test/lltut.h" +  /*****************************************************************************  *   TUT  *****************************************************************************/ @@ -54,6 +69,8 @@ namespace tut          // ensure that apply() actually reaches the target method --          // lack of ensure_equals() failure could be due to no-op apply()          bool called{ false }; +        // capture calls from collect() +        std::vector<std::string> collected;          /*------------------------- test functions -------------------------*/          void various(LLSD::Boolean b, LLSD::Integer i, LLSD::Real f, const LLSD::String& s, @@ -101,6 +118,20 @@ namespace tut          {              called = true;          } + +        // recursion tail +        void collect() +        { +            called = true; +        } + +        // collect(arbitrary) +        template <typename... ARGS> +        void collect(const std::string& first, ARGS&&... rest) +        { +            statics::collected.push_back(first); +            collect(std::forward<ARGS>(rest)...); +        }      } // namespace statics      struct apply_data @@ -109,6 +140,7 @@ namespace tut          {              // reset called before each test              statics::called = false; +            statics::collected.clear();          }      };      typedef test_group<apply_data> apply_group; @@ -168,4 +200,22 @@ namespace tut                                statics::uu, statics::dt, statics::uri, statics::bin));          ensure("apply(LLSD array) failed", statics::called);      } + +    template<> template<> +    void object::test<7>() +    { +        set_test_name("VAPPLY()"); +        // Make a std::array<std::string> from statics::quick. We can't call a +        // variadic function with a data structure of dynamic length. +        std::array<std::string, 5> strray; +        for (size_t i = 0; i < strray.size(); ++i) +            strray[i] = statics::quick[i]; +        // This doesn't work: the compiler doesn't know which overload of +        // collect() to pass to LL::apply(). +        // LL::apply(statics::collect, strray); +        // That's what VAPPLY() is for. +        VAPPLY(statics::collect, strray); +        ensure("VAPPLY() failed", statics::called); +        ensure_equals("collected mismatch", statics::collected, statics::quick); +    }  } // namespace tut  | 
