Skip to content

Commit

Permalink
Make format_specs not depend on code unit type
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Jan 17, 2024
1 parent 090ee13 commit 98e1858
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 116 deletions.
9 changes: 4 additions & 5 deletions include/fmt/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -2037,6 +2037,7 @@ using unsigned_char = typename conditional_t<std::is_integral<Char>::value,
std::make_unsigned<Char>,
type_identity<unsigned>>::type;

// Character (code unit) type is erased to prevent template bloat.
struct fill_t {
private:
enum { max_size = 4 };
Expand Down Expand Up @@ -2106,7 +2107,7 @@ enum class presentation_type : unsigned char {
};

// Format specifiers for built-in and string types.
template <typename Char = char> struct format_specs {
struct format_specs {
int width;
int precision;
presentation_type type;
Expand Down Expand Up @@ -2160,8 +2161,7 @@ template <typename Char> struct arg_ref {
// Format specifiers with width and precision resolved at formatting rather
// than parsing time to allow reusing the same parsed specifiers with
// different sets of arguments (precompilation of format strings).
template <typename Char = char>
struct dynamic_format_specs : format_specs<Char> {
template <typename Char = char> struct dynamic_format_specs : format_specs {
arg_ref<Char> width_ref;
arg_ref<Char> precision_ref;
};
Expand Down Expand Up @@ -2636,8 +2636,7 @@ FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx)
}

// Checks char specs and returns true iff the presentation type is char-like.
template <typename Char>
FMT_CONSTEXPR auto check_char_specs(const format_specs<Char>& specs) -> bool {
FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool {
if (specs.type != presentation_type::none &&
specs.type != presentation_type::chr &&
specs.type != presentation_type::debug) {
Expand Down
6 changes: 3 additions & 3 deletions include/fmt/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -1733,7 +1733,7 @@ auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt {
template <typename Char, typename Rep, typename OutputIt,
FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt {
auto specs = format_specs<Char>();
auto specs = format_specs();
specs.precision = precision;
specs.type =
precision >= 0 ? presentation_type::fixed : presentation_type::general;
Expand Down Expand Up @@ -2076,7 +2076,7 @@ template <typename Char> struct formatter<weekday, Char> {
template <typename Rep, typename Period, typename Char>
struct formatter<std::chrono::duration<Rep, Period>, Char> {
private:
format_specs<Char> specs_;
format_specs specs_;
detail::arg_ref<Char> width_ref_;
detail::arg_ref<Char> precision_ref_;
bool localized_ = false;
Expand Down Expand Up @@ -2218,7 +2218,7 @@ struct formatter<std::chrono::time_point<std::chrono::utc_clock, Duration>,

template <typename Char> struct formatter<std::tm, Char> {
private:
format_specs<Char> specs_;
format_specs specs_;
detail::arg_ref<Char> width_ref_;

protected:
Expand Down
4 changes: 2 additions & 2 deletions include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
#endif

FMT_FUNC auto write_loc(appender out, loc_value value,
const format_specs<>& specs, locale_ref loc) -> bool {
const format_specs& specs, locale_ref loc) -> bool {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
auto locale = loc.get<std::locale>();
// We cannot use the num_put<char> facet because it may produce output in
Expand Down Expand Up @@ -138,7 +138,7 @@ template <typename Locale> format_facet<Locale>::format_facet(Locale& loc) {

template <>
FMT_API FMT_FUNC auto format_facet<std::locale>::do_put(
appender out, loc_value val, const format_specs<>& specs) const -> bool {
appender out, loc_value val, const format_specs& specs) const -> bool {
return val.visit(
detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_});
}
Expand Down
132 changes: 64 additions & 68 deletions include/fmt/format.h

Large diffs are not rendered by default.

37 changes: 18 additions & 19 deletions include/fmt/printf.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ template <typename Char> struct get_cstring {

// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template <typename Char> class printf_width_handler {
class printf_width_handler {
private:
format_specs<Char>& specs_;
format_specs& specs_;

public:
explicit printf_width_handler(format_specs<Char>& specs) : specs_(specs) {}
explicit printf_width_handler(format_specs& specs) : specs_(specs) {}

template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
auto operator()(T value) -> unsigned {
Expand All @@ -220,7 +220,7 @@ template <typename Char> class printf_width_handler {
// Workaround for a bug with the XL compiler when initializing
// printf_arg_formatter's base class.
template <typename Char>
auto make_arg_formatter(basic_appender<Char> iter, format_specs<Char>& s)
auto make_arg_formatter(basic_appender<Char> iter, format_specs& s)
-> arg_formatter<Char> {
return {iter, s, locale_ref()};
}
Expand All @@ -237,11 +237,11 @@ class printf_arg_formatter : public arg_formatter<Char> {
void write_null_pointer(bool is_string = false) {
auto s = this->specs;
s.type = presentation_type::none;
write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
write_bytes<Char>(this->out, is_string ? "(null)" : "(nil)", s);
}

public:
printf_arg_formatter(basic_appender<Char> iter, format_specs<Char>& s,
printf_arg_formatter(basic_appender<Char> iter, format_specs& s,
context_type& ctx)
: base(make_arg_formatter(iter, s)), context_(ctx) {}

Expand All @@ -255,19 +255,18 @@ class printf_arg_formatter : public arg_formatter<Char> {
base::operator()(value);
return;
}
format_specs<Char> fmt_specs = this->specs;
if (fmt_specs.type != presentation_type::none &&
fmt_specs.type != presentation_type::chr) {
format_specs s = this->specs;
if (s.type != presentation_type::none && s.type != presentation_type::chr) {
return (*this)(static_cast<int>(value));
}
fmt_specs.sign = sign::none;
fmt_specs.alt = false;
fmt_specs.fill = ' '; // Ignore '0' flag for char types.
s.sign = sign::none;
s.alt = false;
s.fill = ' '; // Ignore '0' flag for char types.
// align::numeric needs to be overwritten here since the '0' flag is
// ignored for non-numeric types
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
fmt_specs.align = align::right;
write<Char>(this->out, static_cast<Char>(value), fmt_specs);
if (s.align == align::none || s.align == align::numeric)
s.align = align::right;
write<Char>(this->out, static_cast<Char>(value), s);
}

template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
Expand Down Expand Up @@ -309,7 +308,7 @@ class printf_arg_formatter : public arg_formatter<Char> {
};

template <typename Char>
void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) {
void parse_flags(format_specs& specs, const Char*& it, const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-':
Expand All @@ -334,7 +333,7 @@ void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) {
}

template <typename Char, typename GetArg>
auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
auto parse_header(const Char*& it, const Char* end, format_specs& specs,
GetArg get_arg) -> int {
int arg_index = -1;
Char c = *it;
Expand Down Expand Up @@ -365,7 +364,7 @@ auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
} else if (*it == '*') {
++it;
specs.width = static_cast<int>(
get_arg(-1).visit(detail::printf_width_handler<Char>(specs)));
get_arg(-1).visit(detail::printf_width_handler(specs)));
}
}
return arg_index;
Expand Down Expand Up @@ -450,7 +449,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
}
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));

auto specs = format_specs<Char>();
auto specs = format_specs();
specs.align = align::right;

// Parse argument index, flags and width.
Expand Down
14 changes: 7 additions & 7 deletions include/fmt/std.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ template <typename Char> struct formatter<std::error_code, Char> {
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write_bytes(out, ec.category().name(), format_specs<Char>());
out = detail::write_bytes<Char>(out, ec.category().name(), format_specs());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
Expand Down Expand Up @@ -403,10 +403,9 @@ struct formatter<
template <typename Context>
auto format(const std::exception& ex, Context& ctx) const
-> decltype(ctx.out()) {
format_specs<Char> spec;
auto out = ctx.out();
if (!with_typename_)
return detail::write_bytes(out, string_view(ex.what()), spec);
return detail::write_bytes<Char>(out, string_view(ex.what()));

#if FMT_USE_TYPEID
const std::type_info& ti = typeid(ex);
Expand Down Expand Up @@ -448,20 +447,21 @@ struct formatter<
} else {
demangled_name_view = string_view(ti.name());
}
out = detail::write_bytes(out, demangled_name_view, spec);
out = detail::write_bytes<Char>(out, demangled_name_view);
# elif FMT_MSC_VERSION
string_view demangled_name_view(ti.name());
if (demangled_name_view.starts_with("class "))
demangled_name_view.remove_prefix(6);
else if (demangled_name_view.starts_with("struct "))
demangled_name_view.remove_prefix(7);
out = detail::write_bytes(out, demangled_name_view, spec);
out = detail::write_bytes(out, demangled_name_view);
# else
out = detail::write_bytes(out, string_view(ti.name()), spec);
out = detail::write_bytes(out, string_view(ti.name())
});
# endif
*out++ = ':';
*out++ = ' ';
return detail::write_bytes(out, string_view(ex.what()), spec);
return detail::write_bytes<Char>(out, string_view(ex.what()));
#endif
}
};
Expand Down
3 changes: 1 addition & 2 deletions include/fmt/xchar.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ template <typename S>
using format_string_char_t = typename format_string_char<S>::type;

inline auto write_loc(basic_appender<wchar_t> out, loc_value value,
const format_specs<wchar_t>& specs, locale_ref loc)
-> bool {
const format_specs& specs, locale_ref loc) -> bool {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
auto& numpunct =
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
Expand Down
4 changes: 2 additions & 2 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2188,11 +2188,11 @@ class format_facet : public fmt::format_facet<std::locale> {
};

auto do_put(fmt::appender out, fmt::loc_value val,
const fmt::format_specs<>&) const -> bool override;
const fmt::format_specs&) const -> bool override;
};

auto format_facet::do_put(fmt::appender out, fmt::loc_value val,
const fmt::format_specs<>&) const -> bool {
const fmt::format_specs&) const -> bool {
return val.visit(int_formatter{out});
}

Expand Down
16 changes: 8 additions & 8 deletions test/scan.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ class scan_context {
namespace detail {

const char* parse_scan_specs(const char* begin, const char* end,
format_specs<>& specs, scan_type) {
format_specs& specs, scan_type) {
while (begin != end) {
switch (to_ascii(*begin)) {
// TODO: parse more scan format specifiers
Expand Down Expand Up @@ -506,14 +506,14 @@ auto read_hex(scan_iterator it, T& value) -> scan_iterator {
}

template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
auto read(scan_iterator it, T& value, const format_specs<>& specs)
auto read(scan_iterator it, T& value, const format_specs& specs)
-> scan_iterator {
if (specs.type == presentation_type::hex) return read_hex(it, value);
return read(it, value);
}

template <typename T, FMT_ENABLE_IF(std::is_signed<T>::value)>
auto read(scan_iterator it, T& value, const format_specs<>& specs = {})
auto read(scan_iterator it, T& value, const format_specs& specs = {})
-> scan_iterator {
bool negative = it != scan_sentinel() && *it == '-';
if (negative) {
Expand All @@ -528,13 +528,13 @@ auto read(scan_iterator it, T& value, const format_specs<>& specs = {})
return it;
}

auto read(scan_iterator it, std::string& value, const format_specs<>& = {})
auto read(scan_iterator it, std::string& value, const format_specs& = {})
-> scan_iterator {
while (it != scan_sentinel() && *it != ' ') value.push_back(*it++);
return it;
}

auto read(scan_iterator it, string_view& value, const format_specs<>& = {})
auto read(scan_iterator it, string_view& value, const format_specs& = {})
-> scan_iterator {
auto range = to_contiguous(it);
// This could also be checked at compile time in scan.
Expand All @@ -546,7 +546,7 @@ auto read(scan_iterator it, string_view& value, const format_specs<>& = {})
return advance(it, size);
}

auto read(scan_iterator it, monostate, const format_specs<>& = {})
auto read(scan_iterator it, monostate, const format_specs& = {})
-> scan_iterator {
return it;
}
Expand All @@ -563,7 +563,7 @@ struct default_arg_scanner {
// An argument scanner with format specifiers.
struct arg_scanner {
scan_iterator it;
const format_specs<>& specs;
const format_specs& specs;

template <typename T> auto operator()(T&& value) -> scan_iterator {
return read(it, value, specs);
Expand Down Expand Up @@ -617,7 +617,7 @@ struct scan_handler {
scan_arg arg = scan_ctx_.arg(arg_id);
if (arg.scan_custom(begin, parse_ctx_, scan_ctx_))
return parse_ctx_.begin();
auto specs = format_specs<>();
auto specs = format_specs();
begin = parse_scan_specs(begin, end, specs, arg.type());
if (begin == end || *begin != '}') on_error("missing '}' in format string");
scan_ctx_.advance_to(arg.visit(arg_scanner{scan_ctx_.begin(), specs}));
Expand Down

0 comments on commit 98e1858

Please sign in to comment.