From a1e7d33bb9458f76a2d49209a3825940ca7fbe0b Mon Sep 17 00:00:00 2001 From: Tom Honermann Date: Fri, 29 Nov 2019 17:43:37 +0000 Subject: [PATCH] libstdc++: P1423R3 char8_t remediation (1/4) Decouple constraints for u8path from path constructors This patch moves helper classes and functions for std::filesystem::path out of the class definition to a detail namespace so that they are available to the implementations of std::filesystem::u8path. Prior to this patch, the SFINAE constraints for those implementations were specified via delegation to the overloads of path constructors with a std::locale parameter; it just so happened that those overloads had the same constraints. As of P1423R3, u8path and those overloads no longer have the same constraints, so this dependency must be broken. This patch also updates the experimental implementation of the filesystem TS to add SFINAE constraints to its implementations of u8path. These functions were previously unconstrained and marked with a TODO comment. This patch does not provide any intentional behavioral changes other than the added constraints to the experimental filesystem TS implementation of u8path. Alternatives to this refactoring would have been to make the u8path overloads friends of class path, or to make the helpers public members. Both of those approaches struck me as less desirable than this approach, though this approach does require more code changes and will affect implementation detail portions of mangled names for path constructors and inline member functions (mostly function template specializations). 2019-11-29 Tom Honermann 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 available for use by u8path. * include/experimental/bits/fs_path.h: Moved helper utilities out of std::experimental::filesystem::v1::path into a detail namespace to make them available for use by u8path. From-SVN: r278855 --- libstdc++-v3/ChangeLog | 10 + libstdc++-v3/include/bits/fs_path.h | 261 +++++++++-------- .../include/experimental/bits/fs_path.h | 274 +++++++++--------- 3 files changed, 289 insertions(+), 256 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 83deef2e9fb..87c76f9a05c 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,13 @@ +2019-11-29 Tom Honermann + + 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 + available for use by u8path. + * include/experimental/bits/fs_path.h: Moved helper utilities out + of std::experimental::filesystem::v1::path into a detail + namespace to make them available for use by u8path. + 2019-11-29 Jonathan Wakely PR libstdc++/91997 diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h index 031ec3d7c7f..b4c02327f01 100644 --- a/libstdc++-v3/include/bits/fs_path.h +++ b/libstdc++-v3/include/bits/fs_path.h @@ -63,99 +63,107 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 * @{ */ + class path; + + /// @cond undocumented +namespace __detail +{ + template + using __is_encoded_char = __is_one_of, + char, +#ifdef _GLIBCXX_USE_CHAR8_T + char8_t, +#endif +#if _GLIBCXX_USE_WCHAR_T + wchar_t, +#endif + char16_t, char32_t>; + + template> + using __is_path_iter_src + = __and_<__is_encoded_char, + std::is_base_of>; + + template + static __is_path_iter_src<_Iter> + __is_path_src(_Iter, int); + + template + static __is_encoded_char<_CharT> + __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int); + + template + static __is_encoded_char<_CharT> + __is_path_src(const basic_string_view<_CharT, _Traits>&, int); + + template + static std::false_type + __is_path_src(const _Unknown&, ...); + + template + struct __constructible_from; + + template + struct __constructible_from<_Iter, _Iter> + : __is_path_iter_src<_Iter> + { }; + + template + struct __constructible_from<_Source, void> + : decltype(__is_path_src(std::declval<_Source>(), 0)) + { }; + + template + using _Path = typename + std::enable_if<__and_<__not_, path>>, + __not_>>, + __constructible_from<_Tp1, _Tp2>>::value, + path>::type; + + template + static _Source + _S_range_begin(_Source __begin) { return __begin; } + + struct __null_terminated { }; + + template + static __null_terminated + _S_range_end(_Source) { return {}; } + + template + static const _CharT* + _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str) + { return __str.data(); } + + template + static const _CharT* + _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str) + { return __str.data() + __str.size(); } + + template + static const _CharT* + _S_range_begin(const basic_string_view<_CharT, _Traits>& __str) + { return __str.data(); } + + template + static const _CharT* + _S_range_end(const basic_string_view<_CharT, _Traits>& __str) + { return __str.data() + __str.size(); } + + template())), + typename _Val = typename std::iterator_traits<_Iter>::value_type> + using __value_type_is_char + = std::enable_if_t, char>>; + +} // namespace __detail + /// @endcond + /// A filesystem path. class path { - template - using __is_encoded_char = __is_one_of, - char, -#ifdef _GLIBCXX_USE_CHAR8_T - char8_t, -#endif -#if _GLIBCXX_USE_WCHAR_T - wchar_t, -#endif - char16_t, char32_t>; - - template> - using __is_path_iter_src - = __and_<__is_encoded_char, - std::is_base_of>; - - template - static __is_path_iter_src<_Iter> - __is_path_src(_Iter, int); - - template - static __is_encoded_char<_CharT> - __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int); - - template - static __is_encoded_char<_CharT> - __is_path_src(const basic_string_view<_CharT, _Traits>&, int); - - template - static std::false_type - __is_path_src(const _Unknown&, ...); - - template - struct __constructible_from; - - template - struct __constructible_from<_Iter, _Iter> - : __is_path_iter_src<_Iter> - { }; - - template - struct __constructible_from<_Source, void> - : decltype(__is_path_src(std::declval<_Source>(), 0)) - { }; - - template - using _Path = typename - std::enable_if<__and_<__not_, path>>, - __not_>>, - __constructible_from<_Tp1, _Tp2>>::value, - path>::type; - - template - static _Source - _S_range_begin(_Source __begin) { return __begin; } - - struct __null_terminated { }; - - template - static __null_terminated - _S_range_end(_Source) { return {}; } - - template - static const _CharT* - _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str) - { return __str.data(); } - - template - static const _CharT* - _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str) - { return __str.data() + __str.size(); } - - template - static const _CharT* - _S_range_begin(const basic_string_view<_CharT, _Traits>& __str) - { return __str.data(); } - - template - static const _CharT* - _S_range_end(const basic_string_view<_CharT, _Traits>& __str) - { return __str.data() + __str.size(); } - - template())), - typename _Val = typename std::iterator_traits<_Iter>::value_type> - using __value_type_is_char - = std::enable_if_t, char>>; - public: #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS using value_type = wchar_t; @@ -193,29 +201,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { _M_split_cmpts(); } template> + typename _Require = __detail::_Path<_Source>> path(_Source const& __source, format = auto_format) - : _M_pathname(_S_convert(_S_range_begin(__source), - _S_range_end(__source))) + : _M_pathname(_S_convert(__detail::_S_range_begin(__source), + __detail::_S_range_end(__source))) { _M_split_cmpts(); } template> + typename _Require = __detail::_Path<_InputIterator, _InputIterator>> path(_InputIterator __first, _InputIterator __last, format = auto_format) : _M_pathname(_S_convert(__first, __last)) { _M_split_cmpts(); } template, - typename _Require2 = __value_type_is_char<_Source>> + typename _Require = __detail::_Path<_Source>, + typename _Require2 = __detail::__value_type_is_char<_Source>> path(_Source const& __source, const locale& __loc, format = auto_format) - : _M_pathname(_S_convert_loc(_S_range_begin(__source), - _S_range_end(__source), __loc)) + : _M_pathname(_S_convert_loc(__detail::_S_range_begin(__source), + __detail::_S_range_end(__source), __loc)) { _M_split_cmpts(); } template, - typename _Require2 = __value_type_is_char<_InputIterator>> + typename _Require = __detail::_Path<_InputIterator, _InputIterator>, + typename _Require2 = __detail::__value_type_is_char<_InputIterator>> path(_InputIterator __first, _InputIterator __last, const locale& __loc, format = auto_format) : _M_pathname(_S_convert_loc(__first, __last, __loc)) @@ -231,17 +239,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 path& assign(string_type&& __source); template - _Path<_Source>& + __detail::_Path<_Source>& operator=(_Source const& __source) { return *this = path(__source); } template - _Path<_Source>& + __detail::_Path<_Source>& assign(_Source const& __source) { return *this = path(__source); } template - _Path<_InputIterator, _InputIterator>& + __detail::_Path<_InputIterator, _InputIterator>& assign(_InputIterator __first, _InputIterator __last) { return *this = path(__first, __last); } @@ -250,23 +258,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 path& operator/=(const path& __p); template - _Path<_Source>& + __detail::_Path<_Source>& operator/=(_Source const& __source) { - _M_append(_S_convert(_S_range_begin(__source), _S_range_end(__source))); + _M_append(_S_convert(__detail::_S_range_begin(__source), + __detail::_S_range_end(__source))); return *this; } template - _Path<_Source>& + __detail::_Path<_Source>& append(_Source const& __source) { - _M_append(_S_convert(_S_range_begin(__source), _S_range_end(__source))); + _M_append(_S_convert(__detail::_S_range_begin(__source), + __detail::_S_range_end(__source))); return *this; } template - _Path<_InputIterator, _InputIterator>& + __detail::_Path<_InputIterator, _InputIterator>& append(_InputIterator __first, _InputIterator __last) { _M_append(_S_convert(__first, __last)); @@ -282,23 +292,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 path& operator+=(basic_string_view __x); template - _Path<_Source>& + __detail::_Path<_Source>& operator+=(_Source const& __x) { return concat(__x); } template - _Path<_CharT*, _CharT*>& + __detail::_Path<_CharT*, _CharT*>& operator+=(_CharT __x); template - _Path<_Source>& + __detail::_Path<_Source>& concat(_Source const& __x) { - _M_concat(_S_convert(_S_range_begin(__x), _S_range_end(__x))); + _M_concat(_S_convert(__detail::_S_range_begin(__x), + __detail::_S_range_end(__x))); return *this; } template - _Path<_InputIterator, _InputIterator>& + __detail::_Path<_InputIterator, _InputIterator>& concat(_InputIterator __first, _InputIterator __last) { _M_concat(_S_convert(__first, __last)); @@ -496,11 +507,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 struct _Cvt; static basic_string_view - _S_convert(value_type* __src, __null_terminated) + _S_convert(value_type* __src, __detail::__null_terminated) { return __src; } static basic_string_view - _S_convert(const value_type* __src, __null_terminated) + _S_convert(const value_type* __src, __detail::__null_terminated) { return __src; } static basic_string_view @@ -522,7 +533,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template static string_type - _S_convert(_InputIterator __src, __null_terminated) + _S_convert(_InputIterator __src, __detail::__null_terminated) { // Read from iterator into basic_string until a null value is seen: auto __s = _S_string_from_iter(__src); @@ -544,7 +555,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template static string_type - _S_convert_loc(_InputIterator __src, __null_terminated, + _S_convert_loc(_InputIterator __src, __detail::__null_terminated, const std::locale& __loc) { const std::string __s = _S_string_from_iter(__src); @@ -657,10 +668,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 * * @relates std::filesystem::path */ - template - inline auto + template, + typename _Require2 = __detail::__value_type_is_char<_InputIterator>> + inline path u8path(_InputIterator __first, _InputIterator __last) - -> decltype(filesystem::path(__first, __last, std::locale::classic())) { #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS // XXX This assumes native wide encoding is UTF-16. @@ -691,10 +703,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 * * @relates std::filesystem::path */ - template - inline auto + template, + typename _Require2 = __detail::__value_type_is_char<_Source>> + inline path u8path(const _Source& __source) - -> decltype(filesystem::path(__source, std::locale::classic())) { #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS if constexpr (is_convertible_v) @@ -950,7 +963,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } template - inline path::_Path<_CharT*, _CharT*>& + inline __detail::_Path<_CharT*, _CharT*>& path::operator+=(_CharT __x) { auto* __addr = std::__addressof(__x); diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h index a3655f616f2..075e9a8d125 100644 --- a/libstdc++-v3/include/experimental/bits/fs_path.h +++ b/libstdc++-v3/include/experimental/bits/fs_path.h @@ -71,111 +71,116 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 using std::basic_string_view; #endif - /** - * @addtogroup filesystem-ts - * @{ + /** @addtogroup filesystem-ts + * @{ */ + /// @cond undocumented +namespace __detail +{ + template::type> + using __is_encoded_char + = __or_, + is_same<_Ch, wchar_t>, +#ifdef _GLIBCXX_USE_CHAR8_T + is_same<_Ch, char8_t>, +#endif + is_same<_Ch, char16_t>, + is_same<_Ch, char32_t>>; + + template> + using __is_path_iter_src + = __and_<__is_encoded_char, + std::is_base_of>; + + template + static __is_path_iter_src<_Iter> + __is_path_src(_Iter, int); + + template + static __is_encoded_char<_CharT> + __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int); + +#if __cplusplus >= 201402L + template + static __is_encoded_char<_CharT> + __is_path_src(const basic_string_view<_CharT, _Traits>&, int); +#endif + + template + static std::false_type + __is_path_src(const _Unknown&, ...); + + template + struct __constructible_from; + + template + struct __constructible_from<_Iter, _Iter> + : __is_path_iter_src<_Iter> + { }; + + template + struct __constructible_from<_Source, void> + : decltype(__is_path_src(std::declval<_Source>(), 0)) + { }; + + template::type, + typename _Tp1_noptr = typename remove_pointer<_Tp1>::type> + using _Path = typename + std::enable_if<__and_<__not_>, + __not_>, + __constructible_from<_Tp1, _Tp2>>::value, + path>::type; + + template + static _Source + _S_range_begin(_Source __begin) { return __begin; } + + struct __null_terminated { }; + + template + static __null_terminated + _S_range_end(_Source) { return {}; } + + template + static const _CharT* + _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str) + { return __str.data(); } + + template + static const _CharT* + _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str) + { return __str.data() + __str.size(); } + +#if __cplusplus >= 201402L + template + static const _CharT* + _S_range_begin(const basic_string_view<_CharT, _Traits>& __str) + { return __str.data(); } + + template + static const _CharT* + _S_range_end(const basic_string_view<_CharT, _Traits>& __str) + { return __str.data() + __str.size(); } +#endif + + template())), + typename _Val = typename std::iterator_traits<_Iter>::value_type> + using __value_type_is_char = typename std::enable_if< + std::is_same::type, char>::value + >::type; + +} // namespace __detail + /// @endcond + /// A filesystem path. class path { - template::type> - using __is_encoded_char - = __or_, - is_same<_Ch, wchar_t>, -#ifdef _GLIBCXX_USE_CHAR8_T - is_same<_Ch, char8_t>, -#endif - is_same<_Ch, char16_t>, - is_same<_Ch, char32_t>>; - - template> - using __is_path_iter_src - = __and_<__is_encoded_char, - std::is_base_of>; - - template - static __is_path_iter_src<_Iter> - __is_path_src(_Iter, int); - - template - static __is_encoded_char<_CharT> - __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int); - -#if __cplusplus >= 201402L - template - static __is_encoded_char<_CharT> - __is_path_src(const basic_string_view<_CharT, _Traits>&, int); -#endif - - template - static std::false_type - __is_path_src(const _Unknown&, ...); - - template - struct __constructible_from; - - template - struct __constructible_from<_Iter, _Iter> - : __is_path_iter_src<_Iter> - { }; - - template - struct __constructible_from<_Source, void> - : decltype(__is_path_src(std::declval<_Source>(), 0)) - { }; - - template::type, - typename _Tp1_noptr = typename remove_pointer<_Tp1>::type> - using _Path = typename - std::enable_if<__and_<__not_>, - __not_>, - __constructible_from<_Tp1, _Tp2>>::value, - path>::type; - - template - static _Source - _S_range_begin(_Source __begin) { return __begin; } - - struct __null_terminated { }; - - template - static __null_terminated - _S_range_end(_Source) { return {}; } - - template - static const _CharT* - _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str) - { return __str.data(); } - - template - static const _CharT* - _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str) - { return __str.data() + __str.size(); } - -#if __cplusplus >= 201402L - template - static const _CharT* - _S_range_begin(const basic_string_view<_CharT, _Traits>& __str) - { return __str.data(); } - - template - static const _CharT* - _S_range_end(const basic_string_view<_CharT, _Traits>& __str) - { return __str.data() + __str.size(); } -#endif - - template())), - typename _Val = typename std::iterator_traits<_Iter>::value_type> - using __value_type_is_char = typename std::enable_if< - std::is_same::type, char>::value - >::type; - public: #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS typedef wchar_t value_type; @@ -205,29 +210,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { _M_split_cmpts(); } template> + typename _Require = __detail::_Path<_Source>> path(_Source const& __source) - : _M_pathname(_S_convert(_S_range_begin(__source), - _S_range_end(__source))) + : _M_pathname(_S_convert(__detail::_S_range_begin(__source), + __detail::_S_range_end(__source))) { _M_split_cmpts(); } template> + typename _Require = __detail::_Path<_InputIterator, _InputIterator>> path(_InputIterator __first, _InputIterator __last) : _M_pathname(_S_convert(__first, __last)) { _M_split_cmpts(); } template, - typename _Require2 = __value_type_is_char<_Source>> + typename _Require = __detail::_Path<_Source>, + typename _Require2 = __detail::__value_type_is_char<_Source>> path(_Source const& __source, const locale& __loc) - : _M_pathname(_S_convert_loc(_S_range_begin(__source), - _S_range_end(__source), __loc)) + : _M_pathname(_S_convert_loc(__detail::_S_range_begin(__source), + __detail::_S_range_end(__source), __loc)) { _M_split_cmpts(); } template, - typename _Require2 = __value_type_is_char<_InputIterator>> + typename _Require = __detail::_Path<_InputIterator, _InputIterator>, + typename _Require2 = __detail::__value_type_is_char<_InputIterator>> path(_InputIterator __first, _InputIterator __last, const locale& __loc) : _M_pathname(_S_convert_loc(__first, __last, __loc)) { _M_split_cmpts(); } @@ -242,17 +247,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 path& assign(string_type&& __source); template - _Path<_Source>& + __detail::_Path<_Source>& operator=(_Source const& __source) { return *this = path(__source); } template - _Path<_Source>& + __detail::_Path<_Source>& assign(_Source const& __source) { return *this = path(__source); } template - _Path<_InputIterator, _InputIterator>& + __detail::_Path<_InputIterator, _InputIterator>& assign(_InputIterator __first, _InputIterator __last) { return *this = path(__first, __last); } @@ -261,20 +266,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 path& operator/=(const path& __p) { return _M_append(__p._M_pathname); } template - _Path<_Source>& + __detail::_Path<_Source>& operator/=(_Source const& __source) { return append(__source); } template - _Path<_Source>& + __detail::_Path<_Source>& append(_Source const& __source) { - return _M_append(_S_convert(_S_range_begin(__source), - _S_range_end(__source))); + return _M_append(_S_convert(__detail::_S_range_begin(__source), + __detail::_S_range_end(__source))); } template - _Path<_InputIterator, _InputIterator>& + __detail::_Path<_InputIterator, _InputIterator>& append(_InputIterator __first, _InputIterator __last) { return _M_append(_S_convert(__first, __last)); } @@ -289,20 +294,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #endif template - _Path<_Source>& + __detail::_Path<_Source>& operator+=(_Source const& __x) { return concat(__x); } template - _Path<_CharT*, _CharT*>& + __detail::_Path<_CharT*, _CharT*>& operator+=(_CharT __x); template - _Path<_Source>& + __detail::_Path<_Source>& concat(_Source const& __x) - { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); } + { + return *this += _S_convert(__detail::_S_range_begin(__x), + __detail::_S_range_end(__x)); + } template - _Path<_InputIterator, _InputIterator>& + __detail::_Path<_InputIterator, _InputIterator>& concat(_InputIterator __first, _InputIterator __last) { return *this += _S_convert(__first, __last); } @@ -446,11 +454,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 struct _Cvt; static string_type - _S_convert(value_type* __src, __null_terminated) + _S_convert(value_type* __src, __detail::__null_terminated) { return string_type(__src); } static string_type - _S_convert(const value_type* __src, __null_terminated) + _S_convert(const value_type* __src, __detail::__null_terminated) { return string_type(__src); } template @@ -464,7 +472,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template static string_type - _S_convert(_InputIterator __src, __null_terminated) + _S_convert(_InputIterator __src, __detail::__null_terminated) { auto __s = _S_string_from_iter(__src); return _S_convert(__s.c_str(), __s.c_str() + __s.size()); @@ -484,7 +492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 template static string_type - _S_convert_loc(_InputIterator __src, __null_terminated, + _S_convert_loc(_InputIterator __src, __detail::__null_terminated, const std::locale& __loc) { const std::string __s = _S_string_from_iter(__src); @@ -580,8 +588,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } /// Create a path from a UTF-8-encoded sequence of char - // TODO constrain with _Path and __value_type_is_char - template + template, + typename _Require2 = __detail::__value_type_is_char<_InputIterator>> inline path u8path(_InputIterator __first, _InputIterator __last) { @@ -602,8 +611,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 } /// Create a path from a UTF-8-encoded sequence of char - // TODO constrain with _Path and __value_type_is_char - template + template, + typename _Require2 = __detail::__value_type_is_char<_Source>> inline path u8path(const _Source& __source) { @@ -872,7 +882,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #endif template - inline path::_Path<_CharT*, _CharT*>& + inline __detail::_Path<_CharT*, _CharT*>& path::operator+=(_CharT __x) { auto* __addr = std::__addressof(__x);