Simplify format string checks

This commit is contained in:
Victor Zverovich 2021-05-17 18:49:26 -07:00
parent 8d70c0edab
commit ce14eafc24
2 changed files with 14 additions and 38 deletions

View File

@ -2440,9 +2440,9 @@ FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) {
} }
// Checks char specs and returns true if the type spec is char (and not int). // Checks char specs and returns true if the type spec is char (and not int).
template <typename Char, typename ErrorHandler> template <typename Char, typename ErrorHandler = error_handler>
FMT_CONSTEXPR bool check_char_specs(const basic_format_specs<Char>& specs, FMT_CONSTEXPR bool check_char_specs(const basic_format_specs<Char>& specs,
ErrorHandler&& eh) { ErrorHandler&& eh = {}) {
if (specs.type && specs.type != 'c') { if (specs.type && specs.type != 'c') {
check_int_type_spec(specs.type, eh); check_int_type_spec(specs.type, eh);
return false; return false;
@ -2514,23 +2514,11 @@ FMT_CONSTEXPR float_specs parse_float_type_spec(
return result; return result;
} }
template <typename ErrorHandler> template <typename Char, typename ErrorHandler = error_handler>
class cstring_type_checker : public ErrorHandler { FMT_CONSTEXPR bool check_cstring_type_spec(Char spec, ErrorHandler&& eh = {}) {
public: if (spec == 0 || spec == 's') return true;
constexpr explicit cstring_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} if (spec != 'p') eh.on_error("invalid type specifier");
return false;
FMT_CONSTEXPR void on_string() {}
FMT_CONSTEXPR void on_pointer() {}
};
template <typename Char, typename Handler>
FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler&& handler) {
if (spec == 0 || spec == 's')
handler.on_string();
else if (spec == 'p')
handler.on_pointer();
else
handler.on_error("invalid type specifier");
} }
template <typename Char, typename ErrorHandler> template <typename Char, typename ErrorHandler>
@ -2543,8 +2531,8 @@ FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier"); if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier");
} }
// A format specifier handler that checks if specifiers are consistent with the // A parse_format_specs handler that checks if specifiers are consistent with
// argument type. // the argument type.
template <typename Handler> class specs_checker : public Handler { template <typename Handler> class specs_checker : public Handler {
private: private:
detail::type arg_type_; detail::type arg_type_;
@ -2801,8 +2789,7 @@ struct formatter<T, Char,
FMT_ASSERT(false, "long double support disabled"); FMT_ASSERT(false, "long double support disabled");
break; break;
case detail::type::cstring_type: case detail::type::cstring_type:
detail::handle_cstring_type_spec( detail::check_cstring_type_spec(specs_.type, eh);
specs_.type, detail::cstring_type_checker<decltype(eh)>(eh));
break; break;
case detail::type::string_type: case detail::type::string_type:
detail::check_string_type_spec(specs_.type, eh); detail::check_string_type_spec(specs_.type, eh);

View File

@ -1306,7 +1306,7 @@ template <typename Char, typename OutputIt>
FMT_CONSTEXPR OutputIt write(OutputIt out, Char value, FMT_CONSTEXPR OutputIt write(OutputIt out, Char value,
const basic_format_specs<Char>& specs, const basic_format_specs<Char>& specs,
locale_ref loc = {}) { locale_ref loc = {}) {
return check_char_specs(specs, error_handler()) return check_char_specs(specs)
? write_char(out, value, specs) ? write_char(out, value, specs)
: write(out, static_cast<int>(value), specs, loc); : write(out, static_cast<int>(value), specs, loc);
} }
@ -1531,20 +1531,9 @@ template <typename Char, typename OutputIt>
FMT_CONSTEXPR OutputIt write(OutputIt out, const Char* s, FMT_CONSTEXPR OutputIt write(OutputIt out, const Char* s,
const basic_format_specs<Char>& specs, const basic_format_specs<Char>& specs,
locale_ref) { locale_ref) {
struct handler { return check_cstring_type_spec(specs.type)
OutputIt out; ? write(out, basic_string_view<Char>(s), specs, {})
const Char* value; : write_ptr<Char>(out, to_uintptr(s), &specs);
const basic_format_specs<Char>& specs;
void on_string() {
out = write(out, basic_string_view<Char>(value), specs, {});
}
void on_pointer() { out = write_ptr<Char>(out, to_uintptr(value), &specs); }
void on_error(const char* message) { error_handler().on_error(message); }
};
auto h = handler{out, s, specs};
handle_cstring_type_spec(specs.type, h);
return h.out;
} }
template <typename Char, typename OutputIt> template <typename Char, typename OutputIt>