diff --git a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_fr_FR.pass.cpp b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_fr_FR.pass.cpp --- a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_fr_FR.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_fr_FR.pass.cpp @@ -28,6 +28,7 @@ #include #include "test_iterators.h" +#include "locale_helpers.h" #include "platform_support.h" // locale name macros #include "test_macros.h" @@ -52,36 +53,8 @@ : Fw(refs) {} }; -// GLIBC 2.27 and newer use U+202F NARROW NO-BREAK SPACE as a thousands separator. -// This function converts the spaces in string inputs to U+202F if need -// be. FreeBSD's locale data also uses U+202F, since 2018. -// Windows uses U+00A0 NO-BREAK SPACE. static std::wstring convert_thousands_sep(std::wstring const& in) { -#if defined(_CS_GNU_LIBC_VERSION) || defined(__FreeBSD__) || defined(_WIN32) -#if defined(_CS_GNU_LIBC_VERSION) - if (glibc_version_less_than("2.27")) - return in; -#endif - std::wstring out; - unsigned I = 0; - bool seen_decimal = false; - for (; I < in.size(); ++I) { - if (seen_decimal || in[I] != L' ') { - seen_decimal |= in[I] == L','; - out.push_back(in[I]); - continue; - } - assert(in[I] == L' '); -#if defined(_WIN32) - out.push_back(L'\u00A0'); -#else - out.push_back(L'\u202F'); -#endif - } - return out; -#else - return in; -#endif + return LocaleHelpers::convert_thousands_sep_fr_FR(in); } #endif // TEST_HAS_NO_WIDE_CHARACTERS diff --git a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp --- a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.get/locale.money.get.members/get_long_double_ru_RU.pass.cpp @@ -9,14 +9,6 @@ // NetBSD does not support LC_MONETARY at the moment // XFAIL: netbsd -// Failure related to GLIBC's use of U00A0 as mon_thousands_sep -// and U002E as mon_decimal_point. -// TODO: U00A0 should be investigated. -// Possibly related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16006 -// XFAIL: linux - -// XFAIL: LIBCXX-WINDOWS-FIXME - // REQUIRES: locale.ru_RU.UTF-8 // @@ -33,6 +25,7 @@ #include "test_macros.h" #include "test_iterators.h" +#include "locale_helpers.h" #include "platform_support.h" // locale name macros typedef std::money_get > Fn; @@ -55,7 +48,11 @@ explicit my_facetw(std::size_t refs = 0) : Fw(refs) {} }; -#endif + +static std::wstring convert_thousands_sep(std::wstring const& in) { + return LocaleHelpers::convert_thousands_sep_ru_RU(in); +} +#endif // TEST_HAS_NO_WIDE_CHARACTERS int main(int, char**) { @@ -70,6 +67,11 @@ new std::moneypunct_byname(loc_name))); ios.imbue(std::locale(ios.getloc(), new std::moneypunct_byname(loc_name))); +#endif +#if defined(TEST_HAS_GLIBC) || defined(__FreeBSD__) || defined(_WIN32) + std::string symbol = "\xE2\x82\xBD"; +#else + std::string symbol = "\xD1\x80\xD1\x83\xD0\xB1""."; #endif { const my_facet f(1); @@ -130,7 +132,7 @@ assert(ex == -123456789); } { // zero, showbase - std::string v = "0,00 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "0,00 " + symbol; typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -141,7 +143,7 @@ assert(ex == 0); } { // zero, showbase - std::string v = "0,00 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "0,00 " + symbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -154,7 +156,7 @@ std::noshowbase(ios); } { // negative one, showbase - std::string v = "-0,01 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "-0,01 " + symbol; typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -165,7 +167,7 @@ assert(ex == -1); } { // negative one, showbase - std::string v = "-0,01 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "-0,01 " + symbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -178,7 +180,7 @@ std::noshowbase(ios); } { // positive, showbase - std::string v = "1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "1 234 567,89 " + symbol; typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -189,7 +191,7 @@ assert(ex == 123456789); } { // positive, showbase - std::string v = "1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "1 234 567,89 " + symbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -202,7 +204,7 @@ std::noshowbase(ios); } { // negative, showbase - std::string v = "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "-1 234 567,89 " + symbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -382,7 +384,7 @@ std::noshowbase(ios); } { // negative, showbase - std::string v = "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "-1 234 567,89 " + symbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -394,7 +396,7 @@ std::noshowbase(ios); } { // negative, showbase - std::string v = "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."; + std::string v = "-1 234 567,89 " + symbol; typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -406,6 +408,11 @@ } } #ifndef TEST_HAS_NO_WIDE_CHARACTERS +#if defined(TEST_HAS_GLIBC) || defined(__FreeBSD__) || defined(_WIN32) + std::wstring wsymbol = L"\x20BD"; +#else + std::wstring wsymbol = L"\x440\x443\x431""."; +#endif { const my_facetw f(1); // wchar_t, national @@ -432,7 +439,7 @@ assert(ex == -1); } { // positive - std::wstring v = L"1 234 567,89 "; + std::wstring v = convert_thousands_sep(L"1 234 567,89 "); typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -443,7 +450,7 @@ assert(ex == 123456789); } { // negative - std::wstring v = L"-1 234 567,89 "; + std::wstring v = convert_thousands_sep(L"-1 234 567,89 "); typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -465,7 +472,7 @@ assert(ex == -123456789); } { // zero, showbase - std::wstring v = L"0,00 \x440\x443\x431""."; + std::wstring v = L"0,00 " + wsymbol; typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -476,7 +483,7 @@ assert(ex == 0); } { // zero, showbase - std::wstring v = L"0,00 \x440\x443\x431""."; + std::wstring v = L"0,00 " + wsymbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -489,7 +496,7 @@ std::noshowbase(ios); } { // negative one, showbase - std::wstring v = L"-0,01 \x440\x443\x431""."; + std::wstring v = L"-0,01 " + wsymbol; typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -500,7 +507,7 @@ assert(ex == -1); } { // negative one, showbase - std::wstring v = L"-0,01 \x440\x443\x431""."; + std::wstring v = L"-0,01 " + wsymbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -513,7 +520,7 @@ std::noshowbase(ios); } { // positive, showbase - std::wstring v = L"1 234 567,89 \x440\x443\x431""."; + std::wstring v = convert_thousands_sep(L"1 234 567,89 ") + wsymbol; typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -524,7 +531,7 @@ assert(ex == 123456789); } { // positive, showbase - std::wstring v = L"1 234 567,89 \x440\x443\x431""."; + std::wstring v = convert_thousands_sep(L"1 234 567,89 ") + wsymbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -537,7 +544,7 @@ std::noshowbase(ios); } { // negative, showbase - std::wstring v = L"-1 234 567,89 \x440\x443\x431""."; + std::wstring v = convert_thousands_sep(L"-1 234 567,89 ") + wsymbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -550,7 +557,7 @@ std::noshowbase(ios); } { // negative, showbase - std::wstring v = L"-1 234 567,89 RUB"; + std::wstring v = convert_thousands_sep(L"-1 234 567,89 RUB"); std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -562,7 +569,7 @@ std::noshowbase(ios); } { // negative, showbase - std::wstring v = L"-1 234 567,89 RUB"; + std::wstring v = convert_thousands_sep(L"-1 234 567,89 RUB"); typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -599,7 +606,7 @@ assert(ex == -1); } { // positive - std::wstring v = L"1 234 567,89 "; + std::wstring v = convert_thousands_sep(L"1 234 567,89 "); typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -610,7 +617,7 @@ assert(ex == 123456789); } { // negative - std::wstring v = L"-1 234 567,89 "; + std::wstring v = convert_thousands_sep(L"-1 234 567,89 "); typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -680,7 +687,7 @@ std::noshowbase(ios); } { // positive, showbase - std::wstring v = L"1 234 567,89 RUB"; + std::wstring v = convert_thousands_sep(L"1 234 567,89 RUB"); typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; @@ -691,7 +698,7 @@ assert(ex == 123456789); } { // positive, showbase - std::wstring v = L"1 234 567,89 RUB"; + std::wstring v = convert_thousands_sep(L"1 234 567,89 RUB"); std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -704,7 +711,7 @@ std::noshowbase(ios); } { // negative, showbase - std::wstring v = L"-1 234 567,89 RUB"; + std::wstring v = convert_thousands_sep(L"-1 234 567,89 RUB"); std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -717,7 +724,7 @@ std::noshowbase(ios); } { // negative, showbase - std::wstring v = L"-1 234 567,89 \x440\x443\x431""."; + std::wstring v = convert_thousands_sep(L"-1 234 567,89 ") + wsymbol; std::showbase(ios); typedef cpp17_input_iterator I; long double ex; @@ -729,7 +736,7 @@ std::noshowbase(ios); } { // negative, showbase - std::wstring v = L"-1 234 567,89 \x440\x443\x431""."; + std::wstring v = convert_thousands_sep(L"-1 234 567,89 ") + wsymbol; typedef cpp17_input_iterator I; long double ex; std::ios_base::iostate err = std::ios_base::goodbit; diff --git a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_fr_FR.pass.cpp b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_fr_FR.pass.cpp --- a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_fr_FR.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_fr_FR.pass.cpp @@ -28,6 +28,7 @@ #include #include "test_iterators.h" +#include "locale_helpers.h" #include "platform_support.h" // locale name macros #include "test_macros.h" @@ -52,38 +53,8 @@ : Fw(refs) {} }; -// GLIBC 2.27 and newer use U+202F NARROW NO-BREAK SPACE as a thousands separator. -// This function converts the spaces in string inputs to U+202F if need -// be. FreeBSD's locale data also uses U+202F, since 2018. -// Windows uses U+00A0 NO-BREAK SPACE. static std::wstring convert_thousands_sep(std::wstring const& in) { -#if defined(_CS_GNU_LIBC_VERSION) || defined(__FreeBSD__) || defined(_WIN32) -#if defined(_CS_GNU_LIBC_VERSION) - if (glibc_version_less_than("2.27")) - return in; -#endif - std::wstring out; - unsigned I = 0; - bool seen_num_start = false; - bool seen_decimal = false; - for (; I < in.size(); ++I) { - seen_decimal |= in[I] == L','; - seen_num_start |= in[I] == '-' || std::iswdigit(in[I]); - if (seen_decimal || !seen_num_start || in[I] != L' ') { - out.push_back(in[I]); - continue; - } - assert(in[I] == L' '); -#if defined(_WIN32) - out.push_back(L'\u00A0'); -#else - out.push_back(L'\u202F'); -#endif - } - return out; -#else - return in; -#endif + return LocaleHelpers::convert_thousands_sep_fr_FR(in); } #endif // TEST_HAS_NO_WIDE_CHARACTERS diff --git a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp --- a/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.monetary/locale.money.put/locale.money.put.members/put_long_double_ru_RU.pass.cpp @@ -9,14 +9,6 @@ // NetBSD does not support LC_MONETARY at the moment // XFAIL: netbsd -// Failure related to GLIBC's use of U00A0 as mon_thousands_sep -// and U002E as mon_decimal_point. -// TODO: U00A0 should be investigated. -// Possibly related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=16006 -// XFAIL: linux - -// XFAIL: LIBCXX-WINDOWS-FIXME - // REQUIRES: locale.ru_RU.UTF-8 // @@ -33,6 +25,7 @@ #include "test_macros.h" #include "test_iterators.h" +#include "locale_helpers.h" #include "platform_support.h" // locale name macros typedef std::money_put > Fn; @@ -55,7 +48,11 @@ explicit my_facetw(std::size_t refs = 0) : Fw(refs) {} }; -#endif + +static std::wstring convert_thousands_sep(std::wstring const& in) { + return LocaleHelpers::convert_thousands_sep_ru_RU(in); +} +#endif // TEST_HAS_NO_WIDE_CHARACTERS int main(int, char**) { @@ -72,6 +69,11 @@ new std::moneypunct_byname(loc_name))); #endif { +#if defined(TEST_HAS_GLIBC) || defined(__FreeBSD__) || defined(_WIN32) + std::string symbol = "\xE2\x82\xBD"; +#else + std::string symbol = "\xD1\x80\xD1\x83\xD0\xB1""."; +#endif const my_facet f(1); // char, national { // zero @@ -108,7 +110,7 @@ char str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::string ex(str, iter.base()); - assert(ex == "0,00 \xD1\x80\xD1\x83\xD0\xB1""."); + assert(ex == "0,00 " + symbol); } { // negative one, showbase long double v = -1; @@ -116,7 +118,7 @@ char str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::string ex(str, iter.base()); - assert(ex == "-0,01 \xD1\x80\xD1\x83\xD0\xB1""."); + assert(ex == "-0,01 " + symbol); } { // positive, showbase long double v = 123456789; @@ -124,7 +126,7 @@ char str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::string ex(str, iter.base()); - assert(ex == "1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."); + assert(ex == "1 234 567,89 " + symbol); } { // negative, showbase long double v = -123456789; @@ -132,39 +134,39 @@ char str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::string ex(str, iter.base()); - assert(ex == "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."); + assert(ex == "-1 234 567,89 " + symbol); } { // negative, showbase, left long double v = -123456789; std::showbase(ios); - ios.width(20); + ios.width(15); std::left(ios); char str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, ' ', v); std::string ex(str, iter.base()); - assert(ex == "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."); + assert(ex == "-1 234 567,89 " + symbol); assert(ios.width() == 0); } { // negative, showbase, internal long double v = -123456789; std::showbase(ios); - ios.width(20); + ios.width(15); std::internal(ios); char str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, ' ', v); std::string ex(str, iter.base()); - assert(ex == "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."); + assert(ex == "-1 234 567,89 " + symbol); assert(ios.width() == 0); } { // negative, showbase, right long double v = -123456789; std::showbase(ios); - ios.width(20); + ios.width(15); std::right(ios); char str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, ' ', v); std::string ex(str, iter.base()); - assert(ex == "-1 234 567,89 \xD1\x80\xD1\x83\xD0\xB1""."); + assert(ex == "-1 234 567,89 " + symbol); assert(ios.width() == 0); } @@ -267,6 +269,11 @@ } #ifndef TEST_HAS_NO_WIDE_CHARACTERS { +#if defined(TEST_HAS_GLIBC) || defined(__FreeBSD__) || defined(_WIN32) + std::wstring symbol = L"\x20BD"; +#else + std::wstring symbol = L"\x440\x443\x431""."; +#endif const my_facetw f(1); // wchar_t, national std::noshowbase(ios); @@ -290,14 +297,14 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"1 234 567,89"); + assert(ex == convert_thousands_sep(L"1 234 567,89")); } { // negative long double v = -123456789; wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"-1 234 567,89"); + assert(ex == convert_thousands_sep(L"-1 234 567,89")); } { // zero, showbase long double v = 0; @@ -305,7 +312,7 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"0,00 \x440\x443\x431""."); + assert(ex == L"0,00 " + symbol); } { // negative one, showbase long double v = -1; @@ -313,7 +320,7 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"-0,01 \x440\x443\x431""."); + assert(ex == L"-0,01 " + symbol); } { // positive, showbase long double v = 123456789; @@ -321,7 +328,7 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"1 234 567,89 \x440\x443\x431""."); + assert(ex == convert_thousands_sep(L"1 234 567,89 ") + symbol); } { // negative, showbase long double v = -123456789; @@ -329,39 +336,39 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"-1 234 567,89 \x440\x443\x431""."); + assert(ex == convert_thousands_sep(L"-1 234 567,89 ") + symbol); } { // negative, showbase, left long double v = -123456789; std::showbase(ios); - ios.width(20); + ios.width(15); std::left(ios); wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, ' ', v); std::wstring ex(str, iter.base()); - assert(ex == L"-1 234 567,89 \x440\x443\x431"". "); + assert(ex == convert_thousands_sep(L"-1 234 567,89 ") + symbol); assert(ios.width() == 0); } { // negative, showbase, internal long double v = -123456789; std::showbase(ios); - ios.width(20); + ios.width(15); std::internal(ios); wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, ' ', v); std::wstring ex(str, iter.base()); - assert(ex == L"-1 234 567,89 \x440\x443\x431""."); + assert(ex == convert_thousands_sep(L"-1 234 567,89 ") + symbol); assert(ios.width() == 0); } { // negative, showbase, right long double v = -123456789; std::showbase(ios); - ios.width(20); + ios.width(15); std::right(ios); wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), false, ios, ' ', v); std::wstring ex(str, iter.base()); - assert(ex == L" -1 234 567,89 \x440\x443\x431""."); + assert(ex == convert_thousands_sep(L"-1 234 567,89 ") + symbol); assert(ios.width() == 0); } @@ -387,14 +394,14 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), true, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"1 234 567,89"); + assert(ex == convert_thousands_sep(L"1 234 567,89")); } { // negative long double v = -123456789; wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), true, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"-1 234 567,89"); + assert(ex == convert_thousands_sep(L"-1 234 567,89")); } { // zero, showbase long double v = 0; @@ -418,7 +425,7 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), true, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"1 234 567,89 RUB"); + assert(ex == convert_thousands_sep(L"1 234 567,89 RUB")); } { // negative, showbase long double v = -123456789; @@ -426,7 +433,7 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), true, ios, '*', v); std::wstring ex(str, iter.base()); - assert(ex == L"-1 234 567,89 RUB"); + assert(ex == convert_thousands_sep(L"-1 234 567,89 RUB")); } { // negative, showbase, left long double v = -123456789; @@ -436,7 +443,7 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), true, ios, ' ', v); std::wstring ex(str, iter.base()); - assert(ex == L"-1 234 567,89 RUB "); + assert(ex == convert_thousands_sep(L"-1 234 567,89 RUB ")); assert(ios.width() == 0); } { // negative, showbase, internal @@ -447,7 +454,7 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), true, ios, ' ', v); std::wstring ex(str, iter.base()); - assert(ex == L"-1 234 567,89 RUB"); + assert(ex == convert_thousands_sep(L"-1 234 567,89 RUB")); assert(ios.width() == 0); } { // negative, showbase, right @@ -458,7 +465,7 @@ wchar_t str[100]; cpp17_output_iterator iter = f.put(cpp17_output_iterator(str), true, ios, ' ', v); std::wstring ex(str, iter.base()); - assert(ex == L" -1 234 567,89 RUB"); + assert(ex == convert_thousands_sep(L" -1 234 567,89 RUB")); assert(ios.width() == 0); } } diff --git a/libcxx/test/support/locale_helpers.h b/libcxx/test/support/locale_helpers.h new file mode 100644 --- /dev/null +++ b/libcxx/test/support/locale_helpers.h @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef LIBCXX_TEST_SUPPORT_LOCALE_HELPERS_H +#define LIBCXX_TEST_SUPPORT_LOCALE_HELPERS_H + +#include +#include +#include "platform_support.h" +#include "test_macros.h" + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + +namespace LocaleHelpers { + +std::wstring convert_thousands_sep(std::wstring const& in, wchar_t sep) { + std::wstring out; + bool seen_num_start = false; + bool seen_decimal = false; + for (unsigned i = 0; i < in.size(); ++i) { + seen_decimal |= in[i] == L','; + seen_num_start |= in[i] == L'-' || std::iswdigit(in[i]); + if (seen_decimal || !seen_num_start || in[i] != L' ') { + out.push_back(in[i]); + continue; + } + assert(in[i] == L' '); + out.push_back(sep); + } + return out; +} + +// GLIBC 2.27 and newer use U+202F NARROW NO-BREAK SPACE as a thousands separator. +// This function converts the spaces in string inputs to U+202F if need +// be. FreeBSD's locale data also uses U+202F, since 2018. +// Windows uses U+00A0 NO-BREAK SPACE. +std::wstring convert_thousands_sep_fr_FR(std::wstring const& in) { +#if defined(_CS_GNU_LIBC_VERSION) || defined(__FreeBSD__) +#if defined(_CS_GNU_LIBC_VERSION) + if (glibc_version_less_than("2.27")) + return in; +#endif + return convert_thousands_sep(in, L'\u202F'); +#elif defined(_WIN32) + return convert_thousands_sep(in, L'\u00A0'); +#else + return in; +#endif +} + +// GLIBC 2.27 uses U+202F NARROW NO-BREAK SPACE as a thousands separator. +// FreeBSD and Windows use U+00A0 NO-BREAK SPACE. +std::wstring convert_thousands_sep_ru_RU(std::wstring const& in) { +#if defined(TEST_HAS_GLIBC) + return convert_thousands_sep(in, L'\u202F'); +#elif defined(__FreeBSD__) || defined(_WIN32) + return convert_thousands_sep(in, L'\u00A0'); +#else + return in; +#endif +} + +} // namespace LocaleHelpers + +#endif // TEST_HAS_NO_WIDE_CHARACTERS + +#endif // LIBCXX_TEST_SUPPORT_LOCALE_HELPERS_H