xref: /llvm-project/libcxx/src/filesystem/path.cpp (revision b69ddbc62838f23ace237c206676b1ed1c882638)
1c7d3c844SLouis Dionne //===----------------------------------------------------------------------===//
2c7d3c844SLouis Dionne //
3c7d3c844SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c7d3c844SLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5c7d3c844SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c7d3c844SLouis Dionne //
7c7d3c844SLouis Dionne //===----------------------------------------------------------------------===//
8c7d3c844SLouis Dionne 
9c7d3c844SLouis Dionne #include <__config>
10c7d3c844SLouis Dionne #include <filesystem>
11c7d3c844SLouis Dionne #include <vector>
12c7d3c844SLouis Dionne 
13c7d3c844SLouis Dionne #include "error.h"
14c7d3c844SLouis Dionne #include "path_parser.h"
15c7d3c844SLouis Dionne 
16c7d3c844SLouis Dionne _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
17c7d3c844SLouis Dionne 
18c7d3c844SLouis Dionne using detail::ErrorHandler;
19c7d3c844SLouis Dionne using parser::createView;
20c7d3c844SLouis Dionne using parser::PathParser;
21c7d3c844SLouis Dionne using parser::string_view_t;
22c7d3c844SLouis Dionne 
23c7d3c844SLouis Dionne ///////////////////////////////////////////////////////////////////////////////
24c7d3c844SLouis Dionne //                            path definitions
25c7d3c844SLouis Dionne ///////////////////////////////////////////////////////////////////////////////
26c7d3c844SLouis Dionne 
27*b69ddbc6SNikolas Klauser _LIBCPP_DIAGNOSTIC_PUSH
28*b69ddbc6SNikolas Klauser _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated")
29c7d3c844SLouis Dionne constexpr path::value_type path::preferred_separator;
30*b69ddbc6SNikolas Klauser _LIBCPP_DIAGNOSTIC_POP
31c7d3c844SLouis Dionne 
32c7d3c844SLouis Dionne path& path::replace_extension(path const& replacement) {
33c7d3c844SLouis Dionne   path p = extension();
34c7d3c844SLouis Dionne   if (not p.empty()) {
35c7d3c844SLouis Dionne     __pn_.erase(__pn_.size() - p.native().size());
36c7d3c844SLouis Dionne   }
37c7d3c844SLouis Dionne   if (!replacement.empty()) {
38c7d3c844SLouis Dionne     if (replacement.native()[0] != '.') {
39c7d3c844SLouis Dionne       __pn_ += PATHSTR(".");
40c7d3c844SLouis Dionne     }
41c7d3c844SLouis Dionne     __pn_.append(replacement.__pn_);
42c7d3c844SLouis Dionne   }
43c7d3c844SLouis Dionne   return *this;
44c7d3c844SLouis Dionne }
45c7d3c844SLouis Dionne 
46c7d3c844SLouis Dionne ///////////////////////////////////////////////////////////////////////////////
47c7d3c844SLouis Dionne // path.decompose
48c7d3c844SLouis Dionne 
49c7d3c844SLouis Dionne string_view_t path::__root_name() const {
50c7d3c844SLouis Dionne   auto PP = PathParser::CreateBegin(__pn_);
51731db06aSNikolas Klauser   if (PP.State_ == PathParser::PS_InRootName)
52c7d3c844SLouis Dionne     return *PP;
53c7d3c844SLouis Dionne   return {};
54c7d3c844SLouis Dionne }
55c7d3c844SLouis Dionne 
56c7d3c844SLouis Dionne string_view_t path::__root_directory() const {
57c7d3c844SLouis Dionne   auto PP = PathParser::CreateBegin(__pn_);
58731db06aSNikolas Klauser   if (PP.State_ == PathParser::PS_InRootName)
59c7d3c844SLouis Dionne     ++PP;
60731db06aSNikolas Klauser   if (PP.State_ == PathParser::PS_InRootDir)
61c7d3c844SLouis Dionne     return *PP;
62c7d3c844SLouis Dionne   return {};
63c7d3c844SLouis Dionne }
64c7d3c844SLouis Dionne 
65c7d3c844SLouis Dionne string_view_t path::__root_path_raw() const {
66c7d3c844SLouis Dionne   auto PP = PathParser::CreateBegin(__pn_);
67731db06aSNikolas Klauser   if (PP.State_ == PathParser::PS_InRootName) {
68c7d3c844SLouis Dionne     auto NextCh = PP.peek();
69c7d3c844SLouis Dionne     if (NextCh && isSeparator(*NextCh)) {
70c7d3c844SLouis Dionne       ++PP;
71c7d3c844SLouis Dionne       return createView(__pn_.data(), &PP.RawEntry.back());
72c7d3c844SLouis Dionne     }
73c7d3c844SLouis Dionne     return PP.RawEntry;
74c7d3c844SLouis Dionne   }
75731db06aSNikolas Klauser   if (PP.State_ == PathParser::PS_InRootDir)
76c7d3c844SLouis Dionne     return *PP;
77c7d3c844SLouis Dionne   return {};
78c7d3c844SLouis Dionne }
79c7d3c844SLouis Dionne 
80c7d3c844SLouis Dionne static bool ConsumeRootName(PathParser* PP) {
819783f28cSLouis Dionne   static_assert(PathParser::PS_BeforeBegin == 1 && PathParser::PS_InRootName == 2, "Values for enums are incorrect");
82731db06aSNikolas Klauser   while (PP->State_ <= PathParser::PS_InRootName)
83c7d3c844SLouis Dionne     ++(*PP);
84731db06aSNikolas Klauser   return PP->State_ == PathParser::PS_AtEnd;
85c7d3c844SLouis Dionne }
86c7d3c844SLouis Dionne 
87c7d3c844SLouis Dionne static bool ConsumeRootDir(PathParser* PP) {
889783f28cSLouis Dionne   static_assert(PathParser::PS_BeforeBegin == 1 && PathParser::PS_InRootName == 2 && PathParser::PS_InRootDir == 3,
899783f28cSLouis Dionne                 "Values for enums are incorrect");
90731db06aSNikolas Klauser   while (PP->State_ <= PathParser::PS_InRootDir)
91c7d3c844SLouis Dionne     ++(*PP);
92731db06aSNikolas Klauser   return PP->State_ == PathParser::PS_AtEnd;
93c7d3c844SLouis Dionne }
94c7d3c844SLouis Dionne 
95c7d3c844SLouis Dionne string_view_t path::__relative_path() const {
96c7d3c844SLouis Dionne   auto PP = PathParser::CreateBegin(__pn_);
97c7d3c844SLouis Dionne   if (ConsumeRootDir(&PP))
98c7d3c844SLouis Dionne     return {};
99c7d3c844SLouis Dionne   return createView(PP.RawEntry.data(), &__pn_.back());
100c7d3c844SLouis Dionne }
101c7d3c844SLouis Dionne 
102c7d3c844SLouis Dionne string_view_t path::__parent_path() const {
103c7d3c844SLouis Dionne   if (empty())
104c7d3c844SLouis Dionne     return {};
105c7d3c844SLouis Dionne   // Determine if we have a root path but not a relative path. In that case
106c7d3c844SLouis Dionne   // return *this.
107c7d3c844SLouis Dionne   {
108c7d3c844SLouis Dionne     auto PP = PathParser::CreateBegin(__pn_);
109c7d3c844SLouis Dionne     if (ConsumeRootDir(&PP))
110c7d3c844SLouis Dionne       return __pn_;
111c7d3c844SLouis Dionne   }
112c7d3c844SLouis Dionne   // Otherwise remove a single element from the end of the path, and return
113c7d3c844SLouis Dionne   // a string representing that path
114c7d3c844SLouis Dionne   {
115c7d3c844SLouis Dionne     auto PP = PathParser::CreateEnd(__pn_);
116c7d3c844SLouis Dionne     --PP;
117c7d3c844SLouis Dionne     if (PP.RawEntry.data() == __pn_.data())
118c7d3c844SLouis Dionne       return {};
119c7d3c844SLouis Dionne     --PP;
120c7d3c844SLouis Dionne     return createView(__pn_.data(), &PP.RawEntry.back());
121c7d3c844SLouis Dionne   }
122c7d3c844SLouis Dionne }
123c7d3c844SLouis Dionne 
124c7d3c844SLouis Dionne string_view_t path::__filename() const {
125c7d3c844SLouis Dionne   if (empty())
126c7d3c844SLouis Dionne     return {};
127c7d3c844SLouis Dionne   {
128c7d3c844SLouis Dionne     PathParser PP = PathParser::CreateBegin(__pn_);
129c7d3c844SLouis Dionne     if (ConsumeRootDir(&PP))
130c7d3c844SLouis Dionne       return {};
131c7d3c844SLouis Dionne   }
132c7d3c844SLouis Dionne   return *(--PathParser::CreateEnd(__pn_));
133c7d3c844SLouis Dionne }
134c7d3c844SLouis Dionne 
1359783f28cSLouis Dionne string_view_t path::__stem() const { return parser::separate_filename(__filename()).first; }
136c7d3c844SLouis Dionne 
1379783f28cSLouis Dionne string_view_t path::__extension() const { return parser::separate_filename(__filename()).second; }
138c7d3c844SLouis Dionne 
139c7d3c844SLouis Dionne ////////////////////////////////////////////////////////////////////////////
140c7d3c844SLouis Dionne // path.gen
141c7d3c844SLouis Dionne 
1429783f28cSLouis Dionne enum PathPartKind : unsigned char { PK_None, PK_RootSep, PK_Filename, PK_Dot, PK_DotDot, PK_TrailingSep };
143c7d3c844SLouis Dionne 
144c7d3c844SLouis Dionne static PathPartKind ClassifyPathPart(string_view_t Part) {
145c7d3c844SLouis Dionne   if (Part.empty())
146c7d3c844SLouis Dionne     return PK_TrailingSep;
147c7d3c844SLouis Dionne   if (Part == PATHSTR("."))
148c7d3c844SLouis Dionne     return PK_Dot;
149c7d3c844SLouis Dionne   if (Part == PATHSTR(".."))
150c7d3c844SLouis Dionne     return PK_DotDot;
151c7d3c844SLouis Dionne   if (Part == PATHSTR("/"))
152c7d3c844SLouis Dionne     return PK_RootSep;
153c7d3c844SLouis Dionne #if defined(_LIBCPP_WIN32API)
154c7d3c844SLouis Dionne   if (Part == PATHSTR("\\"))
155c7d3c844SLouis Dionne     return PK_RootSep;
156c7d3c844SLouis Dionne #endif
157c7d3c844SLouis Dionne   return PK_Filename;
158c7d3c844SLouis Dionne }
159c7d3c844SLouis Dionne 
160c7d3c844SLouis Dionne path path::lexically_normal() const {
161c7d3c844SLouis Dionne   if (__pn_.empty())
162c7d3c844SLouis Dionne     return *this;
163c7d3c844SLouis Dionne 
164c7d3c844SLouis Dionne   using PartKindPair = pair<string_view_t, PathPartKind>;
165c7d3c844SLouis Dionne   vector<PartKindPair> Parts;
166c7d3c844SLouis Dionne   // Guess as to how many elements the path has to avoid reallocating.
167c7d3c844SLouis Dionne   Parts.reserve(32);
168c7d3c844SLouis Dionne 
169c7d3c844SLouis Dionne   // Track the total size of the parts as we collect them. This allows the
170c7d3c844SLouis Dionne   // resulting path to reserve the correct amount of memory.
171c7d3c844SLouis Dionne   size_t NewPathSize = 0;
172c7d3c844SLouis Dionne   auto AddPart       = [&](PathPartKind K, string_view_t P) {
173c7d3c844SLouis Dionne     NewPathSize += P.size();
174c7d3c844SLouis Dionne     Parts.emplace_back(P, K);
175c7d3c844SLouis Dionne   };
176c7d3c844SLouis Dionne   auto LastPartKind = [&]() {
177c7d3c844SLouis Dionne     if (Parts.empty())
178c7d3c844SLouis Dionne       return PK_None;
179c7d3c844SLouis Dionne     return Parts.back().second;
180c7d3c844SLouis Dionne   };
181c7d3c844SLouis Dionne 
182c7d3c844SLouis Dionne   bool MaybeNeedTrailingSep = false;
183c7d3c844SLouis Dionne   // Build a stack containing the remaining elements of the path, popping off
184c7d3c844SLouis Dionne   // elements which occur before a '..' entry.
185c7d3c844SLouis Dionne   for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
186c7d3c844SLouis Dionne     auto Part         = *PP;
187c7d3c844SLouis Dionne     PathPartKind Kind = ClassifyPathPart(Part);
188c7d3c844SLouis Dionne     switch (Kind) {
189c7d3c844SLouis Dionne     case PK_Filename:
190c7d3c844SLouis Dionne     case PK_RootSep: {
191c7d3c844SLouis Dionne       // Add all non-dot and non-dot-dot elements to the stack of elements.
192c7d3c844SLouis Dionne       AddPart(Kind, Part);
193c7d3c844SLouis Dionne       MaybeNeedTrailingSep = false;
194c7d3c844SLouis Dionne       break;
195c7d3c844SLouis Dionne     }
196c7d3c844SLouis Dionne     case PK_DotDot: {
197c7d3c844SLouis Dionne       // Only push a ".." element if there are no elements preceding the "..",
198c7d3c844SLouis Dionne       // or if the preceding element is itself "..".
199c7d3c844SLouis Dionne       auto LastKind = LastPartKind();
200c7d3c844SLouis Dionne       if (LastKind == PK_Filename) {
201c7d3c844SLouis Dionne         NewPathSize -= Parts.back().first.size();
202c7d3c844SLouis Dionne         Parts.pop_back();
203c7d3c844SLouis Dionne       } else if (LastKind != PK_RootSep)
204c7d3c844SLouis Dionne         AddPart(PK_DotDot, PATHSTR(".."));
205c7d3c844SLouis Dionne       MaybeNeedTrailingSep = LastKind == PK_Filename;
206c7d3c844SLouis Dionne       break;
207c7d3c844SLouis Dionne     }
208c7d3c844SLouis Dionne     case PK_Dot:
209c7d3c844SLouis Dionne     case PK_TrailingSep: {
210c7d3c844SLouis Dionne       MaybeNeedTrailingSep = true;
211c7d3c844SLouis Dionne       break;
212c7d3c844SLouis Dionne     }
213c7d3c844SLouis Dionne     case PK_None:
214c7d3c844SLouis Dionne       __libcpp_unreachable();
215c7d3c844SLouis Dionne     }
216c7d3c844SLouis Dionne   }
217c7d3c844SLouis Dionne   // [fs.path.generic]p6.8: If the path is empty, add a dot.
218c7d3c844SLouis Dionne   if (Parts.empty())
219c7d3c844SLouis Dionne     return PATHSTR(".");
220c7d3c844SLouis Dionne 
221c7d3c844SLouis Dionne   // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
222c7d3c844SLouis Dionne   // trailing directory-separator.
223c7d3c844SLouis Dionne   bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;
224c7d3c844SLouis Dionne 
225c7d3c844SLouis Dionne   path Result;
226c7d3c844SLouis Dionne   Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
227c7d3c844SLouis Dionne   for (auto& PK : Parts)
228c7d3c844SLouis Dionne     Result /= PK.first;
229c7d3c844SLouis Dionne 
230c7d3c844SLouis Dionne   if (NeedTrailingSep)
231c7d3c844SLouis Dionne     Result /= PATHSTR("");
232c7d3c844SLouis Dionne 
233c7d3c844SLouis Dionne   Result.make_preferred();
234c7d3c844SLouis Dionne   return Result;
235c7d3c844SLouis Dionne }
236c7d3c844SLouis Dionne 
237c7d3c844SLouis Dionne static int DetermineLexicalElementCount(PathParser PP) {
238c7d3c844SLouis Dionne   int Count = 0;
239c7d3c844SLouis Dionne   for (; PP; ++PP) {
240c7d3c844SLouis Dionne     auto Elem = *PP;
241c7d3c844SLouis Dionne     if (Elem == PATHSTR(".."))
242c7d3c844SLouis Dionne       --Count;
243c7d3c844SLouis Dionne     else if (Elem != PATHSTR(".") && Elem != PATHSTR(""))
244c7d3c844SLouis Dionne       ++Count;
245c7d3c844SLouis Dionne   }
246c7d3c844SLouis Dionne   return Count;
247c7d3c844SLouis Dionne }
248c7d3c844SLouis Dionne 
249c7d3c844SLouis Dionne path path::lexically_relative(const path& base) const {
250c7d3c844SLouis Dionne   { // perform root-name/root-directory mismatch checks
251c7d3c844SLouis Dionne     auto PP                      = PathParser::CreateBegin(__pn_);
252c7d3c844SLouis Dionne     auto PPBase                  = PathParser::CreateBegin(base.__pn_);
253c7d3c844SLouis Dionne     auto CheckIterMismatchAtBase = [&]() {
254731db06aSNikolas Klauser       return PP.State_ != PPBase.State_ && (PP.inRootPath() || PPBase.inRootPath());
255c7d3c844SLouis Dionne     };
256c7d3c844SLouis Dionne     if (PP.inRootName() && PPBase.inRootName()) {
257c7d3c844SLouis Dionne       if (*PP != *PPBase)
258c7d3c844SLouis Dionne         return {};
259c7d3c844SLouis Dionne     } else if (CheckIterMismatchAtBase())
260c7d3c844SLouis Dionne       return {};
261c7d3c844SLouis Dionne 
262c7d3c844SLouis Dionne     if (PP.inRootPath())
263c7d3c844SLouis Dionne       ++PP;
264c7d3c844SLouis Dionne     if (PPBase.inRootPath())
265c7d3c844SLouis Dionne       ++PPBase;
266c7d3c844SLouis Dionne     if (CheckIterMismatchAtBase())
267c7d3c844SLouis Dionne       return {};
268c7d3c844SLouis Dionne   }
269c7d3c844SLouis Dionne 
270c7d3c844SLouis Dionne   // Find the first mismatching element
271c7d3c844SLouis Dionne   auto PP     = PathParser::CreateBegin(__pn_);
272c7d3c844SLouis Dionne   auto PPBase = PathParser::CreateBegin(base.__pn_);
273aa427b1aSRichardLuo   while (PP && PPBase && PP.State_ == PPBase.State_ && (*PP == *PPBase || PP.inRootDir())) {
274c7d3c844SLouis Dionne     ++PP;
275c7d3c844SLouis Dionne     ++PPBase;
276c7d3c844SLouis Dionne   }
277c7d3c844SLouis Dionne 
278c7d3c844SLouis Dionne   // If there is no mismatch, return ".".
279c7d3c844SLouis Dionne   if (!PP && !PPBase)
280c7d3c844SLouis Dionne     return ".";
281c7d3c844SLouis Dionne 
282c7d3c844SLouis Dionne   // Otherwise, determine the number of elements, 'n', which are not dot or
283c7d3c844SLouis Dionne   // dot-dot minus the number of dot-dot elements.
284c7d3c844SLouis Dionne   int ElemCount = DetermineLexicalElementCount(PPBase);
285c7d3c844SLouis Dionne   if (ElemCount < 0)
286c7d3c844SLouis Dionne     return {};
287c7d3c844SLouis Dionne 
288c7d3c844SLouis Dionne   // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
289c7d3c844SLouis Dionne   if (ElemCount == 0 && (PP.atEnd() || *PP == PATHSTR("")))
290c7d3c844SLouis Dionne     return PATHSTR(".");
291c7d3c844SLouis Dionne 
292c7d3c844SLouis Dionne   // return a path constructed with 'n' dot-dot elements, followed by the
293c7d3c844SLouis Dionne   // elements of '*this' after the mismatch.
294c7d3c844SLouis Dionne   path Result;
295c7d3c844SLouis Dionne   // FIXME: Reserve enough room in Result that it won't have to re-allocate.
296c7d3c844SLouis Dionne   while (ElemCount--)
297c7d3c844SLouis Dionne     Result /= PATHSTR("..");
298c7d3c844SLouis Dionne   for (; PP; ++PP)
299c7d3c844SLouis Dionne     Result /= *PP;
300c7d3c844SLouis Dionne   return Result;
301c7d3c844SLouis Dionne }
302c7d3c844SLouis Dionne 
303c7d3c844SLouis Dionne ////////////////////////////////////////////////////////////////////////////
304c7d3c844SLouis Dionne // path.comparisons
305c7d3c844SLouis Dionne static int CompareRootName(PathParser* LHS, PathParser* RHS) {
306c7d3c844SLouis Dionne   if (!LHS->inRootName() && !RHS->inRootName())
307c7d3c844SLouis Dionne     return 0;
308c7d3c844SLouis Dionne 
3099783f28cSLouis Dionne   auto GetRootName = [](PathParser* Parser) -> string_view_t { return Parser->inRootName() ? **Parser : PATHSTR(""); };
310c7d3c844SLouis Dionne   int res          = GetRootName(LHS).compare(GetRootName(RHS));
311c7d3c844SLouis Dionne   ConsumeRootName(LHS);
312c7d3c844SLouis Dionne   ConsumeRootName(RHS);
313c7d3c844SLouis Dionne   return res;
314c7d3c844SLouis Dionne }
315c7d3c844SLouis Dionne 
316c7d3c844SLouis Dionne static int CompareRootDir(PathParser* LHS, PathParser* RHS) {
317c7d3c844SLouis Dionne   if (!LHS->inRootDir() && RHS->inRootDir())
318c7d3c844SLouis Dionne     return -1;
319c7d3c844SLouis Dionne   else if (LHS->inRootDir() && !RHS->inRootDir())
320c7d3c844SLouis Dionne     return 1;
321c7d3c844SLouis Dionne   else {
322c7d3c844SLouis Dionne     ConsumeRootDir(LHS);
323c7d3c844SLouis Dionne     ConsumeRootDir(RHS);
324c7d3c844SLouis Dionne     return 0;
325c7d3c844SLouis Dionne   }
326c7d3c844SLouis Dionne }
327c7d3c844SLouis Dionne 
328c7d3c844SLouis Dionne static int CompareRelative(PathParser* LHSPtr, PathParser* RHSPtr) {
329c7d3c844SLouis Dionne   auto& LHS = *LHSPtr;
330c7d3c844SLouis Dionne   auto& RHS = *RHSPtr;
331c7d3c844SLouis Dionne 
332c7d3c844SLouis Dionne   int res;
333c7d3c844SLouis Dionne   while (LHS && RHS) {
334c7d3c844SLouis Dionne     if ((res = (*LHS).compare(*RHS)) != 0)
335c7d3c844SLouis Dionne       return res;
336c7d3c844SLouis Dionne     ++LHS;
337c7d3c844SLouis Dionne     ++RHS;
338c7d3c844SLouis Dionne   }
339c7d3c844SLouis Dionne   return 0;
340c7d3c844SLouis Dionne }
341c7d3c844SLouis Dionne 
342c7d3c844SLouis Dionne static int CompareEndState(PathParser* LHS, PathParser* RHS) {
343c7d3c844SLouis Dionne   if (LHS->atEnd() && !RHS->atEnd())
344c7d3c844SLouis Dionne     return -1;
345c7d3c844SLouis Dionne   else if (!LHS->atEnd() && RHS->atEnd())
346c7d3c844SLouis Dionne     return 1;
347c7d3c844SLouis Dionne   return 0;
348c7d3c844SLouis Dionne }
349c7d3c844SLouis Dionne 
350c7d3c844SLouis Dionne int path::__compare(string_view_t __s) const {
351c7d3c844SLouis Dionne   auto LHS = PathParser::CreateBegin(__pn_);
352c7d3c844SLouis Dionne   auto RHS = PathParser::CreateBegin(__s);
353c7d3c844SLouis Dionne   int res;
354c7d3c844SLouis Dionne 
355c7d3c844SLouis Dionne   if ((res = CompareRootName(&LHS, &RHS)) != 0)
356c7d3c844SLouis Dionne     return res;
357c7d3c844SLouis Dionne 
358c7d3c844SLouis Dionne   if ((res = CompareRootDir(&LHS, &RHS)) != 0)
359c7d3c844SLouis Dionne     return res;
360c7d3c844SLouis Dionne 
361c7d3c844SLouis Dionne   if ((res = CompareRelative(&LHS, &RHS)) != 0)
362c7d3c844SLouis Dionne     return res;
363c7d3c844SLouis Dionne 
364c7d3c844SLouis Dionne   return CompareEndState(&LHS, &RHS);
365c7d3c844SLouis Dionne }
366c7d3c844SLouis Dionne 
367c7d3c844SLouis Dionne ////////////////////////////////////////////////////////////////////////////
368c7d3c844SLouis Dionne // path.nonmembers
369c7d3c844SLouis Dionne size_t hash_value(const path& __p) noexcept {
370c7d3c844SLouis Dionne   auto PP           = PathParser::CreateBegin(__p.native());
371c7d3c844SLouis Dionne   size_t hash_value = 0;
372c7d3c844SLouis Dionne   hash<string_view_t> hasher;
373c7d3c844SLouis Dionne   while (PP) {
374aa427b1aSRichardLuo     string_view_t Part = PP.inRootDir() ? PATHSTR("/") : *PP;
375aa427b1aSRichardLuo     hash_value         = __hash_combine(hash_value, hasher(Part));
376c7d3c844SLouis Dionne     ++PP;
377c7d3c844SLouis Dionne   }
378c7d3c844SLouis Dionne   return hash_value;
379c7d3c844SLouis Dionne }
380c7d3c844SLouis Dionne 
381c7d3c844SLouis Dionne ////////////////////////////////////////////////////////////////////////////
382c7d3c844SLouis Dionne // path.itr
383c7d3c844SLouis Dionne path::iterator path::begin() const {
384c7d3c844SLouis Dionne   auto PP = PathParser::CreateBegin(__pn_);
385c7d3c844SLouis Dionne   iterator it;
386c7d3c844SLouis Dionne   it.__path_ptr_ = this;
387731db06aSNikolas Klauser   it.__state_    = static_cast<path::iterator::_ParserState>(PP.State_);
388c7d3c844SLouis Dionne   it.__entry_    = PP.RawEntry;
389c7d3c844SLouis Dionne   it.__stashed_elem_.__assign_view(*PP);
390c7d3c844SLouis Dionne   return it;
391c7d3c844SLouis Dionne }
392c7d3c844SLouis Dionne 
393c7d3c844SLouis Dionne path::iterator path::end() const {
394c7d3c844SLouis Dionne   iterator it{};
395c7d3c844SLouis Dionne   it.__state_    = path::iterator::_AtEnd;
396c7d3c844SLouis Dionne   it.__path_ptr_ = this;
397c7d3c844SLouis Dionne   return it;
398c7d3c844SLouis Dionne }
399c7d3c844SLouis Dionne 
400c7d3c844SLouis Dionne path::iterator& path::iterator::__increment() {
401c7d3c844SLouis Dionne   PathParser PP(__path_ptr_->native(), __entry_, __state_);
402c7d3c844SLouis Dionne   ++PP;
403731db06aSNikolas Klauser   __state_ = static_cast<_ParserState>(PP.State_);
404c7d3c844SLouis Dionne   __entry_ = PP.RawEntry;
405c7d3c844SLouis Dionne   __stashed_elem_.__assign_view(*PP);
406c7d3c844SLouis Dionne   return *this;
407c7d3c844SLouis Dionne }
408c7d3c844SLouis Dionne 
409c7d3c844SLouis Dionne path::iterator& path::iterator::__decrement() {
410c7d3c844SLouis Dionne   PathParser PP(__path_ptr_->native(), __entry_, __state_);
411c7d3c844SLouis Dionne   --PP;
412731db06aSNikolas Klauser   __state_ = static_cast<_ParserState>(PP.State_);
413c7d3c844SLouis Dionne   __entry_ = PP.RawEntry;
414c7d3c844SLouis Dionne   __stashed_elem_.__assign_view(*PP);
415c7d3c844SLouis Dionne   return *this;
416c7d3c844SLouis Dionne }
417c7d3c844SLouis Dionne 
418c7d3c844SLouis Dionne #if defined(_LIBCPP_WIN32API)
419c7d3c844SLouis Dionne ////////////////////////////////////////////////////////////////////////////
420c7d3c844SLouis Dionne // Windows path conversions
421c7d3c844SLouis Dionne size_t __wide_to_char(const wstring& str, char* out, size_t outlen) {
422c7d3c844SLouis Dionne   if (str.empty())
423c7d3c844SLouis Dionne     return 0;
424c7d3c844SLouis Dionne   ErrorHandler<size_t> err("__wide_to_char", nullptr);
425c7d3c844SLouis Dionne   UINT codepage     = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
426c7d3c844SLouis Dionne   BOOL used_default = FALSE;
4279783f28cSLouis Dionne   int ret           = WideCharToMultiByte(codepage, 0, str.data(), str.size(), out, outlen, nullptr, &used_default);
428c7d3c844SLouis Dionne   if (ret <= 0 || used_default)
429c7d3c844SLouis Dionne     return err.report(errc::illegal_byte_sequence);
430c7d3c844SLouis Dionne   return ret;
431c7d3c844SLouis Dionne }
432c7d3c844SLouis Dionne 
433c7d3c844SLouis Dionne size_t __char_to_wide(const string& str, wchar_t* out, size_t outlen) {
434c7d3c844SLouis Dionne   if (str.empty())
435c7d3c844SLouis Dionne     return 0;
436c7d3c844SLouis Dionne   ErrorHandler<size_t> err("__char_to_wide", nullptr);
437c7d3c844SLouis Dionne   UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
4389783f28cSLouis Dionne   int ret       = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str.data(), str.size(), out, outlen);
439c7d3c844SLouis Dionne   if (ret <= 0)
440c7d3c844SLouis Dionne     return err.report(errc::illegal_byte_sequence);
441c7d3c844SLouis Dionne   return ret;
442c7d3c844SLouis Dionne }
443c7d3c844SLouis Dionne #endif
444c7d3c844SLouis Dionne 
445c7d3c844SLouis Dionne _LIBCPP_END_NAMESPACE_FILESYSTEM
446