// Copyright (c) 2023 bradson // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. using System.Diagnostics.CodeAnalysis; using Mono.Collections.Generic; namespace PerformanceFish.Utility; public static class CollectionExtensions { public static bool Any(this T[] array, Predicate predicate) { var length = array.Length; return length != 0 && Any(ref array[0], predicate, (nuint)length); } // overlaps with method in GenCollection // public static bool Any(this List list, Predicate predicate) // { // var count = list.Count; // return count != 0 && Any(ref list._items[0], predicate, count); // } public static bool Any(this IList iList, Predicate predicate) { var count = iList.Count; for (var i = 0; i < count; i++) { if (predicate(iList[i])) return true; } return false; } public static unsafe bool Any(this T[] array, delegate* predicate) { var length = array.Length; return length != 0 && Any(ref array[0], predicate, (nuint)length); } public static unsafe bool Any(this List list, delegate* predicate) { var count = list.Count; return count != 0 && Any(ref list._items[0], predicate, (nuint)count); } public static bool ExistsAndNotNull(this List? list, Predicate match) { if (list is null) return false; var count = list.Count; return count != 0 && Any(ref list._items[0], match, (nuint)count); } public static bool Contains(this T[] array, T item) { var length = array.Length; return length != 0 && Contains(ref array[0], item, (nuint)length); } public static bool Contains(this IList iList, T item) { var count = iList.Count; for (var i = 0; i < count; i++) { if (iList[i].Equals(item)) return true; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T? FirstOrDefault(this T[] array, Predicate predicate) { var length = array.Length; return length == 0 ? default : FirstOrDefault(ref array[0], predicate, (nuint)length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T? FirstOrDefaultFast(this List list, Predicate predicate) { var count = list.Count; return count == 0 ? default : FirstOrDefault(ref list._items[0], predicate, (nuint)count); } public static T? FirstOrDefault(this IList iList, Predicate predicate) { var count = iList.Count; for (var i = 0; i < count; i++) { if (predicate(iList[i])) return iList[i]; } return default; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe T? FirstOrDefault(this T[] array, delegate* predicate) { var length = array.Length; return length == 0 ? default : FirstOrDefault(ref array[0], predicate, (nuint)length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe T? FirstOrDefault(this List list, delegate* predicate) { var count = list.Count; return count == 0 ? default : FirstOrDefault(ref list._items[0], predicate, (nuint)count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T? FirstOrDefault(this T[] array) => array.Length != 0 ? array[0] : default; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T? FirstOrDefault(this List list) => list.Count != 0 ? list[0] : default; public static T? FirstOrDefault(this IList iList) => iList.Count != 0 ? iList[0] : default; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T First(this T[] array, Predicate predicate) { var length = array.Length; return length == 0 ? ThrowForNoElements() : First(ref array[0], predicate, (nuint)length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T First(this List list, Predicate predicate) { var count = list.Count; return count == 0 ? ThrowForNoElements() : First(ref list._items[0], predicate, (nuint)count); } public static T First(this IList iList, Predicate predicate) { var count = iList.Count; for (var i = 0; i < count; i++) { if (predicate(iList[i])) return iList[i]; } return ThrowForNoElements(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe T First(this T[] array, delegate* predicate) { var length = array.Length; return length == 0 ? ThrowForNoElements() : First(ref array[0], predicate, (nuint)length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe T First(this List list, delegate* predicate) { var count = list.Count; return count == 0 ? ThrowForNoElements() : First(ref list._items[0], predicate, (nuint)count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T First(this T[] array) => array.Length != 0 ? array[0] : ThrowForNoElements(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T First(this List list) => list.Count != 0 ? list[0] : ThrowForNoElements(); public static T First(this IList iList) => iList.Count != 0 ? iList[0] : ThrowForNoElements(); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe bool Any(ref T reference, Predicate predicate, nuint length) { nuint i = 0; length *= (nuint)sizeof(T); do { if (predicate(Unsafe.AddByteOffset(ref reference, i))) return true; i += (nuint)sizeof(T); } while (i < length); return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe bool Any(ref T reference, delegate* predicate, nuint length) { nuint i = 0; length *= (nuint)sizeof(T); do { if (predicate(Unsafe.AddByteOffset(ref reference, i))) return true; i += (nuint)sizeof(T); } while (i < length); return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe bool Contains(ref T reference, T item, nuint length) { nuint i = 0; length *= (nuint)sizeof(T); do { if (Unsafe.AddByteOffset(ref reference, i).Equals(item)) return true; i += (nuint)sizeof(T); } while (i < length); return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe T? FirstOrDefault(ref T reference, Predicate predicate, nuint length) { nuint i = 0; length *= (nuint)sizeof(T); do { if (predicate(Unsafe.AddByteOffset(ref reference, i))) return Unsafe.AddByteOffset(ref reference, i); i += (nuint)sizeof(T); } while (i < length); return default; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe T First(ref T reference, Predicate predicate, nuint length) { nuint i = 0; length *= (nuint)sizeof(T); do { if (predicate(Unsafe.AddByteOffset(ref reference, i))) return Unsafe.AddByteOffset(ref reference, i); i += (nuint)sizeof(T); } while (i < length); return ThrowForNoElements(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe T? FirstOrDefault(ref T reference, delegate* predicate, nuint length) { nuint i = 0; length *= (nuint)sizeof(T); do { if (predicate(Unsafe.AddByteOffset(ref reference, i))) return Unsafe.AddByteOffset(ref reference, i); i += (nuint)sizeof(T); } while (i < length); return default; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe T First(ref T reference, delegate* predicate, nuint length) { nuint i = 0; length *= (nuint)sizeof(T); do { if (predicate(Unsafe.AddByteOffset(ref reference, i))) return Unsafe.AddByteOffset(ref reference, i); i += (nuint)sizeof(T); } while (i < length); return ThrowForNoElements(); } [DoesNotReturn] private static T ThrowForNoElements() => throw new InvalidOperationException("Sequence contains no elements"); }