diff --git a/include/etl/format.h b/include/etl/format.h index 8820ac6f..830e64a6 100644 --- a/include/etl/format.h +++ b/include/etl/format.h @@ -35,7 +35,6 @@ SOFTWARE. #include "algorithm.h" #include "array.h" -#include "array_view.h" #include "error_handler.h" #include "limits.h" #include "math.h" @@ -627,7 +626,7 @@ namespace etl }; template - struct has_formatter_parse&>().parse(etl::declval()))> > + struct has_formatter_parse&>().parse(etl::declval()))>> : etl::true_type { }; @@ -642,7 +641,7 @@ namespace etl template struct has_formatter_format&>().format( - etl::declval(), etl::declval&>()))> > : etl::true_type + etl::declval(), etl::declval&>()))>> : etl::true_type { }; @@ -806,7 +805,7 @@ namespace etl // Converting constructor for user-defined types that provide an // etl::formatter specialisation. The value is stored type-erased in a // handle, matching the std::basic_format_arg behaviour for custom types. - template ::value> > + template ::value>> basic_format_arg(const T& v) : data(handle(v)) { @@ -863,7 +862,7 @@ namespace etl return _args.get(i); } - etl::array_view> get() + etl::span> get() { return _args; } @@ -884,6 +883,15 @@ namespace etl { } + // non-standard + // Constructs from externally owned storage, for cases where the number of + // arguments is only known at runtime and so no format_arg_store + // can be formed. The referenced storage must outlive this object. + explicit basic_format_args(etl::span> args_) + : _args(args_) + { + } + basic_format_args(const basic_format_args& other) : _args(other._args) { @@ -908,7 +916,7 @@ namespace etl private: - etl::array_view> _args; + etl::span> _args; }; namespace private_format @@ -2019,7 +2027,7 @@ namespace etl } // for user-defined types routed through basic_format_arg::handle - void operator()(typename basic_format_arg >::handle h) + void operator()(typename basic_format_arg>::handle h) { h.format(parse_ctx, fmt_ctx); } diff --git a/test/test_format.cpp b/test/test_format.cpp index 480345b5..bfd4c848 100644 --- a/test/test_format.cpp +++ b/test/test_format.cpp @@ -950,6 +950,29 @@ namespace CHECK_EQUAL("010", test_format(s, "{:#o}", 8)); } + //************************************************************************* + // Arguments whose count is only known at runtime cannot be held in a + // format_arg_store, so basic_format_args can also be built + // directly over caller owned storage. + TEST(test_vformat_to_runtime_sized_args) + { + etl::string<100> s; + + using iterator_t = etl::back_insert_iterator>; + using arg_t = etl::format_arg; + + etl::array storage = {arg_t(1), arg_t("two"), arg_t(3), arg_t('x')}; + + // Only the first three of the four slots are used. + etl::vformat_to(etl::back_inserter(s), "{} {} {}", etl::format_args(etl::span(storage.data(), 3U))); + CHECK_EQUAL("1 two 3", s); + + // An empty argument list is also valid. + s.clear(); + etl::vformat_to(etl::back_inserter(s), "no args", etl::format_args(etl::span())); + CHECK_EQUAL("no args", s); + } + //************************************************************************* TEST(test_format_custom_type) {