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