| 158 | } |
| 159 | |
| 160 | path path::lexically_normal() const { |
| 161 | if (__pn_.empty()) |
| 162 | return *this; |
| 163 | |
| 164 | using PartKindPair = pair<string_view_t, PathPartKind>; |
| 165 | vector<PartKindPair> Parts; |
| 166 | // Guess as to how many elements the path has to avoid reallocating. |
| 167 | Parts.reserve(32); |
| 168 | |
| 169 | // Track the total size of the parts as we collect them. This allows the |
| 170 | // resulting path to reserve the correct amount of memory. |
| 171 | size_t NewPathSize = 0; |
| 172 | auto AddPart = [&](PathPartKind K, string_view_t P) { |
| 173 | NewPathSize += P.size(); |
| 174 | Parts.emplace_back(P, K); |
| 175 | }; |
| 176 | auto LastPartKind = [&]() { |
| 177 | if (Parts.empty()) |
| 178 | return PK_None; |
| 179 | return Parts.back().second; |
| 180 | }; |
| 181 | |
| 182 | bool MaybeNeedTrailingSep = false; |
| 183 | // Build a stack containing the remaining elements of the path, popping off |
| 184 | // elements which occur before a '..' entry. |
| 185 | for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) { |
| 186 | auto Part = *PP; |
| 187 | PathPartKind Kind = ClassifyPathPart(Part); |
| 188 | switch (Kind) { |
| 189 | case PK_Filename: |
| 190 | case PK_RootSep: { |
| 191 | // Add all non-dot and non-dot-dot elements to the stack of elements. |
| 192 | AddPart(Kind, Part); |
| 193 | MaybeNeedTrailingSep = false; |
| 194 | break; |
| 195 | } |
| 196 | case PK_DotDot: { |
| 197 | // Only push a ".." element if there are no elements preceding the "..", |
| 198 | // or if the preceding element is itself "..". |
| 199 | auto LastKind = LastPartKind(); |
| 200 | if (LastKind == PK_Filename) { |
| 201 | NewPathSize -= Parts.back().first.size(); |
| 202 | Parts.pop_back(); |
| 203 | } else if (LastKind != PK_RootSep) |
| 204 | AddPart(PK_DotDot, PATHSTR("..")); |
| 205 | MaybeNeedTrailingSep = LastKind == PK_Filename; |
| 206 | break; |
| 207 | } |
| 208 | case PK_Dot: |
| 209 | case PK_TrailingSep: { |
| 210 | MaybeNeedTrailingSep = true; |
| 211 | break; |
| 212 | } |
| 213 | case PK_None: |
| 214 | __libcpp_unreachable(); |
| 215 | } |
| 216 | } |
| 217 | // [fs.path.generic]p6.8: If the path is empty, add a dot. |
no test coverage detected