From a577c0c26931090e7c25e56ef5ffc807627961ec Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Sat, 21 Mar 2020 22:11:44 +0000 Subject: [PATCH] libstdc++: Fix experimental::path::generic_string (PR 93245) This function was unimplemented, simply returning the native format string instead. PR libstdc++/93245 * include/experimental/bits/fs_path.h (path::generic_string()): * testsuite/experimental/filesystem/path/generic/generic_string.cc: Improve test coverage. --- libstdc++-v3/ChangeLog | 5 ++ .../include/experimental/bits/fs_path.h | 40 ++++++++++++---- .../filesystem/path/generic/generic_string.cc | 46 +++++++++++++++---- 3 files changed, 73 insertions(+), 18 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 52944dd475c..7b9c30e3b64 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,10 @@ 2020-03-21 Jonathan Wakely + PR libstdc++/93245 + * include/experimental/bits/fs_path.h (path::generic_string()): + * testsuite/experimental/filesystem/path/generic/generic_string.cc: + Improve test coverage. + PR libstdc++/94242 * include/bits/fs_path.h (path::_S_str_convert): Replace first parameter with basic_string_view so that strings with different diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h index 7b3d9926e60..d7234c08a00 100644 --- a/libstdc++-v3/include/experimental/bits/fs_path.h +++ b/libstdc++-v3/include/experimental/bits/fs_path.h @@ -1086,34 +1086,56 @@ namespace __detail inline std::u32string path::u32string() const { return string(); } -#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS template inline std::basic_string<_CharT, _Traits, _Allocator> path::generic_string(const _Allocator& __a) const - { return string<_CharT, _Traits, _Allocator>(__a); } + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + const _CharT __slash = is_same<_CharT, wchar_t>::value + ? _CharT(L'/') + : _CharT('/'); // Assume value is correct for the encoding. +#else + const _CharT __slash = _CharT('/'); +#endif + basic_string<_CharT, _Traits, _Allocator> __str(__a); + __str.reserve(_M_pathname.size()); + bool __add_slash = false; + for (auto& __elem : *this) + { + if (__elem._M_type == _Type::_Root_dir) + { + __str += __slash; + continue; + } + if (__add_slash) + __str += __slash; + __str += __elem.string<_CharT, _Traits, _Allocator>(__a); + __add_slash = __elem._M_type == _Type::_Filename; + } + return __str; + } inline std::string - path::generic_string() const { return string(); } + path::generic_string() const { return generic_string(); } #if _GLIBCXX_USE_WCHAR_T inline std::wstring - path::generic_wstring() const { return wstring(); } + path::generic_wstring() const { return generic_string(); } #endif #ifdef _GLIBCXX_USE_CHAR8_T inline std::u8string - path::generic_u8string() const { return u8string(); } + path::generic_u8string() const { return generic_string(); } #else inline std::string - path::generic_u8string() const { return u8string(); } + path::generic_u8string() const { return generic_string(); } #endif inline std::u16string - path::generic_u16string() const { return u16string(); } + path::generic_u16string() const { return generic_string(); } inline std::u32string - path::generic_u32string() const { return u32string(); } -#endif + path::generic_u32string() const { return generic_string(); } inline int path::compare(const string_type& __s) const { return compare(path(__s)); } diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/generic/generic_string.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/generic/generic_string.cc index 40b39d22023..aa977847436 100644 --- a/libstdc++-v3/testsuite/experimental/filesystem/path/generic/generic_string.cc +++ b/libstdc++-v3/testsuite/experimental/filesystem/path/generic/generic_string.cc @@ -23,27 +23,55 @@ #include #include -#include +#include using std::experimental::filesystem::path; void test01() { - for (const path& p : __gnu_test::test_paths) + __gnu_test::compare_paths( path("///a//b///").generic_string(), "/a/b/." ); + __gnu_test::compare_paths( path("///a//b").generic_u16string(), "/a/b" ); + __gnu_test::compare_paths( path("//a//b").generic_u16string(), "//a/b" ); +} + +using __gnu_test::SimpleAllocator; + +void +test02() +{ + path p = "//foo//bar//."; + using C = char16_t; + auto g = p.generic_string, SimpleAllocator>(); + VERIFY( g == u"//foo/bar/." ); +} + + +void +test03() +{ + for (path p : { "/a///b//c", "///a//b//c", "a:b//c", "a://b///c" }) { - path p2(p), p3; - p2.swap(p3); - VERIFY( p2 == path() ); - VERIFY( p3 == p ); - p2.swap(p3); - VERIFY( p2 == p ); - VERIFY( p3 == path() ); + // A path constructed from the generic format string should compare equal + // to the original, because they represent the same path. + VERIFY( path(p.generic_string()) == p ); + VERIFY( path(p.generic_wstring()) == p ); + VERIFY( path(p.generic_u8string()) == p ); + VERIFY( path(p.generic_u16string()) == p ); + VERIFY( path(p.generic_u32string()) == p ); } + + // Except when the original consists entirely of a root-directory with + // multiple slashes, because path("///").native() is "///" but the + // generic format string is "/". In the Filesystem TS path::compare just + // compares native strings, so path("///") != path("/"). + VERIFY( path("///").generic_string() == "/" ); } int main() { test01(); + test02(); + test03(); } -- 2.30.2