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

Provide more overloads for the wide string flavour #724

Closed
wants to merge 1 commit into from
Closed
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
39 changes: 38 additions & 1 deletion include/fmt/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1093,12 +1093,18 @@ class basic_format_args {

/** An alias to ``basic_format_args<context>``. */
// It is a separate type rather than a typedef to make symbols readable.
// It is also required to disambiguate 'vformat_to' overloads
// in core.h and format.h - which seems a bit brittle!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate on the disambiguation part and why you think it's brittle?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Victor,

this is probably no longer true. During my various attempts, to replace

template <typename Container>
... vformat_to(std::back_insert_iterator<Container> out,
               string_view format_str, format_args args) {
...
}

in core.h by

template <typename Container>
... vformat_to(std::back_insert_iterator<Container> out,
      basic_string_view<typename Container::value_type> format_str,
      basic_format_args<typename buffer_context<typename Container::value_type>::type> args) {
...
}

to reduce code duplication, I got ambiguous overloads of vformat_toin core.h and format.h. My tests from today show that those more-derived structs don't help me to get along with this problem. Sigh ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is not so much due to basic_format_args, but due to overloads taking string_view in format.h. Unfortunately I don't think it's possible to parameterize on character type there: https://godbolt.org/g/bPevXe.

this is probably no longer true

I've removed the comment then.

struct format_args: basic_format_args<format_context> {
template <typename ...Args>
format_args(Args && ... arg)
: basic_format_args<format_context>(std::forward<Args>(arg)...) {}
};
typedef basic_format_args<wformat_context> wformat_args;
struct wformat_args : basic_format_args<wformat_context> {
template <typename ...Args>
wformat_args(Args && ... arg)
: basic_format_args<wformat_context>(std::forward<Args>(arg)...) {}
};

namespace internal {
template <typename Char>
Expand Down Expand Up @@ -1154,6 +1160,7 @@ void arg(S, internal::named_arg<T, Char>) FMT_DELETED;
enum color { black, red, green, yellow, blue, magenta, cyan, white };

FMT_API void vprint_colored(color c, string_view format, format_args args);
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);

/**
Formats a string and prints it to stdout using ANSI escape sequences to
Expand All @@ -1167,6 +1174,12 @@ inline void print_colored(color c, string_view format_str,
vprint_colored(c, format_str, make_format_args(args...));
}

template <typename... Args>
inline void print_colored(color c, wstring_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
}

format_context::iterator vformat_to(
internal::buffer &buf, string_view format_str, format_args args);
wformat_context::iterator vformat_to(
Expand All @@ -1193,6 +1206,17 @@ typename std::enable_if<
return std::back_inserter(container);
}

template <typename Container>
typename std::enable_if<
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
vformat_to(std::back_insert_iterator<Container> out,
wstring_view format_str, wformat_args args) {
auto& container = internal::get_container(out);
internal::container_buffer<Container> buf(container);
vformat_to(buf, format_str, args);
return std::back_inserter(container);
}

std::string vformat(string_view format_str, format_args args);
std::wstring vformat(wstring_view format_str, wformat_args args);

Expand Down Expand Up @@ -1221,6 +1245,7 @@ inline std::wstring format(wstring_view format_str, const Args & ... args) {
}

FMT_API void vprint(std::FILE *f, string_view format_str, format_args args);
FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args);

/**
\rst
Expand All @@ -1236,8 +1261,14 @@ inline void print(std::FILE *f, string_view format_str, const Args & ... args) {
format_arg_store<format_context, Args...> as(args...);
vprint(f, format_str, as);
}
template <typename... Args>
inline void print(std::FILE *f, wstring_view format_str, const Args & ... args) {
format_arg_store<wformat_context, Args...> as(args...);
vprint(f, format_str, as);
}

FMT_API void vprint(string_view format_str, format_args args);
FMT_API void vprint(wstring_view format_str, wformat_args args);

/**
\rst
Expand All @@ -1253,6 +1284,12 @@ inline void print(string_view format_str, const Args & ... args) {
format_arg_store<format_context, Args...> as(args...);
vprint(format_str, as);
}

template <typename... Args>
inline void print(wstring_view format_str, const Args & ... args) {
format_arg_store<wformat_context, Args...> as(args...);
vprint(format_str, as);
}
} // namespace fmt

#endif // FMT_CORE_H_
19 changes: 19 additions & 0 deletions include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)

const char RESET_COLOR[] = "\x1b[0m";
const wchar_t WRESET_COLOR[] = L"\x1b[0m";

typedef void (*FormatFunc)(internal::buffer &, int, string_view);

Expand Down Expand Up @@ -489,10 +490,20 @@ FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
std::fwrite(buffer.data(), 1, buffer.size(), f);
}

FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
wmemory_buffer buffer;
vformat_to(buffer, format_str, args);
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
}

FMT_FUNC void vprint(string_view format_str, format_args args) {
vprint(stdout, format_str, args);
}

FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
vprint(stdout, format_str, args);
}

FMT_FUNC void vprint_colored(color c, string_view format, format_args args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
Expand All @@ -501,6 +512,14 @@ FMT_FUNC void vprint_colored(color c, string_view format, format_args args) {
std::fputs(RESET_COLOR, stdout);
}

FMT_FUNC void vprint_colored(color c, wstring_view format, wformat_args args) {
wchar_t escape[] = L"\x1b[30m";
escape[3] = static_cast<wchar_t>('0' + c);
std::fputws(escape, stdout);
vprint(format, args);
std::fputws(WRESET_COLOR, stdout);
}

FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }

} // namespace fmt
Expand Down
10 changes: 9 additions & 1 deletion include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3419,7 +3419,15 @@ inline typename std::enable_if<
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
format_to(std::back_insert_iterator<Container> out,
string_view format_str, const Args & ... args) {
return vformat_to(out, format_str, make_format_args(args...));
return vformat_to(out, format_str, make_format_args<format_context>(args...));
}

template <typename Container, typename... Args>
inline typename std::enable_if<
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
format_to(std::back_insert_iterator<Container> out,
wstring_view format_str, const Args & ... args) {
return vformat_to(out, format_str, make_format_args<wformat_context>(args...));
}

template <typename OutputIt>
Expand Down
17 changes: 13 additions & 4 deletions include/fmt/ostream.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,14 @@ struct formatter<T, Char,
}
};

inline void vprint(std::ostream &os, string_view format_str, format_args args) {
memory_buffer buffer;
template <typename Char>
inline void vprint(std::basic_ostream<Char> &os,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
vformat_to(buffer, format_str, args);
internal::write(os, buffer);
}

/**
\rst
Prints formatted data to the stream *os*.
Expand All @@ -139,8 +141,15 @@ inline void vprint(std::ostream &os, string_view format_str, format_args args) {
template <typename... Args>
inline void print(std::ostream &os, string_view format_str,
const Args & ... args) {
vprint(os, format_str, make_format_args(args...));
vprint(os, format_str, make_format_args<format_context>(args...));
}

template <typename... Args>
inline void print(std::wostream &os, wstring_view format_str,
const Args & ... args) {
vprint(os, format_str, make_format_args<wformat_context>(args...));
}

} // namespace fmt

#endif // FMT_OSTREAM_H_
78 changes: 64 additions & 14 deletions include/fmt/printf.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ class char_converter: public function<void> {
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
operator()(T value) {
arg_ = internal::make_arg<Context>(static_cast<char>(value));
typedef typename Context::char_type Char;
arg_ = internal::make_arg<Context>(static_cast<Char>(value));
}

template <typename T>
Expand Down Expand Up @@ -223,11 +224,16 @@ class printf_arg_formatter:

context_type &context_;

void write_null_pointer() {
void write_null_pointer(char) {
this->spec().type_ = 0;
this->write("(nil)");
}

void write_null_pointer(wchar_t) {
this->spec().type_ = 0;
this->write(L"(nil)");
}

public:
typedef typename base::format_specs format_specs;

Expand Down Expand Up @@ -270,18 +276,29 @@ class printf_arg_formatter:
if (value)
base::operator()(value);
else if (this->spec().type_ == 'p')
write_null_pointer();
write_null_pointer(char_type());
else
this->write("(null)");
return this->out();
}

/** Formats a null-terminated wide C string. */
iterator operator()(const wchar_t *value) {
if (value)
base::operator()(value);
else if (this->spec().type_ == 'p')
write_null_pointer(char_type());
else
this->write(L"(null)");
return this->out();
}

/** Formats a pointer. */
iterator operator()(const void *value) {
if (value)
return base::operator()(value);
this->spec().type_ = 0;
write_null_pointer();
write_null_pointer(char_type());
return this->out();
}

Expand Down Expand Up @@ -518,7 +535,7 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
spec.type_ = 'd';
break;
case 'c':
// TODO: handle wchar_t
// TODO: handle wchar_t better?
visit(internal::char_converter<basic_printf_context>(arg), arg);
break;
}
Expand Down Expand Up @@ -551,6 +568,7 @@ inline format_arg_store<printf_context<internal::buffer>::type, Args...>
args...);
}
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args;

inline std::string vsprintf(string_view format, printf_args args) {
memory_buffer buffer;
Expand All @@ -573,27 +591,27 @@ inline std::string sprintf(string_view format_str, const Args & ... args) {
make_format_args<typename printf_context<internal::buffer>::type>(args...));
}

inline std::wstring vsprintf(
wstring_view format,
basic_format_args<printf_context<internal::wbuffer>::type> args) {
inline std::wstring vsprintf(wstring_view format, wprintf_args args) {
wmemory_buffer buffer;
printf(buffer, format, args);
return to_string(buffer);
}

template <typename... Args>
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::wbuffer>::type>(args...);
return vsprintf(format_str, vargs);
return vsprintf(format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}

inline int vfprintf(std::FILE *f, string_view format, printf_args args) {
memory_buffer buffer;
template <typename Char>
inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
basic_format_args<typename printf_context<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, format, args);
std::size_t size = buffer.size();
return std::fwrite(
buffer.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
}

/**
Expand All @@ -612,10 +630,20 @@ inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args)
return vfprintf(f, format_str, vargs);
}

template <typename... Args>
inline int fprintf(std::FILE *f, wstring_view format_str, const Args & ... args) {
return vfprintf(f, format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}

inline int vprintf(string_view format, printf_args args) {
return vfprintf(stdout, format, args);
}

inline int vprintf(wstring_view format, wprintf_args args) {
return vfprintf(stdout, format, args);
}

/**
\rst
Prints formatted data to ``stdout``.
Expand All @@ -631,6 +659,12 @@ inline int printf(string_view format_str, const Args & ... args) {
make_format_args<typename printf_context<internal::buffer>::type>(args...));
}

template <typename... Args>
inline int printf(wstring_view format_str, const Args & ... args) {
return vprintf(format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}

inline int vfprintf(std::ostream &os, string_view format_str,
printf_args args) {
memory_buffer buffer;
Expand All @@ -639,6 +673,14 @@ inline int vfprintf(std::ostream &os, string_view format_str,
return static_cast<int>(buffer.size());
}

inline int vfprintf(std::wostream &os, wstring_view format_str,
wprintf_args args) {
wmemory_buffer buffer;
printf(buffer, format_str, args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}

/**
\rst
Prints formatted data to the stream *os*.
Expand All @@ -655,6 +697,14 @@ inline int fprintf(std::ostream &os, string_view format_str,
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
}

template <typename... Args>
inline int fprintf(std::wostream &os, wstring_view format_str,
const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
}
} // namespace fmt

#endif // FMT_PRINTF_H_
3 changes: 2 additions & 1 deletion src/format.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ template FMT_API wchar_t internal::thousands_sep(locale_provider *lp);

template void basic_fixed_buffer<wchar_t>::grow(std::size_t);

template void internal::arg_map<wformat_context>::init(const wformat_args &args);
template void internal::arg_map<wformat_context>::init(
const basic_format_args<wformat_context> &args);

template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
Expand Down
Loading