-
Notifications
You must be signed in to change notification settings - Fork 1k
/
ranges.cs
82 lines (64 loc) · 2.88 KB
/
ranges.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
namespace System
{
public readonly struct Index
{
private readonly int _value;
public int Value => _value < 0 ? ~_value : _value;
public bool FromEnd => _value < 0;
public Index(int value, bool fromEnd)
{
if (value < 0) throw new ArgumentException("Index must not be negative.", nameof(value));
_value = fromEnd ? ~value : value;
}
public static implicit operator Index(int value)
=> new Index(value, fromEnd: false);
}
public readonly struct Range
{
public Index Start { get; }
public Index End { get; }
private Range(Index start, Index end)
{
this.Start = start;
this.End = end;
}
public static Range Create(Index start, Index end) => new Range(start, end);
public static Range FromStart(Index start) => new Range(start, new Index(0, fromEnd: true));
public static Range ToEnd(Index end) => new Range(new Index(0, fromEnd: false), end);
public static Range All() => new Range(new Index(0, fromEnd: false), new Index(0, fromEnd: true));
}
static class Extensions
{
public static int get_IndexerExtension(this int[] array, Index index) =>
index.FromEnd ? array[array.Length - index.Value] : array[index.Value];
public static int get_IndexerExtension(this Span<int> span, Index index) =>
index.FromEnd ? span[span.Length - index.Value] : span[index.Value];
public static char get_IndexerExtension(this string s, Index index) =>
index.FromEnd ? s[s.Length - index.Value] : s[index.Value];
public static Span<int> get_IndexerExtension(this int[] array, Range range) =>
array.Slice(range);
public static Span<int> get_IndexerExtension(this Span<int> span, Range range) =>
span.Slice(range);
public static string get_IndexerExtension(this string s, Range range) =>
s.Substring(range);
public static Span<T> Slice<T>(this T[] array, Range range)
=> array.AsSpan().Slice(range);
public static Span<T> Slice<T>(this Span<T> span, Range range)
{
var (start, length) = GetStartAndLength(range, span.Length);
return span.Slice(start, length);
}
public static string Substring(this string s, Range range)
{
var (start, length) = GetStartAndLength(range, s.Length);
return s.Substring(start, length);
}
private static (int start, int length) GetStartAndLength(Range range, int entityLength)
{
var start = range.Start.FromEnd ? entityLength - range.Start.Value : range.Start.Value;
var end = range.End.FromEnd ? entityLength - range.End.Value : range.End.Value;
var length = end - start;
return (start, length);
}
}
}