112 lines
4.1 KiB
C#
112 lines
4.1 KiB
C#
using System;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Benchmark
|
|
{
|
|
public readonly struct Identity
|
|
{
|
|
public Identity(string prefix, int index, int revision)
|
|
{
|
|
Prefix = prefix;
|
|
Index = index;
|
|
Revision = revision;
|
|
}
|
|
|
|
public string Prefix { get; }
|
|
public int Index { get; }
|
|
public int Revision { get; }
|
|
|
|
public static bool TryParse(string value, out Identity identity)
|
|
{
|
|
identity = default;
|
|
var position = value.Length;
|
|
if (!TryGetNumberOld(ref value, null, ref position, out var revision)) return false;
|
|
if (value[position] != '-') return false;
|
|
if (!TryGetNumberOld(ref value, 7, ref position, out var index)) return false;
|
|
if (!TryGetPrefixOld(ref value, ref position, out var prefix)) return false;
|
|
identity = new Identity(prefix, index, revision);
|
|
return true; }
|
|
|
|
public static bool TryParse(Span<char> value, out Identity identity)
|
|
{
|
|
identity = default;
|
|
var position = value.Length;
|
|
if (!TryGetNumber(ref value, null, ref position, out var revision)) return false;
|
|
if (value[position] != '-') return false;
|
|
if (!TryGetNumber(ref value, 7, ref position, out var index)) return false;
|
|
if (!TryGetPrefix(ref value, ref position, out var prefix)) return false;
|
|
identity = new Identity(prefix, index, revision);
|
|
return true;
|
|
}
|
|
|
|
|
|
private static bool TryGetPrefixOld(ref string identity, ref int lastPosition, out string prefix)
|
|
{
|
|
prefix = identity[(lastPosition + 1)..];
|
|
if (prefix.Length < 3) return false;
|
|
for (int i = 0; i < prefix.Length; i++)
|
|
{
|
|
if (prefix[i] < 'A' || prefix[i] > 'Z') return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static bool TryGetPrefix(ref Span<char> identity, ref int lastPosition, out string prefix)
|
|
{
|
|
var span = identity[(lastPosition + 1)..];
|
|
prefix = span.ToString();
|
|
if (span.Length < 3) return false;
|
|
for (int i = 0; i < span.Length; i++)
|
|
{
|
|
if (span[i] < 'A' || span[i] > 'Z') return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static bool TryGetNumberOld(ref string identity, int? exactLength, ref int currentPosition, out int revision)
|
|
{
|
|
revision = 0;
|
|
var start = currentPosition;
|
|
for (currentPosition = start - 1; currentPosition >= 0; currentPosition--)
|
|
{
|
|
var current = identity[currentPosition];
|
|
if (current == '0') continue;
|
|
if (current < '1' || current > '9') break;
|
|
revision += (current - '0') * IntegerPow(10, start - currentPosition - 1);
|
|
}
|
|
|
|
if (exactLength != null && start - (currentPosition + 1) != exactLength) return false;
|
|
return revision != default;
|
|
}
|
|
|
|
private static bool TryGetNumber(ref Span<char> identity, int? exactLength, ref int currentPosition, out int revision)
|
|
{
|
|
revision = 0;
|
|
var start = currentPosition;
|
|
for (currentPosition = start - 1; currentPosition >= 0; currentPosition--)
|
|
{
|
|
var current = identity[currentPosition];
|
|
if (current == '0') continue;
|
|
if (current < '1' || current > '9') break;
|
|
revision += (current - '0') * IntegerPow(10, start - currentPosition - 1);
|
|
}
|
|
|
|
if (exactLength != null && start - (currentPosition + 1) != exactLength) return false;
|
|
return revision != default;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static int IntegerPow(int x, int y)
|
|
{
|
|
if (y == 0) return 1;
|
|
var result = x;
|
|
for (var i = 1; i < y; i++)
|
|
{
|
|
result *= x;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
} |