public static byte[] HexStringToByteArrayChecked(this string s) { s.ValidateNotNull(nameof(s)); foreach (char c in s) { if (!IsHex(c)) { ThrowHelpers.ThrowArgumentException("Must provide a hex string.", nameof(s)); } } return(s.AsSpan().HexStringToByteArrayUnchecked()); bool IsHex(char c) { // at the time of writing, on both x86 and x64, the assembly for this method is 1 // byte smaller than the assembly for 3 range checks, it has 2 fewer conditional // jumps, and the larger 0-9 case is tighter (early return instead of jump to end). if ('0' <= c && c <= '9') { return(true); } c = unchecked ((char)(c & 0xFFDF)); return('A' <= c && c <= 'F'); } }
// A version of the above that does slightly less work for IReadOnlyCollection<T> instances. // Should JIT to something that gets optimized to something that's only marginally different // than the other one, but it's still cheap and easy to do it this way. public static void CopyTo <T>(this IReadOnlyCollection <T> collection, T[] array, int arrayIndex = 0) { collection.ValidateNotNull(nameof(collection)); array.ValidateNotNull(nameof(array)); arrayIndex.ValidateInRange(nameof(arrayIndex), 0, array.Length); if (array.Length - arrayIndex < collection.Count) { ThrowHelpers.ThrowArgumentException("Not enough room", nameof(array)); } foreach (T item in collection) { array[arrayIndex++] = item; } }
public static void CopyHexStringToByteArrayUnchecked(this ReadOnlySpan <char> s, Span <byte> b) { // this isn't really the kind of "check" that "checked / unchecked" was made for... that // was more "throw if this string isn't *actually* a hex string". if (s.Length != b.Length * 2) { ThrowHelpers.ThrowArgumentException("Hex string must have 2 chars for every desired output byte."); } unchecked { for (int i = 0; i < b.Length; ++i) { int hi = s[i * 2] - 65; hi = hi + 10 + ((hi >> 31) & 7); int lo = s[i * 2 + 1] - 65; lo = lo + 10 + ((lo >> 31) & 7) & 0x0f; b[i] = unchecked ((byte)(lo | hi << 4)); } } }
public static void CopyTo <T>(this IEnumerable <T> enumerable, T[] array, int arrayIndex = 0) { enumerable.ValidateNotNull(nameof(enumerable)); array.ValidateNotNull(nameof(array)); arrayIndex.ValidateInRange(nameof(arrayIndex), 0, array.Length); bool prevalidate = enumerable.TryGetCount(out var count); if (prevalidate && array.Length - arrayIndex < count) { ThrowHelpers.ThrowArgumentException("Not enough room", nameof(array)); } foreach (T item in enumerable) { if (!prevalidate && arrayIndex == array.Length) { ThrowHelpers.ThrowArgumentException("Not enough room", nameof(array)); } array[arrayIndex++] = item; } }