* [committed 0/3] libstdc++: Refactor filesystem::path string conversions
@ 2020-05-23 8:40 Jonathan Wakely
2020-05-23 8:42 ` [committed 1/3] libstdc++: Simplify filesystem::path SFINAE constraints Jonathan Wakely
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-05-23 8:40 UTC (permalink / raw)
To: libstdc++, gcc-patches
This is a series of three patches to simplify the logic used to
construct a std::filesystem::path from strings/ranges of arbitrary
characters, and fix one bug.
The simpler logic also avoids some unnecessary string constructions
when a string view could be used instead. Previously a string view was
only used for strings and pairs of pointers. Now contiguous iterators
will be detected (using the concept in C++20, or by handling the
__normal_iterator wrapper in C++17).
The bug fix should be backported, the rest would be safe but doesn't
need to be.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [committed 1/3] libstdc++: Simplify filesystem::path SFINAE constraints
2020-05-23 8:40 [committed 0/3] libstdc++: Refactor filesystem::path string conversions Jonathan Wakely
@ 2020-05-23 8:42 ` Jonathan Wakely
2020-05-23 8:43 ` [committed 2/3] libstdc++: Remove incorrect static specifiers Jonathan Wakely
2020-05-23 8:44 ` [committed 3/3] libstdc++: Refactor filesystem::path string conversions Jonathan Wakely
2 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-05-23 8:42 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1809 bytes --]
This replaces the filesystem::__detail::_Path SFINAE helper with two
separate helpers, _Path and _Path2. This avoids having one helper which
tries to check two different sets of requirements.
The _Path helper now uses variable templates instead of a set of
overloaded functions to detect specializations of basic_string or
basic_string_view.
The __not_<is_void<remove_pointer_t<_Tp1>> check is not necessary in
C++20 because iterator_traits<void*> is now empty. For C++17 replace
that check with a __safe_iterator_traits helper with partial
specializations for void pointers.
Finally, the __is_encoded_char check no longer uses remove_const_t,
which means that iterators with a const value_type will no longer be
accepted as arguments for path creation. Such iterators resulted in
undefined behaviour anyway, so it's still conforming to reject them in
the constraint checks.
* include/bits/fs_path.h (filesystem::__detail::__is_encoded_char):
Replace alias template with variable template. Don't remove const.
(filesystem::__detail::__is_path_src): Replace overloaded function
template with variable template and specializations.
(filesystem::__detail::__is_path_iter_src): Replace alias template
with class template.
(filesystem::__detail::_Path): Use __is_path_src. Remove support for
iterator pairs.
(filesystem::__detail::_Path2): New alias template for checking
InputIterator requirements.
(filesystem::__detail::__constructible_from): Remove.
(filesystem::path): Replace _Path<Iter, Iter> with _Path2<Iter>.
* testsuite/27_io/filesystem/path/construct/80762.cc: Check with two
constructor arguments of void and void* types.
Tested powerpc64le-linux, committed to master.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 10405 bytes --]
commit 988b853f9c829742907ae22ac66de56facfc7bc5
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Sat May 23 07:28:40 2020 +0100
libstdc++: Simplify filesystem::path SFINAE constraints
This replaces the filesystem::__detail::_Path SFINAE helper with two
separate helpers, _Path and _Path2. This avoids having one helper which
tries to check two different sets of requirements.
The _Path helper now uses variable templates instead of a set of
overloaded functions to detect specializations of basic_string or
basic_string_view.
The __not_<is_void<remove_pointer_t<_Tp1>> check is not necessary in
C++20 because iterator_traits<void*> is now empty. For C++17 replace
that check with a __safe_iterator_traits helper with partial
specializations for void pointers.
Finally, the __is_encoded_char check no longer uses remove_const_t,
which means that iterators with a const value_type will no longer be
accepted as arguments for path creation. Such iterators resulted in
undefined behaviour anyway, so it's still conforming to reject them in
the constraint checks.
* include/bits/fs_path.h (filesystem::__detail::__is_encoded_char):
Replace alias template with variable template. Don't remove const.
(filesystem::__detail::__is_path_src): Replace overloaded function
template with variable template and specializations.
(filesystem::__detail::__is_path_iter_src): Replace alias template
with class template.
(filesystem::__detail::_Path): Use __is_path_src. Remove support for
iterator pairs.
(filesystem::__detail::_Path2): New alias template for checking
InputIterator requirements.
(filesystem::__detail::__constructible_from): Remove.
(filesystem::path): Replace _Path<Iter, Iter> with _Path2<Iter>.
* testsuite/27_io/filesystem/path/construct/80762.cc: Check with two
constructor arguments of void and void* types.
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index ee6ab15cc4c..5a998284a99 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -73,58 +73,87 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
namespace __detail
{
template<typename _CharT>
- using __is_encoded_char = __is_one_of<remove_const_t<_CharT>,
- char,
+ inline constexpr bool __is_encoded_char = false;
+ template<>
+ inline constexpr bool __is_encoded_char<char> = true;
#ifdef _GLIBCXX_USE_CHAR8_T
- char8_t,
+ template<>
+ inline constexpr bool __is_encoded_char<char8_t> = true;
#endif
#if _GLIBCXX_USE_WCHAR_T
- wchar_t,
+ template<>
+ inline constexpr bool __is_encoded_char<wchar_t> = true;
#endif
- char16_t, char32_t>;
-
- template<typename _Iter,
- typename _Iter_traits = std::iterator_traits<_Iter>>
- using __is_path_iter_src
- = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
- std::is_base_of<std::input_iterator_tag,
- typename _Iter_traits::iterator_category>>;
+ template<>
+ inline constexpr bool __is_encoded_char<char16_t> = true;
+ template<>
+ inline constexpr bool __is_encoded_char<char32_t> = true;
+#if __cpp_concepts >= 201907L
template<typename _Iter>
- static __is_path_iter_src<_Iter>
- __is_path_src(_Iter, int);
-
- template<typename _CharT, typename _Traits, typename _Alloc>
- static __is_encoded_char<_CharT>
- __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
-
- template<typename _CharT, typename _Traits>
- static __is_encoded_char<_CharT>
- __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
-
- template<typename _Unknown>
- static std::false_type
- __is_path_src(const _Unknown&, ...);
-
- template<typename _Tp1, typename _Tp2>
- struct __constructible_from;
-
+ using __safe_iterator_traits = std::iterator_traits<_Iter>;
+#else
template<typename _Iter>
- struct __constructible_from<_Iter, _Iter>
- : __is_path_iter_src<_Iter>
+ struct __safe_iterator_traits : std::iterator_traits<_Iter>
+ { };
+
+ // Protect against ill-formed iterator_traits specializations in C++17
+ template<> struct __safe_iterator_traits<void*> { };
+ template<> struct __safe_iterator_traits<const void*> { };
+ template<> struct __safe_iterator_traits<volatile void*> { };
+ template<> struct __safe_iterator_traits<const volatile void*> { };
+#endif
+
+ template<typename _Iter_traits, typename = void>
+ struct __is_path_iter_src
+ : false_type
+ { };
+
+ template<typename _Iter_traits>
+ struct __is_path_iter_src<_Iter_traits,
+ void_t<typename _Iter_traits::value_type>>
+ : bool_constant<__is_encoded_char<typename _Iter_traits::value_type>>
{ };
template<typename _Source>
- struct __constructible_from<_Source, void>
- : decltype(__is_path_src(std::declval<_Source>(), 0))
- { };
+ inline constexpr bool __is_path_src
+ = __is_path_iter_src<iterator_traits<decay_t<_Source>>>::value;
- template<typename _Tp1, typename _Tp2 = void>
- using _Path = typename
- std::enable_if<__and_<__not_<is_same<remove_cv_t<_Tp1>, path>>,
- __not_<is_void<remove_pointer_t<_Tp1>>>,
- __constructible_from<_Tp1, _Tp2>>::value,
- path>::type;
+ template<>
+ inline constexpr bool __is_path_src<path> = false;
+
+ template<>
+ inline constexpr bool __is_path_src<volatile path> = false;
+
+ template<>
+ inline constexpr bool __is_path_src<void*> = false;
+
+ template<>
+ inline constexpr bool __is_path_src<const void*> = false;
+
+ template<>
+ inline constexpr bool __is_path_src<volatile void*> = false;
+
+ template<>
+ inline constexpr bool __is_path_src<const volatile void*> = false;
+
+ template<typename _CharT, typename _Traits, typename _Alloc>
+ inline constexpr bool
+ __is_path_src<basic_string<_CharT, _Traits, _Alloc>>
+ = __is_encoded_char<_CharT>;
+
+ template<typename _CharT, typename _Traits>
+ inline constexpr bool
+ __is_path_src<basic_string_view<_CharT, _Traits>>
+ = __is_encoded_char<_CharT>;
+
+ // SFINAE constraint for Source parameters as required by [fs.path.req].
+ template<typename _Tp>
+ using _Path = enable_if_t<__is_path_src<_Tp>, path>;
+
+ // SFINAE constraint for InputIterator parameters as required by [fs.req].
+ template<typename _Iter, typename _Tr = __safe_iterator_traits<_Iter>>
+ using _Path2 = enable_if_t<__is_path_iter_src<_Tr>::value, path>;
template<typename _Source>
static _Source
@@ -227,7 +256,7 @@ namespace __detail
{ _M_split_cmpts(); }
template<typename _InputIterator,
- typename _Require = __detail::_Path<_InputIterator, _InputIterator>>
+ typename _Require = __detail::_Path2<_InputIterator>>
path(_InputIterator __first, _InputIterator __last, format = auto_format)
: _M_pathname(_S_convert(__first, __last))
{ _M_split_cmpts(); }
@@ -241,8 +270,8 @@ namespace __detail
{ _M_split_cmpts(); }
template<typename _InputIterator,
- typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
- typename _Require2 = __detail::__value_type_is_char<_InputIterator>>
+ typename _Require = __detail::_Path2<_InputIterator>,
+ typename _Req2 = __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))
@@ -268,7 +297,7 @@ namespace __detail
{ return *this = path(__source); }
template<typename _InputIterator>
- __detail::_Path<_InputIterator, _InputIterator>&
+ __detail::_Path2<_InputIterator>&
assign(_InputIterator __first, _InputIterator __last)
{ return *this = path(__first, __last); }
@@ -295,7 +324,7 @@ namespace __detail
}
template<typename _InputIterator>
- __detail::_Path<_InputIterator, _InputIterator>&
+ __detail::_Path2<_InputIterator>&
append(_InputIterator __first, _InputIterator __last)
{
_M_append(_S_convert(__first, __last));
@@ -315,7 +344,7 @@ namespace __detail
operator+=(_Source const& __x) { return concat(__x); }
template<typename _CharT>
- __detail::_Path<_CharT*, _CharT*>&
+ __detail::_Path2<_CharT*>&
operator+=(_CharT __x);
template<typename _Source>
@@ -328,7 +357,7 @@ namespace __detail
}
template<typename _InputIterator>
- __detail::_Path<_InputIterator, _InputIterator>&
+ __detail::_Path2<_InputIterator>&
concat(_InputIterator __first, _InputIterator __last)
{
_M_concat(_S_convert(__first, __last));
@@ -695,7 +724,7 @@ namespace __detail
* @relates std::filesystem::path
*/
template<typename _InputIterator,
- typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
+ typename _Require = __detail::_Path2<_InputIterator>,
typename _CharT
= __detail::__value_type_is_char_or_char8_t<_InputIterator>>
inline path
@@ -1000,7 +1029,7 @@ namespace __detail
}
template<typename _CharT>
- inline __detail::_Path<_CharT*, _CharT*>&
+ inline __detail::_Path2<_CharT*>&
path::operator+=(_CharT __x)
{
auto* __addr = std::__addressof(__x);
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/80762.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/80762.cc
index bfc1e125e0c..2f37b663f26 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/80762.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/80762.cc
@@ -37,3 +37,9 @@ static_assert( !std::is_constructible_v<path, const volatile void*> );
static_assert( !std::is_constructible_v<path, void*&> );
static_assert( !std::is_constructible_v<path, void* const&> );
static_assert( !std::is_constructible_v<path, const void* const&> );
+
+static_assert( !std::is_constructible_v<path, void, void> );
+static_assert( !std::is_constructible_v<path, void*, void*> );
+static_assert( !std::is_constructible_v<path, const void*, void*> );
+static_assert( !std::is_constructible_v<path, volatile void*, void*> );
+static_assert( !std::is_constructible_v<path, const volatile void*, void*> );
^ permalink raw reply [flat|nested] 5+ messages in thread
* [committed 2/3] libstdc++: Remove incorrect static specifiers
2020-05-23 8:40 [committed 0/3] libstdc++: Refactor filesystem::path string conversions Jonathan Wakely
2020-05-23 8:42 ` [committed 1/3] libstdc++: Simplify filesystem::path SFINAE constraints Jonathan Wakely
@ 2020-05-23 8:43 ` Jonathan Wakely
2020-05-23 8:44 ` [committed 3/3] libstdc++: Refactor filesystem::path string conversions Jonathan Wakely
2 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-05-23 8:43 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 639 bytes --]
These functions were originally static members of the path class, but
the 'static' specifiers were not removed when they were moved to
namespace scope. This causes ODR violations when the functions are
called from functions defined in the header, which is incompatible with
Nathan's modules branch. Change them to 'inline' instead.
* include/bits/fs_path.h (__detail::_S_range_begin)
(__detail::_S_range_end): Remove unintentional static specifiers.
* include/experimental/bits/fs_path.h (__detail::_S_range_begin)
(__detail::_S_range_end): Likewise.
Tested powerpc64le-linux, committed to master.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 3810 bytes --]
commit 00c8f2a5e3a21d93a03182cacbae4badc02a37f1
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Sat May 23 09:00:16 2020 +0100
libstdc++: Remove incorrect static specifiers
These functions were originally static members of the path class, but
the 'static' specifiers were not removed when they were moved to
namespace scope. This causes ODR violations when the functions are
called from functions defined in the header, which is incompatible with
Nathan's modules branch. Change them to 'inline' instead.
* include/bits/fs_path.h (__detail::_S_range_begin)
(__detail::_S_range_end): Remove unintentional static specifiers.
* include/experimental/bits/fs_path.h (__detail::_S_range_begin)
(__detail::_S_range_end): Likewise.
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index 5a998284a99..818b5918927 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -156,32 +156,32 @@ namespace __detail
using _Path2 = enable_if_t<__is_path_iter_src<_Tr>::value, path>;
template<typename _Source>
- static _Source
+ _Source
_S_range_begin(_Source __begin) { return __begin; }
struct __null_terminated { };
template<typename _Source>
- static __null_terminated
+ __null_terminated
_S_range_end(_Source) { return {}; }
template<typename _CharT, typename _Traits, typename _Alloc>
- static const _CharT*
+ inline const _CharT*
_S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
{ return __str.data(); }
template<typename _CharT, typename _Traits, typename _Alloc>
- static const _CharT*
+ inline const _CharT*
_S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
{ return __str.data() + __str.size(); }
template<typename _CharT, typename _Traits>
- static const _CharT*
+ inline const _CharT*
_S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
{ return __str.data(); }
template<typename _CharT, typename _Traits>
- static const _CharT*
+ inline const _CharT*
_S_range_end(const basic_string_view<_CharT, _Traits>& __str)
{ return __str.data() + __str.size(); }
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index d7234c08a00..69b823a3466 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -137,33 +137,33 @@ namespace __detail
path>::type;
template<typename _Source>
- static _Source
+ inline _Source
_S_range_begin(_Source __begin) { return __begin; }
struct __null_terminated { };
template<typename _Source>
- static __null_terminated
+ inline __null_terminated
_S_range_end(_Source) { return {}; }
template<typename _CharT, typename _Traits, typename _Alloc>
- static const _CharT*
+ inline const _CharT*
_S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
{ return __str.data(); }
template<typename _CharT, typename _Traits, typename _Alloc>
- static const _CharT*
+ inline const _CharT*
_S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
{ return __str.data() + __str.size(); }
#if __cplusplus >= 201402L
template<typename _CharT, typename _Traits>
- static const _CharT*
+ inline const _CharT*
_S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
{ return __str.data(); }
template<typename _CharT, typename _Traits>
- static const _CharT*
+ inline const _CharT*
_S_range_end(const basic_string_view<_CharT, _Traits>& __str)
{ return __str.data() + __str.size(); }
#endif
^ permalink raw reply [flat|nested] 5+ messages in thread
* [committed 3/3] libstdc++: Refactor filesystem::path string conversions
2020-05-23 8:40 [committed 0/3] libstdc++: Refactor filesystem::path string conversions Jonathan Wakely
2020-05-23 8:42 ` [committed 1/3] libstdc++: Simplify filesystem::path SFINAE constraints Jonathan Wakely
2020-05-23 8:43 ` [committed 2/3] libstdc++: Remove incorrect static specifiers Jonathan Wakely
@ 2020-05-23 8:44 ` Jonathan Wakely
2020-06-01 23:14 ` Jonathan Wakely
2 siblings, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2020-05-23 8:44 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2197 bytes --]
This simplifies the logic of converting Source arguments and pairs of
InputIterator arguments into the native string format. For any input
that is a contiguous range of path::value_type (or char8_t for POSIX)
a string view can be created and the conversion can be done directly,
with no intermediate allocation. Previously some cases created a
basic_string unnecessarily, for example construction from a pair of
path::string_type::iterators, or a pair of non-const value_type*
pointers.
* include/bits/fs_path.h (__detail::_S_range_begin)
(__detail::_S_range_end, path::_S_string_from_iter): Replace with
overloaded function template __detail::__effective_range.
(__detail::__effective_range): New overloaded function template to
create a basic_string or basic_string_view for an effective range.
(__detail::__value_type_is_char): Use __detail::__effective_range.
Do not use remove_const on value type.
(__detail::__value_type_is_char_or_char8_t): Likewise.
(path::path(const Source&, format))
(path::path(const Source&, const locale&))
(path::operator/=(const Source&), path::append(const Source&))
(path::concat(const Source&)): Use __detail::__effective_range.
(path::_S_to_string(InputIterator, InputIterator)): New function
template to create a string view if possible, or string otherwise.
(path::_S_convert): Add overloads that convert a string returned
by __detail::__effective_range. Use if-constexpr to inline conversion
logic from all overloads of _Cvt::_S_convert.
(path::_S_convert_loc): Add overload that converts a string. Use
_S_to_string to avoid allocation when possible.
(path::_Cvt): Remove.
(path::operator+=(CharT)): Remove indirection through path::concat.
* include/experimental/bits/fs_path.h (path::_S_convert_loc): Add
overload for non-const pointers, to avoid constructing a std::string.
* src/c++17/fs_path.cc (path::_S_convert_loc): Replace conditional
compilation with call to _S_convert.
Tested powerpc64le-linux, committed to master.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 20476 bytes --]
commit 584d52b088f9fcf78704b504c3f1f07e17c1cded
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Sat May 23 09:00:32 2020 +0100
libstdc++: Refactor filesystem::path string conversions
This simplifies the logic of converting Source arguments and pairs of
InputIterator arguments into the native string format. For any input
that is a contiguous range of path::value_type (or char8_t for POSIX)
a string view can be created and the conversion can be done directly,
with no intermediate allocation. Previously some cases created a
basic_string unnecessarily, for example construction from a pair of
path::string_type::iterators, or a pair of non-const value_type*
pointers.
* include/bits/fs_path.h (__detail::_S_range_begin)
(__detail::_S_range_end, path::_S_string_from_iter): Replace with
overloaded function template __detail::__effective_range.
(__detail::__effective_range): New overloaded function template to
create a basic_string or basic_string_view for an effective range.
(__detail::__value_type_is_char): Use __detail::__effective_range.
Do not use remove_const on value type.
(__detail::__value_type_is_char_or_char8_t): Likewise.
(path::path(const Source&, format))
(path::path(const Source&, const locale&))
(path::operator/=(const Source&), path::append(const Source&))
(path::concat(const Source&)): Use __detail::__effective_range.
(path::_S_to_string(InputIterator, InputIterator)): New function
template to create a string view if possible, or string otherwise.
(path::_S_convert): Add overloads that convert a string returned
by __detail::__effective_range. Use if-constexpr to inline conversion
logic from all overloads of _Cvt::_S_convert.
(path::_S_convert_loc): Add overload that converts a string. Use
_S_to_string to avoid allocation when possible.
(path::_Cvt): Remove.
(path::operator+=(CharT)): Remove indirection through path::concat.
* include/experimental/bits/fs_path.h (path::_S_convert_loc): Add
overload for non-const pointers, to avoid constructing a std::string.
* src/c++17/fs_path.cc (path::_S_convert_loc): Replace conditional
compilation with call to _S_convert.
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index 818b5918927..2d2766ec62e 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -155,56 +155,61 @@ namespace __detail
template<typename _Iter, typename _Tr = __safe_iterator_traits<_Iter>>
using _Path2 = enable_if_t<__is_path_iter_src<_Tr>::value, path>;
- template<typename _Source>
- _Source
- _S_range_begin(_Source __begin) { return __begin; }
-
- struct __null_terminated { };
-
- template<typename _Source>
- __null_terminated
- _S_range_end(_Source) { return {}; }
+ // The __effective_range overloads convert a Source parameter into
+ // either a basic_string_view or basic_string containing the
+ // effective range of the Source, as defined in [fs.path.req].
template<typename _CharT, typename _Traits, typename _Alloc>
- inline const _CharT*
- _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
- { return __str.data(); }
-
- template<typename _CharT, typename _Traits, typename _Alloc>
- inline const _CharT*
- _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
- { return __str.data() + __str.size(); }
+ inline basic_string_view<_CharT, _Traits>
+ __effective_range(const basic_string<_CharT, _Traits, _Alloc>& __source)
+ { return __source; }
template<typename _CharT, typename _Traits>
- inline const _CharT*
- _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
- { return __str.data(); }
+ inline const basic_string_view<_CharT, _Traits>&
+ __effective_range(const basic_string_view<_CharT, _Traits>& __source)
+ { return __source; }
- template<typename _CharT, typename _Traits>
- inline const _CharT*
- _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
- { return __str.data() + __str.size(); }
+ template<typename _Source>
+ inline auto
+ __effective_range(const _Source& __source)
+ {
+ if constexpr (is_pointer_v<decay_t<_Source>>)
+ return basic_string_view{&*__source};
+ else
+ {
+ // _Source is an input iterator that iterates over an NTCTS.
+ // Create a basic_string by reading until the null character.
+ using value_type
+ = typename iterator_traits<_Source>::value_type;
+ basic_string<value_type> __str;
+ _Source __it = __source;
+ for (value_type __ch = *__it; __ch != value_type(); __ch = *++__it)
+ __str.push_back(__ch);
+ return __str;
+ }
+ }
- 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>>
+ // The value type of a Source parameter's effective range.
+ template<typename _Tp>
+ using __value_t = typename remove_reference_t<
+ decltype(__detail::__effective_range(std::declval<_Tp>()))>::value_type;
+
+ // SFINAE helper to check that an effective range has value_type char,
+ // as required by path constructors taking a std::locale parameter.
+ // The type _Tp must have already been checked by _Path<Tp> or _Path2<_Tp>.
+ template<typename _Tp, typename _Val = __value_t<_Tp>>
using __value_type_is_char
- = std::enable_if_t<std::is_same_v<_UnqualVal, char>,
- _UnqualVal>;
+ = std::enable_if_t<std::is_same_v<_Val, char>, _Val>;
- 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>>
+ // As above, but also allows char8_t, as required by u8path
+ // C++20 [depr.fs.path.factory]
+ template<typename _Tp, typename _Val = __value_t<_Tp>>
using __value_type_is_char_or_char8_t
- = std::enable_if_t<__or_v<
- std::is_same<_UnqualVal, char>
+ = std::enable_if_t<std::is_same_v<_Val, char>
#ifdef _GLIBCXX_USE_CHAR8_T
- , std::is_same<_UnqualVal, char8_t>
+ || std::is_same_v<_Val, char8_t>
#endif
- >,
- _UnqualVal>;
+ , _Val>;
} // namespace __detail
/// @endcond
@@ -251,8 +256,7 @@ namespace __detail
template<typename _Source,
typename _Require = __detail::_Path<_Source>>
path(_Source const& __source, format = auto_format)
- : _M_pathname(_S_convert(__detail::_S_range_begin(__source),
- __detail::_S_range_end(__source)))
+ : _M_pathname(_S_convert(__detail::__effective_range(__source)))
{ _M_split_cmpts(); }
template<typename _InputIterator,
@@ -264,9 +268,8 @@ namespace __detail
template<typename _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(__detail::_S_range_begin(__source),
- __detail::_S_range_end(__source), __loc))
+ path(_Source const& __src, const locale& __loc, format = auto_format)
+ : _M_pathname(_S_convert_loc(__detail::__effective_range(__src), __loc))
{ _M_split_cmpts(); }
template<typename _InputIterator,
@@ -309,8 +312,7 @@ namespace __detail
__detail::_Path<_Source>&
operator/=(_Source const& __source)
{
- _M_append(_S_convert(__detail::_S_range_begin(__source),
- __detail::_S_range_end(__source)));
+ _M_append(_S_convert(__detail::__effective_range(__source)));
return *this;
}
@@ -318,8 +320,7 @@ namespace __detail
__detail::_Path<_Source>&
append(_Source const& __source)
{
- _M_append(_S_convert(__detail::_S_range_begin(__source),
- __detail::_S_range_end(__source)));
+ _M_append(_S_convert(__detail::__effective_range(__source)));
return *this;
}
@@ -351,8 +352,7 @@ namespace __detail
__detail::_Path<_Source>&
concat(_Source const& __x)
{
- _M_concat(_S_convert(__detail::_S_range_begin(__x),
- __detail::_S_range_end(__x)));
+ _M_concat(_S_convert(__detail::__effective_range(__x)));
return *this;
}
@@ -523,22 +523,6 @@ namespace __detail
return __result;
}
- /// @cond undocumented
- // Create a basic_string by reading until a null character.
- template<typename _InputIterator,
- typename _Traits = std::iterator_traits<_InputIterator>,
- typename _CharT
- = typename std::remove_cv_t<typename _Traits::value_type>>
- static std::basic_string<_CharT>
- _S_string_from_iter(_InputIterator __source)
- {
- std::basic_string<_CharT> __str;
- for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
- __str.push_back(__ch);
- return __str;
- }
- /// @endcond
-
private:
enum class _Type : unsigned char {
_Multi = 0, _Root_name, _Root_dir, _Filename
@@ -558,43 +542,67 @@ namespace __detail
pair<const string_type*, size_t> _M_find_extension() const noexcept;
- template<typename _CharT>
- struct _Cvt;
+ // Create a string or string view from an iterator range.
+ template<typename _InputIterator>
+ static auto
+ _S_to_string(_InputIterator __first, _InputIterator __last)
+ {
+ using _EcharT
+ = typename std::iterator_traits<_InputIterator>::value_type;
+ static_assert(__detail::__is_encoded_char<_EcharT>);
- static basic_string_view<value_type>
- _S_convert(value_type* __src, __detail::__null_terminated)
- { return __src; }
+#if __cpp_lib_concepts
+ constexpr bool __contiguous = std::contiguous_iterator<_InputIterator>;
+#else
+ constexpr bool __contiguous
+ = is_pointer_v<decltype(std::__niter_base(__first))>;
+#endif
+ if constexpr (__contiguous)
+ {
+ // For contiguous iterators we can just return a string view.
+ const auto* __f = std::__to_address(std::__niter_base(__first));
+ const auto* __l = std::__to_address(std::__niter_base(__last));
+ return basic_string_view<_EcharT>(__f, __l - __f);
+ }
+ else
+ // Conversion requires contiguous characters, so create a string.
+ return basic_string<_EcharT>(__first, __last);
+ }
- static basic_string_view<value_type>
- _S_convert(const value_type* __src, __detail::__null_terminated)
- { return __src; }
+ // path::_S_convert creates a basic_string<value_type> or
+ // basic_string_view<value_type> from a range (either the effective
+ // range of a Source parameter, or a pair of InputIterator parameters),
+ // performing the conversions required by [fs.path.type.cvt].
+ // If the value_type of the range value type is path::value_type,
+ // no encoding conversion is performed. If the range is contiguous
+ // a string_view
- static basic_string_view<value_type>
- _S_convert(value_type* __first, value_type* __last)
- { return {__first, __last - __first}; }
+ static string_type
+ _S_convert(string_type __str)
+ { return __str; }
- static basic_string_view<value_type>
- _S_convert(const value_type* __first, const value_type* __last)
- { return {__first, __last - __first}; }
+ template<typename _Tp>
+ static auto
+ _S_convert(const _Tp& __str)
+ {
+ if constexpr (is_same_v<_Tp, string_type>)
+ return __str;
+ else if constexpr (is_same_v<_Tp, basic_string_view<value_type>>)
+ return __str;
+ else if constexpr (is_same_v<typename _Tp::value_type, value_type>)
+ return basic_string_view<value_type>(__str.data(), __str.size());
+ else
+ return _S_convert(__str.data(), __str.data() + __str.size());
+ }
+
+ template<typename _EcharT>
+ static auto
+ _S_convert(const _EcharT* __first, const _EcharT* __last);
template<typename _Iter>
- static string_type
+ static auto
_S_convert(_Iter __first, _Iter __last)
- {
- using __value_type = typename std::iterator_traits<_Iter>::value_type;
- return _Cvt<typename remove_cv<__value_type>::type>::
- _S_convert(__first, __last);
- }
-
- template<typename _InputIterator>
- static string_type
- _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);
- // Convert (if needed) from iterator's value type to path::value_type:
- return string_type(_S_convert(__s.data(), __s.data() + __s.size()));
- }
+ { return _S_convert(_S_to_string(__first, __last)); }
static string_type
_S_convert_loc(const char* __first, const char* __last,
@@ -604,16 +612,14 @@ namespace __detail
static string_type
_S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
{
- const std::string __str(__first, __last);
- return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
+ const auto __s = _S_to_string(__first, __last);
+ return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
}
- template<typename _InputIterator>
+ template<typename _Tp>
static string_type
- _S_convert_loc(_InputIterator __src, __detail::__null_terminated,
- const std::locale& __loc)
+ _S_convert_loc(const _Tp& __s, const std::locale& __loc)
{
- const std::string __s = _S_string_from_iter(__src);
return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
}
@@ -803,100 +809,66 @@ namespace __detail
size_t _M_pos;
};
- // specialize _Cvt for degenerate 'noconv' case
- template<>
- struct path::_Cvt<path::value_type>
+ template<typename _EcharT>
+ auto
+ path::_S_convert(const _EcharT* __f, const _EcharT* __l)
{
- template<typename _Iter>
- static string_type
- _S_convert(_Iter __first, _Iter __last)
- { return string_type{__first, __last}; }
- };
+ static_assert(__detail::__is_encoded_char<_EcharT>);
-#if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T
- // For POSIX converting from char8_t to char is also 'noconv'
- template<>
- struct path::_Cvt<char8_t>
- {
- template<typename _Iter>
- static string_type
- _S_convert(_Iter __first, _Iter __last)
- { return string_type(__first, __last); }
- };
+ if constexpr (is_same_v<_EcharT, value_type>)
+ return basic_string_view<value_type>(__f, __l - __f);
+#if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T
+ else if constexpr (is_same_v<_EcharT, char8_t>)
+ // For POSIX converting from char8_t to char is also 'noconv'
+ return string_view(reinterpret_cast<const char*>(__f), __l - __f);
#endif
-
- template<typename _CharT>
- struct path::_Cvt
- {
- static string_type
- _S_convert(const _CharT* __f, const _CharT* __l)
- {
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- std::wstring __wstr;
- if constexpr (is_same_v<_CharT, char>)
- {
- struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t>
- { } __cvt;
- if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
- return __wstr;
- }
-#ifdef _GLIBCXX_USE_CHAR8_T
- else if constexpr (is_same_v<_CharT, char8_t>)
- {
- const char* __f2 = (const char*)__f;
- const char* __l2 = (const char*)__l;
- std::codecvt_utf8_utf16<wchar_t> __wcvt;
- if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
- return __wstr;
- }
-#endif
- else // char16_t or char32_t
- {
- struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
- { } __cvt;
- std::string __str;
- if (__str_codecvt_out_all(__f, __l, __str, __cvt))
- {
- const char* __f2 = __str.data();
- const char* __l2 = __f2 + __str.size();
- std::codecvt_utf8_utf16<wchar_t> __wcvt;
- if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
- return __wstr;
- }
- }
-#else // ! windows
- struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
- { } __cvt;
- std::string __str;
- if (__str_codecvt_out_all(__f, __l, __str, __cvt))
- return __str;
-#endif
- _GLIBCXX_THROW_OR_ABORT(filesystem_error(
- "Cannot convert character sequence",
- std::make_error_code(errc::illegal_byte_sequence)));
- }
-
- static string_type
- _S_convert(_CharT* __f, _CharT* __l)
- {
- return _S_convert(const_cast<const _CharT*>(__f),
- const_cast<const _CharT*>(__l));
- }
-
- template<typename _Iter>
- static string_type
- _S_convert(_Iter __first, _Iter __last)
+ else
{
- const std::basic_string<_CharT> __str(__first, __last);
- return _S_convert(__str.data(), __str.data() + __str.size());
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ std::wstring __wstr;
+ if constexpr (is_same_v<_EcharT, char>)
+ {
+ struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t>
+ { } __cvt;
+ if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
+ return __wstr;
+ }
+#ifdef _GLIBCXX_USE_CHAR8_T
+ else if constexpr (is_same_v<_EcharT, char8_t>)
+ {
+ const char* __f2 = (const char*)__f;
+ const char* __l2 = (const char*)__l;
+ std::codecvt_utf8_utf16<wchar_t> __wcvt;
+ if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
+ return __wstr;
+ }
+#endif
+ else // char16_t or char32_t
+ {
+ struct _UCvt : std::codecvt<_EcharT, char, std::mbstate_t>
+ { } __cvt;
+ std::string __str;
+ if (__str_codecvt_out_all(__f, __l, __str, __cvt))
+ {
+ const char* __f2 = __str.data();
+ const char* __l2 = __f2 + __str.size();
+ std::codecvt_utf8_utf16<wchar_t> __wcvt;
+ if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
+ return __wstr;
+ }
+ }
+#else // ! windows
+ struct _UCvt : std::codecvt<_EcharT, char, std::mbstate_t>
+ { } __cvt;
+ std::string __str;
+ if (__str_codecvt_out_all(__f, __l, __str, __cvt))
+ return __str;
+#endif
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "Cannot convert character sequence",
+ std::make_error_code(errc::illegal_byte_sequence)));
}
-
- template<typename _Iter, typename _Cont>
- static string_type
- _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
- __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
- { return _S_convert(__first.base(), __last.base()); }
- };
+ }
/// @endcond
@@ -1030,10 +1002,10 @@ namespace __detail
template<typename _CharT>
inline __detail::_Path2<_CharT*>&
- path::operator+=(_CharT __x)
+ path::operator+=(const _CharT __x)
{
- auto* __addr = std::__addressof(__x);
- return concat(__addr, __addr + 1);
+ _M_concat(_S_convert(&__x, &__x + 1));
+ return *this;
}
inline path&
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index 69b823a3466..c91937c66d8 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -495,6 +495,13 @@ namespace __detail
_S_convert_loc(const char* __first, const char* __last,
const std::locale& __loc);
+ static string_type
+ _S_convert_loc(char* __first, char* __last, const std::locale& __loc)
+ {
+ return _S_convert_loc(const_cast<const char*>(__first),
+ const_cast<const char*>(__last), __loc);
+ }
+
template<typename _Iter>
static string_type
_S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
diff --git a/libstdc++-v3/src/c++17/fs_path.cc b/libstdc++-v3/src/c++17/fs_path.cc
index 5ff17741f81..cea7aa08601 100644
--- a/libstdc++-v3/src/c++17/fs_path.cc
+++ b/libstdc++-v3/src/c++17/fs_path.cc
@@ -1949,11 +1949,7 @@ path::_S_convert_loc(const char* __first, const char* __last,
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
"Cannot convert character sequence",
std::make_error_code(errc::illegal_byte_sequence)));
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- return __ws;
-#else
- return _Cvt<wchar_t>::_S_convert(__ws.data(), __ws.data() + __ws.size());
-#endif
+ return _S_convert(std::move(__ws));
#else
return {__first, __last};
#endif
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [committed 3/3] libstdc++: Refactor filesystem::path string conversions
2020-05-23 8:44 ` [committed 3/3] libstdc++: Refactor filesystem::path string conversions Jonathan Wakely
@ 2020-06-01 23:14 ` Jonathan Wakely
0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-06-01 23:14 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2347 bytes --]
On 23/05/20 09:44 +0100, Jonathan Wakely wrote:
>This simplifies the logic of converting Source arguments and pairs of
>InputIterator arguments into the native string format. For any input
>that is a contiguous range of path::value_type (or char8_t for POSIX)
>a string view can be created and the conversion can be done directly,
>with no intermediate allocation. Previously some cases created a
>basic_string unnecessarily, for example construction from a pair of
>path::string_type::iterators, or a pair of non-const value_type*
>pointers.
>
> * include/bits/fs_path.h (__detail::_S_range_begin)
> (__detail::_S_range_end, path::_S_string_from_iter): Replace with
> overloaded function template __detail::__effective_range.
> (__detail::__effective_range): New overloaded function template to
> create a basic_string or basic_string_view for an effective range.
> (__detail::__value_type_is_char): Use __detail::__effective_range.
> Do not use remove_const on value type.
> (__detail::__value_type_is_char_or_char8_t): Likewise.
> (path::path(const Source&, format))
> (path::path(const Source&, const locale&))
> (path::operator/=(const Source&), path::append(const Source&))
> (path::concat(const Source&)): Use __detail::__effective_range.
> (path::_S_to_string(InputIterator, InputIterator)): New function
> template to create a string view if possible, or string otherwise.
> (path::_S_convert): Add overloads that convert a string returned
> by __detail::__effective_range. Use if-constexpr to inline conversion
> logic from all overloads of _Cvt::_S_convert.
> (path::_S_convert_loc): Add overload that converts a string. Use
> _S_to_string to avoid allocation when possible.
> (path::_Cvt): Remove.
> (path::operator+=(CharT)): Remove indirection through path::concat.
> * include/experimental/bits/fs_path.h (path::_S_convert_loc): Add
> overload for non-const pointers, to avoid constructing a std::string.
> * src/c++17/fs_path.cc (path::_S_convert_loc): Replace conditional
> compilation with call to _S_convert.
This commit broke *-*-mingw* bootstrap. Fixed with the attached patch.
Tested powerpc64le-linux and x86_64-w64-mingw32, committed to master.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 8517 bytes --]
commit cd3f067b82a1331f5fb695879ba5c3d9bb2cca3a
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue Jun 2 00:07:05 2020 +0100
libstdc++: Fix filesystem::u8path for mingw targets (PR 95392)
When I refactored filesystem::path string conversions in
r11-587-584d52b088f9fcf78704b504c3f1f07e17c1cded I failed to update the
mingw-specific code in filesystem::u8path, causing a bootstrap failure.
This fixes it, and further refactors the mingw-specific code along the
same lines as the previous commit. All conversions from UTF-8 strings to
wide strings now use the same helper function, __wstr_from_utf8.
PR libstdc++/95392
* include/bits/fs_path.h (path::_S_to_string): Move to
namespace-scope and rename to ...
(__detail::__string_from_range): ... this.
[WINDOWS] (__detail::__wstr_from_utf8): New function template to
convert a char sequence containing UTF-8 to wstring.
(path::_S_convert(Iter, Iter)): Adjust call to _S_to_string.
(path::_S_convert_loc(Iter, Iter, const locale&)): Likewise.
(u8path(InputIterator, InputIterator)) [WINDOWS]: Use
__string_from_range to obtain a contiguous range and
__wstr_from_utf8 to obtain a wide string.
(u8path(const Source&)) [WINDOWS]: Use __effective_range to
obtain a contiguous range and __wstr_from_utf8 to obtain a wide
string.
(path::_S_convert(const _EcharT*, const _EcharT)) [WINDOWS]:
Use __wstr_from_utf8.
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index 2d2766ec62e..26ddf0afec4 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -211,6 +211,51 @@ namespace __detail
#endif
, _Val>;
+ // Create a string or string view from an iterator range.
+ template<typename _InputIterator>
+ inline auto
+ __string_from_range(_InputIterator __first, _InputIterator __last)
+ {
+ using _EcharT
+ = typename std::iterator_traits<_InputIterator>::value_type;
+ static_assert(__is_encoded_char<_EcharT>);
+
+#if __cpp_lib_concepts
+ constexpr bool __contiguous = std::contiguous_iterator<_InputIterator>;
+#else
+ constexpr bool __contiguous
+ = is_pointer_v<decltype(std::__niter_base(__first))>;
+#endif
+ if constexpr (__contiguous)
+ {
+ // For contiguous iterators we can just return a string view.
+ const auto* __f = std::__to_address(std::__niter_base(__first));
+ const auto* __l = std::__to_address(std::__niter_base(__last));
+ return basic_string_view<_EcharT>(__f, __l - __f);
+ }
+ else
+ // Conversion requires contiguous characters, so create a string.
+ return basic_string<_EcharT>(__first, __last);
+ }
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ template<typename _Tp>
+ inline std::wstring
+ __wstr_from_utf8(const _Tp& __str)
+ {
+ static_assert(std::is_same_v<typename _Tp::value_type, char>);
+ std::wstring __wstr;
+ // XXX This assumes native wide encoding is UTF-16.
+ std::codecvt_utf8_utf16<wchar_t> __wcvt;
+ const auto __p = __str.data();
+ if (!__str_codecvt_in_all(__p, __p + __str.size(), __wstr, __wcvt))
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "Cannot convert character sequence",
+ std::make_error_code(errc::illegal_byte_sequence)));
+ return __wstr;
+ }
+#endif
+
} // namespace __detail
/// @endcond
@@ -542,33 +587,6 @@ namespace __detail
pair<const string_type*, size_t> _M_find_extension() const noexcept;
- // Create a string or string view from an iterator range.
- template<typename _InputIterator>
- static auto
- _S_to_string(_InputIterator __first, _InputIterator __last)
- {
- using _EcharT
- = typename std::iterator_traits<_InputIterator>::value_type;
- static_assert(__detail::__is_encoded_char<_EcharT>);
-
-#if __cpp_lib_concepts
- constexpr bool __contiguous = std::contiguous_iterator<_InputIterator>;
-#else
- constexpr bool __contiguous
- = is_pointer_v<decltype(std::__niter_base(__first))>;
-#endif
- if constexpr (__contiguous)
- {
- // For contiguous iterators we can just return a string view.
- const auto* __f = std::__to_address(std::__niter_base(__first));
- const auto* __l = std::__to_address(std::__niter_base(__last));
- return basic_string_view<_EcharT>(__f, __l - __f);
- }
- else
- // Conversion requires contiguous characters, so create a string.
- return basic_string<_EcharT>(__first, __last);
- }
-
// path::_S_convert creates a basic_string<value_type> or
// basic_string_view<value_type> from a range (either the effective
// range of a Source parameter, or a pair of InputIterator parameters),
@@ -602,7 +620,7 @@ namespace __detail
template<typename _Iter>
static auto
_S_convert(_Iter __first, _Iter __last)
- { return _S_convert(_S_to_string(__first, __last)); }
+ { return _S_convert(__detail::__string_from_range(__first, __last)); }
static string_type
_S_convert_loc(const char* __first, const char* __last,
@@ -612,7 +630,7 @@ namespace __detail
static string_type
_S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
{
- const auto __s = _S_to_string(__first, __last);
+ const auto __s = __detail::__string_from_range(__first, __last);
return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
}
@@ -738,28 +756,10 @@ namespace __detail
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if constexpr (is_same_v<_CharT, char>)
- {
- // 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 __p = __u8str.data();
- if (__str_codecvt_in_all(__p, __p + __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)));
- }
+ return path{ __detail::__wstr_from_utf8(
+ __detail::__string_from_range(__first, __last)) };
else
- return path{ __first, __last };
+ return path{ __first, __last }; // constructor handles char8_t
#else
// This assumes native normal encoding is UTF-8.
return path{ __first, __last };
@@ -778,21 +778,12 @@ namespace __detail
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if constexpr (is_same_v<_CharT, char>)
- {
- 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());
- }
- }
+ return path{ __detail::__wstr_from_utf8(
+ __detail::__effective_range(__source)) };
else
- return path{ __source };
+ return path{ __source }; // constructor handles char8_t
#else
+ // This assumes native normal encoding is UTF-8.
return path{ __source };
#endif
}
@@ -836,11 +827,8 @@ namespace __detail
#ifdef _GLIBCXX_USE_CHAR8_T
else if constexpr (is_same_v<_EcharT, char8_t>)
{
- const char* __f2 = (const char*)__f;
- const char* __l2 = (const char*)__l;
- std::codecvt_utf8_utf16<wchar_t> __wcvt;
- if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
- return __wstr;
+ const auto __f2 = reinterpret_cast<const char*>(__f);
+ return __detail::__wstr_from_utf8(string_view(__f2, __l - __f));
}
#endif
else // char16_t or char32_t
@@ -849,13 +837,7 @@ namespace __detail
{ } __cvt;
std::string __str;
if (__str_codecvt_out_all(__f, __l, __str, __cvt))
- {
- const char* __f2 = __str.data();
- const char* __l2 = __f2 + __str.size();
- std::codecvt_utf8_utf16<wchar_t> __wcvt;
- if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
- return __wstr;
- }
+ return __detail::__wstr_from_utf8(__str);
}
#else // ! windows
struct _UCvt : std::codecvt<_EcharT, char, std::mbstate_t>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-06-01 23:14 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-23 8:40 [committed 0/3] libstdc++: Refactor filesystem::path string conversions Jonathan Wakely
2020-05-23 8:42 ` [committed 1/3] libstdc++: Simplify filesystem::path SFINAE constraints Jonathan Wakely
2020-05-23 8:43 ` [committed 2/3] libstdc++: Remove incorrect static specifiers Jonathan Wakely
2020-05-23 8:44 ` [committed 3/3] libstdc++: Refactor filesystem::path string conversions Jonathan Wakely
2020-06-01 23:14 ` Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).