Commit 2b4e2c93 by Tom Honermann Committed by Jonathan Wakely

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
parent a1e7d33b
2019-11-29 Tom Honermann <tom@honermann.net> 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 Decouple constraints for u8path from path constructors
* include/bits/fs_path.h: Moved helper utilities out of * include/bits/fs_path.h: Moved helper utilities out of
std::filesystem::path into a detail namespace to make them std::filesystem::path into a detail namespace to make them
......
...@@ -620,7 +620,7 @@ namespace std ...@@ -620,7 +620,7 @@ namespace std
# endif # endif
#endif #endif
#ifdef _GLIBCXX_USE_CHAR8_T #ifdef _GLIBCXX_USE_CHAR8_T
# define __cpp_lib_char8_t 201811L # define __cpp_lib_char8_t 201907L
#endif #endif
/* Define if __float128 is supported on this host. */ /* Define if __float128 is supported on this host. */
......
...@@ -154,9 +154,24 @@ namespace __detail ...@@ -154,9 +154,24 @@ namespace __detail
template<typename _Tp, template<typename _Tp,
typename _Iter = decltype(_S_range_begin(std::declval<_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 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 } // namespace __detail
/// @endcond /// @endcond
...@@ -670,29 +685,41 @@ namespace __detail ...@@ -670,29 +685,41 @@ namespace __detail
*/ */
template<typename _InputIterator, template<typename _InputIterator,
typename _Require = __detail::_Path<_InputIterator, _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 inline path
u8path(_InputIterator __first, _InputIterator __last) u8path(_InputIterator __first, _InputIterator __last)
{ {
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
// XXX This assumes native wide encoding is UTF-16. #ifdef _GLIBCXX_USE_CHAR8_T
std::codecvt_utf8_utf16<path::value_type> __cvt; if constexpr (is_same_v<_CharT, char8_t>)
path::string_type __tmp;
if constexpr (is_pointer_v<_InputIterator>)
{ {
if (__str_codecvt_in_all(__first, __last, __tmp, __cvt)) return path{ __first, __last };
return path{ __tmp };
} }
else else
{ {
const std::string __u8str{__first, __last}; #endif
const char* const __ptr = __u8str.data(); // XXX This assumes native wide encoding is UTF-16.
if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt)) std::codecvt_utf8_utf16<path::value_type> __cvt;
return path{ __tmp }; 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( #endif
"Cannot convert character sequence",
std::make_error_code(errc::illegal_byte_sequence)));
#else #else
// This assumes native normal encoding is UTF-8. // This assumes native normal encoding is UTF-8.
return path{ __first, __last }; return path{ __first, __last };
...@@ -705,21 +732,32 @@ namespace __detail ...@@ -705,21 +732,32 @@ namespace __detail
*/ */
template<typename _Source, template<typename _Source,
typename _Require = __detail::_Path<_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 inline path
u8path(const _Source& __source) u8path(const _Source& __source)
{ {
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS #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 path{ __source };
return filesystem::u8path(__s.data(), __s.data() + __s.size());
} }
else else
{ {
std::string __s = path::_S_string_from_iter(__source); #endif
return filesystem::u8path(__s.data(), __s.data() + __s.size()); 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 #else
return path{ __source }; return path{ __source };
#endif #endif
......
...@@ -170,10 +170,23 @@ namespace __detail ...@@ -170,10 +170,23 @@ namespace __detail
template<typename _Tp, template<typename _Tp,
typename _Iter = decltype(_S_range_begin(std::declval<_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< using __value_type_is_char = typename std::enable_if<
std::is_same<typename std::remove_const<_Val>::type, char>::value std::is_same<_UnqualVal, char>::value,
>::type; _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 } // namespace __detail
/// @endcond /// @endcond
...@@ -588,13 +601,11 @@ namespace __detail ...@@ -588,13 +601,11 @@ namespace __detail
} }
/// Create a path from a UTF-8-encoded sequence of char /// Create a path from a UTF-8-encoded sequence of char
template<typename _InputIterator, #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
typename _Require = __detail::_Path<_InputIterator, _InputIterator>, template<typename _InputIterator>
typename _Require2 = __detail::__value_type_is_char<_InputIterator>>
inline path inline path
u8path(_InputIterator __first, _InputIterator __last) __u8path(_InputIterator __first, _InputIterator __last, char)
{ {
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
// XXX This assumes native wide encoding is UTF-16. // XXX This assumes native wide encoding is UTF-16.
std::codecvt_utf8_utf16<path::value_type> __cvt; std::codecvt_utf8_utf16<path::value_type> __cvt;
path::string_type __tmp; path::string_type __tmp;
...@@ -605,21 +616,61 @@ namespace __detail ...@@ -605,21 +616,61 @@ namespace __detail
_GLIBCXX_THROW_OR_ABORT(filesystem_error( _GLIBCXX_THROW_OR_ABORT(filesystem_error(
"Cannot convert character sequence", "Cannot convert character sequence",
std::make_error_code(errc::illegal_byte_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 #else
return path{ __first, __last }; return path{ __first, __last };
#endif #endif
} }
/// Create a path from a UTF-8-encoded sequence of char /// 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, template<typename _Source,
typename _Require = __detail::_Path<_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 inline path
u8path(const _Source& __source) u8path(const _Source& __source)
{ {
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
std::string __s = path::_S_string_from_iter(__source); return __u8path(__source, _CharT{});
return filesystem::u8path(__s.data(), __s.data() + __s.size());
#else #else
return path{ __source }; return path{ __source };
#endif #endif
......
...@@ -527,6 +527,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -527,6 +527,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline basic_ostream<char, _Traits>& inline basic_ostream<char, _Traits>&
operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c) operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
{ return (__out << static_cast<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 ...@@ -582,6 +623,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline basic_ostream<char, _Traits> & inline basic_ostream<char, _Traits> &
operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s) operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
{ return (__out << reinterpret_cast<const 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 // Standard basic_ostream manipulators
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment