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
replace_extension(path const & replacement)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
__root_name() const4606c3fb27SDimitry 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
__root_directory() const5306c3fb27SDimitry 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
__root_path_raw() const6206c3fb27SDimitry 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
ConsumeRootName(PathParser * PP)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
ConsumeRootDir(PathParser * PP)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
__relative_path() const9206c3fb27SDimitry 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
__parent_path() const9906c3fb27SDimitry 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
__filename() const12106c3fb27SDimitry 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
__stem() const132cb14a3feSDimitry Andric string_view_t path::__stem() const { return parser::separate_filename(__filename()).first; }
13306c3fb27SDimitry Andric
__extension() const134cb14a3feSDimitry 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
ClassifyPathPart(string_view_t Part)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
lexically_normal() const15706c3fb27SDimitry 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
DetermineLexicalElementCount(PathParser PP)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
lexically_relative(const path & base) const24606c3fb27SDimitry 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
CompareRootName(PathParser * LHS,PathParser * RHS)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
CompareRootDir(PathParser * LHS,PathParser * RHS)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
CompareRelative(PathParser * LHSPtr,PathParser * RHSPtr)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
CompareEndState(PathParser * LHS,PathParser * RHS)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
__compare(string_view_t __s) const34706c3fb27SDimitry 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
hash_value(const path & __p)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
begin() const37906c3fb27SDimitry 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
end() const38906c3fb27SDimitry 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
__increment()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
__decrement()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
__wide_to_char(const wstring & str,char * out,size_t outlen)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
__char_to_wide(const string & str,wchar_t * out,size_t outlen)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