-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIndexLookup.cs
More file actions
188 lines (159 loc) · 7.21 KB
/
IndexLookup.cs
File metadata and controls
188 lines (159 loc) · 7.21 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
183
184
185
186
187
188
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace PlainBytes.System.Extensions.Collections
{
/// <summary>
/// Contains the extensions for validation and accessing collection indexes.
/// </summary>
public static class IndexLookup
{
/// <summary>
/// Checks if the index is valid for the collection
/// </summary>
/// <typeparam name="T">The generic type of the collection</typeparam>
/// <param name="source">The collection that is being checked on</param>
/// <param name="index">The index that is being evaluated</param>
/// <returns>True if the index is valid</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasIndex<T>(this IReadOnlyCollection<T> source, int index)
{
ArgumentNullException.ThrowIfNull(source);
return index > -1 && index < source.Count;
}
/// <summary>
/// Tries to get the value from the given index.
/// </summary>
/// <typeparam name="T">The generic type of the collection</typeparam>
/// <param name="source">The collection that is being accessed</param>
/// <param name="index">The index that is being evaluated</param>
/// <returns>The value if the index is valid, otherwise the default of the collection type</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T? AtIndexOrDefault<T>(this IReadOnlyList<T> source, int index)
{
ArgumentNullException.ThrowIfNull(source);
if (source.HasIndex(index))
{
return source[index];
}
Debug.WriteLine($"Index is out of bounds should have been in range of 0 and {source.Count}");
return default;
}
/// <summary>
/// Evaluates if the collection has any elements.
/// </summary>
/// <typeparam name="T">The generic type of the collection</typeparam>
/// <param name="source">The collection that is being evaluated.</param>
/// <returns>True if it has any elements, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsEmpty<T>(this IReadOnlyCollection<T> source)
{
ArgumentNullException.ThrowIfNull(source);
return source.Count == 0;
}
/// <summary>
/// Tries to get the value from the given index.
/// </summary>
/// <typeparam name="T">The generic type of the collection</typeparam>
/// <param name="source">The collection that is being accessed</param>
/// <param name="index">The index that is being evaluated</param>
/// <param name="fallback">The fallback value</param>
/// <returns>The value if the index is valid, otherwise the provided fallback</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T AtIndexOrFallback<T>(this IReadOnlyList<T> source, int index, T fallback)
{
ArgumentNullException.ThrowIfNull(source);
if (source.HasIndex(index))
{
return source[index];
}
Debug.WriteLine($"Index is out of bounds should have been in range of 0 and {source.Count}");
return fallback;
}
/// <summary>
/// Tries to get the value from the given key.
/// </summary>
/// <typeparam name="TKey">The generic type of the key</typeparam>
/// <typeparam name="TValue">The generic type of the value</typeparam>
/// <param name="source">The dictionary that is being accessed</param>
/// <param name="key">The key that is being evaluated</param>
/// <param name="fallback">The fallback value</param>
/// <returns>The value if the key exists, otherwise the provided fallback</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TValue AtKeyOrFallback<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source, TKey key, TValue fallback)
{
ArgumentNullException.ThrowIfNull(source);
if (source.TryGetValue(key, out var value))
{
return value;
}
Debug.WriteLine($"Index is out of bounds should have been in range of 0 and {source.Count}");
return fallback;
}
/// <summary>
/// Evaluates if the collection has any elements.
/// </summary>
/// <typeparam name="TKey">Type of the key.</typeparam>
/// <typeparam name="TValue">Type of the value</typeparam>
/// <param name="source">Dictionary that is being evaluated</param>
/// <returns>True if it has any elements, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsEmpty<TKey, TValue>(this IReadOnlyCollection<KeyValuePair<TKey, TValue>>? source)
{
ArgumentNullException.ThrowIfNull(source);
return source.Count == 0;
}
/// <summary>
/// Tries to get the index for the given value.
/// </summary>
/// <typeparam name="T">The generic type of the collection.</typeparam>
/// <param name="source">The collection that is being accessed.</param>
/// <param name="value">The value that is for which we try to find the index.</param>
/// <returns>The index of the first item that is equals or -1 if not found.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf<T>(this IEnumerable<T> source, T value)
{
ArgumentNullException.ThrowIfNull(source);
switch (source)
{
case T[] array:
return Array.IndexOf(array, value);
case List<T> list:
return list.IndexOf(value);
}
var index = 0;
foreach (var item in source)
{
if (Equals(item, value))
{
return index;
}
index++;
}
return -1;
}
/// <summary>
/// Tries to get the index for an item.
/// </summary>
/// <typeparam name="T">The generic type of the collection.</typeparam>
/// <param name="source">The collection that is being accessed.</param>
/// <param name="filter">Filter expression, that decides if a particular value is a match.</param>
/// <returns>The index of the first item that is matched or -1 if there is no match.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOfMatch<T>(this IEnumerable<T> source, Func<T, bool> filter)
{
ArgumentNullException.ThrowIfNull(source);
var index = 0;
foreach (var item in source)
{
if (filter(item))
{
return index;
}
index++;
}
return -1;
}
}
}