Skip to content

Commit 5ab0267

Browse files
committed
some more things
Introduced StringEx and UnmanagedAnsiString for advanced string allocation and unmanaged string handling. Moved encoding and JSON-related files to SystemEx.Text namespaces. Updated Base32 API to use GetByteCount/GetCharCount. Added NonCopyableAttribute and applied it to relevant structs. Improved string allocation and writable span usage in StringExtensions and Polyfills. Updated project files for new dependencies and target frameworks.
1 parent 284c6c8 commit 5ab0267

22 files changed

Lines changed: 154 additions & 60 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
SystemEx [![NuGet](https://img.shields.io/nuget/vpre/Xpl0itR.SystemEx)](https://www.nuget.org/packages/Xpl0itR.SystemEx/)
22
========
3-
SystemEx is a library which extends the functionality of the .NET standard libraries, written in C# 12, targeting .NET 8.0 and later.
3+
SystemEx is a library which extends the functionality of the .NET standard libraries.
44

55
License
66
-------

src/Cryptography/Otp/HOtp.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
using System;
88
using System.Security.Cryptography;
9-
using SystemEx.Encoding;
9+
using SystemEx.Text.Encoding;
1010

1111
namespace SystemEx.Cryptography.Otp;
1212

@@ -52,7 +52,7 @@ public HOtp(ReadOnlySpan<char> keyBase32, HashAlgorithmName hashAlg)
5252
#else
5353
byte[] key = new byte
5454
#endif
55-
[Base32.CountBytes(keyBase32.Length)];
55+
[Base32.GetByteCount(keyBase32.Length)];
5656

5757
Base32.GetBytesUnchecked(keyBase32, key);
5858

@@ -66,6 +66,7 @@ public uint NumDigits
6666

6767
public int ComputeCode(ReadOnlySpan<byte> counter)
6868
{
69+
// ReSharper disable once InconsistentlySynchronizedField
6970
Span<byte> hash = stackalloc byte[_hmac.HashLengthInBytes];
7071

7172
lock (_hmacLock)

src/Cryptography/Random/MT19937_64.Slim.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
using System.Runtime.CompilerServices;
99
using System.Runtime.InteropServices;
1010
using CommunityToolkit.Diagnostics;
11+
using Microsoft.CodeAnalysis;
1112

1213
namespace SystemEx.Cryptography.Random;
1314

1415
partial class MT19937_64
1516
{
17+
[NonCopyable]
1618
[StructLayout(LayoutKind.Auto)]
1719
public ref struct Slim
1820
{

src/Memory/MemoryReader.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
using System.Runtime.InteropServices;
1010
using CommunityToolkit.Diagnostics;
1111
using CommunityToolkit.HighPerformance;
12+
using Microsoft.CodeAnalysis;
1213

1314
namespace SystemEx.Memory;
1415

16+
[NonCopyable]
1517
[StructLayout(LayoutKind.Auto)]
1618
public ref partial struct MemoryReader
1719
{

src/Memory/MemoryWriter.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
using System.Runtime.InteropServices;
1010
using CommunityToolkit.Diagnostics;
1111
using CommunityToolkit.HighPerformance;
12+
using Microsoft.CodeAnalysis;
1213

1314
namespace SystemEx.Memory;
1415

16+
[NonCopyable]
1517
[StructLayout(LayoutKind.Auto)]
1618
public ref partial struct MemoryWriter
1719
{

src/Memory/StringEx.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright © 2023-2025 Xpl0itR
2+
//
3+
// This Source Code Form is subject to the terms of the Mozilla Public
4+
// License, v. 2.0. If a copy of the MPL was not distributed with this
5+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
7+
using System;
8+
using System.Runtime.CompilerServices;
9+
using System.Runtime.InteropServices;
10+
using CommunityToolkit.HighPerformance;
11+
12+
namespace SystemEx.Memory;
13+
14+
public static class StringEx
15+
{
16+
extension(string str)
17+
{
18+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
19+
public Span<char> AsWriteableSpan() =>
20+
MemoryMarshal.CreateSpan(
21+
ref str.DangerousGetReference(),
22+
str.Length);
23+
24+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
25+
public static string Allocate(int length)
26+
{
27+
#if NET9_0_OR_GREATER
28+
return FastAllocateString(null, length);
29+
30+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "FastAllocateString"), MethodImpl(MethodImplOptions.AggressiveInlining)]
31+
static extern
32+
#if NET10_0_OR_GREATER
33+
string FastAllocateString(string? _, nint length);
34+
#else
35+
string FastAllocateString(string? _, int length);
36+
#endif
37+
#else
38+
return new string('\0', length);
39+
#endif
40+
}
41+
}
42+
}

src/Memory/UnmanagedAnsiString.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright © 2025 Xpl0itR
2+
//
3+
// This Source Code Form is subject to the terms of the Mozilla Public
4+
// License, v. 2.0. If a copy of the MPL was not distributed with this
5+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
7+
using System;
8+
using System.Runtime.CompilerServices;
9+
using System.Runtime.InteropServices;
10+
11+
namespace SystemEx.Memory;
12+
13+
[method: MethodImpl(MethodImplOptions.AggressiveInlining)]
14+
public readonly struct UnmanagedAnsiString(string? str) : IDisposable
15+
{
16+
public readonly nint Ptr = Marshal.StringToCoTaskMemAnsi(str);
17+
18+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
19+
public void Dispose() => Marshal.FreeCoTaskMem(Ptr);
20+
21+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
22+
public static implicit operator nint (UnmanagedAnsiString str) => str.Ptr;
23+
}

src/Memory/UnsafeEx.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,6 @@ public static ReadOnlySpan<byte> AsReadOnlyBytes<T>(this ref T value) where T :
5050
ref Unsafe.As<T, byte>(ref value),
5151
Unsafe.SizeOf<T>());
5252

53-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
54-
public static Span<char> AsWriteableSpan(this string str) =>
55-
MemoryMarshal.CreateSpan(
56-
ref str.DangerousGetReference(),
57-
str.Length);
58-
5953
[MethodImpl(MethodImplOptions.AggressiveInlining)]
6054
public static ref TTo As<TFrom, TTo>(ref TFrom ptr, int offset)
6155
#if NET9_0_OR_GREATER

src/Net/Http/RemoteContainer/CentralDirectory.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,17 @@ public sealed class CentralDirectory : IReadOnlyDictionary<string, CentralDirect
1616
{
1717
private readonly Dictionary<string, CentralDirectoryEntry> _centralDirEntries;
1818

19-
internal CentralDirectory(RentedArray<byte> buffer, ulong entryCount)
19+
internal CentralDirectory(ref MemoryReader reader, ulong entryCount)
2020
{
2121
_centralDirEntries = new Dictionary<string, CentralDirectoryEntry>(
2222
entryCount > int.MaxValue
2323
? int.MaxValue
2424
: (int)entryCount,
2525
StringComparer.Ordinal);
2626

27-
MemoryReader centralDirReader = new(buffer);
28-
while (centralDirReader.Remaining > 0)
27+
while (reader.Remaining > 0)
2928
{
30-
CentralDirectoryEntry entry = new(ref centralDirReader);
29+
CentralDirectoryEntry entry = new(ref reader);
3130
_centralDirEntries.Add(entry.FileName, entry);
3231
}
3332
}

src/Net/Http/RemoteContainer/RemoteZipArchive.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ public static async Task<RemoteZipArchive> Open(HttpMessageInvoker http, Uri? ur
105105
using RentedArray<byte> centralDirBuffer = new(checked((int)centralDirLength));
106106
await http.ReadChunkAsync(centralDirBuffer, uri, eTag, checked((long)centralDirOffset), ct).ConfigureAwait(false);
107107

108-
CentralDirectory centralDirectory = new(centralDirBuffer, entryCount);
108+
MemoryReader centralDirReader = new(centralDirBuffer);
109+
CentralDirectory centralDirectory = new(ref centralDirReader, entryCount);
110+
109111
return new RemoteZipArchive(http, uri, eTag, centralDirectory);
110112
}
111113
}

0 commit comments

Comments
 (0)