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 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 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 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; } } }