< Summary

Information
Class: NostrSure.Domain.Services.OptimizedHexConverter
Assembly: NostrSure.Domain
File(s): /home/runner/work/NostrSure/NostrSure/NostrSure.Domain/Services/OptimizedHexConverter.cs
Line coverage
90%
Covered lines: 46
Uncovered lines: 5
Coverable lines: 51
Total lines: 88
Line coverage: 90.1%
Branch coverage
75%
Covered branches: 30
Total branches: 40
Branch coverage: 75%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%66100%
TryParseHex(...)68.18%232286.36%
ParseHex(...)80%101091.66%
ParseHex(...)50%2280%

File(s)

/home/runner/work/NostrSure/NostrSure/NostrSure.Domain/Services/OptimizedHexConverter.cs

#LineLine coverage
 1using NostrSure.Domain.Validation;
 2
 3namespace NostrSure.Domain.Services;
 4
 5/// <summary>
 6/// High-performance hexadecimal converter using lookup tables for optimal speed
 7/// </summary>
 8public sealed class OptimizedHexConverter : IHexConverter
 9{
 10    // Precomputed lookup table for hex character to byte conversion
 111    private static readonly byte[] HexLookup = new byte[128];
 12
 13    static OptimizedHexConverter()
 114    {
 15        // Initialize lookup table
 25816        for (int i = 0; i < HexLookup.Length; i++)
 12817            HexLookup[i] = 255; // Invalid marker
 18
 19        // Set valid hex characters
 2220        for (int i = 0; i <= 9; i++)
 1021            HexLookup['0' + i] = (byte)i;
 22
 1423        for (int i = 0; i <= 5; i++)
 624        {
 625            HexLookup['A' + i] = (byte)(10 + i);
 626            HexLookup['a' + i] = (byte)(10 + i);
 627        }
 128    }
 29
 30    public bool TryParseHex(ReadOnlySpan<char> hex, Span<byte> bytes, out int bytesWritten)
 33031    {
 33032        bytesWritten = 0;
 33
 34        // Handle 0x prefix
 33035        if (hex.Length >= 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X'))
 036            hex = hex[2..];
 37
 33038        if (hex.Length % 2 != 0)
 139            return false;
 40
 32941        if (bytes.Length < hex.Length / 2)
 042            return false;
 43
 2813844        for (int i = 0; i < hex.Length; i += 2)
 1374345        {
 1374346            var c1 = (int)hex[i];
 1374347            var c2 = (int)hex[i + 1];
 48
 1374349            if (c1 >= HexLookup.Length || c2 >= HexLookup.Length)
 050                return false;
 51
 1374352            var b1 = HexLookup[c1];
 1374353            var b2 = HexLookup[c2];
 54
 1374355            if (b1 == 255 || b2 == 255)
 356                return false;
 57
 1374058            bytes[bytesWritten++] = (byte)((b1 << 4) | b2);
 1374059        }
 60
 32661        return true;
 33062    }
 63
 64    public byte[] ParseHex(ReadOnlySpan<char> hex)
 365    {
 366        var expectedLength = hex.Length;
 67
 68        // Handle 0x prefix
 369        if (hex.Length >= 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X'))
 170        {
 171            hex = hex[2..];
 172            expectedLength -= 2;
 173        }
 74
 375        var bytes = new byte[expectedLength / 2];
 376        if (!TryParseHex(hex, bytes, out _))
 077            throw new ArgumentException("Invalid hex string", nameof(hex));
 378        return bytes;
 379    }
 80
 81    public byte[] ParseHex(string hex)
 382    {
 383        if (string.IsNullOrEmpty(hex))
 084            return Array.Empty<byte>();
 85
 386        return ParseHex(hex.AsSpan());
 387    }
 88}