From db9ffa14055b38dc1a208e764c36bed511bea50b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 29 Oct 2017 07:32:14 -0700 Subject: [PATCH] Make parse_format_string constexpr --- include/fmt/format.h | 18 +++++++++++------- test/format-test.cc | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 4f193308..07e96132 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3519,7 +3519,7 @@ constexpr Iterator parse_format_specs(Iterator it, SpecHandler &handler) { } template -void parse_format_string(Iterator it, Handler &handler) { +constexpr void parse_format_string(Iterator it, Handler &handler) { using char_type = typename std::iterator_traits::value_type; auto start = it; while (*it) { @@ -3530,20 +3530,24 @@ void parse_format_string(Iterator it, Handler &handler) { start = ++it; continue; } - if (ch == '}') + if (ch == '}') { handler.on_error("unmatched '}' in format string"); + return; + } handler.on_text(start, it - 1); struct id_adapter { - explicit id_adapter(Handler &h): handler(h) {} + constexpr explicit id_adapter(Handler &h): handler(h) {} - void operator()() { handler.on_arg_id(); } - void operator()(unsigned id) { handler.on_arg_id(id); } - void operator()(basic_string_view id) { + constexpr void operator()() { handler.on_arg_id(); } + constexpr void operator()(unsigned id) { handler.on_arg_id(id); } + constexpr void operator()(basic_string_view id) { handler.on_arg_id(id); } - void on_error(const char *message) { handler.on_error(message); } + constexpr void on_error(const char *message) { + handler.on_error(message); + } Handler &handler; } adapter(handler); diff --git a/test/format-test.cc b/test/format-test.cc index 9cf8fb27..5d90b17f 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1780,3 +1780,35 @@ TEST(FormatTest, ConstexprSpecsChecker) { static_assert(check_specs("d").type == 'd', ""); static_assert(check_specs("{<").res == handler::ERROR, ""); } + +struct test_format_string_handler { + constexpr void on_text(const char *, const char *) {} + + constexpr void on_arg_id() {} + + template + constexpr void on_arg_id(T) {} + + constexpr void on_replacement_field(const char *) {} + + constexpr const char *on_format_specs(const char *s) { return s; } + + constexpr void on_error(const char *) { error = true; } + + bool error = false; +}; + +constexpr bool parse_string(const char *s) { + test_format_string_handler h; + fmt::internal::parse_format_string(s, h); + return !h.error; +} + +TEST(FormatTest, ConstexprParseFormatString) { + static_assert(parse_string("foo"), ""); + static_assert(!parse_string("}"), ""); + static_assert(parse_string("{}"), ""); + static_assert(parse_string("{42}"), ""); + static_assert(parse_string("{foo}"), ""); + static_assert(parse_string("{:}"), ""); +}