From bd884f520faaa41618d6e901e1631ff02fab3044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 4 Nov 2020 15:59:56 +0200 Subject: [PATCH 14/25] [libcxx] Implement append and operator/ properly for windows The root_path function has to be changed to return the parsed bit as-is; otherwise a path like "//net" gets a root path of "//net/", as the root name, "//net", gets the root directory (an empty string) appended, forming "//net/". (The same doesn't happen for the root dir "c:" though.) Differential Revision: https://reviews.llvm.org/D91178 (cherry picked from commit 78d693faecf98718dadfa6e39f291e5999f380c7) --- libcxx/include/filesystem | 52 ++++++++++++++++--- .../path.member/path.append.pass.cpp | 48 +++++++++++++++++ 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem index eecf416e851c..201cecc0e8b2 100644 --- a/libcxx/include/filesystem +++ b/libcxx/include/filesystem @@ -1006,14 +1006,44 @@ public: return *this; } -private: - template - static bool __source_is_absolute(_ECharT __first_or_null) { - return __is_separator(__first_or_null); - } - public: // appends +#if defined(_LIBCPP_WIN32API) + path& operator/=(const path& __p) { + auto __p_root_name = __p.__root_name(); + auto __p_root_name_size = __p_root_name.size(); + if (__p.is_absolute() || + (!__p_root_name.empty() && __p_root_name != root_name())) { + __pn_ = __p.__pn_; + return *this; + } + if (__p.has_root_directory()) { + path __root_name_str = root_name(); + __pn_ = __root_name_str.native(); + __pn_ += __p.__pn_.substr(__p_root_name_size); + return *this; + } + if (has_filename() || (!has_root_directory() && is_absolute())) + __pn_ += preferred_separator; + __pn_ += __p.__pn_.substr(__p_root_name_size); + return *this; + } + template + _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source> + operator/=(const _Source& __src) { + return operator/=(path(__src)); + } + + template + _EnableIfPathable<_Source> append(const _Source& __src) { + return operator/=(path(__src)); + } + + template + path& append(_InputIt __first, _InputIt __last) { + return operator/=(path(__first, __last)); + } +#else path& operator/=(const path& __p) { if (__p.is_absolute()) { __pn_ = __p.__pn_; @@ -1038,7 +1068,8 @@ public: _EnableIfPathable<_Source> append(const _Source& __src) { using _Traits = __is_pathable<_Source>; using _CVT = _PathCVT<_SourceChar<_Source> >; - if (__source_is_absolute(_Traits::__first_or_null(__src))) + bool __source_is_absolute = __is_separator(_Traits::__first_or_null(__src)); + if (__source_is_absolute) __pn_.clear(); else if (has_filename()) __pn_ += preferred_separator; @@ -1051,13 +1082,14 @@ public: typedef typename iterator_traits<_InputIt>::value_type _ItVal; static_assert(__can_convert_char<_ItVal>::value, "Must convertible"); using _CVT = _PathCVT<_ItVal>; - if (__first != __last && __source_is_absolute(*__first)) + if (__first != __last && __is_separator(*__first)) __pn_.clear(); else if (has_filename()) __pn_ += preferred_separator; _CVT::__append_range(__pn_, __first, __last); return *this; } +#endif // concatenation _LIBCPP_INLINE_VISIBILITY @@ -1295,7 +1327,11 @@ public: return string_type(__root_directory()); } _LIBCPP_INLINE_VISIBILITY path root_path() const { +#if defined(_LIBCPP_WIN32API) + return string_type(__root_path_raw()); +#else return root_name().append(string_type(__root_directory())); +#endif } _LIBCPP_INLINE_VISIBILITY path relative_path() const { return string_type(__relative_path()); diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp index eabd6f92da3c..ad9d06eb9849 100644 --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp @@ -63,6 +63,54 @@ const AppendOperatorTestcase Cases[] = , {S("/p1"), S("/p2/"), S("/p2/")} , {S("p1"), S(""), S("p1/")} , {S("p1/"), S(""), S("p1/")} + + , {S("//host"), S("foo"), S("//host/foo")} + , {S("//host/"), S("foo"), S("//host/foo")} + , {S("//host"), S(""), S("//host/")} + +#ifdef _WIN32 + , {S("foo"), S("C:/bar"), S("C:/bar")} + , {S("foo"), S("C:"), S("C:")} + + , {S("C:"), S(""), S("C:")} + , {S("C:foo"), S("/bar"), S("C:/bar")} + , {S("C:foo"), S("bar"), S("C:foo/bar")} + , {S("C:/foo"), S("bar"), S("C:/foo/bar")} + , {S("C:/foo"), S("/bar"), S("C:/bar")} + + , {S("C:foo"), S("C:/bar"), S("C:/bar")} + , {S("C:foo"), S("C:bar"), S("C:foo/bar")} + , {S("C:/foo"), S("C:/bar"), S("C:/bar")} + , {S("C:/foo"), S("C:bar"), S("C:/foo/bar")} + + , {S("C:foo"), S("c:/bar"), S("c:/bar")} + , {S("C:foo"), S("c:bar"), S("c:bar")} + , {S("C:/foo"), S("c:/bar"), S("c:/bar")} + , {S("C:/foo"), S("c:bar"), S("c:bar")} + + , {S("C:/foo"), S("D:bar"), S("D:bar")} +#else + , {S("foo"), S("C:/bar"), S("foo/C:/bar")} + , {S("foo"), S("C:"), S("foo/C:")} + + , {S("C:"), S(""), S("C:/")} + , {S("C:foo"), S("/bar"), S("/bar")} + , {S("C:foo"), S("bar"), S("C:foo/bar")} + , {S("C:/foo"), S("bar"), S("C:/foo/bar")} + , {S("C:/foo"), S("/bar"), S("/bar")} + + , {S("C:foo"), S("C:/bar"), S("C:foo/C:/bar")} + , {S("C:foo"), S("C:bar"), S("C:foo/C:bar")} + , {S("C:/foo"), S("C:/bar"), S("C:/foo/C:/bar")} + , {S("C:/foo"), S("C:bar"), S("C:/foo/C:bar")} + + , {S("C:foo"), S("c:/bar"), S("C:foo/c:/bar")} + , {S("C:foo"), S("c:bar"), S("C:foo/c:bar")} + , {S("C:/foo"), S("c:/bar"), S("C:/foo/c:/bar")} + , {S("C:/foo"), S("c:bar"), S("C:/foo/c:bar")} + + , {S("C:/foo"), S("D:bar"), S("C:/foo/D:bar")} +#endif }; -- 2.25.1