Skip to content

Commit 78d693f

Browse files
committed
[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
1 parent 3ae27fc commit 78d693f

File tree

2 files changed

+92
-8
lines changed

2 files changed

+92
-8
lines changed

libcxx/include/filesystem

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,14 +1006,44 @@ public:
10061006
return *this;
10071007
}
10081008

1009-
private:
1010-
template <class _ECharT>
1011-
static bool __source_is_absolute(_ECharT __first_or_null) {
1012-
return __is_separator(__first_or_null);
1013-
}
1014-
10151009
public:
10161010
// appends
1011+
#if defined(_LIBCPP_WIN32API)
1012+
path& operator/=(const path& __p) {
1013+
auto __p_root_name = __p.__root_name();
1014+
auto __p_root_name_size = __p_root_name.size();
1015+
if (__p.is_absolute() ||
1016+
(!__p_root_name.empty() && __p_root_name != root_name())) {
1017+
__pn_ = __p.__pn_;
1018+
return *this;
1019+
}
1020+
if (__p.has_root_directory()) {
1021+
path __root_name_str = root_name();
1022+
__pn_ = __root_name_str.native();
1023+
__pn_ += __p.__pn_.substr(__p_root_name_size);
1024+
return *this;
1025+
}
1026+
if (has_filename() || (!has_root_directory() && is_absolute()))
1027+
__pn_ += preferred_separator;
1028+
__pn_ += __p.__pn_.substr(__p_root_name_size);
1029+
return *this;
1030+
}
1031+
template <class _Source>
1032+
_LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source>
1033+
operator/=(const _Source& __src) {
1034+
return operator/=(path(__src));
1035+
}
1036+
1037+
template <class _Source>
1038+
_EnableIfPathable<_Source> append(const _Source& __src) {
1039+
return operator/=(path(__src));
1040+
}
1041+
1042+
template <class _InputIt>
1043+
path& append(_InputIt __first, _InputIt __last) {
1044+
return operator/=(path(__first, __last));
1045+
}
1046+
#else
10171047
path& operator/=(const path& __p) {
10181048
if (__p.is_absolute()) {
10191049
__pn_ = __p.__pn_;
@@ -1038,7 +1068,8 @@ public:
10381068
_EnableIfPathable<_Source> append(const _Source& __src) {
10391069
using _Traits = __is_pathable<_Source>;
10401070
using _CVT = _PathCVT<_SourceChar<_Source> >;
1041-
if (__source_is_absolute(_Traits::__first_or_null(__src)))
1071+
bool __source_is_absolute = __is_separator(_Traits::__first_or_null(__src));
1072+
if (__source_is_absolute)
10421073
__pn_.clear();
10431074
else if (has_filename())
10441075
__pn_ += preferred_separator;
@@ -1051,13 +1082,14 @@ public:
10511082
typedef typename iterator_traits<_InputIt>::value_type _ItVal;
10521083
static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
10531084
using _CVT = _PathCVT<_ItVal>;
1054-
if (__first != __last && __source_is_absolute(*__first))
1085+
if (__first != __last && __is_separator(*__first))
10551086
__pn_.clear();
10561087
else if (has_filename())
10571088
__pn_ += preferred_separator;
10581089
_CVT::__append_range(__pn_, __first, __last);
10591090
return *this;
10601091
}
1092+
#endif
10611093

10621094
// concatenation
10631095
_LIBCPP_INLINE_VISIBILITY
@@ -1295,7 +1327,11 @@ public:
12951327
return string_type(__root_directory());
12961328
}
12971329
_LIBCPP_INLINE_VISIBILITY path root_path() const {
1330+
#if defined(_LIBCPP_WIN32API)
1331+
return string_type(__root_path_raw());
1332+
#else
12981333
return root_name().append(string_type(__root_directory()));
1334+
#endif
12991335
}
13001336
_LIBCPP_INLINE_VISIBILITY path relative_path() const {
13011337
return string_type(__relative_path());

libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,54 @@ const AppendOperatorTestcase Cases[] =
6363
, {S("/p1"), S("/p2/"), S("/p2/")}
6464
, {S("p1"), S(""), S("p1/")}
6565
, {S("p1/"), S(""), S("p1/")}
66+
67+
, {S("//host"), S("foo"), S("//host/foo")}
68+
, {S("//host/"), S("foo"), S("//host/foo")}
69+
, {S("//host"), S(""), S("//host/")}
70+
71+
#ifdef _WIN32
72+
, {S("foo"), S("C:/bar"), S("C:/bar")}
73+
, {S("foo"), S("C:"), S("C:")}
74+
75+
, {S("C:"), S(""), S("C:")}
76+
, {S("C:foo"), S("/bar"), S("C:/bar")}
77+
, {S("C:foo"), S("bar"), S("C:foo/bar")}
78+
, {S("C:/foo"), S("bar"), S("C:/foo/bar")}
79+
, {S("C:/foo"), S("/bar"), S("C:/bar")}
80+
81+
, {S("C:foo"), S("C:/bar"), S("C:/bar")}
82+
, {S("C:foo"), S("C:bar"), S("C:foo/bar")}
83+
, {S("C:/foo"), S("C:/bar"), S("C:/bar")}
84+
, {S("C:/foo"), S("C:bar"), S("C:/foo/bar")}
85+
86+
, {S("C:foo"), S("c:/bar"), S("c:/bar")}
87+
, {S("C:foo"), S("c:bar"), S("c:bar")}
88+
, {S("C:/foo"), S("c:/bar"), S("c:/bar")}
89+
, {S("C:/foo"), S("c:bar"), S("c:bar")}
90+
91+
, {S("C:/foo"), S("D:bar"), S("D:bar")}
92+
#else
93+
, {S("foo"), S("C:/bar"), S("foo/C:/bar")}
94+
, {S("foo"), S("C:"), S("foo/C:")}
95+
96+
, {S("C:"), S(""), S("C:/")}
97+
, {S("C:foo"), S("/bar"), S("/bar")}
98+
, {S("C:foo"), S("bar"), S("C:foo/bar")}
99+
, {S("C:/foo"), S("bar"), S("C:/foo/bar")}
100+
, {S("C:/foo"), S("/bar"), S("/bar")}
101+
102+
, {S("C:foo"), S("C:/bar"), S("C:foo/C:/bar")}
103+
, {S("C:foo"), S("C:bar"), S("C:foo/C:bar")}
104+
, {S("C:/foo"), S("C:/bar"), S("C:/foo/C:/bar")}
105+
, {S("C:/foo"), S("C:bar"), S("C:/foo/C:bar")}
106+
107+
, {S("C:foo"), S("c:/bar"), S("C:foo/c:/bar")}
108+
, {S("C:foo"), S("c:bar"), S("C:foo/c:bar")}
109+
, {S("C:/foo"), S("c:/bar"), S("C:/foo/c:/bar")}
110+
, {S("C:/foo"), S("c:bar"), S("C:/foo/c:bar")}
111+
112+
, {S("C:/foo"), S("D:bar"), S("C:/foo/D:bar")}
113+
#endif
66114
};
67115

68116

0 commit comments

Comments
 (0)