| File: Utils\Globbing\PathTokenizer.cs | Web Access |
| Project: src\sdk\src\StaticWebAssetsSdk\Tasks\Microsoft.NET.Sdk.StaticWebAssets.Tasks.csproj (Microsoft.NET.Sdk.StaticWebAssets.Tasks) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.StaticWebAssets.Tasks.Utils; namespace Microsoft.AspNetCore.StaticWebAssets.Tasks; #if !NET9_0_OR_GREATER public ref struct PathTokenizer(ReadOnlySpan<char> path) { private readonly ReadOnlySpan<char> _path = path; int _index = -1; int _nextSeparatorIndex = -1; public readonly Segment Current => new (_index, (_nextSeparatorIndex == -1 ? _path.Length : _nextSeparatorIndex) - _index); public bool MoveNext() { if (_index != -1 && _nextSeparatorIndex == -1) { return false; } _index = _nextSeparatorIndex + 1; _nextSeparatorIndex = GetSeparator(); return true; } internal SegmentCollection Fill(List<Segment> segments) { while (MoveNext()) { if (Current.Length > 0 && !_path.Slice(Current.Start, Current.Length).Equals(".".AsSpan(), StringComparison.Ordinal) && !_path.Slice(Current.Start, Current.Length).Equals("..".AsSpan(), StringComparison.Ordinal)) { segments.Add(Current); } } return new SegmentCollection(_path, segments); } private readonly int GetSeparator() => _path.Slice(_index).IndexOfAny(OSPath.DirectoryPathSeparators.Span) switch { -1 => -1, var index => index + _index }; public struct Segment(int start, int length) { public int Start { get; set; } = start; public int Length { get; set; } = length; } public readonly ref struct SegmentCollection(ReadOnlySpan<char> path, List<Segment> segments) { private readonly ReadOnlySpan<char> _path = path; private readonly int _index = 0; private SegmentCollection(ReadOnlySpan<char> path, List<Segment> segments, int index) : this(path, segments) => _index = index; public int Count => segments.Count - _index; public ReadOnlySpan<char> this[int index] => _path.Slice(segments[index + _index].Start, segments[index + _index].Length); public ReadOnlyMemory<char> this[ReadOnlyMemory<char> path, int index] => path.Slice(segments[index + _index].Start, segments[index + _index].Length); internal SegmentCollection Slice(int segmentIndex) => new (_path, segments, segmentIndex); } } #else public ref struct PathTokenizer(ReadOnlySpan<char> path) { private readonly ReadOnlySpan<char> _path = path; public struct Segment(int start, int length) { public int Start { get; set; } = start; public int Length { get; set; } = length; } internal SegmentCollection Fill(List<Segment> segments) { foreach (var range in MemoryExtensions.SplitAny(_path, OSPath.DirectoryPathSeparators.Span)) { var length = range.End.Value - range.Start.Value; if (length > 0 && !_path.Slice(range.Start.Value, length).Equals(".".AsSpan(), StringComparison.Ordinal) && !_path.Slice(range.Start.Value, length).Equals("..".AsSpan(), StringComparison.Ordinal)) { segments.Add(new(range.Start.Value, length)); } } return new SegmentCollection(_path, segments); } public readonly ref struct SegmentCollection(ReadOnlySpan<char> path, List<Segment> segments) { private readonly ReadOnlySpan<char> _path = path; private readonly int _index = 0; private SegmentCollection(ReadOnlySpan<char> path, List<Segment> segments, int index) : this(path, segments) => _index = index; public int Count => segments.Count - _index; public ReadOnlySpan<char> this[int index] => _path.Slice(segments[index + _index].Start, segments[index + _index].Length); public ReadOnlyMemory<char> this[ReadOnlyMemory<char> path, int index] => path.Slice(segments[index + _index].Start, segments[index + _index].Length); internal SegmentCollection Slice(int segmentIndex) => new(_path, segments, segmentIndex); } } #endif