-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStringReadOnlySpanExtensions.cs
More file actions
73 lines (61 loc) · 3.22 KB
/
Copy pathStringReadOnlySpanExtensions.cs
File metadata and controls
73 lines (61 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
namespace Texnomic.Types.Extensions;
/// <summary>
/// Hexadecimal parsing extensions for <see cref="ReadOnlySpan{T}"/> of <see cref="char"/>.
/// </summary>
/// <remarks>
/// <para>
/// All members assume a leading <c>0x</c> prefix on the input.
/// </para>
/// <para>
/// Odd-length payloads (after stripping the prefix) are aligned to an even length by
/// overwriting the <c>'x'</c> in the prefix with a <c>'0'</c> nibble in place via
/// <see cref="MemoryMarshal.CreateSpan{T}(ref T, int)"/>. This avoids an allocation but
/// mutates the underlying character storage — the input span must therefore back writable
/// memory (a heap-allocated <see cref="string"/>'s interior qualifies on .NET, but
/// caller-provided stack-allocated spans should be treated as consumed after the call).
/// </para>
/// </remarks>
public static class StringReadOnlySpanExtensions
{
extension(ReadOnlySpan<char> Value)
{
/// <summary>Parses the <c>0x</c>-prefixed hex span into a <see cref="BigDecimal"/> via the unsigned 256-bit path.</summary>
public BigDecimal HexToBigDecimal() => Value.HexToBytes().ToUInt256();
/// <summary>Parses the <c>0x</c>-prefixed hex span into an unsigned 256-bit integer.</summary>
public BigInteger HexToUInt256() => Value.HexToBytes().ToUInt256();
/// <summary>Parses the <c>0x</c>-prefixed hex span into a signed 256-bit integer (two's-complement).</summary>
public BigInteger HexToInt256() => Value.HexToBytes().ToInt256();
/// <summary>Parses the <c>0x</c>-prefixed hex span into an unsigned 64-bit integer.</summary>
public ulong HexToUInt64() => Value.HexToBytes().ToUInt64();
/// <summary>Parses the <c>0x</c>-prefixed hex span into a signed 64-bit integer.</summary>
public long HexToInt64() => Value.HexToBytes().ToInt64();
/// <summary>Parses the <c>0x</c>-prefixed hex span into an unsigned 32-bit integer.</summary>
public uint HexToUInt32() => Value.HexToBytes().ToUInt32();
/// <summary>Parses the <c>0x</c>-prefixed hex span into a signed 32-bit integer.</summary>
public int HexToInt32() => Value.HexToBytes().ToInt32();
/// <summary>
/// Parses a <c>0x</c>-prefixed hex span into a byte array. Odd-length payloads are
/// aligned in place; see the class remarks for the memory model.
/// </summary>
/// <returns>The decoded bytes.</returns>
public byte[] HexToBytes()
{
Value = (Value.Length - 2) % 2 == 0 ? Value[2..] : Align(Value[1..]);
return Convert.FromHexString(Value);
}
}
/// <summary>
/// Pads an odd-length hex payload by overwriting the first character of the supplied span
/// with <c>'0'</c>, returning a span of the same length whose first nibble is now zero.
/// </summary>
/// <remarks>
/// Uses <see cref="MemoryMarshal.CreateSpan{T}(ref T, int)"/> to obtain a writable view of
/// what was passed as a read-only span — the caller's memory is mutated.
/// </remarks>
private static Span<char> Align(ReadOnlySpan<char> Value)
{
var Span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(Value), Value.Length);
Span[0] = '0';
return Span;
}
}