diff --git a/README.md b/README.md index 03dc83a..17d796c 100644 --- a/README.md +++ b/README.md @@ -21,31 +21,51 @@ Currently this project contains 3 components: 2. Value type (struct) only collections 3. Linq operators +### Setup + +Use this line to setup the AllocatorContext, which is used internally in `ValueArray` and any other locations that need to allocate unmanaged memory. + +```csharp + AllocatorContext.SetImplementation(new DefaultAllocatorContextImpl().ConfigureDefault()); +``` + +### Memory allocation strategies + Two types of memory allocation strategy are supported: -### Arena +#### 1. Arena ```csharp +// all 'T' is struct if not specifically mentioned. using (AllocatorContext.BeginAllocationScope()) { - var list = new ValueList(); + var list = new ValueList(); // plain old 'new' var dict = new ValueDictionary(); + var obj = new Allocated(); // let struct works like a class (struct is allocated on the unmanaged heap.) ... -} // all Value* collections are automatically disposed as they go out of scope. +} // all value collections are automatically disposed as they go out of scope, no need to explicitly call Dispose(). ``` -### Explicit lifetime +#### 2. Explicit lifetime + +You can utilize the unmanaged allocator anywhere like this (including inside of arena scope): ```csharp -// You can construct a value type collection anywhere(including inside of arena scope) -// using this overload: -var list = new ValueList(AllocatorTypes.DefaultUnscoped); +// use the overload with parameter 'AllocatorTypes', then specify the unscoped, globally available allocator type. +var list = new ValueList(AllocatorTypes.DefaultUnscoped); +var obj = new Allocated(AllocatorTypes.DefaultUnscoped); ... -// Anywhere after sometime: +// Anywhere after usage: list.Dispose(); ``` -To avoid double-free, when these collections are passed by value, Borrow() should be used. After calling Borrow(), all copies of the original collection can be safely disposed without double-free. +#### Pass by ref or by value + +Since we are using struct everywhere, how to pass a struct which works like a reference type is a little bit tricky. + +Under most circumstances, use `ref` modifier will be sufficient, but there's still somewhere that cannot use the `ref` modifier such as struct field (`ref` type can only be put in a `ref struct`, which is incovienient). + +To avoid double-free, when those value collections are passed by value, Borrow() should be used. After calling Borrow(), all copies of the original collection can be safely disposed without double-free. ```csharp var list = new ValueList(AllocatorTypes.DefaultUnscoped); @@ -54,10 +74,16 @@ var list = new ValueList(AllocatorTypes.DefaultUnscoped); SomeListRefConsumingMethod(in list); SomeListRefConsumingMethod(ref list); -// value passing should call Borrow() +// value passing should call Borrow() unless you're certain the passed one will not be disposed. SomeListConsumingMethod(list.Borrow()) ``` +#### 3. Interop with managed object + +if you have to use managed object(classes) inside a struct, you can use +`Pinned` to pin the object down so that its address is fixed and can be stored on a non-GC rooted place. + + ### Custom collection types * ValueArray<T> @@ -82,8 +108,8 @@ The LINQ interface has 3 variations: ```csharp SomeCollection.LinqValue()... // Enumerate by value. All types implement IEnumerable are supported -SomeCollection.LinqRef()... // Enumerate by ref. Besides built-in value typed collections, only Enumerators that exposes 'ref T Current' are supported (e.g. normal array types) -SomeCollection.LinqPtr()... // Enumerate by pointer. Only built-in value typed collections are supported. +SomeCollection.LinqRef()... // Enumerate by ref. Besides value collections, only Enumerators that exposes 'ref T Current' are supported (e.g. normal array types) +SomeCollection.LinqPtr()... // Enumerate by pointer. Only built-in value typed collections are supported. (Because object address must be fixed to be able to use unmanaged pointer) ``` Most extension methods that needs a delegate type parameter has an overloads with `in` or `ref` modifier to avoid copying too much data if the Linqed type is a big struct. @@ -97,25 +123,27 @@ Most extension methods has overloads with a `TArg arg` parameter to avoid unnece ```csharp TArg someTArg; -.LinqRef()...Select((in T x) => new SomeStruct(in x, someTArg))... // Everytime this line executes, a new capture object for `someTArg` must be allocated . -.LinqRef()...Select(static (in T x, TArg a) => new SomeStruct(in x, a), someTArg)... // No capture is happening. +...Select((in T x) => new SomeStruct(in x, someTArg))... // Everytime this line executes, a new capture object for `someTArg` must be allocated on the managed heap. +...Select(static (in T x, TArg a) => new SomeStruct(in x, a), someTArg)... // No capture is happening. ('static' is not mandatory, just a explicit declaration) ``` ## Things to do -1. More examples. +1. More documentations. 2. Larger test coverage. 3. More collection types. 4. More LINQ providers and support range. +5. Roslyn analyzer for struct lifetime/ownership enforcing. (The actual lifetime is not being enforced, such as the early dispose from the owner side or mutation from the borrower side is still unpreventable, static analysis with attribute markers should be the way to go.) ## Thanks to -Emma Maassen from -Angouri from +* Emma Maassen from + +* Angouri from Details in [THIRD-PARTY-NOTICES.md](https://github.com/fryderykhuang/NullGC/blob/main/THIRD-PARTY-NOTICES.md) ## How to contribute -These framework-like projects will not become generally useful without being battle tested in real world. If your project can protentially benefit from this, feel free to submit an Issue and talk about your use case. Any type of contributions are welcomed. +Framework projects like this will not become generally useful without being battle tested in real world. If your project can protentially benefit from this library, feel free to submit an Issue and talk about your use case. Any type of contributions are welcomed. diff --git a/src/BenchmarkResultPageGenerator/Program.cs b/src/BenchmarkResultPageGenerator/Program.cs index 4799bbb..e526fd5 100644 --- a/src/BenchmarkResultPageGenerator/Program.cs +++ b/src/BenchmarkResultPageGenerator/Program.cs @@ -6,10 +6,9 @@ namespace BenchmarkResultPageGenerator; -internal class Program +internal partial class Program { - private static readonly Regex FileNamePattern = new(@"^(\w+\.)+Benchmarks\.(?\w+)\-report", - RegexOptions.Compiled | RegexOptions.CultureInvariant); + private static readonly Regex FileNamePattern = MyRegex(); private static async Task Main(string[] args) { @@ -35,7 +34,10 @@ private static async Task Main(string[] args) await File.WriteAllTextAsync(output, await (await new RazorEngine().CompileAsync(await sr.ReadToEndAsync())) .RunAsync(new { - Files = lst + Files = lst.OrderBy(x=>x.Title) })); } + + [GeneratedRegex(@"^(\w+\.)+Benchmarks\.(?\w+)\-report", RegexOptions.Compiled | RegexOptions.CultureInvariant)] + private static partial Regex MyRegex(); } \ No newline at end of file diff --git a/src/NullGC.Abstractions/Class.cs b/src/NullGC.Abstractions/Allocated.cs similarity index 62% rename from src/NullGC.Abstractions/Class.cs rename to src/NullGC.Abstractions/Allocated.cs index 06ad0e0..cb4bc42 100644 --- a/src/NullGC.Abstractions/Class.cs +++ b/src/NullGC.Abstractions/Allocated.cs @@ -1,20 +1,32 @@ using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using NullGC.Allocators; namespace NullGC; /// -/// A wrapper to make unmanaged struct work like a class (a pointer) without using 'ref', by allocating struct memory on unmanaged heap. +/// A wrapper to make unmanaged struct work like a class (a pointer) without using 'ref', by allocating struct on unmanaged heap. /// /// -public readonly struct Class : IDisposable where T : unmanaged +/// +/// is needed when passed by value to avoid double-free. +/// +public readonly struct Allocated : ISingleDisposable> where T : unmanaged { public readonly unsafe T* Value; public readonly int AllocatorProviderId; - public Class(int allocatorProviderId = (int) AllocatorTypes.Default) + private unsafe Allocated(T* value, int allocatorProviderId) + { + Value = value; + AllocatorProviderId = allocatorProviderId; + } + + public Allocated(AllocatorTypes allocatorProviderId) : this((int) allocatorProviderId) + { + } + + public Allocated(int allocatorProviderId = (int) AllocatorTypes.Default) { AllocatorProviderId = allocatorProviderId; unsafe @@ -31,13 +43,13 @@ public Class(int allocatorProviderId = (int) AllocatorTypes.Default) /// Allocate memory for from default scoped allocator, dispose is not mandatory. /// /// - public static Class CreateScoped() => new((int) AllocatorTypes.Default); + public static Allocated CreateScoped() => new((int) AllocatorTypes.Default); /// /// Allocate memory for from default unscoped allocator, dispose is mandatory when lifetime ends. /// /// - public static Class CreateUnscoped() => new((int) AllocatorTypes.DefaultUnscoped); + public static Allocated CreateUnscoped() => new((int) AllocatorTypes.DefaultUnscoped); public ref T Ref { @@ -51,11 +63,19 @@ public ref T Ref } } + public Allocated Borrow() + { + unsafe + { + return new Allocated(Value, AllocatorProviderId); + } + } + public void Dispose() { if (AllocatorProviderId == (int) AllocatorTypes.Invalid) return; - + unsafe { AllocatorContext.GetAllocator(AllocatorProviderId).Free((UIntPtr) Value); diff --git a/src/NullGC.Abstractions/IItemAddressFixed.cs b/src/NullGC.Abstractions/IAddressFixed.cs similarity index 77% rename from src/NullGC.Abstractions/IItemAddressFixed.cs rename to src/NullGC.Abstractions/IAddressFixed.cs index f32c630..3e0aba7 100644 --- a/src/NullGC.Abstractions/IItemAddressFixed.cs +++ b/src/NullGC.Abstractions/IAddressFixed.cs @@ -4,8 +4,8 @@ /// A marker interface denotes that the implemented type contains only objects that have a fixed memory address. /// /// -/// Currently used in Linq implementation to enable faster algorithms on native-heap allocated objects. +/// Currently used in Linq implementation to enable faster algorithms on unmanaged-heap-allocated objects. /// -public interface IItemAddressFixed +public interface IAddressFixed { } \ No newline at end of file diff --git a/src/NullGC.Abstractions/ISingleDisposable.cs b/src/NullGC.Abstractions/ISingleDisposable.cs index 90695fb..84fcd5a 100644 --- a/src/NullGC.Abstractions/ISingleDisposable.cs +++ b/src/NullGC.Abstractions/ISingleDisposable.cs @@ -10,8 +10,11 @@ public interface ISingleDisposable : IDisposable where T : struct, IDisposable { /// - /// Get a copy of the implementer itself that will not cause double-dispose problem (e.g. by set a non-dispose flag). + /// Get a copy of the implementer itself that will not cause double-free problem (e.g. by set a non-dispose flag). /// /// + /// + /// Since this is not a built-in lifetime/ownership management system, the actual lifetime is not being enforced, the early dispose from the owner side or mutation from the borrower side is still unpreventable thus should be used with caution. + /// T Borrow(); } diff --git a/src/NullGC.Abstractions/Linq/ILinqPtrEnumerator.cs b/src/NullGC.Abstractions/Linq/ILinqPtrEnumerator.cs index 86ec756..ff88f93 100644 --- a/src/NullGC.Abstractions/Linq/ILinqPtrEnumerator.cs +++ b/src/NullGC.Abstractions/Linq/ILinqPtrEnumerator.cs @@ -1,6 +1,6 @@ namespace NullGC.Linq; -// public interface ILinqPtrEnumerator : ILinqEnumerator, IItemAddressFixed +// public interface ILinqPtrEnumerator : ILinqEnumerator, IAddressFixed // { // unsafe T* Current { get; } // } \ No newline at end of file diff --git a/src/NullGC.Abstractions/Linq/LinqFixedRefEnumerable.cs b/src/NullGC.Abstractions/Linq/LinqFixedRefEnumerable.cs index 6103987..8c5adf4 100644 --- a/src/NullGC.Abstractions/Linq/LinqFixedRefEnumerable.cs +++ b/src/NullGC.Abstractions/Linq/LinqFixedRefEnumerable.cs @@ -4,7 +4,7 @@ namespace NullGC.Linq; public readonly struct LinqFixedRefEnumerable : ILinqEnumerable - where TEnumerator : struct, ILinqRefEnumerator, IItemAddressFixed + where TEnumerator : struct, ILinqRefEnumerator, IAddressFixed { private readonly TEnumerator _enumerator; diff --git a/src/NullGC.Abstractions/Pinned.cs b/src/NullGC.Abstractions/Pinned.cs index ccbd8d0..2873cc7 100644 --- a/src/NullGC.Abstractions/Pinned.cs +++ b/src/NullGC.Abstractions/Pinned.cs @@ -1,5 +1,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type namespace NullGC; @@ -10,21 +11,23 @@ namespace NullGC; /// /// Since pin a managed object on the GC heap will reduce the effectiveness of GC compaction, either use and dispose in a short time or pin as early in the application lifetime as possible. /// -public struct Pinned : IDisposable where T : class +public struct Pinned : IAddressFixed, ISingleDisposable> where T : class { -#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type public readonly unsafe T* Ptr; -#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type private GCHandle _pin; + private unsafe Pinned(T* ptr) + { + Ptr = ptr; + _pin = default; + } + public Pinned(T obj) { unsafe { _pin = GCHandle.Alloc(obj, GCHandleType.Pinned); -#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type - Ptr = (T*) Unsafe.AsPointer(ref obj); -#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type + Ptr = (T*) _pin.AddrOfPinnedObject(); } } @@ -39,8 +42,17 @@ public ref T Ref } } + public Pinned Borrow() + { + unsafe + { + return new Pinned(Ptr); + } + } + public void Dispose() { - _pin.Free(); + if (_pin.IsAllocated) + _pin.Free(); } } \ No newline at end of file diff --git a/src/NullGC.Collections/SlidingTimeWindow.cs b/src/NullGC.Collections/SlidingTimeWindow.cs index db423d1..bba3c43 100644 --- a/src/NullGC.Collections/SlidingTimeWindow.cs +++ b/src/NullGC.Collections/SlidingTimeWindow.cs @@ -4,7 +4,7 @@ namespace NullGC.Collections; -public struct SlidingTimeWindow : IDisposable where T : unmanaged, INumber +public struct SlidingTimeWindow : ISingleDisposable> where T : unmanaged, INumber { private ValueFixedSizeDeque _wnd; @@ -44,6 +44,16 @@ internal Bucket(T sum) public int Count => _count; } + private SlidingTimeWindow(ValueFixedSizeDeque wnd, int resolutionMs, long lastBucket, T wndSum, + int wndCount, Bucket noDataBucket) + { + _wnd = wnd; + _resolutionMs = resolutionMs; + _lastBucket = lastBucket; + _wndSum = wndSum; + _wndCount = wndCount; + _noDataBucket = noDataBucket; + } /// /// @@ -108,6 +118,11 @@ public CurrentWindow Update(T newItem) return new CurrentWindow(ref _wnd, _wndSum, _wndCount); } + public SlidingTimeWindow Borrow() + { + return new SlidingTimeWindow(_wnd.Borrow(), _resolutionMs, _lastBucket, _wndSum, _wndCount, _noDataBucket); + } + public void Dispose() { _wnd.Dispose(); diff --git a/src/NullGC.Collections/UnsafeArrayEnumerator.cs b/src/NullGC.Collections/UnsafeArrayEnumerator.cs index 56d43a2..7a6af0d 100644 --- a/src/NullGC.Collections/UnsafeArrayEnumerator.cs +++ b/src/NullGC.Collections/UnsafeArrayEnumerator.cs @@ -5,7 +5,7 @@ namespace NullGC.Collections; -public struct UnsafeArrayEnumerator : ILinqRefEnumerator, ILinqValueEnumerator, IUnsafeArray, IItemAddressFixed where T : unmanaged +public struct UnsafeArrayEnumerator : ILinqRefEnumerator, ILinqValueEnumerator, IUnsafeArray, IAddressFixed where T : unmanaged { private readonly unsafe T* _items; private readonly int _length; diff --git a/src/NullGC.Collections/ValueArray.cs b/src/NullGC.Collections/ValueArray.cs index ccc12d1..f8423a4 100644 --- a/src/NullGC.Collections/ValueArray.cs +++ b/src/NullGC.Collections/ValueArray.cs @@ -22,14 +22,21 @@ public readonly ValueArray WithAllocationProviderId(int id) } } - public ValueArray(int length, int allocatorProviderId = (int) AllocatorTypes.Default, bool noClear = false) + public ValueArray(int length, AllocatorTypes allocatorProviderId = AllocatorTypes.Default, bool noClear = false) : + this(length, (int) allocatorProviderId, noClear) + { + } + + public ValueArray(int length, int allocatorProviderId, bool noClear = false) { unsafe { if (length > Array.MaxLength || length * (long) sizeof(T) > uint.MaxValue) CommunityToolkit.Diagnostics.ThrowHelper.ThrowArgumentOutOfRangeException(nameof(length)); - Debug.Assert(allocatorProviderId != (int) AllocatorTypes.Invalid); + Debug.Assert(length == 0 || allocatorProviderId != (int) AllocatorTypes.Invalid); AllocatorProviderId = allocatorProviderId; + if (length == 0) + return; var size = checked((uint) (sizeof(T) * length)); if (size > 0) { @@ -266,9 +273,10 @@ internal int TryGrowCheaply(int minLength, int maxLength, bool noClear) (nuint) maxLength * (nuint) sizeof(T)); if (!reallocResult.Success) return -1; #if DEBUG - Debug.Assert(MemoryMarshal.CreateReadOnlySpan(in Unsafe.AsRef((T*) reallocResult.Ptr), _length).SequenceEqual(bak)); + Debug.Assert(MemoryMarshal.CreateReadOnlySpan(in Unsafe.AsRef((T*) reallocResult.Ptr), _length) + .SequenceEqual(bak)); #endif - + Debug.Assert(reallocResult.Ptr % IMemoryAllocator.DefaultAlignment == 0); minLength = (int) (reallocResult.ActualSize / (nuint) sizeof(T)); if (!noClear && minLength > _length) diff --git a/src/NullGC.Collections/ValueDictionary.cs b/src/NullGC.Collections/ValueDictionary.cs index 0947e7d..d7d4378 100644 --- a/src/NullGC.Collections/ValueDictionary.cs +++ b/src/NullGC.Collections/ValueDictionary.cs @@ -60,8 +60,12 @@ private ValueDictionary(ValueArray buckets, ValueArray entries, readonly ICollection IDictionary.Values => Values; - public ValueDictionary(int allocatorProviderId = (int) AllocatorTypes.Default) : this(0, null, - allocatorProviderId) + + public ValueDictionary() : this(0, null, (int) AllocatorTypes.Default) + { + } + + public ValueDictionary(AllocatorTypes allocatorProviderId) : this(0, null, (int) allocatorProviderId) { } @@ -70,12 +74,22 @@ public ValueDictionary(int capacity, int allocatorProviderId = (int) AllocatorTy { } + public ValueDictionary(int capacity, AllocatorTypes allocatorProviderId) : this(capacity, + null, (int) allocatorProviderId) + { + } + public ValueDictionary(IEqualityComparer? comparer, int allocatorProviderId = (int) AllocatorTypes.Default) : this(0, comparer, allocatorProviderId) { } + public ValueDictionary(int capacity, IEqualityComparer? comparer, + AllocatorTypes allocatorProviderId) : this(capacity, comparer, (int) allocatorProviderId) + { + } + public ValueDictionary(int capacity, IEqualityComparer? comparer, int allocatorProviderId = (int) AllocatorTypes.Default) { @@ -237,7 +251,7 @@ public readonly ref TValue GetValueRefOrNullRef(TKey key, out bool exists) public ref TValue GetValueRef(TKey key) { - ref var ret = ref FindValue(key); + ref var ret = ref FindValue(key); if (Unsafe.IsNullRef(ref ret)) ThrowHelper.ThrowKeyNotFoundException(key); return ref ret; @@ -308,7 +322,8 @@ public bool ContainsKey(TKey key) public bool ContainsValue(TValue value) { for (var i = 0; i < _count; i++) - if (_entries.GetRefUnchecked(i).Next >= -1 && EqualityComparer.Default.Equals(_entries.GetRefUnchecked(i).Value, value)) + if (_entries.GetRefUnchecked(i).Next >= -1 && + EqualityComparer.Default.Equals(_entries.GetRefUnchecked(i).Value, value)) return true; return false; @@ -325,7 +340,8 @@ private void CopyTo(KeyValuePair[] array, int index) var count = _count; for (var i = 0; i < count; i++) if (_entries.GetRefUnchecked(i).Next >= -1) - array[index++] = new KeyValuePair(_entries.GetRefUnchecked(i).Key, _entries.GetRefUnchecked(i).Value); + array[index++] = new KeyValuePair(_entries.GetRefUnchecked(i).Key, + _entries.GetRefUnchecked(i).Value); } readonly IEnumerator> IEnumerable>.GetEnumerator() @@ -461,7 +477,8 @@ private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior) // Test uint in if rather than loop condition to drop range check for following array access if ((uint) i >= (uint) _entries.Length) break; - if (_entries.GetRefUnchecked(i).HashCode == hashCode && EqualityComparer.Default.Equals(_entries.GetRefUnchecked(i).Key, key)) + if (_entries.GetRefUnchecked(i).HashCode == hashCode && + EqualityComparer.Default.Equals(_entries.GetRefUnchecked(i).Key, key)) { if (behavior == InsertionBehavior.OverwriteExisting) { @@ -493,7 +510,8 @@ private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior) // Test uint in if rather than loop condition to drop range check for following array access if ((uint) i >= (uint) _entries.Length) break; - if (_entries.GetRefUnchecked(i).HashCode == hashCode && comparer.Equals(_entries.GetRefUnchecked(i).Key, key)) + if (_entries.GetRefUnchecked(i).HashCode == hashCode && + comparer.Equals(_entries.GetRefUnchecked(i).Key, key)) { if (behavior == InsertionBehavior.OverwriteExisting) { @@ -586,7 +604,8 @@ public ref TValue GetValueRefOrAddDefault(TKey key, out bool exists) // Test uint in if rather than loop condition to drop range check for following array access if ((uint) i >= (uint) entries.Length) break; - if (entries.GetRefUnchecked(i).HashCode == hashCode && EqualityComparer.Default.Equals(entries.GetRefUnchecked(i).Key, key)) + if (entries.GetRefUnchecked(i).HashCode == hashCode && + EqualityComparer.Default.Equals(entries.GetRefUnchecked(i).Key, key)) { exists = true; @@ -611,7 +630,8 @@ public ref TValue GetValueRefOrAddDefault(TKey key, out bool exists) // Test uint in if rather than loop condition to drop range check for following array access if ((uint) i >= (uint) entries.Length) break; - if (entries.GetRefUnchecked(i).HashCode == hashCode && _comparer.Equals(entries.GetRefUnchecked(i).Key, key)) + if (entries.GetRefUnchecked(i).HashCode == hashCode && + _comparer.Equals(entries.GetRefUnchecked(i).Key, key)) { exists = true; @@ -668,7 +688,8 @@ public ref TValue GetValueRefOrAddDefault(TKey key, out bool exists) private void Resize(int newSize) { - TraceOn.MemAlloc(nameof(ValueDictionary), $"Before resize {nameof(_entries)}={_entries} {nameof(newSize)}={newSize}"); + TraceOn.MemAlloc(nameof(ValueDictionary), + $"Before resize {nameof(_entries)}={_entries} {nameof(newSize)}={newSize}"); Debug.Assert(_entries.IsInitialized); Debug.Assert(newSize >= _entries.Length); var count = _count; @@ -884,7 +905,8 @@ private void CopyEntries(ValueArray entries, int count) private readonly ref int GetBucket(uint hashCode) { #if TARGET_64BIT - return ref _buckets.GetRefUnchecked((int) HashHelpers.FastMod(hashCode, (uint) _buckets.Length, _fastModMultiplier)); + return ref _buckets.GetRefUnchecked((int) HashHelpers.FastMod(hashCode, (uint) _buckets.Length, + _fastModMultiplier)); #else return ref _buckets.GetRefUnchecked((int) (hashCode % _buckets.Length)); #endif @@ -915,7 +937,7 @@ public KeyCollection(ValueDictionary dictionary) } // ReSharper disable once MemberHidesStaticFromOuterClass - public struct Enumerator : ILinqRefEnumerator, ILinqValueEnumerator, IItemAddressFixed + public struct Enumerator : ILinqRefEnumerator, ILinqValueEnumerator, IAddressFixed { private readonly ValueDictionary _dictionary; private int _index; @@ -950,6 +972,7 @@ public ref TKey Current } public unsafe TKey* CurrentPtr => &_dictionary._entries.Items[_index - 1].Key; + // ref TKey ILinqRefEnumerator.Current => ref _dictionary._entries[_index - 1].Key; public int? Count => _dictionary.Count; @@ -1018,7 +1041,7 @@ public ValueCollection(ValueDictionary dictionary) } // ReSharper disable once MemberHidesStaticFromOuterClass - public struct Enumerator : ILinqRefEnumerator, ILinqValueEnumerator, IItemAddressFixed + public struct Enumerator : ILinqRefEnumerator, ILinqValueEnumerator, IAddressFixed { private readonly ValueDictionary _dictionary; private int _index; @@ -1053,6 +1076,7 @@ public ref TValue Current } public unsafe TValue* CurrentPtr => &_dictionary._entries.Items[_index - 1].Value; + // ref TValue ILinqRefEnumerator.Current => ref _dictionary._entries[_index - 1].Value; public int? Count => _dictionary.Count; @@ -1113,7 +1137,7 @@ public void Dispose() } - public struct Enumerator : ILinqRefEnumerator, ILinqValueEnumerator, IItemAddressFixed + public struct Enumerator : ILinqRefEnumerator, ILinqValueEnumerator, IAddressFixed { private readonly ValueDictionary _dictionary; private int _index; diff --git a/src/NullGC.Collections/ValueFixedSizeDeque.cs b/src/NullGC.Collections/ValueFixedSizeDeque.cs index 8fce521..4cf7f7f 100644 --- a/src/NullGC.Collections/ValueFixedSizeDeque.cs +++ b/src/NullGC.Collections/ValueFixedSizeDeque.cs @@ -5,7 +5,7 @@ namespace NullGC.Collections; -public struct ValueFixedSizeDeque : IDisposable, IList where T : unmanaged +public struct ValueFixedSizeDeque : ISingleDisposable>, IList where T : unmanaged { private ValueArray _items; private int _head = 0; @@ -23,8 +23,22 @@ public readonly bool IsFull get => _items.Length == 0 || (_afterTail + 1) % _items.Length == _head; } + /// + /// + /// Must be greater than 0 + /// + public ValueFixedSizeDeque(int capacity, AllocatorTypes allocatorProviderId) : + this(capacity, (int) allocatorProviderId) + { + } + + /// + /// + /// Must be greater than 0 + /// public ValueFixedSizeDeque(int capacity, int allocatorProviderId = (int) AllocatorTypes.Default) { + Guard.IsGreaterThanOrEqualTo(capacity, 0); _items = new ValueArray(capacity + 1, allocatorProviderId); } @@ -64,18 +78,6 @@ public readonly ref T HeadRef } } - // public readonly T Head - // { - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - // get - // { - // if (_head == _afterTail) ThrowHelper.CollectionIsEmpty(); - // return _items.GetUnchecked(_head); - // } - // } - // - - public readonly ref T HeadRefOrNullRef { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -90,7 +92,6 @@ public readonly ref T HeadRefOrNullRef } /// - /// /// /// 0-based index start at last item increase backward. /// @@ -101,7 +102,6 @@ public readonly ref T GetNthItemRefFromTail(int nth) } /// - /// /// /// 0-based index start at first item increase forward. /// @@ -146,11 +146,13 @@ public void RemoveFront(out T removed) } /// - /// /// /// /// if queue is full, this is the pushed out item. - /// true indicates the queue is full, and there's one item pushed out. + /// + /// true + /// indicates the queue is full, and there's one item pushed out. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool PushBack(T item, out T evicted) { @@ -171,11 +173,13 @@ public bool PushBack(T item, out T evicted) } /// - /// /// /// /// if queue is full, this is the pushed out item. - /// true indicates the queue is full, and there's one item pushed out. + /// + /// true + /// indicates the queue is full, and there's one item pushed out. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool PushFront(T item, out T evicted) { @@ -200,7 +204,7 @@ public readonly int IndexOf(T item) { unsafe { - for (int i = _head;; i++) + for (var i = _head;; i++) { var ii = i % _items.Length; if (ii == _afterTail) break; @@ -256,9 +260,15 @@ public void Dispose() { } - public bool MoveNext() => ++_index % _items.Length != _afterTail; + public bool MoveNext() + { + return ++_index % _items.Length != _afterTail; + } - public void Reset() => throw new NotSupportedException(); + public void Reset() + { + throw new NotSupportedException(); + } public readonly ref T Current { @@ -277,24 +287,42 @@ public readonly ref T Current readonly object IEnumerator.Current => Current; } - public readonly ForwardEnumerator GetEnumerator() => new(_items, _head, _afterTail); + public readonly ForwardEnumerator GetEnumerator() + { + return new ForwardEnumerator(_items, _head, _afterTail); + } - IEnumerator IEnumerable.GetEnumerator() => IsEmpty ? GenericEmptyEnumerator.Instance : GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + { + return IsEmpty ? GenericEmptyEnumerator.Instance : GetEnumerator(); + } - IEnumerator IEnumerable.GetEnumerator() => IsEmpty ? GenericEmptyEnumerator.Instance : GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() + { + return IsEmpty ? GenericEmptyEnumerator.Instance : GetEnumerator(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(T item) => AddBack(item); + public void Add(T item) + { + AddBack(item); + } - public void Clear() => _afterTail = _head; + public void Clear() + { + _afterTail = _head; + } - public bool Contains(T item) => IndexOf(item) != -1; + public bool Contains(T item) + { + return IndexOf(item) != -1; + } public readonly void CopyTo(T[] array, int arrayIndex) { unsafe { - for (int i = _head; ; i++) + for (var i = _head;; i++) { var ii = i % _items.Length; if (ii == _afterTail) @@ -304,7 +332,10 @@ public readonly void CopyTo(T[] array, int arrayIndex) } } - public bool Remove(T item) => CommunityToolkit.Diagnostics.ThrowHelper.ThrowNotSupportedException(); + public bool Remove(T item) + { + return CommunityToolkit.Diagnostics.ThrowHelper.ThrowNotSupportedException(); + } public readonly int Capacity { @@ -320,5 +351,20 @@ public readonly int Count public readonly bool IsReadOnly => false; - public void Dispose() => _items.Dispose(); + private ValueFixedSizeDeque(ValueArray items, int head, int afterTail) + { + _items = items; + _head = head; + _afterTail = afterTail; + } + + public ValueFixedSizeDeque Borrow() + { + return new ValueFixedSizeDeque(_items.Borrow(), _head, _afterTail); + } + + public void Dispose() + { + _items.Dispose(); + } } \ No newline at end of file diff --git a/src/NullGC.Collections/ValueLinkedList.cs b/src/NullGC.Collections/ValueLinkedList.cs index b190fdb..5133851 100644 --- a/src/NullGC.Collections/ValueLinkedList.cs +++ b/src/NullGC.Collections/ValueLinkedList.cs @@ -22,7 +22,7 @@ public static class ValueLinkedList public struct ValueLinkedList : IUnsafeArray.Node>, ISingleDisposable>, ILinqEnumerable.Node, ValueLinkedList.ForwardEnumerator>, IDisposable where T : unmanaged { - public struct ForwardEnumerator : ILinqRefEnumerator, ILinqValueEnumerator, IItemAddressFixed + public struct ForwardEnumerator : ILinqRefEnumerator, ILinqValueEnumerator, IAddressFixed { private readonly ValueArray _items; private int _count; @@ -87,7 +87,7 @@ public struct Node } private const int FreeListBaseIndex = -3; - + private ValueArray _items; private int _head = -1; private int _tail = -1; @@ -105,7 +105,11 @@ private ValueLinkedList(ValueArray items, int head, int tail, int endIndex _freeCount = freeCount; } - public ValueLinkedList() => _items = new ValueArray(0); + public ValueLinkedList() => _items = new ValueArray(0, (int) AllocatorTypes.Default); + + public ValueLinkedList(AllocatorTypes allocatorProviderId) : this(0, (int) allocatorProviderId) + { + } public ValueLinkedList(int capacity, int allocatorProviderId = (int) AllocatorTypes.Default) => _items = new ValueArray(capacity, allocatorProviderId); @@ -121,7 +125,8 @@ public int Capacity } } - IEnumerator IEnumerable.GetEnumerator() => Count == 0 ? GenericEmptyEnumerator.Instance : GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => + Count == 0 ? GenericEmptyEnumerator.Instance : GetEnumerator(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public ForwardEnumerator GetEnumerator() => new(_items, Count, _head); @@ -341,7 +346,7 @@ public ref Node TailRefUnchecked [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref _items.GetRefUnchecked(_tail); } - + public void Remove(int index) { unsafe @@ -430,7 +435,7 @@ private void Resize() _items.Grow(_items.Length + ((newCapacity + 1 - _items.Length) >> 1), newCapacity, true); } - private const int DefaultCapacity = 4; + private const int DefaultCapacity = 4; public unsafe Node* Items => _items.Items; int IUnsafeArray.Length => _endIndex; diff --git a/src/NullGC.Collections/ValueList.cs b/src/NullGC.Collections/ValueList.cs index c389a02..ed53891 100644 --- a/src/NullGC.Collections/ValueList.cs +++ b/src/NullGC.Collections/ValueList.cs @@ -27,9 +27,18 @@ private ValueList(ValueArray items, int size) _size = size; } - public ValueList() + public ValueList() : this(0, (int) AllocatorTypes.Default) + { + } + + public ValueList(AllocatorTypes allocatorProviderId = AllocatorTypes.Default) + { + _items = new ValueArray(0, allocatorProviderId); + } + + public ValueList(int capacity, AllocatorTypes allocatorProviderId) : + this(capacity, (int) allocatorProviderId) { - _items = _items.WithAllocationProviderId((int) AllocatorTypes.Default); } public ValueList(int capacity, int allocatorProviderId = (int) AllocatorTypes.Default) @@ -41,6 +50,11 @@ public ValueList(int capacity, int allocatorProviderId = (int) AllocatorTypes.De : new ValueArray(capacity, allocatorProviderId, true); } + public ValueList(IEnumerable collection, AllocatorTypes allocatorProviderId) : + this(collection, (int) allocatorProviderId) + { + } + public ValueList(IEnumerable collection, int allocatorProviderId = (int) AllocatorTypes.Default) { // ReSharper disable once PossibleMultipleEnumeration @@ -112,14 +126,14 @@ public readonly ref T GetRefUnchecked(int index) Debug.Assert(index >= 0 && index < _size); return ref _items.GetRefUnchecked(index); } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly T GetUnchecked(int index) { Debug.Assert(index >= 0 && index < _size); return _items.GetUnchecked(index); } - + readonly T IReadOnlyList.this[int index] => this[index]; T IList.this[int index] @@ -635,8 +649,9 @@ public void Dispose() } public readonly ValueArray GetInnerArray() => _items; - - readonly IEnumerator IEnumerable.GetEnumerator() => Count == 0 ? GenericEmptyEnumerator.Instance : GetEnumerator(); + + readonly IEnumerator IEnumerable.GetEnumerator() => + Count == 0 ? GenericEmptyEnumerator.Instance : GetEnumerator(); public readonly unsafe T* Items => _items.Items; readonly int IUnsafeArray.Length => _size; diff --git a/src/NullGC.Collections/ValueStack.cs b/src/NullGC.Collections/ValueStack.cs index 48de12b..5de0b43 100644 --- a/src/NullGC.Collections/ValueStack.cs +++ b/src/NullGC.Collections/ValueStack.cs @@ -28,13 +28,20 @@ private ValueStack(ValueArray array, int size) _size = size; } - public ValueStack(int allocatorProviderId = (int) AllocatorTypes.Default) + public ValueStack() : this(0, (int) AllocatorTypes.Default) + { + } + + public ValueStack(AllocatorTypes allocatorProviderId) : this(0, (int) allocatorProviderId) { - _array = ValueArray.Empty; } // Create a stack with a specific initial capacity. The initial capacity // must be a non-negative number. + public ValueStack(int capacity, AllocatorTypes allocatorProviderId) : this(capacity, (int) allocatorProviderId) + { + } + public ValueStack(int capacity, int allocatorProviderId = (int) AllocatorTypes.Default) { Guard.IsGreaterThanOrEqualTo(capacity, 0); @@ -43,6 +50,11 @@ public ValueStack(int capacity, int allocatorProviderId = (int) AllocatorTypes.D // Fills a Stack with the contents of a particular collection. The items are // pushed onto the stack in the same order they are read by the enumerator. + public ValueStack(IEnumerable collection, AllocatorTypes allocatorProviderId) : + this(collection, (int) allocatorProviderId) + { + } + public ValueStack(IEnumerable collection, int allocatorProviderId = (int) AllocatorTypes.Default) { if (collection == null) @@ -86,7 +98,8 @@ void ICollection.CopyTo(Array array, int arrayIndex) public Enumerator GetEnumerator() => new(this); /// - IEnumerator IEnumerable.GetEnumerator() => _size == 0 ? GenericEmptyEnumerator.Instance : new Enumerator(this); + IEnumerator IEnumerable.GetEnumerator() => + _size == 0 ? GenericEmptyEnumerator.Instance : new Enumerator(this); IEnumerator IEnumerable.GetEnumerator() => _size == 0 ? GenericEmptyEnumerator.Instance : new Enumerator(this); @@ -244,7 +257,7 @@ private void ThrowForEmptyStack() throw new InvalidOperationException("InvalidOperation_EmptyStack"); } - public struct Enumerator : ILinqRefEnumerator, ILinqValueEnumerator, IItemAddressFixed + public struct Enumerator : ILinqRefEnumerator, ILinqValueEnumerator, IAddressFixed { private readonly ValueStack _stack; private int _index; diff --git a/src/NullGC.DragRace/BenchmarkBase.cs b/src/NullGC.DragRace/BenchmarkBase.cs index a1b5336..d052b6c 100644 --- a/src/NullGC.DragRace/BenchmarkBase.cs +++ b/src/NullGC.DragRace/BenchmarkBase.cs @@ -1,5 +1,6 @@ using BenchmarkDotNet.Attributes; using NullGC.Allocators; +using NullGC.Allocators.Extensions; namespace NullGC.DragRace; @@ -7,7 +8,7 @@ public abstract class BenchmarkBase : IDisposable { protected BenchmarkBase() { - AllocatorContext.SetImplementation(new DefaultAllocatorContextImpl()); + AllocatorContext.SetImplementation(new DefaultAllocatorContextImpl().ConfigureDefault()); } // [GlobalSetup] diff --git a/src/NullGC.DragRace/Benchmarks/Linq_IntArrWhereOrderBySelfTakeSelectSum.cs b/src/NullGC.DragRace/Benchmarks/Linq_IntArrWhereOrderBySelfTakeSelectSum.cs index 22b2524..f4c0c0c 100644 --- a/src/NullGC.DragRace/Benchmarks/Linq_IntArrWhereOrderBySelfTakeSelectSum.cs +++ b/src/NullGC.DragRace/Benchmarks/Linq_IntArrWhereOrderBySelfTakeSelectSum.cs @@ -1,41 +1,54 @@ using BenchmarkDotNet.Attributes; using Cathei.LinqGen; +using NetFabric.Hyperlinq; using NullGC.Linq; namespace NullGC.DragRace.Benchmarks; [PickedForCicd] -public class Linq_IntArrWhereOrderBySelfTakeSelectSum : LinqBenchmarkBase +public class Linq_IntArrWhereOrderBySelfTakeSelectWithArgSum : LinqBenchmarkBase { [Benchmark] public void NullGCLinqRef_IntArr() { - _dummyFloat = _intArr.LinqRef().Where((in int x) => x > 100).OrderBy().Take(500).Select((in int x, float a) => x * a, 1.5f).Sum(); + var f = 1.5f; + _dummyFloat = _intArr.LinqRef().Where((in int x) => x > 100).Order().Take(500) + .Select((in int x, float a) => x * a, f).Sum(); } - + [Benchmark] public void NullGCLinqRef_ValIntArr() { - _dummyFloat = _valIntArr.LinqRef().Where((in int x) => x > 100).OrderBy().Take(500).Select((in int x, float a) => x * a, 1.5f) + var f = 1.5f; + _dummyFloat = _valIntArr.LinqRef().Where((in int x) => x > 100).Order().Take(500) + .Select((in int x, float a) => x * a, f) .Sum(); } [Benchmark] public void NullGCLinqValue_ValIntArr() { - _dummyFloat = _valIntArr.LinqValue().Where(x => x > 100).OrderBy().Take(500).Select((x, a) => x * a, 1.5f).Sum(); + var f = 1.5f; + _dummyFloat = _valIntArr.LinqValue().Where(x => x > 100).Order().Take(500).Select((x, a) => x * a, f) + .Sum(); + } + + [Benchmark] + public void LinqGen_IntArr_Capture() + { + var f = 1.5f; + _dummyFloat = _intArr.Gen().Where(x => x > 100).OrderBy(x=>x).Take(500).Select(x => x * f).Sum(); + } + + [Benchmark] + public void LinqGen_IntArr_NoArg() + { + _dummyFloat = _intArr.Gen().Where(x => x > 100).OrderBy(x => x).Take(500).Select(x => x * 1.5f).Sum(); } - // - // [Benchmark] - // public void LinqGen_IntArr_Capture() - // { - // var a = 1.5f; - // _dummyFloat = _intArr.Gen().Where(x => x > 100).OrderBy(x=>x).Take(500).Select(x => x * a).Sum(); - // } - // [Benchmark] - // public void LinqGen_IntArr() - // { - // _dummyFloat = _intArr.Gen().Where(x => x > 100).OrderBy(x => x).Take(500).Select(x => x * 1.5f).Sum(); - // } + [Benchmark] + public void HyperLinq_IntArr_NoArg() + { + _dummyFloat = _intArr.AsValueEnumerable().Where(x => x > 100).OrderBy(x => x).Take(500).Select(x => x * 1.5f).Sum(); + } } \ No newline at end of file diff --git a/src/NullGC.DragRace/Benchmarks/Linq_IntArrWhereSelectSum.cs b/src/NullGC.DragRace/Benchmarks/Linq_IntArrWhereSelectSum.cs index f0d8ce1..0dd0242 100644 --- a/src/NullGC.DragRace/Benchmarks/Linq_IntArrWhereSelectSum.cs +++ b/src/NullGC.DragRace/Benchmarks/Linq_IntArrWhereSelectSum.cs @@ -5,12 +5,12 @@ namespace NullGC.DragRace.Benchmarks; -public class Linq_IntArrWhereSelectSum : LinqBenchmarkBase +public class Linq_IntArrWhereSelectWithArgSum : LinqBenchmarkBase { [Benchmark] - public void NullGCLinqRef_IntArr() + public void NullGCLinqValue_IntArr() { - _dummyFloat = _intArr.LinqRef().Where((in int x) => x > 100).Select((in int x, float a) => x * a, 1.5f).Sum(); + _dummyFloat = _intArr.LinqValue().Where(x => x > 100).Select((x, a) => x * a, 1.5f).Sum(); } [Benchmark] @@ -33,14 +33,14 @@ public void RefLinq_IntArr() } [Benchmark] - public void LinqGen_IntArr_Capture() + public void LinqGen_IntArr_CapturedArg() { var a = 1.5f; _dummyFloat = _intArr.Gen().Where(x => x > 100).Select(x => x * a).Sum(); } [Benchmark] - public void LinqGen_IntArr() + public void LinqGen_IntArr_NoArg() { _dummyFloat = _intArr.Gen().Where(x => x > 100).Select(x => x * 1.5f).Sum(); } diff --git a/src/NullGC.Linq/Enumerators/ArrayLinqRefEnumerator.cs b/src/NullGC.Linq/Enumerators/ArrayLinqRefEnumerator.cs index 3a4c153..8888ac0 100644 --- a/src/NullGC.Linq/Enumerators/ArrayLinqRefEnumerator.cs +++ b/src/NullGC.Linq/Enumerators/ArrayLinqRefEnumerator.cs @@ -5,7 +5,7 @@ namespace NullGC.Linq.Enumerators; -public struct ArrayLinqRefEnumerator : ILinqRefEnumerator, IArray +public struct ArrayLinqRefEnumerator : ILinqRefEnumerator, ILinqValueEnumerator, IArray { private readonly T[] _array; private readonly int _length; @@ -49,22 +49,20 @@ public void Reset() CommunityToolkit.Diagnostics.ThrowHelper.ThrowNotSupportedException(); } - T IEnumerator.Current => Current; + T IEnumerator.Current => _array[_index]; #pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type public unsafe T* CurrentPtr #pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type { get { - CommunityToolkit.Diagnostics.ThrowHelper - .ThrowNotSupportedException(); + CommunityToolkit.Diagnostics.ThrowHelper.ThrowNotSupportedException(); return default; //(T*) Unsafe.AsPointer(ref _array[_index]); } } - object? IEnumerator.Current => Current; - + object? IEnumerator.Current => _array[_index]; public int? Count => _length; public int? MaxCount => _length; public ref T Current diff --git a/src/NullGC.Linq/Enumerators/OrderBy.cs b/src/NullGC.Linq/Enumerators/OrderBy.cs index 6ac8768..0e16408 100644 --- a/src/NullGC.Linq/Enumerators/OrderBy.cs +++ b/src/NullGC.Linq/Enumerators/OrderBy.cs @@ -235,7 +235,7 @@ public static ValueEnumerableSorter, Comparer< public struct OrderByRefToFixedRef : ILinqRefEnumerator, ILinqEnumerable>, - IUnsafeArray, IUnsafeArray>, IItemAddressFixed + IUnsafeArray, IUnsafeArray>, IAddressFixed where TPrevious : struct, ILinqRefEnumerator where T : unmanaged where TKey : unmanaged @@ -376,7 +376,7 @@ public bool SetTakeCount(int count) } public struct OrderByValueToFixedRef : ILinqRefEnumerator, ISkipTakeAware, - IItemAddressFixed, + IAddressFixed, ILinqEnumerable>, IUnsafeArray, IUnsafeArray> where TPrevious : struct, ILinqValueEnumerator @@ -696,10 +696,10 @@ public bool SetTakeCount(int count) // public bool IsInitialized => _indexBuffer.IsInitialized; // } -public struct OrderByPtrToPtr : ILinqRefEnumerator, IItemAddressFixed, +public struct OrderByPtrToPtr : ILinqRefEnumerator, IAddressFixed, ILinqEnumerable>, IUnsafeArray, IUnsafeArray> - where TPrevious : ILinqRefEnumerator, IItemAddressFixed + where TPrevious : ILinqRefEnumerator, IAddressFixed where T : unmanaged where TKey : unmanaged where TComparer : IComparer @@ -856,10 +856,10 @@ public bool SetTakeCount(int count) } public struct OrderByFixedRefToFixedRef : ILinqRefEnumerator, - IItemAddressFixed, + IAddressFixed, ILinqEnumerable>, IUnsafeArray, IUnsafeArray> - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where T : unmanaged where TKey : unmanaged where TComparer : IComparer diff --git a/src/NullGC.Linq/Enumerators/Select.cs b/src/NullGC.Linq/Enumerators/Select.cs index 6acdb81..af028d7 100644 --- a/src/NullGC.Linq/Enumerators/Select.cs +++ b/src/NullGC.Linq/Enumerators/Select.cs @@ -223,10 +223,10 @@ public TResult Current } public struct SelectFixedRefToFixedRef : ILinqRefEnumerator, - IItemAddressFixed, + IAddressFixed, ILinqEnumerable> where TSelector : IFuncT1TRRefInvoker - where TPrevious : ILinqRefEnumerator, IItemAddressFixed + where TPrevious : ILinqRefEnumerator, IAddressFixed { private TPrevious _previous = default!; private readonly TSelector _selector = default!; @@ -321,9 +321,9 @@ public TResult Current IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } -public struct SelectPtrToPtr : ILinqRefEnumerator, IItemAddressFixed, +public struct SelectPtrToPtr : ILinqRefEnumerator, IAddressFixed, ILinqEnumerable> - where TPrevious : ILinqRefEnumerator, IItemAddressFixed + where TPrevious : ILinqRefEnumerator, IAddressFixed where TSelector : struct where TResult : unmanaged { diff --git a/src/NullGC.Linq/Enumerators/Skip.cs b/src/NullGC.Linq/Enumerators/Skip.cs index d98ba53..b45db0c 100644 --- a/src/NullGC.Linq/Enumerators/Skip.cs +++ b/src/NullGC.Linq/Enumerators/Skip.cs @@ -66,9 +66,9 @@ public bool SetTakeCount(int count) IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } -public struct SkipFixedRef : ILinqRefEnumerator, IItemAddressFixed, +public struct SkipFixedRef : ILinqRefEnumerator, IAddressFixed, ILinqEnumerable> - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { private TPrevious _previous; private int _skipCount; diff --git a/src/NullGC.Linq/Enumerators/Take.cs b/src/NullGC.Linq/Enumerators/Take.cs index b430bc7..45791cf 100644 --- a/src/NullGC.Linq/Enumerators/Take.cs +++ b/src/NullGC.Linq/Enumerators/Take.cs @@ -74,9 +74,9 @@ public bool SetTakeCount(int count) IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } -public struct TakeFixedRef : ILinqRefEnumerator, IItemAddressFixed, +public struct TakeFixedRef : ILinqRefEnumerator, IAddressFixed, ILinqEnumerable> - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { private TPrevious _previous; private int _takeCount; @@ -210,8 +210,8 @@ public bool SetTakeCount(int count) IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } -public struct TakePtr : ILinqRefEnumerator, ILinqEnumerable>, IItemAddressFixed - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed +public struct TakePtr : ILinqRefEnumerator, ILinqEnumerable>, IAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where T : unmanaged { private TPrevious _previous; diff --git a/src/NullGC.Linq/Enumerators/Where.cs b/src/NullGC.Linq/Enumerators/Where.cs index 6db7b59..433ba14 100644 --- a/src/NullGC.Linq/Enumerators/Where.cs +++ b/src/NullGC.Linq/Enumerators/Where.cs @@ -196,9 +196,9 @@ public bool MoveNext() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } -public struct WhereFixedRefToFixedRef : ILinqRefEnumerator, IItemAddressFixed, +public struct WhereFixedRefToFixedRef : ILinqRefEnumerator, IAddressFixed, ILinqEnumerable> - where TPrevious : ILinqRefEnumerator, IItemAddressFixed + where TPrevious : ILinqRefEnumerator, IAddressFixed where TPredicate : struct, IFuncInvoker { private TPrevious _previous = default!; @@ -243,9 +243,9 @@ public bool MoveNext() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } -public struct WhereFixedRefToFixedRefIn : ILinqRefEnumerator, IItemAddressFixed, +public struct WhereFixedRefToFixedRefIn : ILinqRefEnumerator, IAddressFixed, ILinqEnumerable> - where TPrevious : ILinqRefEnumerator, IItemAddressFixed + where TPrevious : ILinqRefEnumerator, IAddressFixed where TPredicate : struct, IFuncT1InInvoker { private TPrevious _previous = default!; @@ -502,9 +502,9 @@ public bool MoveNext() // } // } // } -public struct WherePtrToPtr : ILinqRefEnumerator, IItemAddressFixed, +public struct WherePtrToPtr : ILinqRefEnumerator, IAddressFixed, ILinqEnumerable> - where TPrevious : ILinqRefEnumerator, IItemAddressFixed + where TPrevious : ILinqRefEnumerator, IAddressFixed where TPredicate : struct where T : unmanaged { diff --git a/src/NullGC.Linq/LinqExtensions.Average.cs b/src/NullGC.Linq/LinqExtensions.Average.cs index 18e63e7..1ff3f76 100644 --- a/src/NullGC.Linq/LinqExtensions.Average.cs +++ b/src/NullGC.Linq/LinqExtensions.Average.cs @@ -17,7 +17,7 @@ public static Option Average(this LinqRefEnumerable Average(this LinqPtrEnumerable source) - where TEnumerator : struct, ILinqRefEnumerator, IItemAddressFixed + where TEnumerator : struct, ILinqRefEnumerator, IAddressFixed { return Average, TEnumerator, long, double>(source); } diff --git a/src/NullGC.Linq/LinqExtensions.OrderBy.cs b/src/NullGC.Linq/LinqExtensions.OrderBy.cs index 47c4172..ab11766 100644 --- a/src/NullGC.Linq/LinqExtensions.OrderBy.cs +++ b/src/NullGC.Linq/LinqExtensions.OrderBy.cs @@ -26,7 +26,7 @@ public static partial class LinqExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static LinqFixedRefEnumerable, T, Comparer, DummyEnumerableSorter>> - OrderBy(this LinqRefEnumerable src) + Order(this LinqRefEnumerable src) where TPrevious : struct, ILinqRefEnumerator where T : unmanaged { return new LinqFixedRefEnumerable, TKey, Comparer, DummyEnumerableSorter>> OrderBy(this LinqFixedRefEnumerable src, FuncT1In keySelector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqFixedRefEnumerable, TKey, Comparer, @@ -55,8 +55,8 @@ public static partial class LinqExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static LinqFixedRefEnumerable, T, Comparer, DummyEnumerableSorter>> - OrderBy(this LinqFixedRefEnumerable src) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where T : unmanaged + Order(this LinqFixedRefEnumerable src) + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where T : unmanaged { return new LinqFixedRefEnumerable, T, Comparer, @@ -84,7 +84,7 @@ public static partial class LinqExtensions public static LinqFixedRefEnumerable, TKey, Comparer, DummyEnumerableSorter>> OrderBy(this LinqFixedRefEnumerable src, Func keySelector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqFixedRefEnumerable, TKey, Comparer, @@ -128,7 +128,7 @@ public static partial class LinqExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static LinqFixedRefEnumerable, T, Comparer, DummyEnumerableSorter>> - OrderBy(this LinqValueEnumerable src) + Order(this LinqValueEnumerable src) where TPrevious : struct, ILinqValueEnumerator where T : unmanaged { return new LinqFixedRefEnumerable, TKey, Comparer, DummyEnumerableSorter>> OrderBy(this LinqPtrEnumerable src, FuncT1Ptr keySelector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqPtrEnumerable, TKey, Comparer, @@ -172,7 +172,7 @@ public static partial class LinqExtensions public static LinqPtrEnumerable, T, Comparer, DummyEnumerableSorter>> OrderBy(this LinqPtrEnumerable src) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where T : unmanaged { return new LinqPtrEnumerable, T, Comparer, @@ -236,7 +236,7 @@ public static partial class LinqExtensions OrderBy( this LinqFixedRefEnumerable src, Func keySelector, Comparison comparer) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqFixedRefEnumerable, TKey, StructComparer, @@ -253,7 +253,7 @@ public static partial class LinqExtensions OrderBy( this LinqFixedRefEnumerable src, FuncT1In keySelector, Comparison comparer) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqFixedRefEnumerable, TKey, StructComparer, @@ -326,7 +326,7 @@ Comparer, DummyEnumerableSorter>> OrderBy( Comparer, DummyEnumerableSorter>> OrderBy( this LinqFixedRefEnumerable src, FuncT1In keySelector, TArg arg) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged where TArg : unmanaged @@ -481,7 +481,7 @@ StructComparerWithArg, DummyEnumerableSorter>> OrderBy, DummyEnumerableSorter>> OrderByDescending(this LinqFixedRefEnumerable src, FuncT1In keySelector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqFixedRefEnumerable, TKey, Comparer, @@ -496,7 +496,7 @@ StructComparerWithArg, DummyEnumerableSorter>> OrderBy, T, Comparer, DummyEnumerableSorter>> OrderByDescending(this LinqFixedRefEnumerable src) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where T : unmanaged { return new LinqFixedRefEnumerable, T, Comparer, @@ -523,7 +523,7 @@ StructComparerWithArg, DummyEnumerableSorter>> OrderBy, TKey, Comparer, DummyEnumerableSorter>> OrderByDescending(this LinqFixedRefEnumerable src, Func keySelector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqFixedRefEnumerable, TKey, Comparer, @@ -581,7 +581,7 @@ StructComparerWithArg, DummyEnumerableSorter>> OrderBy, TKey, Comparer, DummyEnumerableSorter>> OrderByDescending(this LinqPtrEnumerable src, FuncT1Ptr keySelector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqPtrEnumerable, TKey, Comparer, @@ -596,7 +596,7 @@ StructComparerWithArg, DummyEnumerableSorter>> OrderBy, T, Comparer, DummyEnumerableSorter>> OrderByDescending(this LinqPtrEnumerable src) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where T : unmanaged { return new LinqPtrEnumerable, T, Comparer, @@ -629,7 +629,7 @@ StructComparerWithArg, DummyEnumerableSorter>> OrderBy( this LinqFixedRefEnumerable src, FuncT1In keySelector, Comparison comparer) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqFixedRefEnumerable, TKey, StructComparer, @@ -664,7 +664,7 @@ StructComparerWithArg, DummyEnumerableSorter>> OrderBy( this LinqFixedRefEnumerable src, Func keySelector, Comparison comparer) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TKey : unmanaged where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged { return new LinqFixedRefEnumerable, TKey, StructComparer, @@ -738,7 +738,7 @@ Comparer, DummyEnumerableSorter>> OrderByDescending, DummyEnumerableSorter>> OrderByDescending( this LinqFixedRefEnumerable src, FuncT1In keySelector, TArg arg) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged where TArg : unmanaged @@ -824,7 +824,7 @@ StructComparerWithArg, DummyEnumerableSorter>> OrderByDescending< this LinqFixedRefEnumerable src, FuncT1In keySelector, ComparisonWithArg comparer, TArg arg) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged where TArg : unmanaged diff --git a/src/NullGC.Linq/LinqExtensions.OrderByMulti.cs b/src/NullGC.Linq/LinqExtensions.OrderByMulti.cs index aaab481..04ea978 100644 --- a/src/NullGC.Linq/LinqExtensions.OrderByMulti.cs +++ b/src/NullGC.Linq/LinqExtensions.OrderByMulti.cs @@ -29,7 +29,7 @@ public static partial class LinqExtensions Comparer, TNext>> OrderBy(this LinqFixedRefEnumerable src, ValueEnumerableSorter, Comparer, TNext> sorter) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged where TNext : struct, IValueEnumerableSorter @@ -61,7 +61,7 @@ public static partial class LinqExtensions Comparer, TNext>> OrderBy(this LinqFixedRefEnumerable src, ValueEnumerableSorter, Comparer, TNext> sorter) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged where TNext : struct, IValueEnumerableSorter @@ -109,7 +109,7 @@ public static partial class LinqExtensions TNext>> OrderBy(this LinqPtrEnumerable src, ValueEnumerableSorter, Comparer, TNext> sorter) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TKey : unmanaged where T : unmanaged where TNext : struct, IValueEnumerableSorter diff --git a/src/NullGC.Linq/LinqExtensions.Select.cs b/src/NullGC.Linq/LinqExtensions.Select.cs index 8e39682..5238442 100644 --- a/src/NullGC.Linq/LinqExtensions.Select.cs +++ b/src/NullGC.Linq/LinqExtensions.Select.cs @@ -33,7 +33,7 @@ public static LinqRefEnumerable, TResult>> Select( this LinqFixedRefEnumerable src, FuncT1TRRef selector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqFixedRefEnumerable, TResult>>( new SelectFixedRefToFixedRef, TResult>(src.GetEnumerator(), @@ -55,7 +55,7 @@ public static LinqValueEnumerable, TResult>> Select( this LinqFixedRefEnumerable src, FuncT1In selector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqValueEnumerable, TResult>>( new SelectRefToValueIn, TResult>(src.GetEnumerator(), @@ -66,7 +66,7 @@ public static LinqValueEnumerable, TResult>> Select( this LinqFixedRefEnumerable src, Func selector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqValueEnumerable, TResult>>( new SelectRefToValue, TResult>(src.GetEnumerator(), @@ -77,7 +77,7 @@ public static LinqValueEnumerable, TResult>> Select( this LinqFixedRefEnumerable src, Func selector, TArg arg) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqValueEnumerable, TResult>>( new SelectRefToValue, TResult>(src.GetEnumerator(), @@ -88,7 +88,7 @@ public static LinqValueEnumerable, TResult>> Select( this LinqPtrEnumerable src, FuncT1Ptr selector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqValueEnumerable, TResult>>( new SelectPtrToValue, TResult>(src.GetEnumerator(), @@ -99,7 +99,7 @@ public static LinqValueEnumerable, TResult>> Select( this LinqPtrEnumerable src, FuncT1TRPtr selector) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TResult : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TResult : unmanaged { return new LinqPtrEnumerable, TResult>>( new SelectPtrToPtr, TResult>(src.GetEnumerator(), @@ -145,7 +145,7 @@ public static LinqValueEnumerable(this LinqFixedRefEnumerable src, FuncT1In predicate, TArg arg) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TArg : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TArg : unmanaged { return new LinqValueEnumerable, TResult>>( new SelectRefToValueIn, TResult>(src.GetEnumerator(), @@ -157,7 +157,7 @@ public static LinqFixedRefEnumerable(this LinqFixedRefEnumerable src, FuncT1TRRef predicate, TArg arg) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TArg : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TArg : unmanaged { return new LinqFixedRefEnumerable, TResult>>( new SelectFixedRefToFixedRef, TResult>(src.GetEnumerator(), diff --git a/src/NullGC.Linq/LinqExtensions.Skip.cs b/src/NullGC.Linq/LinqExtensions.Skip.cs index a836651..42547cf 100644 --- a/src/NullGC.Linq/LinqExtensions.Skip.cs +++ b/src/NullGC.Linq/LinqExtensions.Skip.cs @@ -26,7 +26,7 @@ public static LinqRefEnumerable> Skip( [MethodImpl(MethodImplOptions.AggressiveInlining)] public static LinqFixedRefEnumerable> Skip( this LinqFixedRefEnumerable src, int count) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqFixedRefEnumerable>( new SkipFixedRef(src.GetEnumerator(), count)); diff --git a/src/NullGC.Linq/LinqExtensions.Take.cs b/src/NullGC.Linq/LinqExtensions.Take.cs index 062c0bc..ea32773 100644 --- a/src/NullGC.Linq/LinqExtensions.Take.cs +++ b/src/NullGC.Linq/LinqExtensions.Take.cs @@ -26,7 +26,7 @@ public static LinqRefEnumerable> Take( [MethodImpl(MethodImplOptions.AggressiveInlining)] public static LinqFixedRefEnumerable> Take( this LinqFixedRefEnumerable src, int count) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqFixedRefEnumerable>( new TakeFixedRef(src.GetEnumerator(), count)); @@ -35,7 +35,7 @@ public static LinqFixedRefEnumerable> Take> Take( this LinqPtrEnumerable src, int count) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where T : unmanaged { return new LinqPtrEnumerable>( new TakePtr(src.GetEnumerator(), count)); diff --git a/src/NullGC.Linq/LinqExtensions.Where.cs b/src/NullGC.Linq/LinqExtensions.Where.cs index acd1bd5..490b3de 100644 --- a/src/NullGC.Linq/LinqExtensions.Where.cs +++ b/src/NullGC.Linq/LinqExtensions.Where.cs @@ -22,7 +22,7 @@ public static LinqRefEnumerable>> Where( this LinqFixedRefEnumerable src, FuncT1In predicate) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqFixedRefEnumerable>>( new WhereFixedRefToFixedRefIn>(src.GetEnumerator(), @@ -44,7 +44,7 @@ public static LinqRefEnumerable>> Where( this LinqFixedRefEnumerable src, Func predicate) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed { return new LinqFixedRefEnumerable>>( new WhereFixedRefToFixedRef>(src.GetEnumerator(), @@ -77,7 +77,7 @@ public static LinqValueEnumerable>> Where( this LinqPtrEnumerable src, FuncT1Ptr predicate) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where T : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where T : unmanaged { return new LinqPtrEnumerable>>( new WherePtrToPtr>(src.GetEnumerator(), @@ -101,7 +101,7 @@ public static LinqFixedRefEnumerable(this LinqFixedRefEnumerable src, FuncT1In predicate, TArg arg) - where TPrevious : struct, ILinqRefEnumerator, IItemAddressFixed where TArg : unmanaged + where TPrevious : struct, ILinqRefEnumerator, IAddressFixed where TArg : unmanaged { return new LinqFixedRefEnumerable>>( new WhereFixedRefToFixedRefIn>(src.GetEnumerator(), diff --git a/src/NullGC.Linq/LinqExtensions.cs b/src/NullGC.Linq/LinqExtensions.cs index 1a18835..3ad3797 100644 --- a/src/NullGC.Linq/LinqExtensions.cs +++ b/src/NullGC.Linq/LinqExtensions.cs @@ -96,6 +96,13 @@ public static LinqRefEnumerable> LinqRef(this T[ return new LinqRefEnumerable>(new ArrayLinqRefEnumerator(src)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static LinqValueEnumerable> LinqValue(this T[] src) + where T : unmanaged + { + return new LinqValueEnumerable>(new ArrayLinqRefEnumerator(src)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static LinqValueEnumerable> LinqValue(this IList src) where T : unmanaged @@ -260,7 +267,7 @@ public static T Sum(this LinqRefEnumerable src) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Sum(this LinqFixedRefEnumerable src) where T : INumber - where TEnumerator : struct, ILinqRefEnumerator, IItemAddressFixed + where TEnumerator : struct, ILinqRefEnumerator, IAddressFixed { using var enumerator = src.GetEnumerator(); T sum = T.Zero; @@ -288,7 +295,7 @@ public static T Sum(this LinqValueEnumerable src [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Min(this LinqPtrEnumerable src) where T : INumber, IMinMaxValue - where TEnumerator : struct, ILinqRefEnumerator, IItemAddressFixed + where TEnumerator : struct, ILinqRefEnumerator, IAddressFixed { using var enumerator = src.GetEnumerator(); T min = T.MaxValue; @@ -333,7 +340,7 @@ public static T Min(this LinqValueEnumerable src [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Max(this LinqPtrEnumerable src) where T : INumber, IMinMaxValue - where TEnumerator : struct, ILinqRefEnumerator, IItemAddressFixed + where TEnumerator : struct, ILinqRefEnumerator, IAddressFixed { using var enumerator = src.GetEnumerator(); T max = T.MinValue; @@ -408,7 +415,7 @@ public static void Drain(this LinqValueEnumerable(this LinqPtrEnumerable src) where TEnumerator : struct, ILinqRefEnumerator, IItemAddressFixed + public static void Drain(this LinqPtrEnumerable src) where TEnumerator : struct, ILinqRefEnumerator, IAddressFixed { using var e = src.GetEnumerator(); while (e.MoveNext())