Commit 744e66bb authored by Victor Zverovich's avatar Victor Zverovich

Deprecate format_context::parse_context()

parent d231d68a
...@@ -226,7 +226,7 @@ struct result_of<F(Args...)> : std::invoke_result<F, Args...> {}; ...@@ -226,7 +226,7 @@ struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
// A workaround for gcc 4.4 that doesn't allow F to be a reference. // A workaround for gcc 4.4 that doesn't allow F to be a reference.
template <typename F, typename... Args> template <typename F, typename... Args>
struct result_of<F(Args...)> struct result_of<F(Args...)>
: std::result_of<typename std::remove_reference<F>::type(Args...)> {}; : std::result_of<typename std::remove_reference<F>::type(Args...)> {};
#endif #endif
// Casts nonnegative integer to unsigned. // Casts nonnegative integer to unsigned.
...@@ -518,6 +518,63 @@ FMT_CONSTEXPR basic_string_view<typename S::char_type> to_string_view( ...@@ -518,6 +518,63 @@ FMT_CONSTEXPR basic_string_view<typename S::char_type> to_string_view(
return s; return s;
} }
// Parsing context consisting of a format string range being parsed and an
// argument counter for automatic indexing.
template <typename Char, typename ErrorHandler = internal::error_handler>
class basic_parse_context : private ErrorHandler {
private:
basic_string_view<Char> format_str_;
int next_arg_id_;
public:
typedef Char char_type;
typedef typename basic_string_view<Char>::iterator iterator;
explicit FMT_CONSTEXPR basic_parse_context(basic_string_view<Char> format_str,
ErrorHandler eh = ErrorHandler())
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
// Returns an iterator to the beginning of the format string range being
// parsed.
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT {
return format_str_.begin();
}
// Returns an iterator past the end of the format string range being parsed.
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
// Advances the begin iterator to ``it``.
FMT_CONSTEXPR void advance_to(iterator it) {
format_str_.remove_prefix(internal::to_unsigned(it - begin()));
}
// Returns the next argument index.
FMT_CONSTEXPR unsigned next_arg_id();
FMT_CONSTEXPR bool check_arg_id(unsigned) {
if (next_arg_id_ > 0) {
on_error("cannot switch from automatic to manual argument indexing");
return false;
}
next_arg_id_ = -1;
return true;
}
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
FMT_CONSTEXPR void on_error(const char* message) {
ErrorHandler::on_error(message);
}
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
};
typedef basic_parse_context<char> format_parse_context;
typedef basic_parse_context<wchar_t> wformat_parse_context;
FMT_DEPRECATED typedef basic_parse_context<char> parse_context;
FMT_DEPRECATED typedef basic_parse_context<wchar_t> wparse_context;
template <typename Context> class basic_format_arg; template <typename Context> class basic_format_arg;
template <typename Context> class basic_format_args; template <typename Context> class basic_format_args;
...@@ -605,7 +662,9 @@ template <typename Char> struct string_value { ...@@ -605,7 +662,9 @@ template <typename Char> struct string_value {
template <typename Context> struct custom_value { template <typename Context> struct custom_value {
const void* value; const void* value;
void (*format)(const void* arg, Context& ctx); void (*format)(const void* arg,
basic_parse_context<typename Context::char_type>& parse_ctx,
Context& ctx);
}; };
// A formatting argument value. // A formatting argument value.
...@@ -673,9 +732,10 @@ template <typename Context> class value { ...@@ -673,9 +732,10 @@ template <typename Context> class value {
private: private:
// Formats an argument of a custom type, such as a user-defined class. // Formats an argument of a custom type, such as a user-defined class.
template <typename T, typename Formatter> template <typename T, typename Formatter>
static void format_custom_arg(const void* arg, Context& ctx) { static void format_custom_arg(const void* arg,
basic_parse_context<char_type>& parse_ctx,
Context& ctx) {
Formatter f; Formatter f;
auto&& parse_ctx = ctx.parse_context();
parse_ctx.advance_to(f.parse(parse_ctx)); parse_ctx.advance_to(f.parse(parse_ctx));
ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx)); ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
} }
...@@ -866,7 +926,9 @@ template <typename Context> class basic_format_arg { ...@@ -866,7 +926,9 @@ template <typename Context> class basic_format_arg {
public: public:
explicit handle(internal::custom_value<Context> custom) : custom_(custom) {} explicit handle(internal::custom_value<Context> custom) : custom_(custom) {}
void format(Context& ctx) const { custom_.format(custom_.value, ctx); } void format(basic_parse_context<char_type>& parse_ctx, Context& ctx) const {
custom_.format(custom_.value, parse_ctx, ctx);
}
private: private:
internal::custom_value<Context> custom_; internal::custom_value<Context> custom_;
...@@ -938,63 +1000,6 @@ visit(Visitor&& vis, const basic_format_arg<Context>& arg) { ...@@ -938,63 +1000,6 @@ visit(Visitor&& vis, const basic_format_arg<Context>& arg) {
return visit_format_arg(std::forward<Visitor>(vis), arg); return visit_format_arg(std::forward<Visitor>(vis), arg);
} }
// Parsing context consisting of a format string range being parsed and an
// argument counter for automatic indexing.
template <typename Char, typename ErrorHandler = internal::error_handler>
class basic_parse_context : private ErrorHandler {
private:
basic_string_view<Char> format_str_;
int next_arg_id_;
public:
typedef Char char_type;
typedef typename basic_string_view<Char>::iterator iterator;
explicit FMT_CONSTEXPR basic_parse_context(basic_string_view<Char> format_str,
ErrorHandler eh = ErrorHandler())
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
// Returns an iterator to the beginning of the format string range being
// parsed.
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT {
return format_str_.begin();
}
// Returns an iterator past the end of the format string range being parsed.
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
// Advances the begin iterator to ``it``.
FMT_CONSTEXPR void advance_to(iterator it) {
format_str_.remove_prefix(internal::to_unsigned(it - begin()));
}
// Returns the next argument index.
FMT_CONSTEXPR unsigned next_arg_id();
FMT_CONSTEXPR bool check_arg_id(unsigned) {
if (next_arg_id_ > 0) {
on_error("cannot switch from automatic to manual argument indexing");
return false;
}
next_arg_id_ = -1;
return true;
}
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
FMT_CONSTEXPR void on_error(const char* message) {
ErrorHandler::on_error(message);
}
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
};
typedef basic_parse_context<char> format_parse_context;
typedef basic_parse_context<wchar_t> wformat_parse_context;
FMT_DEPRECATED typedef basic_parse_context<char> parse_context;
FMT_DEPRECATED typedef basic_parse_context<wchar_t> wparse_context;
namespace internal { namespace internal {
// A map from argument names to their values for named arguments. // A map from argument names to their values for named arguments.
template <typename Context> class arg_map { template <typename Context> class arg_map {
...@@ -1073,15 +1078,21 @@ class context_base { ...@@ -1073,15 +1078,21 @@ class context_base {
return arg; return arg;
} }
friend basic_parse_context<Char>& get_parse_context(context_base& ctx) {
return ctx.parse_context_;
}
// Checks if manual indexing is used and returns the argument with // Checks if manual indexing is used and returns the argument with
// specified index. // specified index.
format_arg arg(unsigned arg_id) { format_arg arg(unsigned arg_id) {
return this->parse_context().check_arg_id(arg_id) ? this->do_get_arg(arg_id) return parse_context_.check_arg_id(arg_id) ? this->do_get_arg(arg_id)
: format_arg(); : format_arg();
} }
public: public:
basic_parse_context<char_type>& parse_context() { return parse_context_; } FMT_DEPRECATED basic_parse_context<Char>& parse_context() {
return parse_context_;
}
// basic_format_context::arg() depends on this // basic_format_context::arg() depends on this
// Cannot be marked as deprecated without causing warnings // Cannot be marked as deprecated without causing warnings
...@@ -1178,7 +1189,7 @@ class basic_format_context ...@@ -1178,7 +1189,7 @@ class basic_format_context
: base(out, format_str, ctx_args, loc) {} : base(out, format_str, ctx_args, loc) {}
format_arg next_arg() { format_arg next_arg() {
return this->do_get_arg(this->parse_context().next_arg_id()); return this->do_get_arg(get_parse_context(*this).next_arg_id());
} }
format_arg arg(unsigned arg_id) { return this->do_get_arg(arg_id); } format_arg arg(unsigned arg_id) { return this->do_get_arg(arg_id); }
......
...@@ -1576,7 +1576,7 @@ class custom_formatter : public function<bool> { ...@@ -1576,7 +1576,7 @@ class custom_formatter : public function<bool> {
explicit custom_formatter(Context& ctx) : ctx_(ctx) {} explicit custom_formatter(Context& ctx) : ctx_(ctx) {}
bool operator()(typename basic_format_arg<Context>::handle h) const { bool operator()(typename basic_format_arg<Context>::handle h) const {
h.format(ctx_); h.format(get_parse_context(ctx_), ctx_);
return true; return true;
} }
...@@ -1762,14 +1762,14 @@ FMT_CONSTEXPR void set_dynamic_spec(T& value, FormatArg arg, ErrorHandler eh) { ...@@ -1762,14 +1762,14 @@ FMT_CONSTEXPR void set_dynamic_spec(T& value, FormatArg arg, ErrorHandler eh) {
struct auto_id {}; struct auto_id {};
// The standard format specifier handler with checking. // The standard format specifier handler with checking.
template <typename Context> template <typename ParseContext, typename Context>
class specs_handler : public specs_setter<typename Context::char_type> { class specs_handler : public specs_setter<typename Context::char_type> {
public: public:
typedef typename Context::char_type char_type; typedef typename Context::char_type char_type;
FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs, FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs,
Context& ctx) ParseContext& parse_ctx, Context& ctx)
: specs_setter<char_type>(specs), context_(ctx) {} : specs_setter<char_type>(specs), parse_ctx_(parse_ctx), context_(ctx) {}
template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
set_dynamic_spec<width_checker>(this->specs_.width_, get_arg(arg_id), set_dynamic_spec<width_checker>(this->specs_.width_, get_arg(arg_id),
...@@ -1790,10 +1790,11 @@ class specs_handler : public specs_setter<typename Context::char_type> { ...@@ -1790,10 +1790,11 @@ class specs_handler : public specs_setter<typename Context::char_type> {
FMT_CONSTEXPR format_arg get_arg(auto_id) { return context_.next_arg(); } FMT_CONSTEXPR format_arg get_arg(auto_id) { return context_.next_arg(); }
template <typename Id> FMT_CONSTEXPR format_arg get_arg(Id arg_id) { template <typename Id> FMT_CONSTEXPR format_arg get_arg(Id arg_id) {
context_.parse_context().check_arg_id(arg_id); parse_ctx_.check_arg_id(arg_id);
return context_.arg(arg_id); return context_.arg(arg_id);
} }
ParseContext& parse_ctx_;
Context& context_; Context& context_;
}; };
...@@ -2273,7 +2274,7 @@ void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref, ...@@ -2273,7 +2274,7 @@ void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref,
ctx.error_handler()); ctx.error_handler());
break; break;
case arg_ref<char_type>::NAME: { case arg_ref<char_type>::NAME: {
const auto arg_id = ref.val.name.to_view(ctx.parse_context().begin()); const auto arg_id = ref.val.name.to_view(get_parse_context(ctx).begin());
internal::set_dynamic_spec<Handler>(value, ctx.arg(arg_id), internal::set_dynamic_spec<Handler>(value, ctx.arg(arg_id),
ctx.error_handler()); ctx.error_handler());
} break; } break;
...@@ -2316,7 +2317,7 @@ class arg_formatter ...@@ -2316,7 +2317,7 @@ class arg_formatter
/** Formats an argument of a user-defined type. */ /** Formats an argument of a user-defined type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) { iterator operator()(typename basic_format_arg<context_type>::handle handle) {
handle.format(ctx_); handle.format(get_parse_context(ctx_), ctx_);
return this->out(); return this->out();
} }
}; };
...@@ -3181,27 +3182,30 @@ struct format_handler : internal::error_handler { ...@@ -3181,27 +3182,30 @@ struct format_handler : internal::error_handler {
void on_arg_id() { arg = context.next_arg(); } void on_arg_id() { arg = context.next_arg(); }
void on_arg_id(unsigned id) { void on_arg_id(unsigned id) {
context.parse_context().check_arg_id(id); get_parse_context(context).check_arg_id(id);
arg = context.arg(id); arg = context.arg(id);
} }
void on_arg_id(basic_string_view<Char> id) { arg = context.arg(id); } void on_arg_id(basic_string_view<Char> id) { arg = context.arg(id); }
void on_replacement_field(const Char* p) { void on_replacement_field(const Char* p) {
context.parse_context().advance_to(p); get_parse_context(context).advance_to(p);
internal::custom_formatter<Char, Context> f(context); internal::custom_formatter<Char, Context> f(context);
if (!visit_format_arg(f, arg)) if (!visit_format_arg(f, arg))
context.advance_to(visit_format_arg(ArgFormatter(context), arg)); context.advance_to(visit_format_arg(ArgFormatter(context), arg));
} }
const Char* on_format_specs(const Char* begin, const Char* end) { const Char* on_format_specs(const Char* begin, const Char* end) {
auto& parse_ctx = context.parse_context(); auto& parse_ctx = get_parse_context(context);
parse_ctx.advance_to(begin); parse_ctx.advance_to(begin);
internal::custom_formatter<Char, Context> f(context); internal::custom_formatter<Char, Context> f(context);
if (visit_format_arg(f, arg)) return parse_ctx.begin(); if (visit_format_arg(f, arg)) return parse_ctx.begin();
basic_format_specs<Char> specs; basic_format_specs<Char> specs;
using internal::specs_handler; using internal::specs_handler;
internal::specs_checker<specs_handler<Context>> handler( typedef basic_parse_context<Char> parse_context;
specs_handler<Context>(specs, context), arg.type()); internal::specs_checker<specs_handler<parse_context, Context>> handler(
specs_handler<parse_context, Context>(specs, get_parse_context(context),
context),
arg.type());
begin = parse_format_specs(begin, end, handler); begin = parse_format_specs(begin, end, handler);
if (begin == end || *begin != '}') on_error("missing '}' in format string"); if (begin == end || *begin != '}') on_error("missing '}' in format string");
parse_ctx.advance_to(begin); parse_ctx.advance_to(begin);
......
...@@ -57,7 +57,7 @@ template <typename T, typename Char> class is_streamable { ...@@ -57,7 +57,7 @@ template <typename T, typename Char> class is_streamable {
private: private:
template <typename U> template <typename U>
static decltype((void)(internal::declval<test_stream<Char>&>() static decltype((void)(internal::declval<test_stream<Char>&>()
<< internal::declval<U>()), << internal::declval<U>()),
std::true_type()) std::true_type())
test(int); test(int);
......
...@@ -310,12 +310,12 @@ class prepared_format { ...@@ -310,12 +310,12 @@ class prepared_format {
const format_part_t& part) const { const format_part_t& part) const {
const auto view = to_string_view(format_); const auto view = to_string_view(format_);
const auto specification_begin = view.data() + part.end_of_argument_id; const auto specification_begin = view.data() + part.end_of_argument_id;
ctx.parse_context().advance_to(specification_begin); get_parse_context(ctx).advance_to(specification_begin);
} }
template <typename Range, typename Context, typename Id> template <typename Range, typename Context, typename Id>
void format_arg(Context& ctx, Id arg_id) const { void format_arg(Context& ctx, Id arg_id) const {
ctx.parse_context().check_arg_id(arg_id); get_parse_context(ctx).check_arg_id(arg_id);
const auto stopped_at = const auto stopped_at =
visit_format_arg(arg_formatter<Range>(ctx), ctx.arg(arg_id)); visit_format_arg(arg_formatter<Range>(ctx), ctx.arg(arg_id));
ctx.advance_to(stopped_at); ctx.advance_to(stopped_at);
...@@ -537,9 +537,9 @@ struct parts_container_concept_check : std::true_type { ...@@ -537,9 +537,9 @@ struct parts_container_concept_check : std::true_type {
template <typename T> static std::false_type has_add_check(check_second); template <typename T> static std::false_type has_add_check(check_second);
template <typename T> template <typename T>
static decltype((void)declval<T>().add( static decltype(
declval<typename T::format_part_type>()), (void)declval<T>().add(declval<typename T::format_part_type>()),
std::true_type()) has_add_check(check_first); std::true_type()) has_add_check(check_first);
typedef decltype(has_add_check<PartsContainer>(check_first())) has_add; typedef decltype(has_add_check<PartsContainer>(check_first())) has_add;
static_assert(has_add::value, "PartsContainer doesn't provide add() method"); static_assert(has_add::value, "PartsContainer doesn't provide add() method");
...@@ -554,10 +554,9 @@ struct parts_container_concept_check : std::true_type { ...@@ -554,10 +554,9 @@ struct parts_container_concept_check : std::true_type {
template <typename T> template <typename T>
static std::false_type has_substitute_last_check(check_second); static std::false_type has_substitute_last_check(check_second);
template <typename T> template <typename T>
static decltype( static decltype((void)declval<T>().substitute_last(
(void)declval<T>().substitute_last( declval<typename T::format_part_type>()),
declval<typename T::format_part_type>()), std::true_type()) has_substitute_last_check(check_first);
std::true_type()) has_substitute_last_check(check_first);
typedef decltype(has_substitute_last_check<PartsContainer>( typedef decltype(has_substitute_last_check<PartsContainer>(
check_first())) has_substitute_last; check_first())) has_substitute_last;
static_assert(has_substitute_last::value, static_assert(has_substitute_last::value,
......
...@@ -319,7 +319,7 @@ class printf_arg_formatter ...@@ -319,7 +319,7 @@ class printf_arg_formatter
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) { iterator operator()(typename basic_format_arg<context_type>::handle handle) {
handle.format(context_); handle.format(get_parse_context(context_), context_);
return this->out(); return this->out();
} }
}; };
...@@ -380,7 +380,6 @@ class basic_printf_context : ...@@ -380,7 +380,6 @@ class basic_printf_context :
using base::advance_to; using base::advance_to;
using base::out; using base::out;
using base::parse_context;
/** Formats stored arguments and writes the output to the range. */ /** Formats stored arguments and writes the output to the range. */
OutputIt format(); OutputIt format();
...@@ -417,7 +416,7 @@ template <typename OutputIt, typename Char, typename AF> ...@@ -417,7 +416,7 @@ template <typename OutputIt, typename Char, typename AF>
typename basic_printf_context<OutputIt, Char, AF>::format_arg typename basic_printf_context<OutputIt, Char, AF>::format_arg
basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) { basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
if (arg_index == std::numeric_limits<unsigned>::max()) if (arg_index == std::numeric_limits<unsigned>::max())
return this->do_get_arg(this->parse_context().next_arg_id()); return this->do_get_arg(get_parse_context(*this).next_arg_id());
return base::arg(arg_index - 1); return base::arg(arg_index - 1);
} }
...@@ -462,7 +461,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header( ...@@ -462,7 +461,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
template <typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
OutputIt basic_printf_context<OutputIt, Char, AF>::format() { OutputIt basic_printf_context<OutputIt, Char, AF>::format() {
auto out = this->out(); auto out = this->out();
const auto range = this->parse_context(); const auto range = get_parse_context(*this);
const Char* const end = range.end(); const Char* const end = range.end();
const Char* start = range.begin(); const Char* start = range.begin();
auto it = start; auto it = start;
......
...@@ -104,11 +104,10 @@ struct is_range_< ...@@ -104,11 +104,10 @@ struct is_range_<
/// tuple_size and tuple_element check. /// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ { template <typename T> class is_tuple_like_ {
template <typename U> template <typename U>
static auto check(U* p) static auto check(U* p) -> decltype(
-> decltype(std::tuple_size<U>::value, std::tuple_size<U>::value,
(void)internal::declval< (void)internal::declval<typename std::tuple_element<0, U>::type>(),
typename std::tuple_element<0, U>::type>(), int());
int());
template <typename> static void check(...); template <typename> static void check(...);
public: public:
......
...@@ -582,8 +582,9 @@ struct format_handler : fmt::internal::error_handler { ...@@ -582,8 +582,9 @@ struct format_handler : fmt::internal::error_handler {
if (visit_format_arg(f, arg)) return parse_ctx.begin(); if (visit_format_arg(f, arg)) return parse_ctx.begin();
fmt::basic_format_specs<Char> specs; fmt::basic_format_specs<Char> specs;
using fmt::internal::specs_handler; using fmt::internal::specs_handler;
fmt::internal::specs_checker<specs_handler<Context>> handler( using parse_context = basic_format_parse_context<Char>;
specs_handler<Context>(specs, context), get_type(arg)); fmt::internal::specs_checker<specs_handler<parse_context, Context>> handler(
specs_handler<parse_context, Context>(specs, parse_ctx, context), get_type(arg));
begin = parse_format_specs(begin, end, handler); begin = parse_format_specs(begin, end, handler);
if (begin == end || *begin != '}') on_error("missing '}' in format string"); if (begin == end || *begin != '}') on_error("missing '}' in format string");
parse_ctx.advance_to(begin); parse_ctx.advance_to(begin);
......
...@@ -223,10 +223,9 @@ struct custom_context { ...@@ -223,10 +223,9 @@ struct custom_context {
}; };
bool called; bool called;
fmt::format_parse_context ctx;
fmt::format_parse_context parse_context() { fmt::format_parse_context& parse_context() { return ctx; }
return fmt::format_parse_context("");
}
void advance_to(const char*) {} void advance_to(const char*) {}
}; };
...@@ -234,8 +233,8 @@ TEST(ArgTest, MakeValueWithCustomContext) { ...@@ -234,8 +233,8 @@ TEST(ArgTest, MakeValueWithCustomContext) {
test_struct t; test_struct t;
fmt::internal::value<custom_context> arg = fmt::internal::value<custom_context> arg =
fmt::internal::make_value<custom_context>(t); fmt::internal::make_value<custom_context>(t);
custom_context ctx = {false}; custom_context ctx = {false, fmt::format_parse_context("")};
arg.custom.format(&t, ctx); arg.custom.format(&t, ctx.parse_context(), ctx);
EXPECT_TRUE(ctx.called); EXPECT_TRUE(ctx.called);
} }
...@@ -379,7 +378,7 @@ struct check_custom { ...@@ -379,7 +378,7 @@ struct check_custom {
} buffer; } buffer;
fmt::internal::basic_buffer<char>& base = buffer; fmt::internal::basic_buffer<char>& base = buffer;
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args()); fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
h.format(ctx); h.format(get_parse_context(ctx), ctx);
EXPECT_EQ("test", std::string(buffer.data, buffer.size())); EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
return test_result(); return test_result();
} }
......
...@@ -2164,6 +2164,18 @@ TEST(FormatTest, ConstexprParseFormatSpecs) { ...@@ -2164,6 +2164,18 @@ TEST(FormatTest, ConstexprParseFormatSpecs) {
static_assert(parse_test_specs("{<").res == handler::ERROR, ""); static_assert(parse_test_specs("{<").res == handler::ERROR, "");
} }
struct test_parse_context {
typedef char char_type;
FMT_CONSTEXPR unsigned next_arg_id() { return 33; }
template <typename Id> FMT_CONSTEXPR void check_arg_id(Id) {}
FMT_CONSTEXPR const char* begin() { return FMT_NULL; }
FMT_CONSTEXPR const char* end() { return FMT_NULL; }
void on_error(const char*) {}
};
struct test_context { struct test_context {
typedef char char_type; typedef char char_type;
typedef fmt::basic_format_arg<test_context> format_arg; typedef fmt::basic_format_arg<test_context> format_arg;
...@@ -2181,23 +2193,18 @@ struct test_context { ...@@ -2181,23 +2193,18 @@ struct test_context {
return fmt::internal::make_arg<test_context>(22); return fmt::internal::make_arg<test_context>(22);
} }
template <typename Id> FMT_CONSTEXPR void check_arg_id(Id) {}
FMT_CONSTEXPR unsigned next_arg_id() { return 33; }
void on_error(const char*) {} void on_error(const char*) {}
FMT_CONSTEXPR test_context& parse_context() { return *this; }
FMT_CONSTEXPR test_context error_handler() { return *this; } FMT_CONSTEXPR test_context error_handler() { return *this; }
FMT_CONSTEXPR const char* begin() { return FMT_NULL; }
FMT_CONSTEXPR const char* end() { return FMT_NULL; }
}; };
template <size_t N> template <size_t N>
FMT_CONSTEXPR fmt::format_specs parse_specs(const char (&s)[N]) { FMT_CONSTEXPR fmt::format_specs parse_specs(const char (&s)[N]) {
fmt::format_specs specs; fmt::format_specs specs;
test_parse_context parse_ctx;
test_context ctx{}; test_context ctx{};
fmt::internal::specs_handler<test_context> h(specs, ctx); fmt::internal::specs_handler<test_parse_context, test_context> h(
specs, parse_ctx, ctx);
parse_format_specs(s, s + N, h); parse_format_specs(s, s + N, h);
return specs; return specs;
} }
...@@ -2223,8 +2230,8 @@ template <size_t N> ...@@ -2223,8 +2230,8 @@ template <size_t N>
FMT_CONSTEXPR fmt::internal::dynamic_format_specs<char> parse_dynamic_specs( FMT_CONSTEXPR fmt::internal::dynamic_format_specs<char> parse_dynamic_specs(
const char (&s)[N]) { const char (&s)[N]) {
fmt::internal::dynamic_format_specs<char> specs; fmt::internal::dynamic_format_specs<char> specs;
test_context ctx{}; test_parse_context ctx{};
fmt::internal::dynamic_specs_handler<test_context> h(specs, ctx); fmt::internal::dynamic_specs_handler<test_parse_context> h(specs, ctx);
parse_format_specs(s, s + N, h); parse_format_specs(s, s + N, h);
return specs; return specs;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment