Skip to content

Commit

Permalink
+ optimized string struct handler
Browse files Browse the repository at this point in the history
  • Loading branch information
Hawkynt committed Jun 19, 2024
1 parent 58d70b0 commit d8174ab
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 5 deletions.
6 changes: 3 additions & 3 deletions Backports/Features/Span/System/MemoryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public static Span<T> AsSpan<T>(this T[] @this, Range range) {
return new(@this, offsetAndLength.Offset, offsetAndLength.Length);
}

public static ReadOnlySpan<char> AsSpan(this string @this) => new(@this.ToCharArray());
public static ReadOnlySpan<char> AsSpan(this string @this, int start) => new(@this.ToCharArray(start, @this.Length - start));
public static ReadOnlySpan<char> AsSpan(this string @this, int start, int length) => new(@this.ToCharArray(start, length));
public static ReadOnlySpan<char> AsSpan(this string @this) => new(@this);
public static ReadOnlySpan<char> AsSpan(this string @this, int start) => new(@this, start, @this.Length - start);
public static ReadOnlySpan<char> AsSpan(this string @this, int start, int length) => new(@this, start, length);
public static ReadOnlySpan<char> AsSpan(this string @this, Index startIndex) => AsSpan(@this, startIndex.GetOffset(@this.Length));

public static ReadOnlySpan<char> AsSpan(this string @this, Range range) {
Expand Down
4 changes: 3 additions & 1 deletion Backports/Features/Span/System/ReadOnlySpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ private ReadOnlySpan(SpanHelper.IMemoryHandler<T> handler, int length) {
}

public ReadOnlySpan(T[] array) : this(array, 0, array?.Length ?? 0) { }
internal ReadOnlySpan(string text) : this(text, 0, text?.Length ?? 0) { }

public ReadOnlySpan(T[] array, int start, int length) : this(SpanHelper.PinnedArrayMemoryHandler<T>.FromManagedArray(array, start), length) { }
internal ReadOnlySpan(string text, int start, int length) : this((SpanHelper.IMemoryHandler<T>)new SpanHelper.StringHandler(text, start), length) { }

#pragma warning disable CS8500
public unsafe ReadOnlySpan(void* pointer, int length) : this(new SpanHelper.UnmanagedPointerMemoryHandler<T>((T*)pointer), length) { }
Expand Down Expand Up @@ -91,7 +93,7 @@ public bool TryCopyTo(Span<T> other) {
public static implicit operator ReadOnlySpan<T>(T[] array) => new(array);

/// <inheritdoc />
public override string ToString() => typeof(T) == typeof(char) ? new((char[])(object)this.ToArray()) : $"System.ReadOnlySpan<{typeof(T).Name}>[{this.Length}]";
public override string ToString() => this._pointerMemoryHandler is SpanHelper.StringHandler sh ? sh.ToString() : typeof(T) == typeof(char) ? new((char[])(object)this.ToArray()) : $"System.ReadOnlySpan<{typeof(T).Name}>[{this.Length}]";

}

Expand Down
2 changes: 1 addition & 1 deletion Backports/Features/Span/System/Span.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public bool TryCopyTo(Span<T> other) {
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();

/// <inheritdoc />
public override string ToString() => typeof(T) == typeof(char) ? new((char[])(object)this.ToArray()) : $"System.ReadOnlySpan<{typeof(T).Name}>[{this.Length}]";
public override string ToString() => typeof(T) == typeof(char) ? new((char[])(object)this.ToArray()) : $"System.Span<{typeof(T).Name}>[{this.Length}]";

}

Expand Down
50 changes: 50 additions & 0 deletions Backports/Features/Span/System/SpanHelper.StringHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// This file is part of Hawkynt's .NET Framework extensions.
//
// Hawkynt's .NET Framework extensions are free software:
// you can redistribute and/or modify it under the terms
// given in the LICENSE file.
//
// Hawkynt's .NET Framework extensions is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the LICENSE file for more details.
//
// You should have received a copy of the License along with Hawkynt's
// .NET Framework extensions. If not, see
// <https://github.com/Hawkynt/C--FrameworkExtensions/blob/master/LICENSE>.

#if !SUPPORTS_SPAN

namespace System;

internal static partial class SpanHelper {
public class StringHandler(string source, int start) : IMemoryHandler<char> {
#region Implementation of IMemoryHandler<char>

/// <inheritdoc />
public ref char this[int index] => ref new[] { source[start + index] }[0];

/// <inheritdoc />
public IMemoryHandler<char> SliceFrom(int offset) => new StringHandler(source, start + offset);

/// <inheritdoc />
public void CopyTo(IMemoryHandler<char> other, int length) {
for (int i = 0, offset = start; i < length; ++offset, ++i)
other[i] = source[offset];
}

/// <inheritdoc />
public void CopyTo(char[] target, int count) => source.CopyTo(start, target, 0, count);

#endregion

#region Overrides of Object

/// <inheritdoc />
public override string ToString() => start == 0 ? source : source[start..];

#endregion
}
}

#endif
1 change: 1 addition & 0 deletions Tests/Corlib.Tests/Corlib.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<LangVersion>default</LangVersion>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<Import Project="..\..\VersionSpecificSymbols.Common.prop" />

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="*" />
Expand Down
34 changes: 34 additions & 0 deletions Tests/Corlib.Tests/System/SpanTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,39 @@ public unsafe void CopyTo_CopiesCorrectly_BlittableTypes(int length) {
}
}

[Test]
public void CopyTo_StringToCharArray() {
var source = "TEST";
var sourceSpan = source.AsSpan();

var targetChars = sourceSpan.ToArray();
var target=new string(targetChars);

Assert.AreEqual(source, target);
}

[Test]
public void CopyTo_StringPartsToCharArray() {
var source = "TEST";
var sourceSpan = source.AsSpan()[1..2];

var targetChars = sourceSpan.ToArray();
var target = new string(targetChars);

Assert.AreEqual(source[1..2], target);
}

[Test]
public void CopyTo_PlainStringsShouldBeTheSameReference() {
var source = "TEST";
var sourceSpan = source.AsSpan();
var target = sourceSpan.ToString();

#if SUPPORTS_SPAN
Assert.AreEqual(source, target);
#else
Assert.AreSame(source, target);
#endif
}
}

0 comments on commit d8174ab

Please sign in to comment.