libstdc++: P1423R3 char8_t remediation (2/4)

Update feature test macro, add deleted operators, update u8path

This patch increments the __cpp_lib_char8_t feature test macro, adds deleted
operator<< overloads for basic_ostream, and modifies u8path to accept
sequences of char8_t for both the C++17 implementation of std::filesystem, and
the filesystem TS implementation.

The implementation mechanism used for u8path differs between the C++17 and
filesystem TS implementations.  The changes to the former take advantage of
C++17 'if constexpr'.  The changes to the latter retain C++11 compatibility
and rely on tag dispatching.

2019-11-29  Tom Honermann  <tom@honermann.net>

	Update feature test macro, add deleted operators, update u8path
	* include/bits/c++config: Bumped the value of the __cpp_lib_char8_t
	feature test macro.
	* include/bits/fs_path.h (u8path): Modified u8path to accept sequences
	of char8_t.
	* include/experimental/bits/fs_path.h (u8path): Modified u8path to
	accept sequences of char8_t.
	* include/std/ostream: Added deleted overloads of wchar_t, char8_t,
	char16_t, and char32_t for ordinary and wide formatted character and
	string inserters.

From-SVN: r278856
This commit is contained in:
Tom Honermann 2019-11-29 17:43:42 +00:00 committed by Jonathan Wakely
parent a1e7d33bb9
commit 2b4e2c93d9
5 changed files with 217 additions and 35 deletions

View File

@ -1,5 +1,16 @@
2019-11-29 Tom Honermann <tom@honermann.net>
Update feature test macro, add deleted operators, update u8path
* include/bits/c++config: Bumped the value of the __cpp_lib_char8_t
feature test macro.
* include/bits/fs_path.h (u8path): Modified u8path to accept sequences
of char8_t.
* include/experimental/bits/fs_path.h (u8path): Modified u8path to
accept sequences of char8_t.
* include/std/ostream: Added deleted overloads of wchar_t, char8_t,
char16_t, and char32_t for ordinary and wide formatted character and
string inserters.
Decouple constraints for u8path from path constructors
* include/bits/fs_path.h: Moved helper utilities out of
std::filesystem::path into a detail namespace to make them

View File

@ -620,7 +620,7 @@ namespace std
# endif
#endif
#ifdef _GLIBCXX_USE_CHAR8_T
# define __cpp_lib_char8_t 201811L
# define __cpp_lib_char8_t 201907L
#endif
/* Define if __float128 is supported on this host. */

View File

@ -154,9 +154,24 @@ namespace __detail
template<typename _Tp,
typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
typename _Val = typename std::iterator_traits<_Iter>::value_type>
typename _Val = typename std::iterator_traits<_Iter>::value_type,
typename _UnqualVal = std::remove_const_t<_Val>>
using __value_type_is_char
= std::enable_if_t<std::is_same_v<std::remove_const_t<_Val>, char>>;
= std::enable_if_t<std::is_same_v<_UnqualVal, char>,
_UnqualVal>;
template<typename _Tp,
typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
typename _Val = typename std::iterator_traits<_Iter>::value_type,
typename _UnqualVal = std::remove_const_t<_Val>>
using __value_type_is_char_or_char8_t
= std::enable_if_t<__or_v<
std::is_same<_UnqualVal, char>
#ifdef _GLIBCXX_USE_CHAR8_T
, std::is_same<_UnqualVal, char8_t>
#endif
>,
_UnqualVal>;
} // namespace __detail
/// @endcond
@ -670,29 +685,41 @@ namespace __detail
*/
template<typename _InputIterator,
typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
typename _Require2 = __detail::__value_type_is_char<_InputIterator>>
typename _CharT
= __detail::__value_type_is_char_or_char8_t<_InputIterator>>
inline path
u8path(_InputIterator __first, _InputIterator __last)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
// XXX This assumes native wide encoding is UTF-16.
std::codecvt_utf8_utf16<path::value_type> __cvt;
path::string_type __tmp;
if constexpr (is_pointer_v<_InputIterator>)
#ifdef _GLIBCXX_USE_CHAR8_T
if constexpr (is_same_v<_CharT, char8_t>)
{
if (__str_codecvt_in_all(__first, __last, __tmp, __cvt))
return path{ __tmp };
return path{ __first, __last };
}
else
{
const std::string __u8str{__first, __last};
const char* const __ptr = __u8str.data();
if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
return path{ __tmp };
#endif
// XXX This assumes native wide encoding is UTF-16.
std::codecvt_utf8_utf16<path::value_type> __cvt;
path::string_type __tmp;
if constexpr (is_pointer_v<_InputIterator>)
{
if (__str_codecvt_in_all(__first, __last, __tmp, __cvt))
return path{ __tmp };
}
else
{
const std::string __u8str{__first, __last};
const char* const __ptr = __u8str.data();
if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
return path{ __tmp };
}
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
"Cannot convert character sequence",
std::make_error_code(errc::illegal_byte_sequence)));
#ifdef _GLIBCXX_USE_CHAR8_T
}
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
"Cannot convert character sequence",
std::make_error_code(errc::illegal_byte_sequence)));
#endif
#else
// This assumes native normal encoding is UTF-8.
return path{ __first, __last };
@ -705,21 +732,32 @@ namespace __detail
*/
template<typename _Source,
typename _Require = __detail::_Path<_Source>,
typename _Require2 = __detail::__value_type_is_char<_Source>>
typename _CharT = __detail::__value_type_is_char_or_char8_t<_Source>>
inline path
u8path(const _Source& __source)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if constexpr (is_convertible_v<const _Source&, std::string_view>)
#ifdef _GLIBCXX_USE_CHAR8_T
if constexpr (is_same_v<_CharT, char8_t>)
{
const std::string_view __s = __source;
return filesystem::u8path(__s.data(), __s.data() + __s.size());
return path{ __source };
}
else
{
std::string __s = path::_S_string_from_iter(__source);
return filesystem::u8path(__s.data(), __s.data() + __s.size());
#endif
if constexpr (is_convertible_v<const _Source&, std::string_view>)
{
const std::string_view __s = __source;
return filesystem::u8path(__s.data(), __s.data() + __s.size());
}
else
{
std::string __s = path::_S_string_from_iter(__source);
return filesystem::u8path(__s.data(), __s.data() + __s.size());
}
#ifdef _GLIBCXX_USE_CHAR8_T
}
#endif
#else
return path{ __source };
#endif

View File

@ -170,10 +170,23 @@ namespace __detail
template<typename _Tp,
typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
typename _Val = typename std::iterator_traits<_Iter>::value_type>
typename _Val = typename std::iterator_traits<_Iter>::value_type,
typename _UnqualVal = typename std::remove_const<_Val>::type>
using __value_type_is_char = typename std::enable_if<
std::is_same<typename std::remove_const<_Val>::type, char>::value
>::type;
std::is_same<_UnqualVal, char>::value,
_UnqualVal>::type;
template<typename _Tp,
typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
typename _Val = typename std::iterator_traits<_Iter>::value_type,
typename _UnqualVal = typename std::remove_const<_Val>::type>
using __value_type_is_char_or_char8_t = typename std::enable_if<
__or_<
std::is_same<_UnqualVal, char>
#ifdef _GLIBCXX_USE_CHAR8_T
,std::is_same<_UnqualVal, char8_t>
#endif
>::value, _UnqualVal>::type;
} // namespace __detail
/// @endcond
@ -588,13 +601,11 @@ namespace __detail
}
/// Create a path from a UTF-8-encoded sequence of char
template<typename _InputIterator,
typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
typename _Require2 = __detail::__value_type_is_char<_InputIterator>>
inline path
u8path(_InputIterator __first, _InputIterator __last)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
template<typename _InputIterator>
inline path
__u8path(_InputIterator __first, _InputIterator __last, char)
{
// XXX This assumes native wide encoding is UTF-16.
std::codecvt_utf8_utf16<path::value_type> __cvt;
path::string_type __tmp;
@ -605,21 +616,61 @@ namespace __detail
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
"Cannot convert character sequence",
std::make_error_code(errc::illegal_byte_sequence)));
}
#ifdef _GLIBCXX_USE_CHAR8_T
template<typename _InputIterator>
inline path
__u8path(_InputIterator __first, _InputIterator __last, char8_t)
{
return path{ __first, __last };
}
#endif // _GLIBCXX_USE_CHAR8_T
#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
template<typename _InputIterator,
typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
typename _CharT =
__detail::__value_type_is_char_or_char8_t<_InputIterator>>
inline path
u8path(_InputIterator __first, _InputIterator __last)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
return __u8path(__first, __last, _CharT{});
#else
return path{ __first, __last };
#endif
}
/// Create a path from a UTF-8-encoded sequence of char
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
template<typename _Source>
inline path
__u8path(const _Source& __source, char)
{
std::string __s = path::_S_string_from_iter(__source);
return filesystem::u8path(__s.data(), __s.data() + __s.size());
}
#ifdef _GLIBCXX_USE_CHAR8_T
template<typename _Source>
inline path
__u8path(const _Source& __source, char8_t)
{
return path{ __source };
}
#endif // _GLIBCXX_USE_CHAR8_T
#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
template<typename _Source,
typename _Require = __detail::_Path<_Source>,
typename _Require2 = __detail::__value_type_is_char<_Source>>
typename _CharT =
__detail::__value_type_is_char_or_char8_t<_Source>>
inline path
u8path(const _Source& __source)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
std::string __s = path::_S_string_from_iter(__source);
return filesystem::u8path(__s.data(), __s.data() + __s.size());
return __u8path(__source, _CharT{});
#else
return path{ __source };
#endif

View File

@ -527,6 +527,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
{ return (__out << static_cast<char>(__c)); }
#if __cplusplus > 201703L
// The following deleted overloads prevent formatting character values as
// numeric values.
#ifdef _GLIBCXX_USE_WCHAR_T
template<class _Traits>
basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>&, wchar_t) = delete;
#endif // _GLIBCXX_USE_WCHAR_T
#ifdef _GLIBCXX_USE_CHAR8_T
template<class _Traits>
basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>&, char8_t) = delete;
#endif
template<class _Traits>
basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>&, char16_t) = delete;
template<class _Traits>
basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>&, char32_t) = delete;
#ifdef _GLIBCXX_USE_WCHAR_T
#ifdef _GLIBCXX_USE_CHAR8_T
template<class _Traits>
basic_ostream<wchar_t, _Traits>&
operator<<(basic_ostream<wchar_t, _Traits>&, char8_t) = delete;
#endif // _GLIBCXX_USE_CHAR8_T
template<class _Traits>
basic_ostream<wchar_t, _Traits>&
operator<<(basic_ostream<wchar_t, _Traits>&, char16_t) = delete;
template<class _Traits>
basic_ostream<wchar_t, _Traits>&
operator<<(basic_ostream<wchar_t, _Traits>&, char32_t) = delete;
#endif // _GLIBCXX_USE_WCHAR_T
#endif // C++20
//@}
//@{
@ -582,6 +623,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline basic_ostream<char, _Traits> &
operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
{ return (__out << reinterpret_cast<const char*>(__s)); }
#if __cplusplus > 201703L
// The following deleted overloads prevent formatting strings as
// pointer values.
#ifdef _GLIBCXX_USE_WCHAR_T
template<class _Traits>
basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>&, const wchar_t*) = delete;
#endif // _GLIBCXX_USE_WCHAR_T
#ifdef _GLIBCXX_USE_CHAR8_T
template<class _Traits>
basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>&, const char8_t*) = delete;
#endif // _GLIBCXX_USE_CHAR8_T
template<class _Traits>
basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>&, const char16_t*) = delete;
template<class _Traits>
basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>&, const char32_t*) = delete;
#ifdef _GLIBCXX_USE_WCHAR_T
#ifdef _GLIBCXX_USE_CHAR8_T
template<class _Traits>
basic_ostream<wchar_t, _Traits>&
operator<<(basic_ostream<wchar_t, _Traits>&, const char8_t*) = delete;
#endif
template<class _Traits>
basic_ostream<wchar_t, _Traits>&
operator<<(basic_ostream<wchar_t, _Traits>&, const char16_t*) = delete;
template<class _Traits>
basic_ostream<wchar_t, _Traits>&
operator<<(basic_ostream<wchar_t, _Traits>&, const char32_t*) = delete;
#endif // _GLIBCXX_USE_WCHAR_T
#endif // C++20
//@}
// Standard basic_ostream manipulators