| | | 1 | | /******************************************************************************** |
| | | 2 | | * DelimitedSegment.cs * |
| | | 3 | | * * |
| | | 4 | | * Author: Denes Solti * |
| | | 5 | | ********************************************************************************/ |
| | | 6 | | using System; |
| | | 7 | | using System.Collections; |
| | | 8 | | using System.Collections.Generic; |
| | | 9 | | |
| | | 10 | | namespace NanoRoute.Internals |
| | | 11 | | { |
| | | 12 | | internal struct DelimitedSegment(ReadOnlyMemory<char> original, char separator) : IEnumerator<ReadOnlyMemory<char>> |
| | | 13 | | { |
| | | 14 | | private const int DONE = -1; |
| | | 15 | | |
| | | 16 | | private int _next; |
| | | 17 | | |
| | | 18 | | public bool MoveNext() |
| | 2 | 19 | | { |
| | 2 | 20 | | if (_next is DONE) |
| | 2 | 21 | | { |
| | 2 | 22 | | Current = default; |
| | 2 | 23 | | return false; |
| | | 24 | | } |
| | | 25 | | |
| | 2 | 26 | | ReadOnlySpan<char> span = Original.Span; |
| | | 27 | | |
| | 2 | 28 | | while (_next < span.Length && span[_next] == Separator) |
| | 2 | 29 | | _next++; |
| | | 30 | | |
| | 2 | 31 | | if (_next >= span.Length) |
| | 1 | 32 | | { |
| | 1 | 33 | | Current = default; |
| | 1 | 34 | | _next = DONE; |
| | 1 | 35 | | return false; |
| | | 36 | | } |
| | | 37 | | |
| | 2 | 38 | | int i = span.Slice(_next).IndexOf(Separator); |
| | 2 | 39 | | if (i < 0) |
| | 2 | 40 | | { |
| | 2 | 41 | | Current = Original.Slice(_next); |
| | 2 | 42 | | _next = DONE; |
| | 2 | 43 | | } |
| | | 44 | | else |
| | 1 | 45 | | { |
| | 1 | 46 | | Current = Original.Slice(_next, i); |
| | 1 | 47 | | _next += i + 1; |
| | 1 | 48 | | } |
| | | 49 | | |
| | 2 | 50 | | return true; |
| | 2 | 51 | | } |
| | | 52 | | |
| | | 53 | | public void Reset() |
| | 1 | 54 | | { |
| | 1 | 55 | | _next = 0; |
| | 1 | 56 | | Current = default; |
| | 1 | 57 | | } |
| | | 58 | | |
| | 1 | 59 | | public readonly void Dispose() { } |
| | | 60 | | |
| | | 61 | | public ReadOnlyMemory<char> Current { get; private set; } |
| | | 62 | | |
| | 1 | 63 | | readonly object IEnumerator.Current => Current; |
| | | 64 | | |
| | | 65 | | public readonly ReadOnlyMemory<char> Remaining |
| | | 66 | | { |
| | | 67 | | get |
| | 2 | 68 | | { |
| | 2 | 69 | | if (!HasValue) |
| | 2 | 70 | | return _next > DONE ? Original.Slice(Math.Max(0, _next - 1)) : default; |
| | | 71 | | |
| | 1 | 72 | | int segmentStart = _next is DONE |
| | 1 | 73 | | ? Original.Length - Current.Length |
| | 1 | 74 | | : _next - Current.Length - 1; |
| | | 75 | | |
| | 1 | 76 | | return Original.Slice(Math.Max(0, segmentStart - 1)); |
| | 2 | 77 | | } |
| | | 78 | | } |
| | | 79 | | |
| | 2 | 80 | | public ReadOnlyMemory<char> Original { get; } = original; |
| | | 81 | | |
| | 2 | 82 | | public char Separator { get; } = separator; |
| | | 83 | | |
| | 2 | 84 | | public readonly bool HasValue => Current.Length > 0; |
| | | 85 | | } |
| | | 86 | | } |