зеркало из https://github.com/microsoft/STL.git
Implement P2419R2 Clarify Handling Of Encodings In Localized Formatting Of `chrono` Types (#2977)
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
Родитель
2ae879b73c
Коммит
ff29e7a6d0
|
@ -10,6 +10,12 @@
|
|||
#if _STL_COMPILER_PREPROCESSOR
|
||||
#include <__msvc_chrono.hpp>
|
||||
|
||||
#if _HAS_CXX17
|
||||
#include <system_error>
|
||||
#include <xfilesystem_abi.h>
|
||||
#include <xstring>
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#if _HAS_CXX20
|
||||
#include <__msvc_tzdb.hpp>
|
||||
#include <algorithm>
|
||||
|
@ -45,6 +51,55 @@ _STL_DISABLE_CLANG_WARNINGS
|
|||
#undef new
|
||||
|
||||
_STD_BEGIN
|
||||
#if _HAS_CXX17
|
||||
// We would really love to use the proper way of building error_code by specializing
|
||||
// is_error_code_enum and make_error_code for __std_win_error, but because:
|
||||
// 1. We would like to keep the definition of __std_win_error in xfilesystem_abi.h
|
||||
// 2. and xfilesystem_abi.h cannot include <system_error>
|
||||
// 3. and specialization of is_error_code_enum and overload of make_error_code
|
||||
// need to be kept together with the enum (see limerick in N4810 [temp.expl.spec]/7)
|
||||
// we resort to using this _Make_ec helper.
|
||||
_NODISCARD inline error_code _Make_ec(__std_win_error _Errno) noexcept { // make an error_code
|
||||
return {static_cast<int>(_Errno), _STD system_category()};
|
||||
}
|
||||
|
||||
[[noreturn]] inline void _Throw_system_error_from_std_win_error(const __std_win_error _Errno) {
|
||||
_THROW(system_error{_Make_ec(_Errno)});
|
||||
}
|
||||
|
||||
_NODISCARD inline int _Check_convert_result(const __std_fs_convert_result _Result) {
|
||||
if (_Result._Err != __std_win_error::_Success) {
|
||||
_Throw_system_error_from_std_win_error(_Result._Err);
|
||||
}
|
||||
|
||||
return _Result._Len;
|
||||
}
|
||||
|
||||
template <class _Traits, class _Alloc>
|
||||
_NODISCARD basic_string<typename _Traits::char_type, _Traits, _Alloc> _Convert_wide_to_narrow(
|
||||
const __std_code_page _Code_page, const wstring_view _Input, const _Alloc& _Al) {
|
||||
basic_string<typename _Traits::char_type, _Traits, _Alloc> _Output(_Al);
|
||||
|
||||
if (!_Input.empty()) {
|
||||
if (_Input.size() > static_cast<size_t>(INT_MAX)) {
|
||||
_Throw_system_error(errc::invalid_argument);
|
||||
}
|
||||
|
||||
const int _Len = _Check_convert_result(
|
||||
__std_fs_convert_wide_to_narrow(_Code_page, _Input.data(), static_cast<int>(_Input.size()), nullptr, 0));
|
||||
|
||||
_Output.resize(static_cast<size_t>(_Len));
|
||||
|
||||
const auto _Data_as_char = reinterpret_cast<char*>(_Output.data());
|
||||
|
||||
(void) _Check_convert_result(__std_fs_convert_wide_to_narrow(
|
||||
_Code_page, _Input.data(), static_cast<int>(_Input.size()), _Data_as_char, _Len));
|
||||
}
|
||||
|
||||
return _Output;
|
||||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#if _HAS_CXX20
|
||||
namespace chrono {
|
||||
// [time.duration.io]
|
||||
|
@ -5189,6 +5244,18 @@ namespace chrono {
|
|||
return _Os << _Local_time_format_t<_Duration>{_Val.get_local_time(), &_Info.abbrev};
|
||||
}
|
||||
|
||||
template <class _CharT>
|
||||
_NODISCARD const _CharT* _Fmt_string(const _Chrono_spec<_CharT>& _Spec, _CharT (&_Fmt_str)[4]) {
|
||||
size_t _Next_idx = 0;
|
||||
_Fmt_str[_Next_idx++] = _CharT{'%'};
|
||||
if (_Spec._Modifier != '\0') {
|
||||
_Fmt_str[_Next_idx++] = static_cast<_CharT>(_Spec._Modifier);
|
||||
}
|
||||
_Fmt_str[_Next_idx++] = static_cast<_CharT>(_Spec._Type);
|
||||
_Fmt_str[_Next_idx] = _CharT{'\0'};
|
||||
return _Fmt_str;
|
||||
}
|
||||
|
||||
template <class _CharT>
|
||||
struct _Chrono_formatter {
|
||||
_Chrono_formatter() = default;
|
||||
|
@ -5351,6 +5418,24 @@ namespace chrono {
|
|||
|
||||
_Validate_specifiers(_Spec, _Val);
|
||||
|
||||
#if defined(_MSVC_EXECUTION_CHARACTER_SET) && _MSVC_EXECUTION_CHARACTER_SET == 65001 // TRANSITION, VSO-1468747 (EDG)
|
||||
if constexpr (is_same_v<_CharT, char>) {
|
||||
if (_Specs._Localized) {
|
||||
wostringstream _Wstream;
|
||||
_Wstream.imbue(_FormatCtx.locale());
|
||||
|
||||
wchar_t _Fmt_str[4];
|
||||
_Chrono_spec<wchar_t> _Wspec{._Modifier = _Spec._Modifier, ._Type = _Spec._Type};
|
||||
_Wstream << _STD put_time<wchar_t>(&_Time, _Fmt_string(_Wspec, _Fmt_str));
|
||||
|
||||
_Stream << _Convert_wide_to_narrow<char_traits<char>>(
|
||||
__std_code_page::_Utf8, _Wstream.view(), allocator<char>{});
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif // defined(_MSVC_EXECUTION_CHARACTER_SET) && _MSVC_EXECUTION_CHARACTER_SET == 65001
|
||||
|
||||
_CharT _Fmt_str[4];
|
||||
_Stream << _STD put_time<_CharT>(&_Time, _Fmt_string(_Spec, _Fmt_str));
|
||||
}
|
||||
|
@ -5675,17 +5760,6 @@ namespace chrono {
|
|||
}
|
||||
}
|
||||
|
||||
_NODISCARD static const _CharT* _Fmt_string(const _Chrono_spec<_CharT>& _Spec, _CharT (&_Fmt_str)[4]) {
|
||||
size_t _Next_idx = 0;
|
||||
_Fmt_str[_Next_idx++] = _CharT{'%'};
|
||||
if (_Spec._Modifier != '\0') {
|
||||
_Fmt_str[_Next_idx++] = static_cast<_CharT>(_Spec._Modifier);
|
||||
}
|
||||
_Fmt_str[_Next_idx++] = static_cast<_CharT>(_Spec._Type);
|
||||
_Fmt_str[_Next_idx] = _CharT{'\0'};
|
||||
return _Fmt_str;
|
||||
}
|
||||
|
||||
_Chrono_format_specs<_CharT> _Specs{};
|
||||
basic_string_view<_CharT> _Time_zone_abbreviation{};
|
||||
};
|
||||
|
|
|
@ -19,7 +19,6 @@ _EMIT_STL_WARNING(STL4038, "The contents of <filesystem> are available only with
|
|||
#include <list>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
@ -39,29 +38,6 @@ _STL_DISABLE_CLANG_WARNINGS
|
|||
|
||||
_STD_BEGIN
|
||||
namespace filesystem {
|
||||
// We would really love to use the proper way of building error_code by specializing
|
||||
// is_error_code_enum and make_error_code for __std_win_error, but because:
|
||||
// 1. We would like to keep the definition of __std_win_error in xfilesystem_abi.h
|
||||
// 2. and xfilesystem_abi.h cannot include <system_error>
|
||||
// 3. and specialization of is_error_code_enum and overload of make_error_code
|
||||
// need to be kept together with the enum (see limerick in N4810 [temp.expl.spec]/7)
|
||||
// we resort to using this _Make_ec helper.
|
||||
_NODISCARD inline error_code _Make_ec(__std_win_error _Errno) noexcept { // make an error_code
|
||||
return {static_cast<int>(_Errno), _STD system_category()};
|
||||
}
|
||||
|
||||
[[noreturn]] inline void _Throw_system_error_from_std_win_error(const __std_win_error _Errno) {
|
||||
_THROW(system_error{_Make_ec(_Errno)});
|
||||
}
|
||||
|
||||
_NODISCARD inline int _Check_convert_result(const __std_fs_convert_result _Result) {
|
||||
if (_Result._Err != __std_win_error::_Success) {
|
||||
_Throw_system_error_from_std_win_error(_Result._Err);
|
||||
}
|
||||
|
||||
return _Result._Len;
|
||||
}
|
||||
|
||||
_NODISCARD inline wstring _Convert_narrow_to_wide(const __std_code_page _Code_page, const string_view _Input) {
|
||||
wstring _Output;
|
||||
|
||||
|
@ -82,30 +58,6 @@ namespace filesystem {
|
|||
return _Output;
|
||||
}
|
||||
|
||||
template <class _Traits, class _Alloc>
|
||||
_NODISCARD basic_string<typename _Traits::char_type, _Traits, _Alloc> _Convert_wide_to_narrow(
|
||||
const __std_code_page _Code_page, const wstring_view _Input, const _Alloc& _Al) {
|
||||
basic_string<typename _Traits::char_type, _Traits, _Alloc> _Output(_Al);
|
||||
|
||||
if (!_Input.empty()) {
|
||||
if (_Input.size() > static_cast<size_t>(INT_MAX)) {
|
||||
_Throw_system_error(errc::invalid_argument);
|
||||
}
|
||||
|
||||
const int _Len = _Check_convert_result(__std_fs_convert_wide_to_narrow(
|
||||
_Code_page, _Input.data(), static_cast<int>(_Input.size()), nullptr, 0));
|
||||
|
||||
_Output.resize(static_cast<size_t>(_Len));
|
||||
|
||||
const auto _Data_as_char = reinterpret_cast<char*>(_Output.data());
|
||||
|
||||
(void) _Check_convert_result(__std_fs_convert_wide_to_narrow(
|
||||
_Code_page, _Input.data(), static_cast<int>(_Input.size()), _Data_as_char, _Len));
|
||||
}
|
||||
|
||||
return _Output;
|
||||
}
|
||||
|
||||
// More lenient version of _Convert_wide_to_narrow: Instead of failing on non-representable characters,
|
||||
// replace them with a replacement character.
|
||||
template <class _Traits, class _Alloc>
|
||||
|
|
|
@ -280,6 +280,7 @@
|
|||
// P2408R5 Ranges Iterators As Inputs To Non-Ranges Algorithms
|
||||
// P2415R2 What Is A view?
|
||||
// P2418R2 Add Support For std::generator-like Types To std::format
|
||||
// P2419R2 Clarify Handling Of Encodings In Localized Formatting Of chrono Types
|
||||
// P2432R1 Fix istream_view
|
||||
// P2520R0 move_iterator<T*> Should Be A Random-Access Iterator
|
||||
|
||||
|
|
|
@ -1119,6 +1119,7 @@ void test() {
|
|||
|
||||
#if !defined(_DLL) || _ITERATOR_DEBUG_LEVEL == DEFAULT_IDL_SETTING
|
||||
test_locale<wchar_t>();
|
||||
test_locale<char>();
|
||||
assert(setlocale(LC_ALL, ".UTF-8") != nullptr);
|
||||
test_locale<char>();
|
||||
#endif // !defined(_DLL) || _ITERATOR_DEBUG_LEVEL == DEFAULT_IDL_SETTING
|
||||
|
|
Загрузка…
Ссылка в новой задаче