// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-**
-** Purpose: Allows developers to view the base data types as
-** an arbitrary array of bits.
-**
-**
-===========================================================*/
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Security;
namespace System
{
- using System;
- using System.Runtime.CompilerServices;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
- using System.Security;
-
// The BitConverter class contains methods for
// converting an array of bytes to one of the base data
// types, as well as for converting a base data type to an
// array of bytes.
- //
- // Only statics, does not need to be marked with the serializable attribute
public static class BitConverter
{
// This field indicates the "endianess" of the architecture.
public static readonly bool IsLittleEndian = true;
#endif
- // Converts a byte into an array of bytes with length one.
+ // Converts a Boolean into an array of bytes with length one.
public static byte[] GetBytes(bool value)
{
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 1);
byte[] r = new byte[1];
- r[0] = (value ? (byte)Boolean.True : (byte)Boolean.False);
+ r[0] = (value ? (byte)1 : (byte)0);
return r;
}
// Converts a short into an array of bytes with length
// two.
- public unsafe static byte[] GetBytes(short value)
+ public static unsafe byte[] GetBytes(short value)
{
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 2);
// Converts an int into an array of bytes with length
// four.
- public unsafe static byte[] GetBytes(int value)
+ public static unsafe byte[] GetBytes(int value)
{
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 4);
// Converts a long into an array of bytes with length
// eight.
- public unsafe static byte[] GetBytes(long value)
+ public static unsafe byte[] GetBytes(long value)
{
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 8);
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 2);
- return GetBytes((short)value);
+ return GetBytes(unchecked((short)value));
}
// Converts an uint into an array of bytes with
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 4);
- return GetBytes((int)value);
+ return GetBytes(unchecked((int)value));
}
// Converts an unsigned long into an array of bytes with
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 8);
- return GetBytes((long)value);
+ return GetBytes(unchecked((long)value));
}
// Converts a float into an array of bytes with length
// four.
- public unsafe static byte[] GetBytes(float value)
+ public static unsafe byte[] GetBytes(float value)
{
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 4);
// Converts a double into an array of bytes with length
// eight.
- public unsafe static byte[] GetBytes(double value)
+ public static unsafe byte[] GetBytes(double value)
{
Contract.Ensures(Contract.Result<byte[]>() != null);
Contract.Ensures(Contract.Result<byte[]>().Length == 8);
public static char ToChar(byte[] value, int startIndex)
{
if (value == null)
- {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- }
-
- if ((uint)startIndex >= value.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
-
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 2)
- {
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
- }
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
- return (char)ToInt16(value, startIndex);
+ return unchecked((char)ToInt16(value, startIndex));
}
// Converts an array of bytes into a short.
public static unsafe short ToInt16(byte[] value, int startIndex)
{
if (value == null)
- {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- }
-
- if ((uint)startIndex >= value.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
-
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 2)
- {
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
- }
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
fixed (byte* pbyte = &value[startIndex])
{
if (startIndex % 2 == 0)
- { // data is aligned
+ {
+ // data is aligned
return *((short*)pbyte);
}
+ else if (IsLittleEndian)
+ {
+ return (short)((*pbyte) | (*(pbyte + 1) << 8));
+ }
else
{
- if (IsLittleEndian)
- {
- return (short)((*pbyte) | (*(pbyte + 1) << 8));
- }
- else
- {
- return (short)((*pbyte << 8) | (*(pbyte + 1)));
- }
+ return (short)((*pbyte << 8) | (*(pbyte + 1)));
}
}
}
public static unsafe int ToInt32(byte[] value, int startIndex)
{
if (value == null)
- {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- }
-
- if ((uint)startIndex >= value.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
-
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 4)
- {
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
- }
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
fixed (byte* pbyte = &value[startIndex])
{
if (startIndex % 4 == 0)
- { // data is aligned
+ {
+ // data is aligned
return *((int*)pbyte);
}
+ else if (IsLittleEndian)
+ {
+ return (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);
+ }
else
{
- if (IsLittleEndian)
- {
- return (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);
- }
- else
- {
- return (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3));
- }
+ return (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3));
}
}
}
public static unsafe long ToInt64(byte[] value, int startIndex)
{
if (value == null)
- {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- }
-
- if ((uint)startIndex >= value.Length)
- {
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
- }
-
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 8)
- {
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
- }
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
fixed (byte* pbyte = &value[startIndex])
{
if (startIndex % 8 == 0)
- { // data is aligned
+ {
+ // data is aligned
return *((long*)pbyte);
}
+ else if (IsLittleEndian)
+ {
+ int i1 = (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);
+ int i2 = (*(pbyte + 4)) | (*(pbyte + 5) << 8) | (*(pbyte + 6) << 16) | (*(pbyte + 7) << 24);
+ return unchecked((uint)i1) | ((long)i2 << 32);
+ }
else
{
- if (IsLittleEndian)
- {
- int i1 = (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);
- int i2 = (*(pbyte + 4)) | (*(pbyte + 5) << 8) | (*(pbyte + 6) << 16) | (*(pbyte + 7) << 24);
- return (uint)i1 | ((long)i2 << 32);
- }
- else
- {
- int i1 = (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3));
- int i2 = (*(pbyte + 4) << 24) | (*(pbyte + 5) << 16) | (*(pbyte + 6) << 8) | (*(pbyte + 7));
- return (uint)i2 | ((long)i1 << 32);
- }
+ int i1 = (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3));
+ int i2 = (*(pbyte + 4) << 24) | (*(pbyte + 5) << 16) | (*(pbyte + 6) << 8) | (*(pbyte + 7));
+ return unchecked((uint)i2) | ((long)i1 << 32);
}
}
}
{
if (value == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- if ((uint)startIndex >= value.Length)
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 2)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
- return (ushort)ToInt16(value, startIndex);
+ return unchecked((ushort)ToInt16(value, startIndex));
}
// Converts an array of bytes into an uint.
{
if (value == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- if ((uint)startIndex >= value.Length)
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 4)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
- return (uint)ToInt32(value, startIndex);
+ return unchecked((uint)ToInt32(value, startIndex));
}
// Converts an array of bytes into an unsigned long.
{
if (value == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- if ((uint)startIndex >= value.Length)
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 8)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
- return (ulong)ToInt64(value, startIndex);
+ return unchecked((ulong)ToInt64(value, startIndex));
}
// Converts an array of bytes into a float.
- unsafe public static float ToSingle(byte[] value, int startIndex)
+ public static unsafe float ToSingle(byte[] value, int startIndex)
{
if (value == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- if ((uint)startIndex >= value.Length)
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 4)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
int val = ToInt32(value, startIndex);
}
// Converts an array of bytes into a double.
- unsafe public static double ToDouble(byte[] value, int startIndex)
+ public static unsafe double ToDouble(byte[] value, int startIndex)
{
if (value == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
- if ((uint)startIndex >= value.Length)
- ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index();
+ if (unchecked((uint)startIndex) >= value.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 8)
- ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
long val = ToInt64(value, startIndex);
}
// Converts an array of bytes into a String.
- public static String ToString(byte[] value, int startIndex, int length)
+ public static string ToString(byte[] value, int startIndex, int length)
{
if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
-
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
if (startIndex < 0 || startIndex >= value.Length && startIndex > 0)
- { // Don't throw for a 0 length array.
- throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
- }
-
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (length < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(length), Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
- }
-
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_GenericPositive);
if (startIndex > value.Length - length)
- {
- throw new ArgumentException(Environment.GetResourceString("Arg_ArrayPlusOffTooSmall"));
- }
+ ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value);
Contract.EndContractBlock();
if (length == 0)
return string.Empty;
}
- if (length > (Int32.MaxValue / 3))
+ if (length > (int.MaxValue / 3))
{
// (Int32.MaxValue / 3) == 715,827,882 Bytes == 699 MB
- throw new ArgumentOutOfRangeException(nameof(length), Environment.GetResourceString("ArgumentOutOfRange_LengthTooLarge", (Int32.MaxValue / 3)));
+ throw new ArgumentOutOfRangeException(nameof(length), SR.Format(SR.ArgumentOutOfRange_LengthTooLarge, (int.MaxValue / 3)));
}
int chArrayLength = length * 3;
+ const int StackLimit = 512; // arbitrary limit to switch from stack to heap allocation
+ unsafe
+ {
+ if (chArrayLength < StackLimit)
+ {
+ char* chArrayPtr = stackalloc char[chArrayLength];
+ return ToString(value, startIndex, length, chArrayPtr, chArrayLength);
+ }
+ else
+ {
+ char[] chArray = new char[chArrayLength];
+ fixed (char* chArrayPtr = &chArray[0])
+ return ToString(value, startIndex, length, chArrayPtr, chArrayLength);
+ }
+ }
+ }
+
+ private static unsafe string ToString(byte[] value, int startIndex, int length, char* chArray, int chArrayLength)
+ {
+ Debug.Assert(length > 0);
+ Debug.Assert(chArrayLength == length * 3);
- char[] chArray = new char[chArrayLength];
- int i = 0;
- int index = startIndex;
- for (i = 0; i < chArrayLength; i += 3)
+ char* p = chArray;
+ int endIndex = startIndex + length;
+ for (int i = startIndex; i < endIndex; i++)
{
- byte b = value[index++];
- chArray[i] = GetHexValue(b / 16);
- chArray[i + 1] = GetHexValue(b % 16);
- chArray[i + 2] = '-';
+ byte b = value[i];
+ *p++ = GetHexValue(b >> 4);
+ *p++ = GetHexValue(b & 0xF);
+ *p++ = '-';
}
// We don't need the last '-' character
- return new String(chArray, 0, chArray.Length - 1);
+ return new string(chArray, 0, chArrayLength - 1);
}
// Converts an array of bytes into a String.
- public static String ToString(byte[] value)
+ public static string ToString(byte[] value)
{
if (value == null)
- throw new ArgumentNullException(nameof(value));
- Contract.Ensures(Contract.Result<String>() != null);
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
+ Contract.Ensures(Contract.Result<string>() != null);
Contract.EndContractBlock();
return ToString(value, 0, value.Length);
}
// Converts an array of bytes into a String.
- public static String ToString(byte[] value, int startIndex)
+ public static string ToString(byte[] value, int startIndex)
{
if (value == null)
- throw new ArgumentNullException(nameof(value));
- Contract.Ensures(Contract.Result<String>() != null);
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
+ Contract.Ensures(Contract.Result<string>() != null);
Contract.EndContractBlock();
return ToString(value, startIndex, value.Length - startIndex);
}
public static bool ToBoolean(byte[] value, int startIndex)
{
if (value == null)
- throw new ArgumentNullException(nameof(value));
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
if (startIndex < 0)
- throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);;
if (startIndex > value.Length - 1)
- throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);; // differs from other overloads, which throw base ArgumentException
Contract.EndContractBlock();
- return (value[startIndex] == 0) ? false : true;
+ return value[startIndex] != 0;
}
public static unsafe long DoubleToInt64Bits(double value)