1*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 2*06c3fb27SDimitry Andric // 3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06c3fb27SDimitry Andric // 7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 8*06c3fb27SDimitry Andric 9*06c3fb27SDimitry Andric #ifndef PATH_PARSER_H 10*06c3fb27SDimitry Andric #define PATH_PARSER_H 11*06c3fb27SDimitry Andric 12*06c3fb27SDimitry Andric #include <__config> 13*06c3fb27SDimitry Andric #include <__utility/unreachable.h> 14*06c3fb27SDimitry Andric #include <cstddef> 15*06c3fb27SDimitry Andric #include <filesystem> 16*06c3fb27SDimitry Andric #include <utility> 17*06c3fb27SDimitry Andric 18*06c3fb27SDimitry Andric #include "format_string.h" 19*06c3fb27SDimitry Andric 20*06c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 21*06c3fb27SDimitry Andric 22*06c3fb27SDimitry Andric inline bool isSeparator(path::value_type C) { 23*06c3fb27SDimitry Andric if (C == '/') 24*06c3fb27SDimitry Andric return true; 25*06c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API) 26*06c3fb27SDimitry Andric if (C == '\\') 27*06c3fb27SDimitry Andric return true; 28*06c3fb27SDimitry Andric #endif 29*06c3fb27SDimitry Andric return false; 30*06c3fb27SDimitry Andric } 31*06c3fb27SDimitry Andric 32*06c3fb27SDimitry Andric inline bool isDriveLetter(path::value_type C) { 33*06c3fb27SDimitry Andric return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z'); 34*06c3fb27SDimitry Andric } 35*06c3fb27SDimitry Andric 36*06c3fb27SDimitry Andric namespace parser { 37*06c3fb27SDimitry Andric 38*06c3fb27SDimitry Andric using string_view_t = path::__string_view; 39*06c3fb27SDimitry Andric using string_view_pair = pair<string_view_t, string_view_t>; 40*06c3fb27SDimitry Andric using PosPtr = path::value_type const*; 41*06c3fb27SDimitry Andric 42*06c3fb27SDimitry Andric struct PathParser { 43*06c3fb27SDimitry Andric enum ParserState : unsigned char { 44*06c3fb27SDimitry Andric // Zero is a special sentinel value used by default constructed iterators. 45*06c3fb27SDimitry Andric PS_BeforeBegin = path::iterator::_BeforeBegin, 46*06c3fb27SDimitry Andric PS_InRootName = path::iterator::_InRootName, 47*06c3fb27SDimitry Andric PS_InRootDir = path::iterator::_InRootDir, 48*06c3fb27SDimitry Andric PS_InFilenames = path::iterator::_InFilenames, 49*06c3fb27SDimitry Andric PS_InTrailingSep = path::iterator::_InTrailingSep, 50*06c3fb27SDimitry Andric PS_AtEnd = path::iterator::_AtEnd 51*06c3fb27SDimitry Andric }; 52*06c3fb27SDimitry Andric 53*06c3fb27SDimitry Andric const string_view_t Path; 54*06c3fb27SDimitry Andric string_view_t RawEntry; 55*06c3fb27SDimitry Andric ParserState State; 56*06c3fb27SDimitry Andric 57*06c3fb27SDimitry Andric private: 58*06c3fb27SDimitry Andric PathParser(string_view_t P, ParserState State) noexcept : Path(P), 59*06c3fb27SDimitry Andric State(State) {} 60*06c3fb27SDimitry Andric 61*06c3fb27SDimitry Andric public: 62*06c3fb27SDimitry Andric PathParser(string_view_t P, string_view_t E, unsigned char S) 63*06c3fb27SDimitry Andric : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) { 64*06c3fb27SDimitry Andric // S cannot be '0' or PS_BeforeBegin. 65*06c3fb27SDimitry Andric } 66*06c3fb27SDimitry Andric 67*06c3fb27SDimitry Andric static PathParser CreateBegin(string_view_t P) noexcept { 68*06c3fb27SDimitry Andric PathParser PP(P, PS_BeforeBegin); 69*06c3fb27SDimitry Andric PP.increment(); 70*06c3fb27SDimitry Andric return PP; 71*06c3fb27SDimitry Andric } 72*06c3fb27SDimitry Andric 73*06c3fb27SDimitry Andric static PathParser CreateEnd(string_view_t P) noexcept { 74*06c3fb27SDimitry Andric PathParser PP(P, PS_AtEnd); 75*06c3fb27SDimitry Andric return PP; 76*06c3fb27SDimitry Andric } 77*06c3fb27SDimitry Andric 78*06c3fb27SDimitry Andric PosPtr peek() const noexcept { 79*06c3fb27SDimitry Andric auto TkEnd = getNextTokenStartPos(); 80*06c3fb27SDimitry Andric auto End = getAfterBack(); 81*06c3fb27SDimitry Andric return TkEnd == End ? nullptr : TkEnd; 82*06c3fb27SDimitry Andric } 83*06c3fb27SDimitry Andric 84*06c3fb27SDimitry Andric void increment() noexcept { 85*06c3fb27SDimitry Andric const PosPtr End = getAfterBack(); 86*06c3fb27SDimitry Andric const PosPtr Start = getNextTokenStartPos(); 87*06c3fb27SDimitry Andric if (Start == End) 88*06c3fb27SDimitry Andric return makeState(PS_AtEnd); 89*06c3fb27SDimitry Andric 90*06c3fb27SDimitry Andric switch (State) { 91*06c3fb27SDimitry Andric case PS_BeforeBegin: { 92*06c3fb27SDimitry Andric PosPtr TkEnd = consumeRootName(Start, End); 93*06c3fb27SDimitry Andric if (TkEnd) 94*06c3fb27SDimitry Andric return makeState(PS_InRootName, Start, TkEnd); 95*06c3fb27SDimitry Andric } 96*06c3fb27SDimitry Andric _LIBCPP_FALLTHROUGH(); 97*06c3fb27SDimitry Andric case PS_InRootName: { 98*06c3fb27SDimitry Andric PosPtr TkEnd = consumeAllSeparators(Start, End); 99*06c3fb27SDimitry Andric if (TkEnd) 100*06c3fb27SDimitry Andric return makeState(PS_InRootDir, Start, TkEnd); 101*06c3fb27SDimitry Andric else 102*06c3fb27SDimitry Andric return makeState(PS_InFilenames, Start, consumeName(Start, End)); 103*06c3fb27SDimitry Andric } 104*06c3fb27SDimitry Andric case PS_InRootDir: 105*06c3fb27SDimitry Andric return makeState(PS_InFilenames, Start, consumeName(Start, End)); 106*06c3fb27SDimitry Andric 107*06c3fb27SDimitry Andric case PS_InFilenames: { 108*06c3fb27SDimitry Andric PosPtr SepEnd = consumeAllSeparators(Start, End); 109*06c3fb27SDimitry Andric if (SepEnd != End) { 110*06c3fb27SDimitry Andric PosPtr TkEnd = consumeName(SepEnd, End); 111*06c3fb27SDimitry Andric if (TkEnd) 112*06c3fb27SDimitry Andric return makeState(PS_InFilenames, SepEnd, TkEnd); 113*06c3fb27SDimitry Andric } 114*06c3fb27SDimitry Andric return makeState(PS_InTrailingSep, Start, SepEnd); 115*06c3fb27SDimitry Andric } 116*06c3fb27SDimitry Andric 117*06c3fb27SDimitry Andric case PS_InTrailingSep: 118*06c3fb27SDimitry Andric return makeState(PS_AtEnd); 119*06c3fb27SDimitry Andric 120*06c3fb27SDimitry Andric case PS_AtEnd: 121*06c3fb27SDimitry Andric __libcpp_unreachable(); 122*06c3fb27SDimitry Andric } 123*06c3fb27SDimitry Andric } 124*06c3fb27SDimitry Andric 125*06c3fb27SDimitry Andric void decrement() noexcept { 126*06c3fb27SDimitry Andric const PosPtr REnd = getBeforeFront(); 127*06c3fb27SDimitry Andric const PosPtr RStart = getCurrentTokenStartPos() - 1; 128*06c3fb27SDimitry Andric if (RStart == REnd) // we're decrementing the begin 129*06c3fb27SDimitry Andric return makeState(PS_BeforeBegin); 130*06c3fb27SDimitry Andric 131*06c3fb27SDimitry Andric switch (State) { 132*06c3fb27SDimitry Andric case PS_AtEnd: { 133*06c3fb27SDimitry Andric // Try to consume a trailing separator or root directory first. 134*06c3fb27SDimitry Andric if (PosPtr SepEnd = consumeAllSeparators(RStart, REnd)) { 135*06c3fb27SDimitry Andric if (SepEnd == REnd) 136*06c3fb27SDimitry Andric return makeState(PS_InRootDir, Path.data(), RStart + 1); 137*06c3fb27SDimitry Andric PosPtr TkStart = consumeRootName(SepEnd, REnd); 138*06c3fb27SDimitry Andric if (TkStart == REnd) 139*06c3fb27SDimitry Andric return makeState(PS_InRootDir, RStart, RStart + 1); 140*06c3fb27SDimitry Andric return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1); 141*06c3fb27SDimitry Andric } else { 142*06c3fb27SDimitry Andric PosPtr TkStart = consumeRootName(RStart, REnd); 143*06c3fb27SDimitry Andric if (TkStart == REnd) 144*06c3fb27SDimitry Andric return makeState(PS_InRootName, TkStart + 1, RStart + 1); 145*06c3fb27SDimitry Andric TkStart = consumeName(RStart, REnd); 146*06c3fb27SDimitry Andric return makeState(PS_InFilenames, TkStart + 1, RStart + 1); 147*06c3fb27SDimitry Andric } 148*06c3fb27SDimitry Andric } 149*06c3fb27SDimitry Andric case PS_InTrailingSep: 150*06c3fb27SDimitry Andric return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1, 151*06c3fb27SDimitry Andric RStart + 1); 152*06c3fb27SDimitry Andric case PS_InFilenames: { 153*06c3fb27SDimitry Andric PosPtr SepEnd = consumeAllSeparators(RStart, REnd); 154*06c3fb27SDimitry Andric if (SepEnd == REnd) 155*06c3fb27SDimitry Andric return makeState(PS_InRootDir, Path.data(), RStart + 1); 156*06c3fb27SDimitry Andric PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd); 157*06c3fb27SDimitry Andric if (TkStart == REnd) { 158*06c3fb27SDimitry Andric if (SepEnd) 159*06c3fb27SDimitry Andric return makeState(PS_InRootDir, SepEnd + 1, RStart + 1); 160*06c3fb27SDimitry Andric return makeState(PS_InRootName, TkStart + 1, RStart + 1); 161*06c3fb27SDimitry Andric } 162*06c3fb27SDimitry Andric TkStart = consumeName(SepEnd, REnd); 163*06c3fb27SDimitry Andric return makeState(PS_InFilenames, TkStart + 1, SepEnd + 1); 164*06c3fb27SDimitry Andric } 165*06c3fb27SDimitry Andric case PS_InRootDir: 166*06c3fb27SDimitry Andric return makeState(PS_InRootName, Path.data(), RStart + 1); 167*06c3fb27SDimitry Andric case PS_InRootName: 168*06c3fb27SDimitry Andric case PS_BeforeBegin: 169*06c3fb27SDimitry Andric __libcpp_unreachable(); 170*06c3fb27SDimitry Andric } 171*06c3fb27SDimitry Andric } 172*06c3fb27SDimitry Andric 173*06c3fb27SDimitry Andric /// \brief Return a view with the "preferred representation" of the current 174*06c3fb27SDimitry Andric /// element. For example trailing separators are represented as a '.' 175*06c3fb27SDimitry Andric string_view_t operator*() const noexcept { 176*06c3fb27SDimitry Andric switch (State) { 177*06c3fb27SDimitry Andric case PS_BeforeBegin: 178*06c3fb27SDimitry Andric case PS_AtEnd: 179*06c3fb27SDimitry Andric return PATHSTR(""); 180*06c3fb27SDimitry Andric case PS_InRootDir: 181*06c3fb27SDimitry Andric if (RawEntry[0] == '\\') 182*06c3fb27SDimitry Andric return PATHSTR("\\"); 183*06c3fb27SDimitry Andric else 184*06c3fb27SDimitry Andric return PATHSTR("/"); 185*06c3fb27SDimitry Andric case PS_InTrailingSep: 186*06c3fb27SDimitry Andric return PATHSTR(""); 187*06c3fb27SDimitry Andric case PS_InRootName: 188*06c3fb27SDimitry Andric case PS_InFilenames: 189*06c3fb27SDimitry Andric return RawEntry; 190*06c3fb27SDimitry Andric } 191*06c3fb27SDimitry Andric __libcpp_unreachable(); 192*06c3fb27SDimitry Andric } 193*06c3fb27SDimitry Andric 194*06c3fb27SDimitry Andric explicit operator bool() const noexcept { 195*06c3fb27SDimitry Andric return State != PS_BeforeBegin && State != PS_AtEnd; 196*06c3fb27SDimitry Andric } 197*06c3fb27SDimitry Andric 198*06c3fb27SDimitry Andric PathParser& operator++() noexcept { 199*06c3fb27SDimitry Andric increment(); 200*06c3fb27SDimitry Andric return *this; 201*06c3fb27SDimitry Andric } 202*06c3fb27SDimitry Andric 203*06c3fb27SDimitry Andric PathParser& operator--() noexcept { 204*06c3fb27SDimitry Andric decrement(); 205*06c3fb27SDimitry Andric return *this; 206*06c3fb27SDimitry Andric } 207*06c3fb27SDimitry Andric 208*06c3fb27SDimitry Andric bool atEnd() const noexcept { 209*06c3fb27SDimitry Andric return State == PS_AtEnd; 210*06c3fb27SDimitry Andric } 211*06c3fb27SDimitry Andric 212*06c3fb27SDimitry Andric bool inRootDir() const noexcept { 213*06c3fb27SDimitry Andric return State == PS_InRootDir; 214*06c3fb27SDimitry Andric } 215*06c3fb27SDimitry Andric 216*06c3fb27SDimitry Andric bool inRootName() const noexcept { 217*06c3fb27SDimitry Andric return State == PS_InRootName; 218*06c3fb27SDimitry Andric } 219*06c3fb27SDimitry Andric 220*06c3fb27SDimitry Andric bool inRootPath() const noexcept { 221*06c3fb27SDimitry Andric return inRootName() || inRootDir(); 222*06c3fb27SDimitry Andric } 223*06c3fb27SDimitry Andric 224*06c3fb27SDimitry Andric private: 225*06c3fb27SDimitry Andric void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept { 226*06c3fb27SDimitry Andric State = NewState; 227*06c3fb27SDimitry Andric RawEntry = string_view_t(Start, End - Start); 228*06c3fb27SDimitry Andric } 229*06c3fb27SDimitry Andric void makeState(ParserState NewState) noexcept { 230*06c3fb27SDimitry Andric State = NewState; 231*06c3fb27SDimitry Andric RawEntry = {}; 232*06c3fb27SDimitry Andric } 233*06c3fb27SDimitry Andric 234*06c3fb27SDimitry Andric PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); } 235*06c3fb27SDimitry Andric 236*06c3fb27SDimitry Andric PosPtr getBeforeFront() const noexcept { return Path.data() - 1; } 237*06c3fb27SDimitry Andric 238*06c3fb27SDimitry Andric /// \brief Return a pointer to the first character after the currently 239*06c3fb27SDimitry Andric /// lexed element. 240*06c3fb27SDimitry Andric PosPtr getNextTokenStartPos() const noexcept { 241*06c3fb27SDimitry Andric switch (State) { 242*06c3fb27SDimitry Andric case PS_BeforeBegin: 243*06c3fb27SDimitry Andric return Path.data(); 244*06c3fb27SDimitry Andric case PS_InRootName: 245*06c3fb27SDimitry Andric case PS_InRootDir: 246*06c3fb27SDimitry Andric case PS_InFilenames: 247*06c3fb27SDimitry Andric return &RawEntry.back() + 1; 248*06c3fb27SDimitry Andric case PS_InTrailingSep: 249*06c3fb27SDimitry Andric case PS_AtEnd: 250*06c3fb27SDimitry Andric return getAfterBack(); 251*06c3fb27SDimitry Andric } 252*06c3fb27SDimitry Andric __libcpp_unreachable(); 253*06c3fb27SDimitry Andric } 254*06c3fb27SDimitry Andric 255*06c3fb27SDimitry Andric /// \brief Return a pointer to the first character in the currently lexed 256*06c3fb27SDimitry Andric /// element. 257*06c3fb27SDimitry Andric PosPtr getCurrentTokenStartPos() const noexcept { 258*06c3fb27SDimitry Andric switch (State) { 259*06c3fb27SDimitry Andric case PS_BeforeBegin: 260*06c3fb27SDimitry Andric case PS_InRootName: 261*06c3fb27SDimitry Andric return &Path.front(); 262*06c3fb27SDimitry Andric case PS_InRootDir: 263*06c3fb27SDimitry Andric case PS_InFilenames: 264*06c3fb27SDimitry Andric case PS_InTrailingSep: 265*06c3fb27SDimitry Andric return &RawEntry.front(); 266*06c3fb27SDimitry Andric case PS_AtEnd: 267*06c3fb27SDimitry Andric return &Path.back() + 1; 268*06c3fb27SDimitry Andric } 269*06c3fb27SDimitry Andric __libcpp_unreachable(); 270*06c3fb27SDimitry Andric } 271*06c3fb27SDimitry Andric 272*06c3fb27SDimitry Andric // Consume all consecutive separators. 273*06c3fb27SDimitry Andric PosPtr consumeAllSeparators(PosPtr P, PosPtr End) const noexcept { 274*06c3fb27SDimitry Andric if (P == nullptr || P == End || !isSeparator(*P)) 275*06c3fb27SDimitry Andric return nullptr; 276*06c3fb27SDimitry Andric const int Inc = P < End ? 1 : -1; 277*06c3fb27SDimitry Andric P += Inc; 278*06c3fb27SDimitry Andric while (P != End && isSeparator(*P)) 279*06c3fb27SDimitry Andric P += Inc; 280*06c3fb27SDimitry Andric return P; 281*06c3fb27SDimitry Andric } 282*06c3fb27SDimitry Andric 283*06c3fb27SDimitry Andric // Consume exactly N separators, or return nullptr. 284*06c3fb27SDimitry Andric PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept { 285*06c3fb27SDimitry Andric PosPtr Ret = consumeAllSeparators(P, End); 286*06c3fb27SDimitry Andric if (Ret == nullptr) 287*06c3fb27SDimitry Andric return nullptr; 288*06c3fb27SDimitry Andric if (P < End) { 289*06c3fb27SDimitry Andric if (Ret == P + N) 290*06c3fb27SDimitry Andric return Ret; 291*06c3fb27SDimitry Andric } else { 292*06c3fb27SDimitry Andric if (Ret == P - N) 293*06c3fb27SDimitry Andric return Ret; 294*06c3fb27SDimitry Andric } 295*06c3fb27SDimitry Andric return nullptr; 296*06c3fb27SDimitry Andric } 297*06c3fb27SDimitry Andric 298*06c3fb27SDimitry Andric PosPtr consumeName(PosPtr P, PosPtr End) const noexcept { 299*06c3fb27SDimitry Andric PosPtr Start = P; 300*06c3fb27SDimitry Andric if (P == nullptr || P == End || isSeparator(*P)) 301*06c3fb27SDimitry Andric return nullptr; 302*06c3fb27SDimitry Andric const int Inc = P < End ? 1 : -1; 303*06c3fb27SDimitry Andric P += Inc; 304*06c3fb27SDimitry Andric while (P != End && !isSeparator(*P)) 305*06c3fb27SDimitry Andric P += Inc; 306*06c3fb27SDimitry Andric if (P == End && Inc < 0) { 307*06c3fb27SDimitry Andric // Iterating backwards and consumed all the rest of the input. 308*06c3fb27SDimitry Andric // Check if the start of the string would have been considered 309*06c3fb27SDimitry Andric // a root name. 310*06c3fb27SDimitry Andric PosPtr RootEnd = consumeRootName(End + 1, Start); 311*06c3fb27SDimitry Andric if (RootEnd) 312*06c3fb27SDimitry Andric return RootEnd - 1; 313*06c3fb27SDimitry Andric } 314*06c3fb27SDimitry Andric return P; 315*06c3fb27SDimitry Andric } 316*06c3fb27SDimitry Andric 317*06c3fb27SDimitry Andric PosPtr consumeDriveLetter(PosPtr P, PosPtr End) const noexcept { 318*06c3fb27SDimitry Andric if (P == End) 319*06c3fb27SDimitry Andric return nullptr; 320*06c3fb27SDimitry Andric if (P < End) { 321*06c3fb27SDimitry Andric if (P + 1 == End || !isDriveLetter(P[0]) || P[1] != ':') 322*06c3fb27SDimitry Andric return nullptr; 323*06c3fb27SDimitry Andric return P + 2; 324*06c3fb27SDimitry Andric } else { 325*06c3fb27SDimitry Andric if (P - 1 == End || !isDriveLetter(P[-1]) || P[0] != ':') 326*06c3fb27SDimitry Andric return nullptr; 327*06c3fb27SDimitry Andric return P - 2; 328*06c3fb27SDimitry Andric } 329*06c3fb27SDimitry Andric } 330*06c3fb27SDimitry Andric 331*06c3fb27SDimitry Andric PosPtr consumeNetworkRoot(PosPtr P, PosPtr End) const noexcept { 332*06c3fb27SDimitry Andric if (P == End) 333*06c3fb27SDimitry Andric return nullptr; 334*06c3fb27SDimitry Andric if (P < End) 335*06c3fb27SDimitry Andric return consumeName(consumeNSeparators(P, End, 2), End); 336*06c3fb27SDimitry Andric else 337*06c3fb27SDimitry Andric return consumeNSeparators(consumeName(P, End), End, 2); 338*06c3fb27SDimitry Andric } 339*06c3fb27SDimitry Andric 340*06c3fb27SDimitry Andric PosPtr consumeRootName(PosPtr P, PosPtr End) const noexcept { 341*06c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API) 342*06c3fb27SDimitry Andric if (PosPtr Ret = consumeDriveLetter(P, End)) 343*06c3fb27SDimitry Andric return Ret; 344*06c3fb27SDimitry Andric if (PosPtr Ret = consumeNetworkRoot(P, End)) 345*06c3fb27SDimitry Andric return Ret; 346*06c3fb27SDimitry Andric #endif 347*06c3fb27SDimitry Andric return nullptr; 348*06c3fb27SDimitry Andric } 349*06c3fb27SDimitry Andric }; 350*06c3fb27SDimitry Andric 351*06c3fb27SDimitry Andric inline string_view_pair separate_filename(string_view_t const& s) { 352*06c3fb27SDimitry Andric if (s == PATHSTR(".") || s == PATHSTR("..") || s.empty()) 353*06c3fb27SDimitry Andric return string_view_pair{s, PATHSTR("")}; 354*06c3fb27SDimitry Andric auto pos = s.find_last_of('.'); 355*06c3fb27SDimitry Andric if (pos == string_view_t::npos || pos == 0) 356*06c3fb27SDimitry Andric return string_view_pair{s, string_view_t{}}; 357*06c3fb27SDimitry Andric return string_view_pair{s.substr(0, pos), s.substr(pos)}; 358*06c3fb27SDimitry Andric } 359*06c3fb27SDimitry Andric 360*06c3fb27SDimitry Andric inline string_view_t createView(PosPtr S, PosPtr E) noexcept { 361*06c3fb27SDimitry Andric return {S, static_cast<size_t>(E - S) + 1}; 362*06c3fb27SDimitry Andric } 363*06c3fb27SDimitry Andric 364*06c3fb27SDimitry Andric } // namespace parser 365*06c3fb27SDimitry Andric 366*06c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_FILESYSTEM 367*06c3fb27SDimitry Andric 368*06c3fb27SDimitry Andric #endif // PATH_PARSER_H 369