diff --git a/include/fmt/core.h b/include/fmt/core.h index 4961310a..83adfe2a 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -675,6 +675,20 @@ template class basic_format_parse_context { */ constexpr auto end() const noexcept -> iterator { return format_str_.end(); } + /** + * Checks whether the format string starts with the given prefix + */ + constexpr bool starts_with(iterator prefix) const noexcept { + auto first = begin(); + auto last = end(); + while (first != last && *prefix != '\0') { + if (*prefix++ != *first++) { + return false; + } + } + return *prefix == '\0'; + } + /** Advances the begin iterator to ``it``. */ FMT_CONSTEXPR void advance_to(iterator it) { format_str_.remove_prefix(detail::to_unsigned(it - begin())); diff --git a/test/args-test.cc b/test/args-test.cc index 3ab31335..4ffd3d78 100644 --- a/test/args-test.cc +++ b/test/args-test.cc @@ -38,12 +38,23 @@ struct custom_type { FMT_BEGIN_NAMESPACE template <> struct formatter { - auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { + private: + bool hex = false; + + public: + auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + if (ctx.starts_with("hex")) { + hex = true; + return ctx.begin() + 3; + } return ctx.begin(); } template auto format(const custom_type& p, FormatContext& ctx) -> decltype(ctx.out()) { + if (hex) { + return fmt::format_to(ctx.out(), "cust={:x}", p.i); + } return fmt::format_to(ctx.out(), "cust={}", p.i); } }; @@ -57,9 +68,9 @@ TEST(args_test, custom_format) { store.push_back(c); ++c.i; store.push_back(std::cref(c)); - ++c.i; - auto result = fmt::vformat("{} and {} and {}", store); - EXPECT_EQ("cust=0 and cust=1 and cust=3", result); + c.i = 15; + auto result = fmt::vformat("{} and {} and {:hex}", store); + EXPECT_EQ("cust=0 and cust=1 and cust=f", result); } struct to_stringable {