From aadb38a5e6190a647035321cc988430abea22ffa Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 23 Oct 2017 21:02:54 -0700 Subject: [PATCH] Make specs_checker constexpr --- include/fmt/format.h | 79 +++++++++++++++++++++++++------------------- test/format-test.cc | 24 ++++++++++++++ 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 54cdbe2d..298db537 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1088,12 +1088,12 @@ enum type { CSTRING, STRING, TSTRING, POINTER, CUSTOM }; -inline bool is_integral(type t) { +constexpr bool is_integral(type t) { FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type"); return t > internal::NONE && t <= internal::LAST_INTEGER_TYPE; } -inline bool is_numeric(type t) { +constexpr bool is_numeric(type t) { FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type"); return t > internal::NONE && t <= internal::LAST_NUMERIC_TYPE; } @@ -2378,11 +2378,8 @@ void basic_writer::write_str( internal::report_unknown_type(spec.type_, "string"); const StrChar *str_value = s.data(); std::size_t str_size = s.size(); - if (str_size == 0) { - if (!str_value) { - FMT_THROW(format_error("string pointer is null")); - } - } + if (str_size == 0 && !str_value) + FMT_THROW(format_error("string pointer is null")); std::size_t precision = static_cast(spec.precision_); if (spec.precision_ >= 0 && precision < str_size) str_size = precision; @@ -3072,38 +3069,52 @@ struct is_integer { }; }; -struct width_checker { +template +class width_checker { + public: + explicit constexpr width_checker(ErrorHandler &eh) : handler_(eh) {} + template constexpr typename std::enable_if< is_integer::value, unsigned long long>::type operator()(T value) { if (is_negative(value)) - FMT_THROW(format_error("negative width")); + handler_.on_error("negative width"); return value; } template constexpr typename std::enable_if< !is_integer::value, unsigned long long>::type operator()(T) { - FMT_THROW(format_error("width is not integer")); + handler_.on_error("width is not integer"); return 0; } + + private: + ErrorHandler &handler_; }; -struct precision_checker { +template +class precision_checker { + public: + explicit constexpr precision_checker(ErrorHandler &eh) : handler_(eh) {} + template constexpr typename std::enable_if< is_integer::value, unsigned long long>::type operator()(T value) { if (is_negative(value)) - FMT_THROW(format_error("negative precision")); + handler_.on_error("negative precision"); return value; } template constexpr typename std::enable_if< !is_integer::value, unsigned long long>::type operator()(T) { - FMT_THROW(format_error("precision is not integer")); + handler_.on_error("precision is not integer"); return 0; } + + private: + ErrorHandler &handler_; }; struct error_handler { @@ -3148,41 +3159,41 @@ class specs_setter : public error_handler { template class specs_checker : public Handler { public: - specs_checker(const Handler& handler, type arg_type) + constexpr specs_checker(const Handler& handler, internal::type arg_type) : Handler(handler), arg_type_(arg_type) {} - void on_align(alignment align) { + constexpr void on_align(alignment align) { if (align == ALIGN_NUMERIC) require_numeric_argument('='); Handler::on_align(align); } - void on_plus() { + constexpr void on_plus() { check_sign('+'); Handler::on_plus(); } - void on_minus() { + constexpr void on_minus() { check_sign('-'); Handler::on_minus(); } - void on_space() { + constexpr void on_space() { check_sign(' '); Handler::on_space(); } - void on_hash() { + constexpr void on_hash() { require_numeric_argument('#'); Handler::on_hash(); } - void on_zero() { + constexpr void on_zero() { require_numeric_argument('0'); Handler::on_zero(); } - void end_precision() { + constexpr void end_precision() { if (is_integral(arg_type_) || arg_type_ == POINTER) { report_error("precision not allowed in {} format specifier", arg_type_ == POINTER ? "pointer" : "integer"); @@ -3191,12 +3202,12 @@ class specs_checker : public Handler { private: template - static void report_error(string_view format_str, const Args &... args) { - FMT_THROW(format_error(format(format_str, args...))); + void report_error(string_view format_str, const Args &... args) { + this->on_error(format(format_str, args...).c_str()); } template - void require_numeric_argument(Char spec) const { + constexpr void require_numeric_argument(Char spec) { if (!is_numeric(arg_type_)) { report_error("format specifier '{}' requires numeric argument", static_cast(spec)); @@ -3204,7 +3215,7 @@ class specs_checker : public Handler { } template - void check_sign(Char sign) const { + constexpr void check_sign(Char sign) { require_numeric_argument(sign); if (is_integral(arg_type_) && arg_type_ != INT && arg_type_ != LONG_LONG && arg_type_ != CHAR) { @@ -3213,14 +3224,15 @@ class specs_checker : public Handler { } } - type arg_type_; + internal::type arg_type_; }; -template +template