-
-
Notifications
You must be signed in to change notification settings - Fork 909
/
EnumerableExtensions.cs
170 lines (157 loc) · 6.76 KB
/
EnumerableExtensions.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
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
// Copyright (c) Stride contributors (https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Runtime.CompilerServices;
using Stride.Core.Annotations;
namespace Stride.Core.Extensions
{
public static class EnumerableExtensions
{
/// <summary>
/// Tells whether a sequence is null or empty.
/// </summary>
/// <param name="source">The source sequence.</param>
/// <returns>Returns true if the sequence is null or empty, false if it is not null and contains at least one element.</returns>
[Pure]
public static bool IsNullOrEmpty(this IEnumerable source)
{
if (source == null)
return true;
var enumerator = source.GetEnumerator();
if (enumerator == null)
throw new ArgumentException("Invalid 'source' IEnumerable.");
return enumerator.MoveNext() == false;
}
/// <summary>
/// Executes an action for each (casted) item of the given enumerable.
/// </summary>
/// <typeparam name="T">Type of the item value in the enumerable.</typeparam>
/// <param name="source">Input enumerable to work on.</param>
/// <param name="action">Action performed for each item in the enumerable.</param>
/// <remarks>This extension method do not yield. It acts just like a foreach statement, and performs a cast to a typed enumerable in the middle.</remarks>
public static void ForEach<T>([NotNull] this IEnumerable source, [NotNull] Action<T> action)
{
source.Cast<T>().ForEach(action);
}
/// <summary>
/// Executes an action for each item of the given enumerable.
/// </summary>
/// <typeparam name="T">Type of the item value in the enumerable.</typeparam>
/// <param name="source">Input enumerable to work on.</param>
/// <param name="action">Action performed for each item in the enumerable.</param>
/// <remarks>This extension method do not yield. It acts just like a foreach statement.</remarks>
public static void ForEach<T>([NotNull] this IEnumerable<T> source, [NotNull] Action<T> action)
{
foreach (var item in source)
{
action(item);
}
}
/// <summary>
/// An <see cref="IEnumerable{T}"/> extension method that searches for the first match and returns its index.
/// </summary>
/// <typeparam name="T">Generic type parameter.</typeparam>
/// <param name="source">Input enumerable to work on.</param>
/// <param name="predicate">The predicate.</param>
/// <returns>The index of the first element matching.</returns>
[Pure]
public static int IndexOf<T>([NotNull] this IEnumerable<T> source, [NotNull] Func<T, bool> predicate)
{
var index = 0;
foreach (var item in source)
{
if (predicate(item))
return index;
index++;
}
return -1;
}
/// <summary>
/// An <see cref="IEnumerable{T}"/> extension method that searches for the last match and returns its index.
/// </summary>
/// <typeparam name="T">Generic type parameter.</typeparam>
/// <param name="source">Input enumerable to work on.</param>
/// <param name="predicate">The predicate.</param>
/// <returns>The index of the last element matching.</returns>
[Pure]
public static int LastIndexOf<T>([NotNull] this IEnumerable<T> source, [NotNull] Func<T, bool> predicate)
{
var list = source as IList<T>;
if (list != null)
{
// Faster search for lists.
for (var i = list.Count - 1; i >= 0; --i)
{
if (predicate(list[i]))
return i;
}
return -1;
}
var index = 0;
var lastIndex = -1;
foreach (var item in source)
{
if (predicate(item))
lastIndex = index;
index++;
}
return lastIndex;
}
/// <summary>
/// Filters out null items from the enumerable.
/// </summary>
/// <typeparam name="T">Generic type parameter.</typeparam>
/// <param name="source">Input enumerable to work on.</param>
/// <returns>An enumeration of all items in <paramref name="source"/> that are not <c>null</c>.</returns>
[ItemNotNull, NotNull, Pure]
public static IEnumerable<T> NotNull<T>([NotNull] this IEnumerable<T> source) where T : class
{
return source.Where(x => x != null);
}
/// <summary>
/// Filters out null items from the enumerable.
/// </summary>
/// <typeparam name="T">Generic type parameter.</typeparam>
/// <param name="source">Input enumerable to work on.</param>
/// <returns>An enumeration of all items in <paramref name="source"/> that are not <c>null</c>.</returns>
[NotNull, Pure]
public static IEnumerable<T> NotNull<T>([NotNull] this IEnumerable<T?> source) where T : struct
{
return source.Where(item => item.HasValue).Select(item => item.Value);
}
/// <summary>
/// Enumerates the linked list nodes.
/// </summary>
/// <param name="list">The linked list.</param>
/// <returns>An enumeration of the linked list nodes.</returns>
[ItemNotNull, NotNull, Pure]
internal static IEnumerable<LinkedListNode<T>> EnumerateNodes<T>([NotNull] this LinkedList<T> list)
{
var node = list.First;
while (node != null)
{
yield return node;
node = node.Next;
}
}
/// <summary>
/// Calculates a combined hash code for items of the enumerbale.
/// </summary>
/// <typeparam name="T">Generic type parameter.</typeparam>
/// <param name="source">Input enumerable to work on.</param>
/// <returns>A combined hash code or 0 if the source is empty.</returns>
[Pure]
public static int ToHashCode<T>(this IEnumerable<T> source) where T : class
{
if (source.IsNullOrEmpty()) return 0;
unchecked
{
return source.Aggregate(17, (hash, item) => hash * 23 + item.GetHashCode());
}
}
}
}