Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the s format specifier to bool (#2094) #2109

Merged
merged 1 commit into from
Jan 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1423,6 +1423,14 @@ FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
}
}

template <typename Char, typename Handler>
FMT_CONSTEXPR void handle_bool_type_spec(const basic_format_specs<Char>* specs,
Handler&& handler) {
if (!specs) return handler.on_str();
if (specs->type && specs->type != 's') return handler.on_int();
handler.on_str();
}

template <typename ErrorHandler = error_handler, typename Char>
FMT_CONSTEXPR float_specs parse_float_type_spec(
const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) {
Expand Down Expand Up @@ -1542,6 +1550,21 @@ class cstring_type_checker : public ErrorHandler {
FMT_CONSTEXPR void on_pointer() {}
};

template <typename ErrorHandler>
class bool_type_checker : private ErrorHandler {
private:
char type_;

public:
FMT_CONSTEXPR explicit bool_type_checker(char type, ErrorHandler eh)
: ErrorHandler(eh), type_(type) {}

FMT_CONSTEXPR void on_int() {
handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this));
}
FMT_CONSTEXPR void on_str() {}
};

template <typename OutputIt, typename Char>
FMT_NOINLINE FMT_CONSTEXPR OutputIt fill(OutputIt it, size_t n,
const fill_t<Char>& fill) {
Expand Down Expand Up @@ -2344,7 +2367,8 @@ class arg_formatter_base {
}

FMT_CONSTEXPR iterator operator()(bool value) {
if (specs_ && specs_->type) return (*this)(value ? 1 : 0);
if (specs_ && specs_->type && specs_->type != 's')
return (*this)(value ? 1 : 0);
write(value != 0);
return out_;
}
Expand Down Expand Up @@ -3515,10 +3539,13 @@ struct formatter<T, Char,
case detail::type::ulong_long_type:
case detail::type::int128_type:
case detail::type::uint128_type:
case detail::type::bool_type:
handle_int_type_spec(specs_.type,
detail::int_type_checker<decltype(eh)>(eh));
break;
case detail::type::bool_type:
handle_bool_type_spec(
&specs_, detail::bool_type_checker<decltype(eh)>(specs_.type, eh));
break;
case detail::type::char_type:
handle_char_specs(
&specs_, detail::char_specs_checker<decltype(eh)>(specs_.type, eh));
Expand Down
4 changes: 3 additions & 1 deletion test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,9 @@ TEST(BoolTest, FormatBool) {
EXPECT_EQ("1", format("{:d}", true));
EXPECT_EQ("true ", format("{:5}", true));
EXPECT_EQ(L"true", format(L"{}", true));
EXPECT_EQ("true", format("{:s}", true));
EXPECT_EQ("false", format("{:s}", false));
EXPECT_EQ("false ", format("{:6s}", false));
}

TEST(FormatterTest, FormatShort) {
Expand Down Expand Up @@ -2435,7 +2438,6 @@ TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("{:.{}}", "argument not found", double);
EXPECT_ERROR("{:.2}", "precision not allowed for this argument type", int);
EXPECT_ERROR("{:s}", "invalid type specifier", int);
EXPECT_ERROR("{:s}", "invalid type specifier", bool);
EXPECT_ERROR("{:s}", "invalid type specifier", char);
EXPECT_ERROR("{:+}", "invalid format specifier for char", char);
EXPECT_ERROR("{:s}", "invalid type specifier", double);
Expand Down