xref: /freebsd-src/contrib/llvm-project/libcxx/src/filesystem/path.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include <__config>
1006c3fb27SDimitry Andric #include <filesystem>
1106c3fb27SDimitry Andric #include <vector>
1206c3fb27SDimitry Andric 
1306c3fb27SDimitry Andric #include "error.h"
1406c3fb27SDimitry Andric #include "path_parser.h"
1506c3fb27SDimitry Andric 
1606c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
1706c3fb27SDimitry Andric 
1806c3fb27SDimitry Andric using detail::ErrorHandler;
1906c3fb27SDimitry Andric using parser::createView;
2006c3fb27SDimitry Andric using parser::PathParser;
2106c3fb27SDimitry Andric using parser::string_view_t;
2206c3fb27SDimitry Andric 
2306c3fb27SDimitry Andric ///////////////////////////////////////////////////////////////////////////////
2406c3fb27SDimitry Andric //                            path definitions
2506c3fb27SDimitry Andric ///////////////////////////////////////////////////////////////////////////////
2606c3fb27SDimitry Andric 
2706c3fb27SDimitry Andric constexpr path::value_type path::preferred_separator;
2806c3fb27SDimitry Andric 
2906c3fb27SDimitry Andric path& path::replace_extension(path const& replacement) {
3006c3fb27SDimitry Andric   path p = extension();
3106c3fb27SDimitry Andric   if (not p.empty()) {
3206c3fb27SDimitry Andric     __pn_.erase(__pn_.size() - p.native().size());
3306c3fb27SDimitry Andric   }
3406c3fb27SDimitry Andric   if (!replacement.empty()) {
3506c3fb27SDimitry Andric     if (replacement.native()[0] != '.') {
3606c3fb27SDimitry Andric       __pn_ += PATHSTR(".");
3706c3fb27SDimitry Andric     }
3806c3fb27SDimitry Andric     __pn_.append(replacement.__pn_);
3906c3fb27SDimitry Andric   }
4006c3fb27SDimitry Andric   return *this;
4106c3fb27SDimitry Andric }
4206c3fb27SDimitry Andric 
4306c3fb27SDimitry Andric ///////////////////////////////////////////////////////////////////////////////
4406c3fb27SDimitry Andric // path.decompose
4506c3fb27SDimitry Andric 
4606c3fb27SDimitry Andric string_view_t path::__root_name() const {
4706c3fb27SDimitry Andric   auto PP = PathParser::CreateBegin(__pn_);
48*0fca6ea1SDimitry Andric   if (PP.State_ == PathParser::PS_InRootName)
4906c3fb27SDimitry Andric     return *PP;
5006c3fb27SDimitry Andric   return {};
5106c3fb27SDimitry Andric }
5206c3fb27SDimitry Andric 
5306c3fb27SDimitry Andric string_view_t path::__root_directory() const {
5406c3fb27SDimitry Andric   auto PP = PathParser::CreateBegin(__pn_);
55*0fca6ea1SDimitry Andric   if (PP.State_ == PathParser::PS_InRootName)
5606c3fb27SDimitry Andric     ++PP;
57*0fca6ea1SDimitry Andric   if (PP.State_ == PathParser::PS_InRootDir)
5806c3fb27SDimitry Andric     return *PP;
5906c3fb27SDimitry Andric   return {};
6006c3fb27SDimitry Andric }
6106c3fb27SDimitry Andric 
6206c3fb27SDimitry Andric string_view_t path::__root_path_raw() const {
6306c3fb27SDimitry Andric   auto PP = PathParser::CreateBegin(__pn_);
64*0fca6ea1SDimitry Andric   if (PP.State_ == PathParser::PS_InRootName) {
6506c3fb27SDimitry Andric     auto NextCh = PP.peek();
6606c3fb27SDimitry Andric     if (NextCh && isSeparator(*NextCh)) {
6706c3fb27SDimitry Andric       ++PP;
6806c3fb27SDimitry Andric       return createView(__pn_.data(), &PP.RawEntry.back());
6906c3fb27SDimitry Andric     }
7006c3fb27SDimitry Andric     return PP.RawEntry;
7106c3fb27SDimitry Andric   }
72*0fca6ea1SDimitry Andric   if (PP.State_ == PathParser::PS_InRootDir)
7306c3fb27SDimitry Andric     return *PP;
7406c3fb27SDimitry Andric   return {};
7506c3fb27SDimitry Andric }
7606c3fb27SDimitry Andric 
7706c3fb27SDimitry Andric static bool ConsumeRootName(PathParser* PP) {
78cb14a3feSDimitry Andric   static_assert(PathParser::PS_BeforeBegin == 1 && PathParser::PS_InRootName == 2, "Values for enums are incorrect");
79*0fca6ea1SDimitry Andric   while (PP->State_ <= PathParser::PS_InRootName)
8006c3fb27SDimitry Andric     ++(*PP);
81*0fca6ea1SDimitry Andric   return PP->State_ == PathParser::PS_AtEnd;
8206c3fb27SDimitry Andric }
8306c3fb27SDimitry Andric 
8406c3fb27SDimitry Andric static bool ConsumeRootDir(PathParser* PP) {
85cb14a3feSDimitry Andric   static_assert(PathParser::PS_BeforeBegin == 1 && PathParser::PS_InRootName == 2 && PathParser::PS_InRootDir == 3,
86cb14a3feSDimitry Andric                 "Values for enums are incorrect");
87*0fca6ea1SDimitry Andric   while (PP->State_ <= PathParser::PS_InRootDir)
8806c3fb27SDimitry Andric     ++(*PP);
89*0fca6ea1SDimitry Andric   return PP->State_ == PathParser::PS_AtEnd;
9006c3fb27SDimitry Andric }
9106c3fb27SDimitry Andric 
9206c3fb27SDimitry Andric string_view_t path::__relative_path() const {
9306c3fb27SDimitry Andric   auto PP = PathParser::CreateBegin(__pn_);
9406c3fb27SDimitry Andric   if (ConsumeRootDir(&PP))
9506c3fb27SDimitry Andric     return {};
9606c3fb27SDimitry Andric   return createView(PP.RawEntry.data(), &__pn_.back());
9706c3fb27SDimitry Andric }
9806c3fb27SDimitry Andric 
9906c3fb27SDimitry Andric string_view_t path::__parent_path() const {
10006c3fb27SDimitry Andric   if (empty())
10106c3fb27SDimitry Andric     return {};
10206c3fb27SDimitry Andric   // Determine if we have a root path but not a relative path. In that case
10306c3fb27SDimitry Andric   // return *this.
10406c3fb27SDimitry Andric   {
10506c3fb27SDimitry Andric     auto PP = PathParser::CreateBegin(__pn_);
10606c3fb27SDimitry Andric     if (ConsumeRootDir(&PP))
10706c3fb27SDimitry Andric       return __pn_;
10806c3fb27SDimitry Andric   }
10906c3fb27SDimitry Andric   // Otherwise remove a single element from the end of the path, and return
11006c3fb27SDimitry Andric   // a string representing that path
11106c3fb27SDimitry Andric   {
11206c3fb27SDimitry Andric     auto PP = PathParser::CreateEnd(__pn_);
11306c3fb27SDimitry Andric     --PP;
11406c3fb27SDimitry Andric     if (PP.RawEntry.data() == __pn_.data())
11506c3fb27SDimitry Andric       return {};
11606c3fb27SDimitry Andric     --PP;
11706c3fb27SDimitry Andric     return createView(__pn_.data(), &PP.RawEntry.back());
11806c3fb27SDimitry Andric   }
11906c3fb27SDimitry Andric }
12006c3fb27SDimitry Andric 
12106c3fb27SDimitry Andric string_view_t path::__filename() const {
12206c3fb27SDimitry Andric   if (empty())
12306c3fb27SDimitry Andric     return {};
12406c3fb27SDimitry Andric   {
12506c3fb27SDimitry Andric     PathParser PP = PathParser::CreateBegin(__pn_);
12606c3fb27SDimitry Andric     if (ConsumeRootDir(&PP))
12706c3fb27SDimitry Andric       return {};
12806c3fb27SDimitry Andric   }
12906c3fb27SDimitry Andric   return *(--PathParser::CreateEnd(__pn_));
13006c3fb27SDimitry Andric }
13106c3fb27SDimitry Andric 
132cb14a3feSDimitry Andric string_view_t path::__stem() const { return parser::separate_filename(__filename()).first; }
13306c3fb27SDimitry Andric 
134cb14a3feSDimitry Andric string_view_t path::__extension() const { return parser::separate_filename(__filename()).second; }
13506c3fb27SDimitry Andric 
13606c3fb27SDimitry Andric ////////////////////////////////////////////////////////////////////////////
13706c3fb27SDimitry Andric // path.gen
13806c3fb27SDimitry Andric 
139cb14a3feSDimitry Andric enum PathPartKind : unsigned char { PK_None, PK_RootSep, PK_Filename, PK_Dot, PK_DotDot, PK_TrailingSep };
14006c3fb27SDimitry Andric 
14106c3fb27SDimitry Andric static PathPartKind ClassifyPathPart(string_view_t Part) {
14206c3fb27SDimitry Andric   if (Part.empty())
14306c3fb27SDimitry Andric     return PK_TrailingSep;
14406c3fb27SDimitry Andric   if (Part == PATHSTR("."))
14506c3fb27SDimitry Andric     return PK_Dot;
14606c3fb27SDimitry Andric   if (Part == PATHSTR(".."))
14706c3fb27SDimitry Andric     return PK_DotDot;
14806c3fb27SDimitry Andric   if (Part == PATHSTR("/"))
14906c3fb27SDimitry Andric     return PK_RootSep;
15006c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
15106c3fb27SDimitry Andric   if (Part == PATHSTR("\\"))
15206c3fb27SDimitry Andric     return PK_RootSep;
15306c3fb27SDimitry Andric #endif
15406c3fb27SDimitry Andric   return PK_Filename;
15506c3fb27SDimitry Andric }
15606c3fb27SDimitry Andric 
15706c3fb27SDimitry Andric path path::lexically_normal() const {
15806c3fb27SDimitry Andric   if (__pn_.empty())
15906c3fb27SDimitry Andric     return *this;
16006c3fb27SDimitry Andric 
16106c3fb27SDimitry Andric   using PartKindPair = pair<string_view_t, PathPartKind>;
16206c3fb27SDimitry Andric   vector<PartKindPair> Parts;
16306c3fb27SDimitry Andric   // Guess as to how many elements the path has to avoid reallocating.
16406c3fb27SDimitry Andric   Parts.reserve(32);
16506c3fb27SDimitry Andric 
16606c3fb27SDimitry Andric   // Track the total size of the parts as we collect them. This allows the
16706c3fb27SDimitry Andric   // resulting path to reserve the correct amount of memory.
16806c3fb27SDimitry Andric   size_t NewPathSize = 0;
16906c3fb27SDimitry Andric   auto AddPart       = [&](PathPartKind K, string_view_t P) {
17006c3fb27SDimitry Andric     NewPathSize += P.size();
17106c3fb27SDimitry Andric     Parts.emplace_back(P, K);
17206c3fb27SDimitry Andric   };
17306c3fb27SDimitry Andric   auto LastPartKind = [&]() {
17406c3fb27SDimitry Andric     if (Parts.empty())
17506c3fb27SDimitry Andric       return PK_None;
17606c3fb27SDimitry Andric     return Parts.back().second;
17706c3fb27SDimitry Andric   };
17806c3fb27SDimitry Andric 
17906c3fb27SDimitry Andric   bool MaybeNeedTrailingSep = false;
18006c3fb27SDimitry Andric   // Build a stack containing the remaining elements of the path, popping off
18106c3fb27SDimitry Andric   // elements which occur before a '..' entry.
18206c3fb27SDimitry Andric   for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
18306c3fb27SDimitry Andric     auto Part         = *PP;
18406c3fb27SDimitry Andric     PathPartKind Kind = ClassifyPathPart(Part);
18506c3fb27SDimitry Andric     switch (Kind) {
18606c3fb27SDimitry Andric     case PK_Filename:
18706c3fb27SDimitry Andric     case PK_RootSep: {
18806c3fb27SDimitry Andric       // Add all non-dot and non-dot-dot elements to the stack of elements.
18906c3fb27SDimitry Andric       AddPart(Kind, Part);
19006c3fb27SDimitry Andric       MaybeNeedTrailingSep = false;
19106c3fb27SDimitry Andric       break;
19206c3fb27SDimitry Andric     }
19306c3fb27SDimitry Andric     case PK_DotDot: {
19406c3fb27SDimitry Andric       // Only push a ".." element if there are no elements preceding the "..",
19506c3fb27SDimitry Andric       // or if the preceding element is itself "..".
19606c3fb27SDimitry Andric       auto LastKind = LastPartKind();
19706c3fb27SDimitry Andric       if (LastKind == PK_Filename) {
19806c3fb27SDimitry Andric         NewPathSize -= Parts.back().first.size();
19906c3fb27SDimitry Andric         Parts.pop_back();
20006c3fb27SDimitry Andric       } else if (LastKind != PK_RootSep)
20106c3fb27SDimitry Andric         AddPart(PK_DotDot, PATHSTR(".."));
20206c3fb27SDimitry Andric       MaybeNeedTrailingSep = LastKind == PK_Filename;
20306c3fb27SDimitry Andric       break;
20406c3fb27SDimitry Andric     }
20506c3fb27SDimitry Andric     case PK_Dot:
20606c3fb27SDimitry Andric     case PK_TrailingSep: {
20706c3fb27SDimitry Andric       MaybeNeedTrailingSep = true;
20806c3fb27SDimitry Andric       break;
20906c3fb27SDimitry Andric     }
21006c3fb27SDimitry Andric     case PK_None:
21106c3fb27SDimitry Andric       __libcpp_unreachable();
21206c3fb27SDimitry Andric     }
21306c3fb27SDimitry Andric   }
21406c3fb27SDimitry Andric   // [fs.path.generic]p6.8: If the path is empty, add a dot.
21506c3fb27SDimitry Andric   if (Parts.empty())
21606c3fb27SDimitry Andric     return PATHSTR(".");
21706c3fb27SDimitry Andric 
21806c3fb27SDimitry Andric   // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
21906c3fb27SDimitry Andric   // trailing directory-separator.
22006c3fb27SDimitry Andric   bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;
22106c3fb27SDimitry Andric 
22206c3fb27SDimitry Andric   path Result;
22306c3fb27SDimitry Andric   Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
22406c3fb27SDimitry Andric   for (auto& PK : Parts)
22506c3fb27SDimitry Andric     Result /= PK.first;
22606c3fb27SDimitry Andric 
22706c3fb27SDimitry Andric   if (NeedTrailingSep)
22806c3fb27SDimitry Andric     Result /= PATHSTR("");
22906c3fb27SDimitry Andric 
23006c3fb27SDimitry Andric   Result.make_preferred();
23106c3fb27SDimitry Andric   return Result;
23206c3fb27SDimitry Andric }
23306c3fb27SDimitry Andric 
23406c3fb27SDimitry Andric static int DetermineLexicalElementCount(PathParser PP) {
23506c3fb27SDimitry Andric   int Count = 0;
23606c3fb27SDimitry Andric   for (; PP; ++PP) {
23706c3fb27SDimitry Andric     auto Elem = *PP;
23806c3fb27SDimitry Andric     if (Elem == PATHSTR(".."))
23906c3fb27SDimitry Andric       --Count;
24006c3fb27SDimitry Andric     else if (Elem != PATHSTR(".") && Elem != PATHSTR(""))
24106c3fb27SDimitry Andric       ++Count;
24206c3fb27SDimitry Andric   }
24306c3fb27SDimitry Andric   return Count;
24406c3fb27SDimitry Andric }
24506c3fb27SDimitry Andric 
24606c3fb27SDimitry Andric path path::lexically_relative(const path& base) const {
24706c3fb27SDimitry Andric   { // perform root-name/root-directory mismatch checks
24806c3fb27SDimitry Andric     auto PP                      = PathParser::CreateBegin(__pn_);
24906c3fb27SDimitry Andric     auto PPBase                  = PathParser::CreateBegin(base.__pn_);
25006c3fb27SDimitry Andric     auto CheckIterMismatchAtBase = [&]() {
251*0fca6ea1SDimitry Andric       return PP.State_ != PPBase.State_ && (PP.inRootPath() || PPBase.inRootPath());
25206c3fb27SDimitry Andric     };
25306c3fb27SDimitry Andric     if (PP.inRootName() && PPBase.inRootName()) {
25406c3fb27SDimitry Andric       if (*PP != *PPBase)
25506c3fb27SDimitry Andric         return {};
25606c3fb27SDimitry Andric     } else if (CheckIterMismatchAtBase())
25706c3fb27SDimitry Andric       return {};
25806c3fb27SDimitry Andric 
25906c3fb27SDimitry Andric     if (PP.inRootPath())
26006c3fb27SDimitry Andric       ++PP;
26106c3fb27SDimitry Andric     if (PPBase.inRootPath())
26206c3fb27SDimitry Andric       ++PPBase;
26306c3fb27SDimitry Andric     if (CheckIterMismatchAtBase())
26406c3fb27SDimitry Andric       return {};
26506c3fb27SDimitry Andric   }
26606c3fb27SDimitry Andric 
26706c3fb27SDimitry Andric   // Find the first mismatching element
26806c3fb27SDimitry Andric   auto PP     = PathParser::CreateBegin(__pn_);
26906c3fb27SDimitry Andric   auto PPBase = PathParser::CreateBegin(base.__pn_);
270*0fca6ea1SDimitry Andric   while (PP && PPBase && PP.State_ == PPBase.State_ && *PP == *PPBase) {
27106c3fb27SDimitry Andric     ++PP;
27206c3fb27SDimitry Andric     ++PPBase;
27306c3fb27SDimitry Andric   }
27406c3fb27SDimitry Andric 
27506c3fb27SDimitry Andric   // If there is no mismatch, return ".".
27606c3fb27SDimitry Andric   if (!PP && !PPBase)
27706c3fb27SDimitry Andric     return ".";
27806c3fb27SDimitry Andric 
27906c3fb27SDimitry Andric   // Otherwise, determine the number of elements, 'n', which are not dot or
28006c3fb27SDimitry Andric   // dot-dot minus the number of dot-dot elements.
28106c3fb27SDimitry Andric   int ElemCount = DetermineLexicalElementCount(PPBase);
28206c3fb27SDimitry Andric   if (ElemCount < 0)
28306c3fb27SDimitry Andric     return {};
28406c3fb27SDimitry Andric 
28506c3fb27SDimitry Andric   // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
28606c3fb27SDimitry Andric   if (ElemCount == 0 && (PP.atEnd() || *PP == PATHSTR("")))
28706c3fb27SDimitry Andric     return PATHSTR(".");
28806c3fb27SDimitry Andric 
28906c3fb27SDimitry Andric   // return a path constructed with 'n' dot-dot elements, followed by the
29006c3fb27SDimitry Andric   // elements of '*this' after the mismatch.
29106c3fb27SDimitry Andric   path Result;
29206c3fb27SDimitry Andric   // FIXME: Reserve enough room in Result that it won't have to re-allocate.
29306c3fb27SDimitry Andric   while (ElemCount--)
29406c3fb27SDimitry Andric     Result /= PATHSTR("..");
29506c3fb27SDimitry Andric   for (; PP; ++PP)
29606c3fb27SDimitry Andric     Result /= *PP;
29706c3fb27SDimitry Andric   return Result;
29806c3fb27SDimitry Andric }
29906c3fb27SDimitry Andric 
30006c3fb27SDimitry Andric ////////////////////////////////////////////////////////////////////////////
30106c3fb27SDimitry Andric // path.comparisons
30206c3fb27SDimitry Andric static int CompareRootName(PathParser* LHS, PathParser* RHS) {
30306c3fb27SDimitry Andric   if (!LHS->inRootName() && !RHS->inRootName())
30406c3fb27SDimitry Andric     return 0;
30506c3fb27SDimitry Andric 
306cb14a3feSDimitry Andric   auto GetRootName = [](PathParser* Parser) -> string_view_t { return Parser->inRootName() ? **Parser : PATHSTR(""); };
30706c3fb27SDimitry Andric   int res          = GetRootName(LHS).compare(GetRootName(RHS));
30806c3fb27SDimitry Andric   ConsumeRootName(LHS);
30906c3fb27SDimitry Andric   ConsumeRootName(RHS);
31006c3fb27SDimitry Andric   return res;
31106c3fb27SDimitry Andric }
31206c3fb27SDimitry Andric 
31306c3fb27SDimitry Andric static int CompareRootDir(PathParser* LHS, PathParser* RHS) {
31406c3fb27SDimitry Andric   if (!LHS->inRootDir() && RHS->inRootDir())
31506c3fb27SDimitry Andric     return -1;
31606c3fb27SDimitry Andric   else if (LHS->inRootDir() && !RHS->inRootDir())
31706c3fb27SDimitry Andric     return 1;
31806c3fb27SDimitry Andric   else {
31906c3fb27SDimitry Andric     ConsumeRootDir(LHS);
32006c3fb27SDimitry Andric     ConsumeRootDir(RHS);
32106c3fb27SDimitry Andric     return 0;
32206c3fb27SDimitry Andric   }
32306c3fb27SDimitry Andric }
32406c3fb27SDimitry Andric 
32506c3fb27SDimitry Andric static int CompareRelative(PathParser* LHSPtr, PathParser* RHSPtr) {
32606c3fb27SDimitry Andric   auto& LHS = *LHSPtr;
32706c3fb27SDimitry Andric   auto& RHS = *RHSPtr;
32806c3fb27SDimitry Andric 
32906c3fb27SDimitry Andric   int res;
33006c3fb27SDimitry Andric   while (LHS && RHS) {
33106c3fb27SDimitry Andric     if ((res = (*LHS).compare(*RHS)) != 0)
33206c3fb27SDimitry Andric       return res;
33306c3fb27SDimitry Andric     ++LHS;
33406c3fb27SDimitry Andric     ++RHS;
33506c3fb27SDimitry Andric   }
33606c3fb27SDimitry Andric   return 0;
33706c3fb27SDimitry Andric }
33806c3fb27SDimitry Andric 
33906c3fb27SDimitry Andric static int CompareEndState(PathParser* LHS, PathParser* RHS) {
34006c3fb27SDimitry Andric   if (LHS->atEnd() && !RHS->atEnd())
34106c3fb27SDimitry Andric     return -1;
34206c3fb27SDimitry Andric   else if (!LHS->atEnd() && RHS->atEnd())
34306c3fb27SDimitry Andric     return 1;
34406c3fb27SDimitry Andric   return 0;
34506c3fb27SDimitry Andric }
34606c3fb27SDimitry Andric 
34706c3fb27SDimitry Andric int path::__compare(string_view_t __s) const {
34806c3fb27SDimitry Andric   auto LHS = PathParser::CreateBegin(__pn_);
34906c3fb27SDimitry Andric   auto RHS = PathParser::CreateBegin(__s);
35006c3fb27SDimitry Andric   int res;
35106c3fb27SDimitry Andric 
35206c3fb27SDimitry Andric   if ((res = CompareRootName(&LHS, &RHS)) != 0)
35306c3fb27SDimitry Andric     return res;
35406c3fb27SDimitry Andric 
35506c3fb27SDimitry Andric   if ((res = CompareRootDir(&LHS, &RHS)) != 0)
35606c3fb27SDimitry Andric     return res;
35706c3fb27SDimitry Andric 
35806c3fb27SDimitry Andric   if ((res = CompareRelative(&LHS, &RHS)) != 0)
35906c3fb27SDimitry Andric     return res;
36006c3fb27SDimitry Andric 
36106c3fb27SDimitry Andric   return CompareEndState(&LHS, &RHS);
36206c3fb27SDimitry Andric }
36306c3fb27SDimitry Andric 
36406c3fb27SDimitry Andric ////////////////////////////////////////////////////////////////////////////
36506c3fb27SDimitry Andric // path.nonmembers
36606c3fb27SDimitry Andric size_t hash_value(const path& __p) noexcept {
36706c3fb27SDimitry Andric   auto PP           = PathParser::CreateBegin(__p.native());
36806c3fb27SDimitry Andric   size_t hash_value = 0;
36906c3fb27SDimitry Andric   hash<string_view_t> hasher;
37006c3fb27SDimitry Andric   while (PP) {
37106c3fb27SDimitry Andric     hash_value = __hash_combine(hash_value, hasher(*PP));
37206c3fb27SDimitry Andric     ++PP;
37306c3fb27SDimitry Andric   }
37406c3fb27SDimitry Andric   return hash_value;
37506c3fb27SDimitry Andric }
37606c3fb27SDimitry Andric 
37706c3fb27SDimitry Andric ////////////////////////////////////////////////////////////////////////////
37806c3fb27SDimitry Andric // path.itr
37906c3fb27SDimitry Andric path::iterator path::begin() const {
38006c3fb27SDimitry Andric   auto PP = PathParser::CreateBegin(__pn_);
38106c3fb27SDimitry Andric   iterator it;
38206c3fb27SDimitry Andric   it.__path_ptr_ = this;
383*0fca6ea1SDimitry Andric   it.__state_    = static_cast<path::iterator::_ParserState>(PP.State_);
38406c3fb27SDimitry Andric   it.__entry_    = PP.RawEntry;
38506c3fb27SDimitry Andric   it.__stashed_elem_.__assign_view(*PP);
38606c3fb27SDimitry Andric   return it;
38706c3fb27SDimitry Andric }
38806c3fb27SDimitry Andric 
38906c3fb27SDimitry Andric path::iterator path::end() const {
39006c3fb27SDimitry Andric   iterator it{};
39106c3fb27SDimitry Andric   it.__state_    = path::iterator::_AtEnd;
39206c3fb27SDimitry Andric   it.__path_ptr_ = this;
39306c3fb27SDimitry Andric   return it;
39406c3fb27SDimitry Andric }
39506c3fb27SDimitry Andric 
39606c3fb27SDimitry Andric path::iterator& path::iterator::__increment() {
39706c3fb27SDimitry Andric   PathParser PP(__path_ptr_->native(), __entry_, __state_);
39806c3fb27SDimitry Andric   ++PP;
399*0fca6ea1SDimitry Andric   __state_ = static_cast<_ParserState>(PP.State_);
40006c3fb27SDimitry Andric   __entry_ = PP.RawEntry;
40106c3fb27SDimitry Andric   __stashed_elem_.__assign_view(*PP);
40206c3fb27SDimitry Andric   return *this;
40306c3fb27SDimitry Andric }
40406c3fb27SDimitry Andric 
40506c3fb27SDimitry Andric path::iterator& path::iterator::__decrement() {
40606c3fb27SDimitry Andric   PathParser PP(__path_ptr_->native(), __entry_, __state_);
40706c3fb27SDimitry Andric   --PP;
408*0fca6ea1SDimitry Andric   __state_ = static_cast<_ParserState>(PP.State_);
40906c3fb27SDimitry Andric   __entry_ = PP.RawEntry;
41006c3fb27SDimitry Andric   __stashed_elem_.__assign_view(*PP);
41106c3fb27SDimitry Andric   return *this;
41206c3fb27SDimitry Andric }
41306c3fb27SDimitry Andric 
41406c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
41506c3fb27SDimitry Andric ////////////////////////////////////////////////////////////////////////////
41606c3fb27SDimitry Andric // Windows path conversions
41706c3fb27SDimitry Andric size_t __wide_to_char(const wstring& str, char* out, size_t outlen) {
41806c3fb27SDimitry Andric   if (str.empty())
41906c3fb27SDimitry Andric     return 0;
42006c3fb27SDimitry Andric   ErrorHandler<size_t> err("__wide_to_char", nullptr);
42106c3fb27SDimitry Andric   UINT codepage     = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
42206c3fb27SDimitry Andric   BOOL used_default = FALSE;
423cb14a3feSDimitry Andric   int ret           = WideCharToMultiByte(codepage, 0, str.data(), str.size(), out, outlen, nullptr, &used_default);
42406c3fb27SDimitry Andric   if (ret <= 0 || used_default)
42506c3fb27SDimitry Andric     return err.report(errc::illegal_byte_sequence);
42606c3fb27SDimitry Andric   return ret;
42706c3fb27SDimitry Andric }
42806c3fb27SDimitry Andric 
42906c3fb27SDimitry Andric size_t __char_to_wide(const string& str, wchar_t* out, size_t outlen) {
43006c3fb27SDimitry Andric   if (str.empty())
43106c3fb27SDimitry Andric     return 0;
43206c3fb27SDimitry Andric   ErrorHandler<size_t> err("__char_to_wide", nullptr);
43306c3fb27SDimitry Andric   UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
434cb14a3feSDimitry Andric   int ret       = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str.data(), str.size(), out, outlen);
43506c3fb27SDimitry Andric   if (ret <= 0)
43606c3fb27SDimitry Andric     return err.report(errc::illegal_byte_sequence);
43706c3fb27SDimitry Andric   return ret;
43806c3fb27SDimitry Andric }
43906c3fb27SDimitry Andric #endif
44006c3fb27SDimitry Andric 
44106c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_FILESYSTEM
442