Update BitConverter from CoreFX (dotnet/coreclr#9788)
authorJan Kotas <jkotas@microsoft.com>
Sun, 26 Feb 2017 02:27:32 +0000 (18:27 -0800)
committerGitHub <noreply@github.com>
Sun, 26 Feb 2017 02:27:32 +0000 (18:27 -0800)
* Update BitConverter from CoreFX

Related to dotnet/coreclr#9701

* Use ThrowHelper

Commit migrated from https://github.com/dotnet/coreclr/commit/a5e01900f1b3f58006abb349ca2f96e33da47110

src/coreclr/src/mscorlib/corefx/SR.cs
src/coreclr/src/mscorlib/src/System/BitConverter.cs

index 012bb86..b33bb79 100644 (file)
@@ -815,4 +815,19 @@ internal static class SR
     {
         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"); }
+    }
 }
index 3040216..caa0ae5 100644 (file)
@@ -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 @@ namespace System
         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;
         }
 
@@ -59,7 +45,7 @@ namespace System
 
         // 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);
@@ -72,7 +58,7 @@ namespace System
 
         // 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);
@@ -85,7 +71,7 @@ namespace System
 
         // 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);
@@ -104,7 +90,7 @@ namespace System
             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
@@ -115,7 +101,7 @@ namespace System
             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
@@ -126,12 +112,12 @@ namespace System
             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);
@@ -141,7 +127,7 @@ namespace System
 
         // 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);
@@ -153,59 +139,41 @@ namespace System
         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 @@ namespace System
         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 @@ namespace System
         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 @@ namespace System
         {
             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 @@ namespace System
         {
             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 @@ namespace System
         {
             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 @@ namespace System
         }
 
         // 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 @@ namespace System
         }
 
         // 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 @@ namespace System
                 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);
         }
@@ -466,14 +423,14 @@ namespace System
         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)