-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArrayViewExtensions.cs
More file actions
182 lines (162 loc) · 7.47 KB
/
ArrayViewExtensions.cs
File metadata and controls
182 lines (162 loc) · 7.47 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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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>.GetBuffer(list);
var count = Math.Min(list.Count, array.Length);
return new ArrayView<T>(array, 0, count);
}
return ArrayView<T>.Empty;
}
#region Inner type: ListAccessor<T>
/// <summary>
/// Provides low-level access to the internal array buffer of a <see cref="List{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the elements in the list.</typeparam>
private static class ListAccessor<T>
{
/// <summary>
/// Retrieves a reference to the internal array buffer of the specified <see cref="List{T}"/>.
/// </summary>
/// <param name="list">The list whose internal buffer is to be accessed.</param>
/// <returns>
/// A reference to the internal array used by the list.
/// </returns>
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_items")]
public static extern ref T[] GetBuffer(List<T> list);
}
#endregion
#endif
}