-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArrayViewExtensions.cs
More file actions
165 lines (148 loc) · 6.86 KB
/
ArrayViewExtensions.cs
File metadata and controls
165 lines (148 loc) · 6.86 KB
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
namespace Ramstack.Collections;
/// <summary>
/// Provides extension methods for the <see cref="ArrayView{T}"/> structure.
/// </summary>
public static class ArrayViewExtensions
{
/// <summary>
/// Creates a new <see cref="ArrayView{T}"/> over an array.
/// </summary>
/// <param name="value">The target array.</param>
/// <returns>
/// An <see cref="ArrayView{T}"/> representing the array.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ArrayView<T> AsView<T>(this T[]? value) =>
new(value ?? []);
/// <summary>
/// Creates a new <see cref="ArrayView{T}"/> over a portion of the target array from a specified position to the end of the array.
/// </summary>
/// <param name="value">The target array.</param>
/// <param name="index">The index at which to begin the array view.</param>
/// <returns>
/// An <see cref="ArrayView{T}"/> representing the array.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ArrayView<T> AsView<T>(this T[]? value, int index) =>
new(value ?? [], index);
/// <summary>
/// Creates a new <see cref="ArrayView{T}"/> over a portion of the target array from a specified position for a specified number of elements.
/// </summary>
/// <param name="value">The target array.</param>
/// <param name="index">The index at which to begin the array view.</param>
/// <param name="count">The number of items in the array view.</param>
/// <returns>
/// An <see cref="ArrayView{T}"/> representing the array.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ArrayView<T> AsView<T>(this T[]? value, int index, int count) =>
new(value ?? [], index, count);
/// <summary>
/// Finds the index of the first occurrence of a specified value in this instance.
/// </summary>
/// <param name="view">The <see cref="ArrayView{T}"/> instance.</param>
/// <param name="value">The value to locate in the array view.</param>
/// <returns>
/// The zero-based index of the first occurrence of the value in this instance; otherwise, <c>-1</c>.
/// </returns>
public static int IndexOf<T>(this ArrayView<T> view, T value) where T : IEquatable<T> =>
view.AsSpan().IndexOf(value);
/// <summary>
/// Finds the index of the first occurrence of a specified value in the array view.
/// </summary>
/// <param name="view">The <see cref="ArrayView{T}"/> instance.</param>
/// <param name="value">The value to locate in the array view.</param>
/// <param name="comparer">The equality comparer to use for the search.
/// If <see langword="null"/>, the default equality comparer is used.</param>
/// <returns>
/// The zero-based index of the first occurrence of the value in the array view; otherwise, <c>-1</c>.
/// </returns>
public static int IndexOf<T>(this ArrayView<T> view, T value, IEqualityComparer<T>? comparer)
{
return Impl(view.AsSpan(), value, comparer);
static int Impl(ReadOnlySpan<T> span, T value, IEqualityComparer<T>? comparer)
{
if (typeof(T).IsValueType && (comparer is null || ReferenceEquals(comparer, EqualityComparer<T>.Default)))
{
for (var i = 0; i < span.Length; i++)
if (EqualityComparer<T>.Default.Equals(span[i], value))
return i;
}
else
{
comparer ??= EqualityComparer<T>.Default;
for (var i = 0; i < span.Length; i++)
if (comparer.Equals(span[i], value))
return i;
}
return -1;
}
}
/// <summary>
/// Finds the index of the last occurrence of a specified value in the array view.
/// </summary>
/// <param name="view">The <see cref="ArrayView{T}"/> instance.</param>
/// <param name="value">The value to locate in the array view.</param>
/// <returns>
/// The zero-based index of the last occurrence of the value in the array view; otherwise, <c>-1</c>.
/// </returns>
public static int LastIndexOf<T>(this ArrayView<T> view, T value) where T : IEquatable<T> =>
view.AsSpan().LastIndexOf(value);
/// <summary>
/// Finds the index of the last occurrence of a specified value in the array view.
/// </summary>
/// <param name="view">The <see cref="ArrayView{T}"/> instance.</param>
/// <param name="value">The value to locate in the array view.</param>
/// <param name="comparer">The equality comparer to use for the search.
/// If <see langword="null"/>, the default equality comparer is used.</param>
/// <returns>
/// The zero-based index of the last occurrence of the value in the array view; otherwise, <c>-1</c>.
/// </returns>
public static int LastIndexOf<T>(this ArrayView<T> view, T value, IEqualityComparer<T>? comparer)
{
return Impl(view.AsSpan(), value, comparer);
static int Impl(ReadOnlySpan<T> span, T value, IEqualityComparer<T>? comparer)
{
if (typeof(T).IsValueType && (comparer is null || ReferenceEquals(comparer, EqualityComparer<T>.Default)))
{
for (var i = span.Length - 1; i >= 0; i--)
if (EqualityComparer<T>.Default.Equals(span[i], value))
return i;
}
else
{
comparer ??= EqualityComparer<T>.Default;
for (var i = span.Length - 1; i >= 0; i--)
if (comparer.Equals(span[i], value))
return i;
}
return -1;
}
}
#if NET9_0_OR_GREATER
/// <summary>
/// Returns an <see cref="ArrayView{T}"/> over the specified list.
/// Items should not be added or removed from the <see cref="List{T}"/>
/// while the <see cref="ArrayView{T}"/> is in use.
/// </summary>
/// <typeparam name="T">The type of the elements in the list.</typeparam>
/// <param name="list">The list to get the data view over.</param>
/// <returns>
/// A <see cref="ArrayView{T}"/> instance over the specified list.
/// </returns>
public static ArrayView<T> AsView<T>(this List<T>? list)
{
if (list is not null)
{
var array = ListAccessor<T>.GetArray(list);
_ = array.Length;
//
// SCG.List<T> maintains internal invariants, so we can safely use the unchecked constructor
// to bypass redundant bounds checks for better performance.
//
return new ArrayView<T>(array, 0, list.Count, unused: 0);
}
return ArrayView<T>.Empty;
}
#endif
}