mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 19:24:48 +02:00
Deprecate locale.h
This commit is contained in:
@@ -15,7 +15,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "locale.h"
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
@@ -582,7 +582,7 @@ inline std::basic_string<Char> vformat(
|
|||||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return vformat(ts, to_string_view(format_str),
|
return fmt::vformat(ts, to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -624,6 +624,11 @@ void iterator_buffer<OutputIt, T, Traits>::flush() {
|
|||||||
this->clear();
|
this->clear();
|
||||||
out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
|
out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct is_locale : std::false_type {};
|
||||||
|
template <typename T>
|
||||||
|
struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_MODULE_EXPORT_BEGIN
|
||||||
@@ -2208,6 +2213,15 @@ template <typename Char> struct udl_arg {
|
|||||||
# endif
|
# endif
|
||||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
|
||||||
|
template <typename Locale, typename Char>
|
||||||
|
std::basic_string<Char> vformat(
|
||||||
|
const Locale& loc, basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
|
||||||
|
return {buffer.data(), buffer.size()};
|
||||||
|
}
|
||||||
|
|
||||||
using format_func = void (*)(detail::buffer<char>&, int, const char*);
|
using format_func = void (*)(detail::buffer<char>&, int, const char*);
|
||||||
|
|
||||||
FMT_API void format_error_code(buffer<char>& out, int error_code,
|
FMT_API void format_error_code(buffer<char>& out, int error_code,
|
||||||
@@ -2771,6 +2785,19 @@ auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
|||||||
return vformat(to_string_view(format_str), vargs);
|
return vformat(to_string_view(format_str), vargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
|
||||||
|
inline std::string vformat(const Locale& loc, string_view fmt,
|
||||||
|
format_args args) {
|
||||||
|
return detail::vformat(loc, fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Locale, typename... T,
|
||||||
|
FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
|
||||||
|
inline std::string format(const Locale& loc, format_string<T...> fmt,
|
||||||
|
T&&... args) {
|
||||||
|
return vformat(loc, fmt, fmt::make_format_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>,
|
template <typename S, typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||||
inline void vformat_to(
|
inline void vformat_to(
|
||||||
@@ -2809,6 +2836,25 @@ inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
|
|||||||
return vformat_to(out, to_string_view(fmt), vargs);
|
return vformat_to(out, to_string_view(fmt), vargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename Locale,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
|
||||||
|
detail::is_locale<Locale>::value)>
|
||||||
|
auto vformat_to(const Locale& loc, OutputIt out, string_view fmt,
|
||||||
|
format_args args) -> OutputIt {
|
||||||
|
using detail::get_buffer;
|
||||||
|
auto&& buf = get_buffer<char>(out);
|
||||||
|
detail::vformat_to(buf, string_view(fmt), args, detail::locale_ref(loc));
|
||||||
|
return detail::get_iterator(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename Locale, typename... T,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
|
||||||
|
detail::is_locale<Locale>::value)>
|
||||||
|
FMT_INLINE auto format_to(OutputIt out, const Locale& loc,
|
||||||
|
format_string<T...> fmt, T&&... args) -> OutputIt {
|
||||||
|
return vformat_to(loc, out, fmt, fmt::make_format_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char, typename... Args,
|
template <typename OutputIt, typename Char, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
|
||||||
!std::is_same<Char, char>::value)>
|
!std::is_same<Char, char>::value)>
|
||||||
|
@@ -1,67 +1,2 @@
|
|||||||
// Formatting library for C++ - std::locale support
|
#include "wchar.h"
|
||||||
//
|
#warning fmt/locale.h is deprecated, include fmt/format.h or fmt/wchar.h instead
|
||||||
// Copyright (c) 2012 - present, Victor Zverovich
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// For the license information refer to format.h.
|
|
||||||
|
|
||||||
#ifndef FMT_LOCALE_H_
|
|
||||||
#define FMT_LOCALE_H_
|
|
||||||
|
|
||||||
#include <locale>
|
|
||||||
|
|
||||||
#include "format.h"
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template <typename Char>
|
|
||||||
std::basic_string<Char> vformat(
|
|
||||||
const std::locale& loc, basic_string_view<Char> format_str,
|
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
|
||||||
basic_memory_buffer<Char> buffer;
|
|
||||||
detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
|
|
||||||
return fmt::to_string(buffer);
|
|
||||||
}
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
|
||||||
inline std::basic_string<Char> vformat(
|
|
||||||
const std::locale& loc, const S& format_str,
|
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
|
||||||
return detail::vformat(loc, to_string_view(format_str), args);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
|
||||||
inline std::basic_string<Char> format(const std::locale& loc,
|
|
||||||
const S& format_str, Args&&... args) {
|
|
||||||
return detail::vformat(loc, to_string_view(format_str),
|
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename S, typename OutputIt, typename... Args,
|
|
||||||
typename Char = char_t<S>,
|
|
||||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
|
|
||||||
inline OutputIt vformat_to(
|
|
||||||
OutputIt out, const std::locale& loc, const S& format_str,
|
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
|
||||||
auto&& buf = detail::get_buffer<Char>(out);
|
|
||||||
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
|
|
||||||
return detail::get_iterator(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename OutputIt, typename S, typename... Args,
|
|
||||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
|
|
||||||
inline auto format_to(OutputIt out, const std::locale& loc, const S& format_str,
|
|
||||||
Args&&... args) ->
|
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
|
||||||
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
|
|
||||||
#endif // FMT_LOCALE_H_
|
|
||||||
|
@@ -64,6 +64,50 @@ arg_join<const T*, const T*, wchar_t> join(std::initializer_list<T> list,
|
|||||||
return join(std::begin(list), std::end(list), sep);
|
return join(std::begin(list), std::end(list), sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Locale, typename S, typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_locale<Locale>::value &&
|
||||||
|
!std::is_same<Char, char>::value)>
|
||||||
|
inline std::basic_string<Char> vformat(
|
||||||
|
const Locale& loc, const S& format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
|
return detail::vformat(loc, to_string_view(format_str), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Locale, typename S, typename... Args,
|
||||||
|
typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_locale<Locale>::value &&
|
||||||
|
!std::is_same<Char, char>::value)>
|
||||||
|
inline std::basic_string<Char> format(const Locale& loc, const S& format_str,
|
||||||
|
Args&&... args) {
|
||||||
|
return detail::vformat(loc, to_string_view(format_str),
|
||||||
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Locale, typename S, typename OutputIt, typename... Args,
|
||||||
|
typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
|
detail::is_locale<Locale>::value &&
|
||||||
|
!std::is_same<Char, char>::value)>
|
||||||
|
inline OutputIt vformat_to(
|
||||||
|
OutputIt out, const Locale& loc, const S& format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
|
auto&& buf = detail::get_buffer<Char>(out);
|
||||||
|
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
|
||||||
|
return detail::get_iterator(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename Locale, typename S, typename... Args,
|
||||||
|
typename Char = char_t<S>,
|
||||||
|
bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
|
detail::is_locale<Locale>::value &&
|
||||||
|
!std::is_same<Char, char>::value>
|
||||||
|
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
|
||||||
|
Args&&... args) ->
|
||||||
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
|
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
||||||
|
}
|
||||||
|
|
||||||
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
|
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
|
||||||
wmemory_buffer buffer;
|
wmemory_buffer buffer;
|
||||||
detail::vformat_to(buffer, fmt, args);
|
detail::vformat_to(buffer, fmt, args);
|
||||||
@@ -91,7 +135,6 @@ template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
|
|||||||
template <typename T> inline std::wstring to_wstring(const T& value) {
|
template <typename T> inline std::wstring to_wstring(const T& value) {
|
||||||
return format(FMT_STRING(L"{}"), value);
|
return format(FMT_STRING(L"{}"), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_MODULE_EXPORT_END
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
@@ -72,7 +72,6 @@ endif ()
|
|||||||
if (NOT (MSVC AND BUILD_SHARED_LIBS))
|
if (NOT (MSVC AND BUILD_SHARED_LIBS))
|
||||||
add_fmt_test(format-impl-test HEADER_ONLY header-only-test.cc)
|
add_fmt_test(format-impl-test HEADER_ONLY header-only-test.cc)
|
||||||
endif ()
|
endif ()
|
||||||
add_fmt_test(locale-test)
|
|
||||||
add_fmt_test(ostream-test)
|
add_fmt_test(ostream-test)
|
||||||
add_fmt_test(compile-test)
|
add_fmt_test(compile-test)
|
||||||
add_fmt_test(printf-test)
|
add_fmt_test(printf-test)
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
#include "fmt/chrono.h"
|
#include "fmt/chrono.h"
|
||||||
#include "fmt/color.h"
|
#include "fmt/color.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "fmt/locale.h"
|
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
#include "fmt/ranges.h"
|
#include "fmt/ranges.h"
|
||||||
#include "fmt/wchar.h"
|
#include "fmt/wchar.h"
|
||||||
|
@@ -1,168 +0,0 @@
|
|||||||
// Formatting library for C++ - locale tests
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012 - present, Victor Zverovich
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// For the license information refer to format.h.
|
|
||||||
|
|
||||||
#include "fmt/locale.h"
|
|
||||||
|
|
||||||
#include <complex>
|
|
||||||
|
|
||||||
#include "gmock/gmock.h"
|
|
||||||
|
|
||||||
using fmt::detail::max_value;
|
|
||||||
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
|
||||||
template <typename Char> struct numpunct : std::numpunct<Char> {
|
|
||||||
protected:
|
|
||||||
Char do_decimal_point() const override { return '?'; }
|
|
||||||
std::string do_grouping() const override { return "\03"; }
|
|
||||||
Char do_thousands_sep() const override { return '~'; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char> struct no_grouping : std::numpunct<Char> {
|
|
||||||
protected:
|
|
||||||
Char do_decimal_point() const override { return '.'; }
|
|
||||||
std::string do_grouping() const override { return ""; }
|
|
||||||
Char do_thousands_sep() const override { return ','; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char> struct special_grouping : std::numpunct<Char> {
|
|
||||||
protected:
|
|
||||||
Char do_decimal_point() const override { return '.'; }
|
|
||||||
std::string do_grouping() const override { return "\03\02"; }
|
|
||||||
Char do_thousands_sep() const override { return ','; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char> struct small_grouping : std::numpunct<Char> {
|
|
||||||
protected:
|
|
||||||
Char do_decimal_point() const override { return '.'; }
|
|
||||||
std::string do_grouping() const override { return "\01"; }
|
|
||||||
Char do_thousands_sep() const override { return ','; }
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(locale_test, double_decimal_point) {
|
|
||||||
auto loc = std::locale(std::locale(), new numpunct<char>());
|
|
||||||
EXPECT_EQ("1?23", fmt::format(loc, "{:L}", 1.23));
|
|
||||||
EXPECT_EQ("1?230000", fmt::format(loc, "{:Lf}", 1.23));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(locale_test, format) {
|
|
||||||
auto loc = std::locale(std::locale(), new numpunct<char>());
|
|
||||||
EXPECT_EQ("1234567", fmt::format(std::locale(), "{:L}", 1234567));
|
|
||||||
EXPECT_EQ("1~234~567", fmt::format(loc, "{:L}", 1234567));
|
|
||||||
EXPECT_EQ("-1~234~567", fmt::format(loc, "{:L}", -1234567));
|
|
||||||
EXPECT_EQ("-256", fmt::format(loc, "{:L}", -256));
|
|
||||||
fmt::format_arg_store<fmt::format_context, int> as{1234567};
|
|
||||||
EXPECT_EQ("1~234~567", fmt::vformat(loc, "{:L}", fmt::format_args(as)));
|
|
||||||
auto s = std::string();
|
|
||||||
fmt::format_to(std::back_inserter(s), loc, "{:L}", 1234567);
|
|
||||||
EXPECT_EQ("1~234~567", s);
|
|
||||||
|
|
||||||
auto no_grouping_loc = std::locale(std::locale(), new no_grouping<char>());
|
|
||||||
EXPECT_EQ("1234567", fmt::format(no_grouping_loc, "{:L}", 1234567));
|
|
||||||
|
|
||||||
auto special_grouping_loc =
|
|
||||||
std::locale(std::locale(), new special_grouping<char>());
|
|
||||||
EXPECT_EQ("1,23,45,678", fmt::format(special_grouping_loc, "{:L}", 12345678));
|
|
||||||
EXPECT_EQ("12,345", fmt::format(special_grouping_loc, "{:L}", 12345));
|
|
||||||
|
|
||||||
auto small_grouping_loc =
|
|
||||||
std::locale(std::locale(), new small_grouping<char>());
|
|
||||||
EXPECT_EQ("4,2,9,4,9,6,7,2,9,5",
|
|
||||||
fmt::format(small_grouping_loc, "{:L}", max_value<uint32_t>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(locale_test, format_detault_align) {
|
|
||||||
auto loc = std::locale({}, new special_grouping<char>());
|
|
||||||
EXPECT_EQ(" 12,345", fmt::format(loc, "{:8L}", 12345));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(locale_test, format_plus) {
|
|
||||||
auto loc = std::locale({}, new special_grouping<char>());
|
|
||||||
EXPECT_EQ("+100", fmt::format(loc, "{:+L}", 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(locale_test, wformat) {
|
|
||||||
auto loc = std::locale(std::locale(), new numpunct<wchar_t>());
|
|
||||||
EXPECT_EQ(L"1234567", fmt::format(std::locale(), L"{:L}", 1234567));
|
|
||||||
EXPECT_EQ(L"1~234~567", fmt::format(loc, L"{:L}", 1234567));
|
|
||||||
using wcontext = fmt::buffer_context<wchar_t>;
|
|
||||||
fmt::format_arg_store<wcontext, int> as{1234567};
|
|
||||||
EXPECT_EQ(L"1~234~567",
|
|
||||||
fmt::vformat(loc, L"{:L}", fmt::basic_format_args<wcontext>(as)));
|
|
||||||
EXPECT_EQ(L"1234567", fmt::format(std::locale("C"), L"{:L}", 1234567));
|
|
||||||
|
|
||||||
auto no_grouping_loc = std::locale(std::locale(), new no_grouping<wchar_t>());
|
|
||||||
EXPECT_EQ(L"1234567", fmt::format(no_grouping_loc, L"{:L}", 1234567));
|
|
||||||
|
|
||||||
auto special_grouping_loc =
|
|
||||||
std::locale(std::locale(), new special_grouping<wchar_t>());
|
|
||||||
EXPECT_EQ(L"1,23,45,678",
|
|
||||||
fmt::format(special_grouping_loc, L"{:L}", 12345678));
|
|
||||||
|
|
||||||
auto small_grouping_loc =
|
|
||||||
std::locale(std::locale(), new small_grouping<wchar_t>());
|
|
||||||
EXPECT_EQ(L"4,2,9,4,9,6,7,2,9,5",
|
|
||||||
fmt::format(small_grouping_loc, L"{:L}", max_value<uint32_t>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(locale_test, double_formatter) {
|
|
||||||
auto loc = std::locale(std::locale(), new special_grouping<char>());
|
|
||||||
auto f = fmt::formatter<int>();
|
|
||||||
auto parse_ctx = fmt::format_parse_context("L");
|
|
||||||
f.parse(parse_ctx);
|
|
||||||
char buf[10] = {};
|
|
||||||
fmt::basic_format_context<char*, char> format_ctx(
|
|
||||||
buf, {}, fmt::detail::locale_ref(loc));
|
|
||||||
*f.format(12345, format_ctx) = 0;
|
|
||||||
EXPECT_STREQ("12,345", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
template <class charT> struct formatter<std::complex<double>, charT> {
|
|
||||||
private:
|
|
||||||
detail::dynamic_format_specs<char> specs_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FMT_CONSTEXPR typename basic_format_parse_context<charT>::iterator parse(
|
|
||||||
basic_format_parse_context<charT>& ctx) {
|
|
||||||
using handler_type =
|
|
||||||
detail::dynamic_specs_handler<basic_format_parse_context<charT>>;
|
|
||||||
detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
|
|
||||||
detail::type::string_type);
|
|
||||||
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
|
|
||||||
detail::parse_float_type_spec(specs_, ctx.error_handler());
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class FormatContext>
|
|
||||||
typename FormatContext::iterator format(const std::complex<double>& c,
|
|
||||||
FormatContext& ctx) {
|
|
||||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
|
||||||
specs_.precision, specs_.precision_ref, ctx);
|
|
||||||
auto specs = std::string();
|
|
||||||
if (specs_.precision > 0) specs = fmt::format(".{}", specs_.precision);
|
|
||||||
if (specs_.type) specs += specs_.type;
|
|
||||||
auto real = fmt::format(ctx.locale().template get<std::locale>(),
|
|
||||||
"{:" + specs + "}", c.real());
|
|
||||||
auto imag = fmt::format(ctx.locale().template get<std::locale>(),
|
|
||||||
"{:" + specs + "}", c.imag());
|
|
||||||
auto fill_align_width = std::string();
|
|
||||||
if (specs_.width > 0) fill_align_width = fmt::format(">{}", specs_.width);
|
|
||||||
return format_to(ctx.out(), runtime("{:" + fill_align_width + "}"),
|
|
||||||
c.real() != 0 ? fmt::format("({}+{}i)", real, imag)
|
|
||||||
: fmt::format("{}i", imag));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
|
|
||||||
TEST(locale_test, complex) {
|
|
||||||
std::string s = fmt::format("{}", std::complex<double>(1, 2));
|
|
||||||
EXPECT_EQ(s, "(1+2i)");
|
|
||||||
EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)");
|
|
||||||
EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
|
@@ -7,8 +7,12 @@
|
|||||||
|
|
||||||
#include "fmt/wchar.h"
|
#include "fmt/wchar.h"
|
||||||
|
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
using fmt::detail::max_value;
|
||||||
|
|
||||||
// std::is_constructible is broken in MSVC until version 2015.
|
// std::is_constructible is broken in MSVC until version 2015.
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1900
|
#if !FMT_MSC_VER || FMT_MSC_VER >= 1900
|
||||||
struct explicitly_convertible_to_wstring_view {
|
struct explicitly_convertible_to_wstring_view {
|
||||||
@@ -82,3 +86,157 @@ TEST(wchar_test, join) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(wchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }
|
TEST(wchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }
|
||||||
|
|
||||||
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
template <typename Char> struct numpunct : std::numpunct<Char> {
|
||||||
|
protected:
|
||||||
|
Char do_decimal_point() const override { return '?'; }
|
||||||
|
std::string do_grouping() const override { return "\03"; }
|
||||||
|
Char do_thousands_sep() const override { return '~'; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct no_grouping : std::numpunct<Char> {
|
||||||
|
protected:
|
||||||
|
Char do_decimal_point() const override { return '.'; }
|
||||||
|
std::string do_grouping() const override { return ""; }
|
||||||
|
Char do_thousands_sep() const override { return ','; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct special_grouping : std::numpunct<Char> {
|
||||||
|
protected:
|
||||||
|
Char do_decimal_point() const override { return '.'; }
|
||||||
|
std::string do_grouping() const override { return "\03\02"; }
|
||||||
|
Char do_thousands_sep() const override { return ','; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct small_grouping : std::numpunct<Char> {
|
||||||
|
protected:
|
||||||
|
Char do_decimal_point() const override { return '.'; }
|
||||||
|
std::string do_grouping() const override { return "\01"; }
|
||||||
|
Char do_thousands_sep() const override { return ','; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(locale_test, double_decimal_point) {
|
||||||
|
auto loc = std::locale(std::locale(), new numpunct<char>());
|
||||||
|
EXPECT_EQ("1?23", fmt::format(loc, "{:L}", 1.23));
|
||||||
|
EXPECT_EQ("1?230000", fmt::format(loc, "{:Lf}", 1.23));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(locale_test, format) {
|
||||||
|
auto loc = std::locale(std::locale(), new numpunct<char>());
|
||||||
|
EXPECT_EQ("1234567", fmt::format(std::locale(), "{:L}", 1234567));
|
||||||
|
EXPECT_EQ("1~234~567", fmt::format(loc, "{:L}", 1234567));
|
||||||
|
EXPECT_EQ("-1~234~567", fmt::format(loc, "{:L}", -1234567));
|
||||||
|
EXPECT_EQ("-256", fmt::format(loc, "{:L}", -256));
|
||||||
|
fmt::format_arg_store<fmt::format_context, int> as{1234567};
|
||||||
|
EXPECT_EQ("1~234~567", fmt::vformat(loc, "{:L}", fmt::format_args(as)));
|
||||||
|
auto s = std::string();
|
||||||
|
fmt::format_to(std::back_inserter(s), loc, "{:L}", 1234567);
|
||||||
|
EXPECT_EQ("1~234~567", s);
|
||||||
|
|
||||||
|
auto no_grouping_loc = std::locale(std::locale(), new no_grouping<char>());
|
||||||
|
EXPECT_EQ("1234567", fmt::format(no_grouping_loc, "{:L}", 1234567));
|
||||||
|
|
||||||
|
auto special_grouping_loc =
|
||||||
|
std::locale(std::locale(), new special_grouping<char>());
|
||||||
|
EXPECT_EQ("1,23,45,678", fmt::format(special_grouping_loc, "{:L}", 12345678));
|
||||||
|
EXPECT_EQ("12,345", fmt::format(special_grouping_loc, "{:L}", 12345));
|
||||||
|
|
||||||
|
auto small_grouping_loc =
|
||||||
|
std::locale(std::locale(), new small_grouping<char>());
|
||||||
|
EXPECT_EQ("4,2,9,4,9,6,7,2,9,5",
|
||||||
|
fmt::format(small_grouping_loc, "{:L}", max_value<uint32_t>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(locale_test, format_detault_align) {
|
||||||
|
auto loc = std::locale({}, new special_grouping<char>());
|
||||||
|
EXPECT_EQ(" 12,345", fmt::format(loc, "{:8L}", 12345));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(locale_test, format_plus) {
|
||||||
|
auto loc = std::locale({}, new special_grouping<char>());
|
||||||
|
EXPECT_EQ("+100", fmt::format(loc, "{:+L}", 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(locale_test, wformat) {
|
||||||
|
auto loc = std::locale(std::locale(), new numpunct<wchar_t>());
|
||||||
|
EXPECT_EQ(L"1234567", fmt::format(std::locale(), L"{:L}", 1234567));
|
||||||
|
EXPECT_EQ(L"1~234~567", fmt::format(loc, L"{:L}", 1234567));
|
||||||
|
using wcontext = fmt::buffer_context<wchar_t>;
|
||||||
|
fmt::format_arg_store<wcontext, int> as{1234567};
|
||||||
|
EXPECT_EQ(L"1~234~567",
|
||||||
|
fmt::vformat(loc, L"{:L}", fmt::basic_format_args<wcontext>(as)));
|
||||||
|
EXPECT_EQ(L"1234567", fmt::format(std::locale("C"), L"{:L}", 1234567));
|
||||||
|
|
||||||
|
auto no_grouping_loc = std::locale(std::locale(), new no_grouping<wchar_t>());
|
||||||
|
EXPECT_EQ(L"1234567", fmt::format(no_grouping_loc, L"{:L}", 1234567));
|
||||||
|
|
||||||
|
auto special_grouping_loc =
|
||||||
|
std::locale(std::locale(), new special_grouping<wchar_t>());
|
||||||
|
EXPECT_EQ(L"1,23,45,678",
|
||||||
|
fmt::format(special_grouping_loc, L"{:L}", 12345678));
|
||||||
|
|
||||||
|
auto small_grouping_loc =
|
||||||
|
std::locale(std::locale(), new small_grouping<wchar_t>());
|
||||||
|
EXPECT_EQ(L"4,2,9,4,9,6,7,2,9,5",
|
||||||
|
fmt::format(small_grouping_loc, L"{:L}", max_value<uint32_t>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(locale_test, double_formatter) {
|
||||||
|
auto loc = std::locale(std::locale(), new special_grouping<char>());
|
||||||
|
auto f = fmt::formatter<int>();
|
||||||
|
auto parse_ctx = fmt::format_parse_context("L");
|
||||||
|
f.parse(parse_ctx);
|
||||||
|
char buf[10] = {};
|
||||||
|
fmt::basic_format_context<char*, char> format_ctx(
|
||||||
|
buf, {}, fmt::detail::locale_ref(loc));
|
||||||
|
*f.format(12345, format_ctx) = 0;
|
||||||
|
EXPECT_STREQ("12,345", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <class charT> struct formatter<std::complex<double>, charT> {
|
||||||
|
private:
|
||||||
|
detail::dynamic_format_specs<char> specs_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR typename basic_format_parse_context<charT>::iterator parse(
|
||||||
|
basic_format_parse_context<charT>& ctx) {
|
||||||
|
using handler_type =
|
||||||
|
detail::dynamic_specs_handler<basic_format_parse_context<charT>>;
|
||||||
|
detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
|
||||||
|
detail::type::string_type);
|
||||||
|
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
|
||||||
|
detail::parse_float_type_spec(specs_, ctx.error_handler());
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class FormatContext>
|
||||||
|
typename FormatContext::iterator format(const std::complex<double>& c,
|
||||||
|
FormatContext& ctx) {
|
||||||
|
detail::handle_dynamic_spec<detail::precision_checker>(
|
||||||
|
specs_.precision, specs_.precision_ref, ctx);
|
||||||
|
auto specs = std::string();
|
||||||
|
if (specs_.precision > 0) specs = fmt::format(".{}", specs_.precision);
|
||||||
|
if (specs_.type) specs += specs_.type;
|
||||||
|
auto real = fmt::format(ctx.locale().template get<std::locale>(),
|
||||||
|
fmt::runtime("{:" + specs + "}"), c.real());
|
||||||
|
auto imag = fmt::format(ctx.locale().template get<std::locale>(),
|
||||||
|
fmt::runtime("{:" + specs + "}"), c.imag());
|
||||||
|
auto fill_align_width = std::string();
|
||||||
|
if (specs_.width > 0) fill_align_width = fmt::format(">{}", specs_.width);
|
||||||
|
return format_to(ctx.out(), runtime("{:" + fill_align_width + "}"),
|
||||||
|
c.real() != 0 ? fmt::format("({}+{}i)", real, imag)
|
||||||
|
: fmt::format("{}i", imag));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
TEST(locale_test, complex) {
|
||||||
|
std::string s = fmt::format("{}", std::complex<double>(1, 2));
|
||||||
|
EXPECT_EQ(s, "(1+2i)");
|
||||||
|
EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)");
|
||||||
|
EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
Reference in New Issue
Block a user