-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add MemoryStream.AsIBufferWriter() Add byte[].AsStream(). Add List<T>.AsMemory() and .AsSpan(). Add PickFirstEnumerator<T>. Move SystemExtensions.System.FIle to SystemExtensions.System.IO.File. Update README.md
- Loading branch information
Showing
21 changed files
with
446 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,10 @@ | ||
[![NuGet](https://img.shields.io/nuget/v/aianlinb.SystemExtensions)](https://www.nuget.org/packages/aianlinb.SystemExtensions) | ||
[![Test](https://github.com/aianlinb/SystemExtensions/actions/workflows/test.yml/badge.svg)](https://github.com/aianlinb/SystemExtensions/actions/workflows/test.yml) | ||
[![Test](https://github.com/aianlinb/SystemExtensions/actions/workflows/test.yml/badge.svg)](https://github.com/aianlinb/SystemExtensions/actions/workflows/test.yml) | ||
|
||
Useful and high-performance helper classes and extension methods. | ||
|
||
## Highlights | ||
- SpanExtensions | ||
- StreamExtensions | ||
- ValueList | ||
- SubStream |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace System.IO; | ||
/// <summary> | ||
/// Forwarded to System.Private.CoreLib.dll at runtime | ||
/// </summary> | ||
public class MemoryStream { | ||
public byte[] _buffer; | ||
public readonly int _origin; | ||
public int _position; | ||
public int _length; | ||
public int _capacity; | ||
public bool _expandable; | ||
public bool _writable; | ||
public bool _exposable; | ||
public bool _isOpen; | ||
public Task<int>? _lastReadTask; | ||
public const int MemStreamMaxLength = int.MaxValue; | ||
|
||
public extern void EnsureNotClosed(); | ||
public extern bool EnsureCapacity(int value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,50 @@ | ||
namespace SystemExtensions.Tests; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace SystemExtensions.Tests; | ||
|
||
[TestClass] | ||
public class CollectionExtensionsTests { | ||
private static readonly int[] enumerable = [1, 2, 3, 4, 5]; | ||
[TestMethod] | ||
public void IndexOf_Test() { | ||
// Arrange | ||
var enumerable = new[] { 1, 2, 3, 4, 5 }; | ||
|
||
// Act + Assert | ||
for (var i = 0; i < enumerable.Length; ++i) | ||
Assert.AreEqual(i, Collections.CollectionExtensions.IndexOf(enumerable, enumerable[i])); | ||
} | ||
|
||
[TestMethod] | ||
public void PickFirstEnumerator_Test() { | ||
// Arrange | ||
using var pfe = new PickFirstEnumerator<int>(enumerable); | ||
|
||
// Act + Assert | ||
Assert.AreEqual(enumerable[0], pfe.First); | ||
using var et = enumerable.AsEnumerable().GetEnumerator(); | ||
while (pfe.MoveNext()) { | ||
Assert.IsTrue(et.MoveNext()); | ||
Assert.AreEqual(et.Current, pfe.Current); | ||
} | ||
pfe.Reset(); | ||
Assert.AreEqual(enumerable[0], pfe.First); | ||
Assert.IsTrue(enumerable.SequenceEqual(pfe)); | ||
} | ||
|
||
[TestMethod] | ||
public unsafe void ListAsSpanAsMemory_Test() { | ||
// Arrange | ||
var list = new List<int>(enumerable); | ||
|
||
// Act | ||
var span = list.AsSpan(); | ||
var memory = list.AsMemory(); | ||
|
||
// Assert | ||
Assert.AreEqual(list.Count, span.Length); | ||
Assert.AreEqual(list.Count, memory.Length); | ||
fixed (int* expected = CollectionsMarshal.AsSpan(list), actual1 = span) { | ||
var actual2 = (int*)memory.Pin().Pointer; | ||
Assert.IsTrue(expected == actual1); | ||
Assert.IsTrue(expected == actual2); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using System.Collections; | ||
|
||
namespace SystemExtensions.Collections; | ||
|
||
/// <summary> | ||
/// Wrap a <see cref="IEnumerator{T}"/> to pick its first value and save to <see cref="First"/>, | ||
/// but still can iterate all values including the first one without calling <see cref="IEnumerator.Reset"/>. | ||
/// </summary> | ||
/// <remarks> | ||
/// <para> | ||
/// This is useful when you want to get the first value before a foreach loop, | ||
/// but don't want to re-enumerate the collection. | ||
/// </para> | ||
/// <para> | ||
/// Note that the <see cref="GetEnumerator"/> returns the <see cref="PickFirstEnumerator{T}"/> itself, | ||
/// so this <see cref="IEnumerable{T}"/> can't be used again before calling <see cref="Reset"/>. | ||
/// </para> | ||
/// </remarks> | ||
public struct PickFirstEnumerator<T> : IEnumerator<T>, IEnumerable<T> { | ||
public PickFirstEnumerator(IEnumerable<T> enumerable) : this(enumerable.GetEnumerator()) { } | ||
public PickFirstEnumerator(IEnumerator<T> enumerator) { | ||
if (enumerator.MoveNext()) | ||
First = enumerator.Current; | ||
else | ||
State = 1; | ||
BaseEnumerator = enumerator; | ||
} | ||
|
||
/// <summary> | ||
/// The base <see cref="IEnumerator{T}"/> that was passed to the constructor. | ||
/// </summary> | ||
public readonly IEnumerator<T> BaseEnumerator { get; } | ||
/// <summary> | ||
/// The first value of <see cref="BaseEnumerator"/>, or <see langword="default"/> if it's empty. | ||
/// </summary> | ||
public readonly T? First { get; } | ||
private byte State; // 0: Initial, 1: Initial (Empty), 2: First moved, 3: Other | ||
|
||
public readonly T Current => State switch { | ||
0 or 1 => default!, | ||
2 => First!, | ||
_ => BaseEnumerator.Current | ||
}; | ||
readonly object IEnumerator.Current => Current!; | ||
|
||
public bool MoveNext() { | ||
switch (State) { | ||
case 0: | ||
State = 2; | ||
return true; | ||
case 1: | ||
State = 3; | ||
return false; | ||
case 2: | ||
State = 3; | ||
break; | ||
} | ||
return BaseEnumerator.MoveNext(); | ||
} | ||
|
||
public void Reset() { | ||
BaseEnumerator.Reset(); | ||
this = new(BaseEnumerator); | ||
} | ||
|
||
public readonly void Dispose() => BaseEnumerator.Dispose(); | ||
|
||
/// <summary> | ||
/// Returns <see langword="this"/> as is. | ||
/// </summary> | ||
/// <remarks> | ||
/// See the remarks of <see cref="PickFirstEnumerator{T}"/>. | ||
/// </remarks> | ||
public readonly IEnumerator<T> GetEnumerator() => this; | ||
readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | ||
} |
Oops, something went wrong.