Skip to main content
Code Review

Return to Question

edited title
Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

handling Handling hexadecimal strings &and byte arrays

swapped hexadecimal literals for binary literals to aid readability
Source Link
Kittoes0124
  • 2k
  • 2
  • 18
  • 24
/// <summary>
/// Represents a single byte in hexadecimal notation.
/// </summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 4)]
public struct Hexadecimal
{
 private const string ALPHABET = "0123456789ABCDEFabcdef";
 private static readonly uint[] m_byteToHexMap = Enumerable
 .Range(0, 256)
 .Select(ai => (((uint)(GetChar((byte)(ai & 0x0000000F0b1111)) << 16)) | GetChar((byte)(ai >> 4))))
 .ToArray();
 private static readonly unsafe Hexadecimal* m_byteToHexMapPointer = ((Hexadecimal*)GCHandle.Alloc(m_byteToHexMap, GCHandleType.Pinned).AddrOfPinnedObject());
 private static readonly byte[] m_hexToByteMap = Enumerable
 .Range(0, 103)
 .Select(ai => ("0123456789ABCDEFabcdef"ALPHABET.Contains((char)ai) ? GetNybble((char)ai) : ((byte)0xFF255)))
 .ToArray();
 private static readonly unsafe byte* m_hexToByteMapPointer = ((byte*)GCHandle.Alloc(m_hexToByteMap, GCHandleType.Pinned).AddrOfPinnedObject());
 [FieldOffset((sizeof(char) * 0))]
 private readonly char m_high;
 [FieldOffset((sizeof(char) * 1))]
 private readonly char m_low;
 /// <summary>
 /// Returns the left symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char High { get => m_high; }
 /// <summary>
 /// Returns the right symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char Low { get => m_low; }
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
 /// <param name="prefixLength">The length of the prefix to be skipped over.</param>
 public static unsafe byte[] GetBytes(string value, int prefixLength) {
 if (prefixLength < 0) {
 throw new ArgumentOutOfRangeException(message: "prefix length cannot be less than zero", paramName: nameof(prefixLength));
 }
 if (value == null.IsNull()) {
 return null;
 }
 var stringLength = checked(value.Length - prefixLength);
 if (stringLength < 1) {
#if (NET40 || NET45 || NET451 || NET452)
 return new byte[0];
#else
 return Array.Empty<byte>();
#endif
 }
 if (stringLength.IsOdd()) {
 throw new ArgumentOutOfRangeException(message: "hexadecimal string cannot have an odd length", paramName: nameof(value));
 }
 var count = (stringLength >> 1);
 var result = new byte[count];
 fixed (char* source = value)
 fixed (byte* target = &result[0]) {
 var m = m_hexToByteMapPointer;
 var s = ((Hexadecimal*)(source + prefixLength));
 var t = target;
 while (0 < count--) {
 var high = (*s).High;
 var low = (*s).Low;
 if (((high < 0x67103) && (low < 0x67103)) && ((m[high] < 0xFF255) && (m[low] < 0xFF255))) {
 *t = ((byte)(((uint)(m[high] << 4)) | m[low]));
 }
 else {
 throw new IndexOutOfRangeException(message: ("invalid hexadecimal string encountered: " + high + low));
 }
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static byte[] GetBytes(string value) {
 return GetBytes(value, 0);
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
 /// <param name="prefix">The prefix that will be appended to the hexadecimal string.</param>
 public static unsafe string GetString(byte[] value, string prefix) {
 if (value == null.IsNull()) {
 return null;
 }
 prefix = (prefix ?? string.Empty);
 if (value.Length == 0IsEmpty()) {
 return prefix;
 }
 var count = value.Length;
 var result = new string('☠', ((count << 1) + prefix.Length));
 fixed (byte* source = &value[0])
 fixed (char* target = result) {
 for (var i = 0; i < prefix.Length; i++) {
 *(target + i) = prefix[i];
 }
 var m = m_byteToHexMapPointer;
 var s = source;
 var t = ((Hexadecimal*)(target + prefix.Length));
 while (0 < count--) {
 *t = m[*s];
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static unsafe string GetString(byte[] value) {
 return GetString(value, string.Empty);
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static char GetChar(byte value) { // https://stackoverflow.com/a/14333437
 return ((char)unchecked((55 + value) + (((value - 10) >> 31) & 0xFFFFFFF90b11111111_11111001)));
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static byte GetNybble(char value) { // https://stackoverflow.com/a/20695932
 if (ALPHABET.Contains(value)) {
 return ((byte)unchecked(((value - 48) + (((57 - value) >> 31) & 0xFFFFFFF90b1001)) & 0x0000000F0b1111));
 }
 else {
 throw new ArgumentOutOfRangeException(message: ("invalid hexadecimal character encountered: " + value), paramName: nameof(value));
 }
 }
}
/// <summary>
/// Represents a single byte in hexadecimal notation.
/// </summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 4)]
public struct Hexadecimal
{
 private static readonly uint[] m_byteToHexMap = Enumerable
 .Range(0, 256)
 .Select(a => (((uint)(GetChar((byte)(a & 0x0000000F)) << 16)) | GetChar((byte)(a >> 4))))
 .ToArray();
 private static readonly unsafe Hexadecimal* m_byteToHexMapPointer = ((Hexadecimal*)GCHandle.Alloc(m_byteToHexMap, GCHandleType.Pinned).AddrOfPinnedObject());
 private static readonly byte[] m_hexToByteMap = Enumerable
 .Range(0, 103)
 .Select(a => ("0123456789ABCDEFabcdef".Contains((char)a) ? GetNybble((char)a) : ((byte)0xFF)))
 .ToArray();
 private static readonly unsafe byte* m_hexToByteMapPointer = ((byte*)GCHandle.Alloc(m_hexToByteMap, GCHandleType.Pinned).AddrOfPinnedObject());
 [FieldOffset((sizeof(char) * 0))]
 private readonly char m_high;
 [FieldOffset((sizeof(char) * 1))]
 private readonly char m_low;
 /// <summary>
 /// Returns the left symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char High => m_high;
 /// <summary>
 /// Returns the right symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char Low => m_low;
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
 /// <param name="prefixLength">The length of the prefix to be skipped over.</param>
 public static unsafe byte[] GetBytes(string value, int prefixLength) {
 if (prefixLength < 0) {
 throw new ArgumentOutOfRangeException(message: "prefix length cannot be less than zero", paramName: nameof(prefixLength));
 }
 if (value == null) {
 return null;
 }
 var stringLength = checked(value.Length - prefixLength);
 if (stringLength < 1) {
#if (NET40 || NET45 || NET451 || NET452)
 return new byte[0];
#else
 return Array.Empty<byte>();
#endif
 }
 if (stringLength.IsOdd()) {
 throw new ArgumentOutOfRangeException(message: "hexadecimal string cannot have an odd length", paramName: nameof(value));
 }
 var count = (stringLength >> 1);
 var result = new byte[count];
 fixed (char* source = value)
 fixed (byte* target = &result[0]) {
 var m = m_hexToByteMapPointer;
 var s = ((Hexadecimal*)(source + prefixLength));
 var t = target;
 while (0 < count--) {
 var high = (*s).High;
 var low = (*s).Low;
 if (((high < 0x67) && (low < 0x67)) && ((m[high] < 0xFF) && (m[low] < 0xFF))) {
 *t = ((byte)(((uint)(m[high] << 4)) | m[low]));
 }
 else {
 throw new IndexOutOfRangeException(message: ("invalid hexadecimal string encountered: " + high + low));
 }
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static byte[] GetBytes(string value) {
 return GetBytes(value, 0);
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
 /// <param name="prefix">The prefix that will be appended to the hexadecimal string.</param>
 public static unsafe string GetString(byte[] value, string prefix) {
 if (value == null) {
 return null;
 }
 prefix = (prefix ?? string.Empty);
 if (value.Length == 0) {
 return prefix;
 }
 var count = value.Length;
 var result = new string('☠', ((count << 1) + prefix.Length));
 fixed (byte* source = &value[0])
 fixed (char* target = result) {
 for (var i = 0; i < prefix.Length; i++) {
 *(target + i) = prefix[i];
 }
 var m = m_byteToHexMapPointer;
 var s = source;
 var t = ((Hexadecimal*)(target + prefix.Length));
 while (0 < count--) {
 *t = m[*s];
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static unsafe string GetString(byte[] value) {
 return GetString(value, string.Empty);
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static char GetChar(byte value) { // https://stackoverflow.com/a/14333437
 return ((char)((55 + value) + (((value - 10) >> 31) & 0xFFFFFFF9)));
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static byte GetNybble(char value) { // https://stackoverflow.com/a/20695932
 return ((byte)(((value - 48) + (((57 - value) >> 31) & 0xFFFFFFF9)) & 0x0000000F));
 }
}
/// <summary>
/// Represents a single byte in hexadecimal notation.
/// </summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 4)]
public struct Hexadecimal
{
 private const string ALPHABET = "0123456789ABCDEFabcdef";
 private static readonly uint[] m_byteToHexMap = Enumerable
 .Range(0, 256)
 .Select(i => (((uint)(GetChar((byte)(i & 0b1111)) << 16)) | GetChar((byte)(i >> 4))))
 .ToArray();
 private static readonly unsafe Hexadecimal* m_byteToHexMapPointer = ((Hexadecimal*)GCHandle.Alloc(m_byteToHexMap, GCHandleType.Pinned).AddrOfPinnedObject());
 private static readonly byte[] m_hexToByteMap = Enumerable
 .Range(0, 103)
 .Select(i => (ALPHABET.Contains((char)i) ? GetNybble((char)i) : ((byte)255)))
 .ToArray();
 private static readonly unsafe byte* m_hexToByteMapPointer = ((byte*)GCHandle.Alloc(m_hexToByteMap, GCHandleType.Pinned).AddrOfPinnedObject());
 [FieldOffset((sizeof(char) * 0))]
 private readonly char m_high;
 [FieldOffset((sizeof(char) * 1))]
 private readonly char m_low;
 /// <summary>
 /// Returns the left symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char High { get => m_high; }
 /// <summary>
 /// Returns the right symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char Low { get => m_low; }
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
 /// <param name="prefixLength">The length of the prefix to be skipped over.</param>
 public static unsafe byte[] GetBytes(string value, int prefixLength) {
 if (prefixLength < 0) {
 throw new ArgumentOutOfRangeException(message: "prefix length cannot be less than zero", paramName: nameof(prefixLength));
 }
 if (value.IsNull()) {
 return null;
 }
 var stringLength = checked(value.Length - prefixLength);
 if (stringLength < 1) {
#if (NET40 || NET45 || NET451 || NET452)
 return new byte[0];
#else
 return Array.Empty<byte>();
#endif
 }
 if (stringLength.IsOdd()) {
 throw new ArgumentOutOfRangeException(message: "hexadecimal string cannot have an odd length", paramName: nameof(value));
 }
 var count = (stringLength >> 1);
 var result = new byte[count];
 fixed (char* source = value)
 fixed (byte* target = &result[0]) {
 var m = m_hexToByteMapPointer;
 var s = ((Hexadecimal*)(source + prefixLength));
 var t = target;
 while (0 < count--) {
 var high = (*s).High;
 var low = (*s).Low;
 if (((high < 103) && (low < 103)) && ((m[high] < 255) && (m[low] < 255))) {
 *t = ((byte)(((uint)(m[high] << 4)) | m[low]));
 }
 else {
 throw new IndexOutOfRangeException(message: ("invalid hexadecimal string encountered: " + high + low));
 }
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static byte[] GetBytes(string value) {
 return GetBytes(value, 0);
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
 /// <param name="prefix">The prefix that will be appended to the hexadecimal string.</param>
 public static unsafe string GetString(byte[] value, string prefix) {
 if (value.IsNull()) {
 return null;
 }
 prefix = (prefix ?? string.Empty);
 if (value.IsEmpty()) {
 return prefix;
 }
 var count = value.Length;
 var result = new string('☠', ((count << 1) + prefix.Length));
 fixed (byte* source = &value[0])
 fixed (char* target = result) {
 for (var i = 0; i < prefix.Length; i++) {
 *(target + i) = prefix[i];
 }
 var m = m_byteToHexMapPointer;
 var s = source;
 var t = ((Hexadecimal*)(target + prefix.Length));
 while (0 < count--) {
 *t = m[*s];
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static unsafe string GetString(byte[] value) {
 return GetString(value, string.Empty);
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static char GetChar(byte value) { // https://stackoverflow.com/a/14333437
 return ((char)unchecked((55 + value) + (((value - 10) >> 31) & 0b11111111_11111001)));
 }
 private static byte GetNybble(char value) { // https://stackoverflow.com/a/20695932
 if (ALPHABET.Contains(value)) {
 return ((byte)unchecked(((value - 48) + (((57 - value) >> 31) & 0b1001)) & 0b1111));
 }
 else {
 throw new ArgumentOutOfRangeException(message: ("invalid hexadecimal character encountered: " + value), paramName: nameof(value));
 }
 }
}
Tweeted twitter.com/StackCodeReview/status/921666746041413632
various bug fixes related to null or empty values
Source Link
Kittoes0124
  • 2k
  • 2
  • 18
  • 24
/// <summary>
/// Represents a single byte in hexadecimal notation.
/// </summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 4)]
public struct Hexadecimal
{
 private static readonly uint[] m_byteToHexMap = Enumerable
 .Range(0, 256)
 .Select(ia => (((uint)(GetChar((byte)(ia & 0x0000000F)) << 16)) | GetChar((byte)(ia >> 4))))
 .ToArray();
 private static readonly unsafe Hexadecimal* m_byteToHexMapPointer = ((Hexadecimal*)GCHandle.Alloc(m_byteToHexMap, GCHandleType.Pinned).AddrOfPinnedObject());
 private static readonly byte[] m_hexToByteMap = Enumerable
 .Range(0, 256103)
 .Select(ia => ("0123456789ABCDEFabcdef".Contains((char)ia) ? GetNybble((char)ia) : ((byte)0xFF)))
 .ToArray();
 private static readonly unsafe byte* m_hexToByteMapPointer = ((byte*)GCHandle.Alloc(m_hexToByteMap, GCHandleType.Pinned).AddrOfPinnedObject());
 [FieldOffset((sizeof(char) * 0))]
 private readonly char m_high;
 [FieldOffset((sizeof(char) * 1))]
 private readonly char m_low;
 /// <summary>
 /// Returns the left symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char High => m_high;
 /// <summary>
 /// Returns the right symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char Low => m_low;
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
 /// <param name="prefixLength">The length of the prefix to be skipped over.</param>
 public static unsafe byte[] GetBytes(string value, int prefixLength) {
 if (prefixLength < 0) {
 throw new ArgumentOutOfRangeException(message: "prefix length cannot be less than zero", paramName: nameof(prefixLength));
 }
 if (value == null) {
 return null;
 }
 var stringLength = checked(value.Length - prefixLength);

 if ((prefixLength < 0) || (prefixLength > stringLength)) {
 throw new ArgumentOutOfRangeException(message: "prefix length cannot be less than zero or greater than hexadecimal string length", paramName: nameof(prefixLength));
 }

 if (stringLength ==< 01) {
#if (NET40 || NET45 || NET451 || NET452)
 return new byte[0];
#else
 return Array.Empty<byte>();
#endif
 }
 if (stringLength.IsOdd()) {
 throw new ArgumentOutOfRangeException(message: "hexadecimal string cannot have an odd length", paramName: nameof(value));
 }
 var count = (stringLength >> 1);
 var result = new byte[count];
 fixed (char* source = value)
 fixed (byte* target = &result[0]) {
 var m = m_hexToByteMapPointer;
 var s = ((Hexadecimal*)(source + prefixLength));
 var t = target;
 while (0 < count--) {
 var high = (*s).High;
 var low = (*s).Low;
 if (((high < 0xFF0x67) && (low < 0xFF0x67)) && ((m[high] < 0xFF) && (m[low] < 0xFF))) {
 *t = ((byte)(((uint)(m[high] << 4)) | m[low]));
 }
 else {
 throw new IndexOutOfRangeException(message: ("invalid hexadecimal string encountered: " + high + low));
 }
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static byte[] GetBytes(string value) {
 return GetBytes(value, 0);
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
 /// <param name="prefix">The prefix that will be appended to the hexadecimal string.</param>
 public static unsafe string GetString(byte[] value, string prefix) {
 if (value == null) {
 return null;
 }
 prefix = (prefix ?? string.Empty);
 if (value.Length == 0) {
 return string.Empty;prefix;
 }

 prefix = (prefix ?? string.Empty);

 var count = value.Length;
 var result = new string('☠', ((count << 1) + prefix.Length));
 fixed (byte* source = &value[0])
 fixed (char* target = result) {
 for (var i = 0; i < prefix.Length; i++) {
 *(target + i) = prefix[i];
 }
 var m = m_byteToHexMapPointer;
 var s = source;
 var t = ((Hexadecimal*)(target + prefix.Length));
 while (0 < count--) {
 *t = m[*s];
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static unsafe string GetString(byte[] value) {
 return GetString(value, string.Empty);
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static char GetChar(byte value) { // https://stackoverflow.com/a/14333437
 return ((char)((55 + value) + (((value - 10) >> 31) & 0xFFFFFFF9)));
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static byte GetNybble(char value) { // https://stackoverflow.com/a/20695932
 return ((byte)(((value - 48) + (((57 - value) >> 31) & 0xFFFFFFF9)) & 0x0000000F));
 }
}
/// <summary>
/// Represents a single byte in hexadecimal notation.
/// </summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 4)]
public struct Hexadecimal
{
 private static readonly uint[] m_byteToHexMap = Enumerable
 .Range(0, 256)
 .Select(i => (((uint)(GetChar((byte)(i & 0x0000000F)) << 16)) | GetChar((byte)(i >> 4))))
 .ToArray();
 private static readonly unsafe Hexadecimal* m_byteToHexMapPointer = ((Hexadecimal*)GCHandle.Alloc(m_byteToHexMap, GCHandleType.Pinned).AddrOfPinnedObject());
 private static readonly byte[] m_hexToByteMap = Enumerable
 .Range(0, 256)
 .Select(i => ("0123456789ABCDEFabcdef".Contains((char)i) ? GetNybble((char)i) : ((byte)0xFF)))
 .ToArray();
 private static readonly unsafe byte* m_hexToByteMapPointer = ((byte*)GCHandle.Alloc(m_hexToByteMap, GCHandleType.Pinned).AddrOfPinnedObject());
 [FieldOffset((sizeof(char) * 0))]
 private readonly char m_high;
 [FieldOffset((sizeof(char) * 1))]
 private readonly char m_low;
 /// <summary>
 /// Returns the left symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char High => m_high;
 /// <summary>
 /// Returns the right symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char Low => m_low;
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
 /// <param name="prefixLength">The length of the prefix to be skipped over.</param>
 public static unsafe byte[] GetBytes(string value, int prefixLength) {
 if (value == null) {
 return null;
 }
 var stringLength = checked(value.Length - prefixLength);

 if ((prefixLength < 0) || (prefixLength > stringLength)) {
 throw new ArgumentOutOfRangeException(message: "prefix length cannot be less than zero or greater than hexadecimal string length", paramName: nameof(prefixLength));
 }

 if (stringLength == 0) {
#if (NET40 || NET45 || NET451 || NET452)
 return new byte[0];
#else
 Array.Empty<byte>();
#endif
 }
 if (stringLength.IsOdd()) {
 throw new ArgumentOutOfRangeException(message: "hexadecimal string cannot have an odd length", paramName: nameof(value));
 }
 var count = (stringLength >> 1);
 var result = new byte[count];
 fixed (char* source = value)
 fixed (byte* target = &result[0]) {
 var m = m_hexToByteMapPointer;
 var s = ((Hexadecimal*)(source + prefixLength));
 var t = target;
 while (0 < count--) {
 var high = (*s).High;
 var low = (*s).Low;
 if (((high < 0xFF) && (low < 0xFF)) && ((m[high] < 0xFF) && (m[low] < 0xFF))) {
 *t = ((byte)(((uint)(m[high] << 4)) | m[low]));
 }
 else {
 throw new IndexOutOfRangeException(message: ("invalid hexadecimal string encountered: " + high + low));
 }
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static byte[] GetBytes(string value) {
 return GetBytes(value, 0);
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
 /// <param name="prefix">The prefix that will be appended to the hexadecimal string.</param>
 public static unsafe string GetString(byte[] value, string prefix) {
 if (value == null) {
 return null;
 }
 if (value.Length == 0) {
 return string.Empty;
 }

 prefix = (prefix ?? string.Empty);

 var count = value.Length;
 var result = new string('☠', ((count << 1) + prefix.Length));
 fixed (byte* source = &value[0])
 fixed (char* target = result) {
 for (var i = 0; i < prefix.Length; i++) {
 *(target + i) = prefix[i];
 }
 var m = m_byteToHexMapPointer;
 var s = source;
 var t = ((Hexadecimal*)(target + prefix.Length));
 while (0 < count--) {
 *t = m[*s];
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static unsafe string GetString(byte[] value) {
 return GetString(value, string.Empty);
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static char GetChar(byte value) { // https://stackoverflow.com/a/14333437
 return ((char)((55 + value) + (((value - 10) >> 31) & 0xFFFFFFF9)));
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static byte GetNybble(char value) { // https://stackoverflow.com/a/20695932
 return ((byte)(((value - 48) + (((57 - value) >> 31) & 0xFFFFFFF9)) & 0x0000000F));
 }
}
/// <summary>
/// Represents a single byte in hexadecimal notation.
/// </summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 4)]
public struct Hexadecimal
{
 private static readonly uint[] m_byteToHexMap = Enumerable
 .Range(0, 256)
 .Select(a => (((uint)(GetChar((byte)(a & 0x0000000F)) << 16)) | GetChar((byte)(a >> 4))))
 .ToArray();
 private static readonly unsafe Hexadecimal* m_byteToHexMapPointer = ((Hexadecimal*)GCHandle.Alloc(m_byteToHexMap, GCHandleType.Pinned).AddrOfPinnedObject());
 private static readonly byte[] m_hexToByteMap = Enumerable
 .Range(0, 103)
 .Select(a => ("0123456789ABCDEFabcdef".Contains((char)a) ? GetNybble((char)a) : ((byte)0xFF)))
 .ToArray();
 private static readonly unsafe byte* m_hexToByteMapPointer = ((byte*)GCHandle.Alloc(m_hexToByteMap, GCHandleType.Pinned).AddrOfPinnedObject());
 [FieldOffset((sizeof(char) * 0))]
 private readonly char m_high;
 [FieldOffset((sizeof(char) * 1))]
 private readonly char m_low;
 /// <summary>
 /// Returns the left symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char High => m_high;
 /// <summary>
 /// Returns the right symbol of this <see cref="Hexadecimal"/> value.
 /// </summary>
 public char Low => m_low;
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
 /// <param name="prefixLength">The length of the prefix to be skipped over.</param>
 public static unsafe byte[] GetBytes(string value, int prefixLength) {
 if (prefixLength < 0) {
 throw new ArgumentOutOfRangeException(message: "prefix length cannot be less than zero", paramName: nameof(prefixLength));
 }
 if (value == null) {
 return null;
 }
 var stringLength = checked(value.Length - prefixLength);
 if (stringLength < 1) {
#if (NET40 || NET45 || NET451 || NET452)
 return new byte[0];
#else
 return Array.Empty<byte>();
#endif
 }
 if (stringLength.IsOdd()) {
 throw new ArgumentOutOfRangeException(message: "hexadecimal string cannot have an odd length", paramName: nameof(value));
 }
 var count = (stringLength >> 1);
 var result = new byte[count];
 fixed (char* source = value)
 fixed (byte* target = &result[0]) {
 var m = m_hexToByteMapPointer;
 var s = ((Hexadecimal*)(source + prefixLength));
 var t = target;
 while (0 < count--) {
 var high = (*s).High;
 var low = (*s).Low;
 if (((high < 0x67) && (low < 0x67)) && ((m[high] < 0xFF) && (m[low] < 0xFF))) {
 *t = ((byte)(((uint)(m[high] << 4)) | m[low]));
 }
 else {
 throw new IndexOutOfRangeException(message: ("invalid hexadecimal string encountered: " + high + low));
 }
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts a hexadecimal string into an array of bytes.
 /// </summary>
 /// <param name="value">The hexadecimal string that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static byte[] GetBytes(string value) {
 return GetBytes(value, 0);
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
 /// <param name="prefix">The prefix that will be appended to the hexadecimal string.</param>
 public static unsafe string GetString(byte[] value, string prefix) {
 if (value == null) {
 return null;
 }
 prefix = (prefix ?? string.Empty);
 if (value.Length == 0) {
 return prefix;
 }
 var count = value.Length;
 var result = new string('☠', ((count << 1) + prefix.Length));
 fixed (byte* source = &value[0])
 fixed (char* target = result) {
 for (var i = 0; i < prefix.Length; i++) {
 *(target + i) = prefix[i];
 }
 var m = m_byteToHexMapPointer;
 var s = source;
 var t = ((Hexadecimal*)(target + prefix.Length));
 while (0 < count--) {
 *t = m[*s];
 s++;
 t++;
 }
 }
 return result;
 }
 /// <summary>
 /// Converts an array of bytes into a hexadecimal string.
 /// </summary>
 /// <param name="value">The array of bytes that will be converted.</param>
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 public static unsafe string GetString(byte[] value) {
 return GetString(value, string.Empty);
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static char GetChar(byte value) { // https://stackoverflow.com/a/14333437
 return ((char)((55 + value) + (((value - 10) >> 31) & 0xFFFFFFF9)));
 }
#if !(NET40)
 [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
 private static byte GetNybble(char value) { // https://stackoverflow.com/a/20695932
 return ((byte)(((value - 48) + (((57 - value) >> 31) & 0xFFFFFFF9)) & 0x0000000F));
 }
}
Source Link
Kittoes0124
  • 2k
  • 2
  • 18
  • 24
Loading
lang-cs

AltStyle によって変換されたページ (->オリジナル) /