From 54daa0864afb57e9d12c26f50a4c4e2f1e2d5dea Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 10 Aug 2020 09:13:13 -0700 Subject: [PATCH] Add dynamic width support to FMT_COMPILE (#1809) --- include/fmt/compile.h | 14 ++++++++------ include/fmt/core.h | 8 +++++--- test/compile-test.cc | 5 +++++ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 679da4f2..40e1a5a0 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -443,7 +443,8 @@ template struct spec_field { OutputIt format(OutputIt out, const Args&... args) const { // This ensures that the argument type is convertile to `const T&`. const T& arg = get(args...); - basic_format_context ctx(out, {}); + const auto& vargs = make_format_args(args...); + basic_format_context ctx(out, vargs); return fmt.format(arg, ctx); } }; @@ -502,16 +503,17 @@ constexpr auto parse_tail(T head, S format_str) { template struct parse_specs_result { formatter fmt; size_t end; + int next_arg_id; }; template constexpr parse_specs_result parse_specs(basic_string_view str, - size_t pos) { + size_t pos, int arg_id) { str.remove_prefix(pos); - auto ctx = basic_format_parse_context(str); + auto ctx = basic_format_parse_context(str, {}, arg_id + 1); auto f = formatter(); auto end = f.parse(ctx); - return {f, pos + (end - str.data()) + 1}; + return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()}; } // Compiles a non-empty format string and returns the compiled representation @@ -531,8 +533,8 @@ constexpr auto compile_format_string(S format_str) { format_str); } else if constexpr (str[POS + 1] == ':') { using type = get_type; - constexpr auto result = parse_specs(str, POS + 2); - return parse_tail( + constexpr auto result = parse_specs(str, POS + 2, ID); + return parse_tail( spec_field{result.fmt}, format_str); } else { return unknown_format(); diff --git a/include/fmt/core.h b/include/fmt/core.h index 2816a64b..2b474e36 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -298,7 +298,8 @@ template struct std_string_view {}; #ifdef FMT_USE_INT128 // Do nothing. -#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && !(FMT_CLANG_VERSION && FMT_MSC_VER) +#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ + !(FMT_CLANG_VERSION && FMT_MSC_VER) # define FMT_USE_INT128 1 using int128_t = __int128_t; using uint128_t = __uint128_t; @@ -556,8 +557,9 @@ class basic_format_parse_context : private ErrorHandler { using iterator = typename basic_string_view::iterator; explicit constexpr basic_format_parse_context( - basic_string_view format_str, ErrorHandler eh = {}) - : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} + basic_string_view format_str, ErrorHandler eh = {}, + int next_arg_id = 0) + : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {} /** Returns an iterator to the beginning of the format string range being diff --git a/test/compile-test.cc b/test/compile-test.cc index 6dca548d..fd98c772 100644 --- a/test/compile-test.cc +++ b/test/compile-test.cc @@ -153,6 +153,11 @@ TEST(CompileTest, FormatSpecs) { EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42)); } +TEST(CompileTest, DynamicWidth) { + EXPECT_EQ(" 42foo ", + fmt::format(FMT_COMPILE("{:{}}{:{}}"), 42, 4, "foo", 5)); +} + TEST(CompileTest, FormatTo) { char buf[8]; auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);