diff --git a/src/mscorlib/corefx/SR.cs b/src/mscorlib/corefx/SR.cs index 012bb86a6680..b33bb795662b 100644 --- a/src/mscorlib/corefx/SR.cs +++ b/src/mscorlib/corefx/SR.cs @@ -815,4 +815,19 @@ internal static string Arg_UnauthorizedAccessException { get { return Environment.GetResourceString("Arg_UnauthorizedAccessException"); } } + + internal static string ArgumentOutOfRange_GenericPositive + { + get { return Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"); } + } + + internal static string ArgumentOutOfRange_LengthTooLarge + { + get { return Environment.GetResourceString("ArgumentOutOfRange_LengthTooLarge"); } + } + + internal static string Arg_ArrayPlusOffTooSmall + { + get { return Environment.GetResourceString("Arg_ArrayPlusOffTooSmall"); } + } } diff --git a/src/mscorlib/src/System/BitConverter.cs b/src/mscorlib/src/System/BitConverter.cs index 304021674af0..caa0ae5c88c5 100644 --- a/src/mscorlib/src/System/BitConverter.cs +++ b/src/mscorlib/src/System/BitConverter.cs @@ -2,30 +2,16 @@ // 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. @@ -37,14 +23,14 @@ public static class BitConverter 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() != null); Contract.Ensures(Contract.Result().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; } @@ -59,7 +45,7 @@ public static byte[] GetBytes(char value) // 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() != null); Contract.Ensures(Contract.Result().Length == 2); @@ -72,7 +58,7 @@ public unsafe static byte[] GetBytes(short value) // 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() != null); Contract.Ensures(Contract.Result().Length == 4); @@ -85,7 +71,7 @@ public unsafe static byte[] GetBytes(int value) // 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() != null); Contract.Ensures(Contract.Result().Length == 8); @@ -104,7 +90,7 @@ public static byte[] GetBytes(ushort value) Contract.Ensures(Contract.Result() != null); Contract.Ensures(Contract.Result().Length == 2); - return GetBytes((short)value); + return GetBytes(unchecked((short)value)); } // Converts an uint into an array of bytes with @@ -115,7 +101,7 @@ public static byte[] GetBytes(uint value) Contract.Ensures(Contract.Result() != null); Contract.Ensures(Contract.Result().Length == 4); - return GetBytes((int)value); + return GetBytes(unchecked((int)value)); } // Converts an unsigned long into an array of bytes with @@ -126,12 +112,12 @@ public static byte[] GetBytes(ulong value) Contract.Ensures(Contract.Result() != null); Contract.Ensures(Contract.Result().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() != null); Contract.Ensures(Contract.Result().Length == 4); @@ -141,7 +127,7 @@ public unsafe static byte[] GetBytes(float value) // 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() != null); Contract.Ensures(Contract.Result().Length == 8); @@ -153,59 +139,41 @@ public unsafe static byte[] GetBytes(double value) 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))); } } } @@ -214,37 +182,27 @@ public static unsafe short ToInt16(byte[] value, int startIndex) 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)); } } } @@ -253,41 +211,31 @@ public static unsafe int ToInt32(byte[] value, int startIndex) 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); } } } @@ -300,13 +248,13 @@ public static ushort ToUInt16(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 (ushort)ToInt16(value, startIndex); + return unchecked((ushort)ToInt16(value, startIndex)); } // Converts an array of bytes into an uint. @@ -316,13 +264,13 @@ public static uint ToUInt32(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(); - return (uint)ToInt32(value, startIndex); + return unchecked((uint)ToInt32(value, startIndex)); } // Converts an array of bytes into an unsigned long. @@ -332,24 +280,24 @@ public static ulong ToUInt64(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(); - 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); @@ -357,14 +305,14 @@ unsafe public static float ToSingle(byte[] value, int 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); @@ -383,27 +331,16 @@ private static char GetHexValue(int i) } // 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) @@ -411,45 +348,65 @@ public static String ToString(byte[] value, int startIndex, int length) 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() != null); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); + Contract.Ensures(Contract.Result() != 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() != null); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); + Contract.Ensures(Contract.Result() != null); Contract.EndContractBlock(); return ToString(value, startIndex, value.Length - startIndex); } @@ -466,14 +423,14 @@ public static String ToString(byte[] value, int 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)