Add wchar.h for wide char overloads
This commit is contained in:
parent
ce14eafc24
commit
0dd91e20d5
@ -187,7 +187,8 @@ endfunction()
|
|||||||
|
|
||||||
# Define the fmt library, its includes and the needed defines.
|
# Define the fmt library, its includes and the needed defines.
|
||||||
add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
|
add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
|
||||||
format-inl.h locale.h os.h ostream.h printf.h ranges.h)
|
format-inl.h locale.h os.h ostream.h printf.h ranges.h
|
||||||
|
wchar.h)
|
||||||
if (FMT_OS)
|
if (FMT_OS)
|
||||||
set(FMT_SOURCES src/format.cc src/os.cc)
|
set(FMT_SOURCES src/format.cc src/os.cc)
|
||||||
else()
|
else()
|
||||||
|
@ -392,8 +392,8 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
|||||||
|
|
||||||
FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
|
FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
|
||||||
|
|
||||||
template <typename Char> constexpr bool is_unicode() {
|
constexpr bool is_utf8() {
|
||||||
return FMT_UNICODE || sizeof(Char) != 1 ||
|
return FMT_UNICODE ||
|
||||||
(sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5);
|
(sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5);
|
||||||
}
|
}
|
||||||
FMT_END_DETAIL_NAMESPACE
|
FMT_END_DETAIL_NAMESPACE
|
||||||
@ -2895,12 +2895,12 @@ FMT_INLINE auto vformat(
|
|||||||
return detail::vformat(to_string_view(format_str), args);
|
return detail::vformat(to_string_view(format_str), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_COMPILE_TIME_CHECKS
|
|
||||||
template <typename Char, typename... Args> class basic_format_string {
|
template <typename Char, typename... Args> class basic_format_string {
|
||||||
private:
|
private:
|
||||||
basic_string_view<Char> str;
|
basic_string_view<Char> str;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
#if FMT_COMPILE_TIME_CHECKS
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
consteval basic_format_string(const char (&s)[N]) : str(s) {
|
consteval basic_format_string(const char (&s)[N]) : str(s) {
|
||||||
if constexpr (detail::count_named_args<Args...>() == 0) {
|
if constexpr (detail::count_named_args<Args...>() == 0) {
|
||||||
@ -2909,21 +2909,29 @@ template <typename Char, typename... Args> class basic_format_string {
|
|||||||
detail::parse_format_string<true>(string_view(s, N), checker(s, {}));
|
detail::parse_format_string<true>(string_view(s, N), checker(s, {}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
FMT_ENABLE_IF(std::is_constructible_v<string_view, const T&>)>
|
FMT_ENABLE_IF(std::is_constructible<basic_string_view<Char>,
|
||||||
basic_format_string(const T& s) : str(s) {}
|
const T&>::value)>
|
||||||
|
basic_format_string(const T& s) : str(s) {
|
||||||
|
static_assert(
|
||||||
|
detail::count<
|
||||||
|
(std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
|
||||||
|
std::is_reference<Args>::value)...>() == 0,
|
||||||
|
"passing views as lvalues is disallowed");
|
||||||
|
detail::check_format_string<Args...>(s);
|
||||||
|
}
|
||||||
|
|
||||||
operator basic_string_view<Char>() const { return str; }
|
FMT_INLINE operator basic_string_view<Char>() const { return str; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||||
|
// Workaround broken conversion on older gcc.
|
||||||
|
template <typename... Args> using format_string = string_view;
|
||||||
|
#else
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
using format_string = basic_format_string<char, std::type_identity_t<Args>...>;
|
using format_string = basic_format_string<char, type_identity_t<Args>...>;
|
||||||
|
|
||||||
template <typename... T>
|
|
||||||
FMT_INLINE auto format(format_string<T...> str, T&&... args) -> std::string {
|
|
||||||
return detail::vformat(str, make_format_args(args...));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2936,15 +2944,9 @@ FMT_INLINE auto format(format_string<T...> str, T&&... args) -> std::string {
|
|||||||
std::string message = fmt::format("The answer is {}", 42);
|
std::string message = fmt::format("The answer is {}", 42);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
// Pass char_t as a default template parameter instead of using
|
template <typename... T>
|
||||||
// std::basic_string<char_t<S>> to reduce the symbol size.
|
FMT_INLINE auto format(format_string<T...> str, T&&... args) -> std::string {
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
return detail::vformat(str, make_format_args(args...));
|
||||||
FMT_ENABLE_IF(!FMT_COMPILE_TIME_CHECKS ||
|
|
||||||
!std::is_same<Char, char>::value)>
|
|
||||||
FMT_INLINE auto format(const S& format_str, Args&&... args)
|
|
||||||
-> std::basic_string<Char> {
|
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
|
||||||
return detail::vformat(to_string_view(format_str), vargs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_API void vprint(string_view, format_args);
|
FMT_API void vprint(string_view, format_args);
|
||||||
@ -2952,8 +2954,8 @@ FMT_API void vprint(std::FILE*, string_view, format_args);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Formats ``args`` according to specifications in ``format_str`` and writes the
|
Formats ``args`` according to specifications in ``str`` and writes the
|
||||||
output to the file ``f``. Strings are assumed to be Unicode-encoded unless the
|
output to the file ``f``. Strings are assumed to be in UTF-8 unless the
|
||||||
``FMT_UNICODE`` macro is set to 0.
|
``FMT_UNICODE`` macro is set to 0.
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
@ -2961,32 +2963,29 @@ FMT_API void vprint(std::FILE*, string_view, format_args);
|
|||||||
fmt::print(stderr, "Don't {}!", "panic");
|
fmt::print(stderr, "Don't {}!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
template <typename... T>
|
||||||
inline void print(std::FILE* f, const S& format_str, Args&&... args) {
|
inline void print(std::FILE* f, format_string<T...> str, T&&... args) {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
const auto& vargs = make_format_args(args...);
|
||||||
return detail::is_unicode<Char>()
|
return detail::is_utf8() ? vprint(f, str, vargs)
|
||||||
? vprint(f, to_string_view(format_str), vargs)
|
: detail::vprint_mojibake(f, str, vargs);
|
||||||
: detail::vprint_mojibake(f, to_string_view(format_str), vargs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Formats ``args`` according to specifications in ``format_str`` and writes
|
Formats ``args`` according to specifications in ``str`` and writes the output
|
||||||
the output to ``stdout``. Strings are assumed to be Unicode-encoded unless
|
to ``stdout``. Strings are assumed to be in UTF-8 unless the ``FMT_UNICODE``
|
||||||
the ``FMT_UNICODE`` macro is set to 0.
|
macro is set to 0.
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
|
fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
template <typename... T>
|
||||||
inline void print(const S& format_str, Args&&... args) {
|
inline void print(format_string<T...> str, T&&... args) {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
const auto& vargs = make_format_args(args...);
|
||||||
return detail::is_unicode<Char>()
|
return detail::is_utf8() ? vprint(str, vargs)
|
||||||
? vprint(to_string_view(format_str), vargs)
|
: detail::vprint_mojibake(stdout, str, vargs);
|
||||||
: detail::vprint_mojibake(stdout, to_string_view(format_str),
|
|
||||||
vargs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_MODULE_EXPORT_END
|
||||||
|
@ -2658,6 +2658,16 @@ auto detail::vformat(
|
|||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass char_t as a default template parameter instead of using
|
||||||
|
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||||
|
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||||
|
FMT_INLINE auto format(const S& format_str, Args&&... args)
|
||||||
|
-> std::basic_string<Char> {
|
||||||
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
|
return detail::vformat(to_string_view(format_str), vargs);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>
|
template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>
|
||||||
void vprint(std::FILE* f, basic_string_view<Char> format_str,
|
void vprint(std::FILE* f, basic_string_view<Char> format_str,
|
||||||
wformat_args args) {
|
wformat_args args) {
|
||||||
|
39
include/fmt/wchar.h
Normal file
39
include/fmt/wchar.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Formatting library for C++ - experimental wchar_t support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_WCHAR_H_
|
||||||
|
#define FMT_WCHAR_H_
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||||
|
// Workaround broken conversion on older gcc.
|
||||||
|
template <typename... Args> using wformat_string = wstring_view;
|
||||||
|
#else
|
||||||
|
template <typename... Args>
|
||||||
|
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
|
||||||
|
const Args&... args) {
|
||||||
|
return {args...};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
void print(std::FILE* f, wformat_string<T...> str, T&&... args) {
|
||||||
|
return vprint(f, wstring_view(str), make_wformat_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T> void print(wformat_string<T...> str, T&&... args) {
|
||||||
|
return vprint(wstring_view(str), make_wformat_args(args...));
|
||||||
|
}
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
#endif // FMT_WCHAR_H_
|
@ -72,6 +72,7 @@ add_fmt_test(compile-test)
|
|||||||
add_fmt_test(printf-test)
|
add_fmt_test(printf-test)
|
||||||
add_fmt_test(ranges-test)
|
add_fmt_test(ranges-test)
|
||||||
add_fmt_test(scan-test)
|
add_fmt_test(scan-test)
|
||||||
|
add_fmt_test(wchar-test)
|
||||||
|
|
||||||
if (NOT MSVC)
|
if (NOT MSVC)
|
||||||
# FMT_ENFORCE_COMPILE_STRING is not supported under MSVC due to compiler bugs.
|
# FMT_ENFORCE_COMPILE_STRING is not supported under MSVC due to compiler bugs.
|
||||||
|
@ -590,11 +590,6 @@ TEST(core_test, to_string_view_foreign_strings) {
|
|||||||
EXPECT_EQ(type, fmt::detail::type::string_type);
|
EXPECT_EQ(type, fmt::detail::type::string_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(core_test, format_foreign_strings) {
|
|
||||||
using namespace test_ns;
|
|
||||||
EXPECT_EQ(fmt::format(test_string<char>("{}"), 42), "42");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct implicitly_convertible_to_string {
|
struct implicitly_convertible_to_string {
|
||||||
operator std::string() const { return "foo"; }
|
operator std::string() const { return "foo"; }
|
||||||
};
|
};
|
||||||
|
@ -1580,8 +1580,6 @@ TEST(format_test, print) {
|
|||||||
EXPECT_WRITE(stdout, fmt::print("Don't {}!", "panic"), "Don't panic!");
|
EXPECT_WRITE(stdout, fmt::print("Don't {}!", "panic"), "Don't panic!");
|
||||||
EXPECT_WRITE(stderr, fmt::print(stderr, "Don't {}!", "panic"),
|
EXPECT_WRITE(stderr, fmt::print(stderr, "Don't {}!", "panic"),
|
||||||
"Don't panic!");
|
"Don't panic!");
|
||||||
// Check that the wide print overload compiles.
|
|
||||||
if (fmt::detail::const_check(false)) fmt::print(L"test");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, variadic) {
|
TEST(format_test, variadic) {
|
||||||
|
15
test/wchar-test.cc
Normal file
15
test/wchar-test.cc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Formatting library for C++ - formatting library tests
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include "fmt/wchar.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
TEST(wchar_test, print) {
|
||||||
|
// Check that the wide print overload compiles.
|
||||||
|
if (fmt::detail::const_check(false)) fmt::print(L"test");
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user