Hi,

I did some work on BitConverter.cs which accomplishes the following:

1) Removed all unsafe code, everything is managed now
2) Improved performance of DoubleToInt64Bits and Int64BitsToDouble
pretty significantly, about 2.5x faster. I'd say this is mostly
because this implementation doesn't create an intermediate array when
performing the conversion.
3) Small speed increase to the GetBytes() overloads (1-4%)
4) ToInt16 and ToInt32 takes a 30% and 25% speed hit respectively.
ToInt64 is 7% slower.

I've tested the changes and they pass all the NUnit tests. If someone
on a big endian or middle endian system can test the changes to ensure
that there isn't some hidden gotcha that i didn't notice, that'd be
great.

BitConverter.cs and Main.cs can be compiled together and run as the
testbench program. To testbench different bitconverter methods, just
edit Main.cs and change the method that is called in the loop.

Finally, is this patch worth committing?

Thanks,
Alan.
Index: BitConverter.cs
===================================================================
--- BitConverter.cs	(revision 102166)
+++ BitConverter.cs	(working copy)
@@ -28,6 +28,7 @@
 //
 
 using System.Text;
+using System.Runtime.InteropServices;
 
 namespace System
 {
@@ -44,126 +45,211 @@
 		{
 		}
 #endif
+		[StructLayoutAttribute(LayoutKind.Explicit)]
+		private struct Convert16
+		{
+			[FieldOffsetAttribute(0)]
+			public bool boolean;
+			
+			[FieldOffsetAttribute(0)]
+			public char c;
+			
+			[FieldOffsetAttribute(0)]
+			public short s;
+			
+			[FieldOffsetAttribute(0)]
+			public ushort us;
 
+			[FieldOffsetAttribute(0)]
+			public byte b0;
+			
+			[FieldOffsetAttribute(1)]
+			public byte b1;
+		}
+		
+		[StructLayoutAttribute(LayoutKind.Explicit)]
+		private struct Convert32
+		{
+			[FieldOffsetAttribute(0)]
+			public int i;
+			
+			[FieldOffsetAttribute(0)]
+			public float f;
+			
+			[FieldOffsetAttribute(0)]
+			public uint ui;
+			
+			[FieldOffsetAttribute(0)]
+			public byte b0;
+			
+			[FieldOffsetAttribute(1)]
+			public byte b1;
+			
+			[FieldOffsetAttribute(2)]
+			public byte b2;
+			
+			[FieldOffsetAttribute(3)]
+			public byte b3;
+		}
+	
+		[StructLayoutAttribute(LayoutKind.Explicit)]
+		private struct Convert64
+		{
+			[FieldOffsetAttribute(0)]
+			public double d;
+			
+			[FieldOffsetAttribute(0)]
+			public long l;
+			
+			[FieldOffsetAttribute(0)]
+			public ulong ul;
+			
+			[FieldOffsetAttribute(0)]
+			public byte b0;
+			
+			[FieldOffsetAttribute(1)]
+			public byte b1;
+			
+			[FieldOffsetAttribute(2)]
+			public byte b2;
+			
+			[FieldOffsetAttribute(3)]
+			public byte b3;
+		
+			[FieldOffsetAttribute(4)]
+			public byte b4;
+			
+			[FieldOffsetAttribute(5)]
+			public byte b5;
+			
+			[FieldOffsetAttribute(6)]
+			public byte b6;
+			
+			[FieldOffsetAttribute(7)]
+			public byte b7;
+		}
+		
 		static readonly bool SwappedWordsInDouble = DoubleWordsAreSwapped ();
 		public static readonly bool IsLittleEndian = AmILittleEndian ();
 
-		static unsafe bool AmILittleEndian ()
+		static bool AmILittleEndian ()
 		{
 			// binary representations of 1.0:
 			// big endian: 3f f0 00 00 00 00 00 00
 			// little endian: 00 00 00 00 00 00 f0 3f
 			// arm fpa little endian: 00 00 f0 3f 00 00 00 00
-			double d = 1.0;
-			byte *b = (byte*)&d;
-			return (b [0] == 0);
+			Convert64 c = new Convert64 ();
+			c.d = 1.0;
+			return c.b0 == 0;
 		}
 
-		static unsafe bool DoubleWordsAreSwapped ()
+		static bool DoubleWordsAreSwapped ()
 		{
 			// binary representations of 1.0:
 			// big endian: 3f f0 00 00 00 00 00 00
 			// little endian: 00 00 00 00 00 00 f0 3f
 			// arm fpa little endian: 00 00 f0 3f 00 00 00 00
-			double d = 1.0;
-			byte *b = (byte*)&d;
-			return b [2] == 0xf0;
+			Convert64 c = new Convert64 ();
+			c.d = 1.0;
+			return c.b2 == 0xf0;
 		}
 
 		public static long DoubleToInt64Bits (double value)
 		{
-			return ToInt64 (GetBytes (value), 0);
+			Convert64 c = new Convert64 ();
+			c.d = value;
+			return c.l;
 		}
 
 		public static double Int64BitsToDouble (long value)
 		{
-			return ToDouble (GetBytes (value), 0);
+			Convert64 c = new Convert64 ();
+			c.l = value;
+			return c.d;
 		}
 
 		internal static double InternalInt64BitsToDouble (long value)
 		{
 			return SwappableToDouble (GetBytes (value), 0);
 		}
-		
-		unsafe static byte[] GetBytes (byte *ptr, int count)
-		{
-			byte [] ret = new byte [count];
 
-			for (int i = 0; i < count; i++) {
-				ret [i] = ptr [i];
-			}
-
-			return ret;
-		}
-
-		unsafe public static byte[] GetBytes (bool value)
+		public static byte[] GetBytes (bool value)
 		{
-			return GetBytes ((byte *) &value, 1);
+			return value ? new byte[] { 1 } : new byte[] { 0 };
 		}
 
-		unsafe public static byte[] GetBytes (char value)
+		public static byte[] GetBytes (char value)
 		{
-			return GetBytes ((byte *) &value, 2);
+			Convert16 c = new Convert16 ();
+			c.c = value;
+			return new byte[] { c.b0, c.b1 };
 		}
 
-		unsafe public static byte[] GetBytes (short value)
+		public static byte[] GetBytes (short value)
 		{
-			return GetBytes ((byte *) &value, 2);
+			Convert16 c = new Convert16 ();
+			c.s = value;
+			return new byte[] { c.b0, c.b1 };
 		}
 
-		unsafe public static byte[] GetBytes (int value)
+		public static byte[] GetBytes (int value)
 		{
-			return GetBytes ((byte *) &value, 4);
+			Convert32 c = new Convert32 ();
+			c.i = value;
+			return new byte[] { c.b0, c.b1, c.b2, c.b3 };
 		}
 
-		unsafe public static byte[] GetBytes (long value)
+		public static byte[] GetBytes (long value)
 		{
-			return GetBytes ((byte *) &value, 8);
+			Convert64 c = new Convert64 ();
+			c.l = value;
+			return new byte[] { c.b0, c.b1, c.b2, c.b3, c.b4, c.b5, c.b6, c.b7 };
 		}
 
 		[CLSCompliant (false)]
-		unsafe public static byte[] GetBytes (ushort value)
+		public static byte[] GetBytes (ushort value)
 		{
-			return GetBytes ((byte *) &value, 2);
+			Convert16 c = new Convert16 ();
+			c.us = value;
+			return new byte[] { c.b0, c.b1 };
 		}
 
 		[CLSCompliant (false)]
-		unsafe public static byte[] GetBytes (uint value)
+		public static byte[] GetBytes (uint value)
 		{
-			return GetBytes ((byte *) &value, 4);
+			Convert32 c = new Convert32 ();
+			c.ui = value;
+			return new byte[] { c.b0, c.b1, c.b2, c.b3 };
 		}
 
 		[CLSCompliant (false)]
-		unsafe public static byte[] GetBytes (ulong value)
+		public static byte[] GetBytes (ulong value)
 		{
-			return GetBytes ((byte *) &value, 8);
+			Convert64 c = new Convert64 ();
+			c.ul = value;
+			return new byte[] { c.b0, c.b1, c.b2, c.b3, c.b4, c.b5, c.b6, c.b7 };
 		}
 
-		unsafe public static byte[] GetBytes (float value)
+		public static byte[] GetBytes (float value)
 		{
-			return GetBytes ((byte *) &value, 4);
+			Convert32 c = new Convert32 ();
+			c.f = value;
+			return new byte[] { c.b0, c.b1, c.b2, c.b3 };
 		}
 
-		unsafe public static byte[] GetBytes (double value)
+		public static byte[] GetBytes (double value)
 		{
+			Convert64 c = new Convert64 ();
+			c.d = value;
+			
 			if (SwappedWordsInDouble) {
-				byte[] data = new byte [8];
-				byte *p = (byte*)&value;
-				data [0] = p [4];
-				data [1] = p [5];
-				data [2] = p [6];
-				data [3] = p [7];
-				data [4] = p [0];
-				data [5] = p [1];
-				data [6] = p [2];
-				data [7] = p [3];
-				return data;
+				return new byte[] { c.b4, c.b5, c.b6, c.b7, c.b0, c.b1, c.b2, c.b3 };
 			} else {
-				return GetBytes ((byte *) &value, 8);
+				return new byte[] { c.b0, c.b1, c.b2, c.b3, c.b4, c.b5, c.b6, c.b7 };
 			}
 		}
 
-		unsafe static void PutBytes (byte *dst, byte[] src, int start_index, int count)
+		private static void CheckArguments (byte[] src, int start_index, int count)
 		{
 			if (src == null)
 #if NET_2_0
@@ -182,12 +268,36 @@
 				throw new ArgumentException ("Destination array is not long"
 					+ " enough to copy all the items in the collection."
 					+ " Check array index and length.");
-
-			for (int i = 0; i < count; i++)
-				dst[i] = src[i + start_index];
 		}
+		
+		static void PutBytes16 (ref Convert16 c, byte[] src, int start_index)
+		{
+			CheckArguments (src, start_index, 2);
+			c.b0 = src[start_index];
+			c.b1 = src[start_index + 1];
+		}
+		static void PutBytes32 (ref Convert32 c, byte[] src, int start_index)
+		{
+			CheckArguments (src, start_index, 4);
+			c.b0 = src[start_index];
+			c.b1 = src[start_index + 1];
+			c.b2 = src[start_index + 2];
+			c.b3 = src[start_index + 3];
+		}
+		static void PutBytes64 (ref Convert64 c, byte[] src, int start_index)
+		{
+			CheckArguments (src, start_index, 8);
+			c.b0 = src[start_index];
+			c.b1 = src[start_index + 1];
+			c.b2 = src[start_index + 2];
+			c.b3 = src[start_index + 3];
+			c.b4 = src[start_index + 4];
+			c.b5 = src[start_index + 5];
+			c.b6 = src[start_index + 6];
+			c.b7 = src[start_index + 7];
+		}
 
-		unsafe public static bool ToBoolean (byte[] value, int startIndex)
+		public static bool ToBoolean (byte[] value, int startIndex)
 		{
 			if (value == null) 
 				throw new ArgumentNullException ("value");
@@ -203,87 +313,86 @@
 			return false;
 		}
 
-		unsafe public static char ToChar (byte[] value, int startIndex)
+		public static char ToChar (byte[] value, int startIndex)
 		{
-			char ret;
-
-			PutBytes ((byte *) &ret, value, startIndex, 2);
-
-			return ret;
+			Convert16 c = new Convert16 ();
+			
+			PutBytes16 (ref c, value, startIndex);
+			
+			return c.c;
 		}
 
-		unsafe public static short ToInt16 (byte[] value, int startIndex)
+		public static short ToInt16 (byte[] value, int startIndex)
 		{
-			short ret;
-
-			PutBytes ((byte *) &ret, value, startIndex, 2);
-
-			return ret;
+			Convert16 c = new Convert16 ();
+			
+			PutBytes16 (ref c, value, startIndex);
+			
+			return c.s;
 		}
 
-		unsafe public static int ToInt32 (byte[] value, int startIndex)
+		public static int ToInt32 (byte[] value, int startIndex)
 		{
-			int ret;
-
-			PutBytes ((byte *) &ret, value, startIndex, 4);
-
-			return ret;
+			Convert32 c = new Convert32 ();
+			
+			PutBytes32 (ref c, value, startIndex);
+			
+			return c.i;
 		}
 
-		unsafe public static long ToInt64 (byte[] value, int startIndex)
+		public static long ToInt64 (byte[] value, int startIndex)
 		{
-			long ret;
-
-			PutBytes ((byte *) &ret, value, startIndex, 8);
-
-			return ret;
+			Convert64 c = new Convert64();
+			
+			PutBytes64 (ref c, value, startIndex);
+			
+			return c.l;
 		}
 
 		[CLSCompliant (false)]
-		unsafe public static ushort ToUInt16 (byte[] value, int startIndex)
+		public static ushort ToUInt16 (byte[] value, int startIndex)
 		{
-			ushort ret;
-
-			PutBytes ((byte *) &ret, value, startIndex, 2);
-
-			return ret;
+			Convert16 c = new Convert16 ();
+			
+			PutBytes16 (ref c, value, startIndex);
+			
+			return c.us;
 		}
 
 		[CLSCompliant (false)]
-		unsafe public static uint ToUInt32 (byte[] value, int startIndex)
+		public static uint ToUInt32 (byte[] value, int startIndex)
 		{
-			uint ret;
-
-			PutBytes ((byte *) &ret, value, startIndex, 4);
-
-			return ret;
+			Convert32 c = new Convert32 ();
+			
+			PutBytes32 (ref c, value, startIndex);
+			
+			return c.ui;
 		}
 
 		[CLSCompliant (false)]
-		unsafe public static ulong ToUInt64 (byte[] value, int startIndex)
+		public static ulong ToUInt64 (byte[] value, int startIndex)
 		{
-			ulong ret;
-
-			PutBytes ((byte *) &ret, value, startIndex, 8);
-
-			return ret;
+			Convert64 c = new Convert64 ();
+			
+			PutBytes64 (ref c, value, startIndex);
+			
+			return c.ul;
 		}
 
-		unsafe public static float ToSingle (byte[] value, int startIndex)
+		public static float ToSingle (byte[] value, int startIndex)
 		{
-			float ret;
-
-			PutBytes ((byte *) &ret, value, startIndex, 4);
-
-			return ret;
+			Convert32 c = new Convert32 ();
+			
+			PutBytes32 (ref c, value, startIndex);
+			
+			return c.f;
 		}
 
-		unsafe public static double ToDouble (byte[] value, int startIndex)
+		public static double ToDouble (byte[] value, int startIndex)
 		{
-			double ret;
+			Convert64 c = new Convert64 ();
 
 			if (SwappedWordsInDouble) {
-				byte* p = (byte*)&ret;
 				if (value == null)
 					throw new ArgumentNullException ("value");
 
@@ -297,30 +406,28 @@
 					throw new ArgumentException ("Destination array is not long"
 						+ " enough to copy all the items in the collection."
 						+ " Check array index and length.");
+				
+				c.b0 = value [startIndex + 4];
+				c.b1 = value [startIndex + 5];
+				c.b2 = value [startIndex + 6];
+				c.b3 = value [startIndex + 7];
+				c.b4 = value [startIndex + 0];
+				c.b5 = value [startIndex + 1];
+				c.b6 = value [startIndex + 2];
+				c.b7 = value [startIndex + 3];
 
-				p [0] = value [startIndex + 4];
-				p [1] = value [startIndex + 5];
-				p [2] = value [startIndex + 6];
-				p [3] = value [startIndex + 7];
-				p [4] = value [startIndex + 0];
-				p [5] = value [startIndex + 1];
-				p [6] = value [startIndex + 2];
-				p [7] = value [startIndex + 3];
-
-				return ret;
+				return c.d;
 			}
-
-			PutBytes ((byte *) &ret, value, startIndex, 8);
-
-			return ret;
+			
+			PutBytes64 (ref c, value, startIndex);
+			return c.d;
 		}
 
-		unsafe internal static double SwappableToDouble (byte[] value, int startIndex)
+		internal static double SwappableToDouble (byte[] value, int startIndex)
 		{
-			double ret;
+			Convert64 c = new Convert64 ();
 
 			if (SwappedWordsInDouble) {
-				byte* p = (byte*)&ret;
 				if (value == null)
 					throw new ArgumentNullException ("value");
 
@@ -335,18 +442,17 @@
 						+ " enough to copy all the items in the collection."
 						+ " Check array index and length.");
 
-				p [0] = value [startIndex + 4];
-				p [1] = value [startIndex + 5];
-				p [2] = value [startIndex + 6];
-				p [3] = value [startIndex + 7];
-				p [4] = value [startIndex + 0];
-				p [5] = value [startIndex + 1];
-				p [6] = value [startIndex + 2];
-				p [7] = value [startIndex + 3];
+				c.b0 = value [startIndex + 4];
+				c.b1 = value [startIndex + 5];
+				c.b2 = value [startIndex + 6];
+				c.b3 = value [startIndex + 7];
+				c.b4 = value [startIndex + 0];
+				c.b5 = value [startIndex + 1];
+				c.b6 = value [startIndex + 2];
+				c.b7 = value [startIndex + 3];
 
-				return ret;
+				return c.d;
 			} else if (!IsLittleEndian) {
-				byte* p = (byte*)&ret;
 				if (value == null)
 					throw new ArgumentNullException ("value");
 
@@ -361,21 +467,21 @@
 						+ " enough to copy all the items in the collection."
 						+ " Check array index and length.");
 
-				p [0] = value [startIndex + 7];
-				p [1] = value [startIndex + 6];
-				p [2] = value [startIndex + 5];
-				p [3] = value [startIndex + 4];
-				p [4] = value [startIndex + 3];
-				p [5] = value [startIndex + 2];
-				p [6] = value [startIndex + 1];
-				p [7] = value [startIndex + 0];
+				c.b0 = value [startIndex + 7];
+				c.b1 = value [startIndex + 6];
+				c.b2 = value [startIndex + 5];
+				c.b3 = value [startIndex + 4];
+				c.b4 = value [startIndex + 3];
+				c.b5 = value [startIndex + 2];
+				c.b6 = value [startIndex + 1];
+				c.b7 = value [startIndex + 0];
 
-				return ret;
+				return c.d;
 			}
 
-			PutBytes ((byte *) &ret, value, startIndex, 8);
+			PutBytes64 (ref c, value, startIndex);
 
-			return ret;
+			return c.d;
 		}
 		
 		public static string ToString (byte[] value)
@@ -456,3 +562,4 @@
 		}
 	}
 }
+
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 102166)
+++ ChangeLog	(working copy)
@@ -1,3 +1,8 @@
+2008-05-10  Alan McGovern  <[EMAIL PROTECTED]>
+
+	* BitConverter.cs: Replace unsafe code with safe equivalents. Improves
+	performance of DoubleToInt64Bits and Int64BitsToDouble.
+
 2008-04-26  Zoltan Varga  <[EMAIL PROTECTED]>
 
 	* Array.cs (LastIndexOf): Return GetLowerBound (0) -1 instead of -1.
//
// System.BitConverter.cs
//
// Author:
//   Matt Kimball ([EMAIL PROTECTED])
//
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace Test
{
	public
#if NET_2_0
	static
#else
	sealed
#endif
	class BitConverter
	{
#if !NET_2_0
		private BitConverter ()
		{
		}
#endif
		[StructLayoutAttribute(LayoutKind.Explicit)]
		private struct Convert16
		{
			[FieldOffsetAttribute(0)]
			public bool boolean;
			
			[FieldOffsetAttribute(0)]
			public char c;
			
			[FieldOffsetAttribute(0)]
			public short s;
			
			[FieldOffsetAttribute(0)]
			public ushort us;

			[FieldOffsetAttribute(0)]
			public byte b0;
			
			[FieldOffsetAttribute(1)]
			public byte b1;
		}
		
		[StructLayoutAttribute(LayoutKind.Explicit)]
		private struct Convert32
		{
			[FieldOffsetAttribute(0)]
			public int i;
			
			[FieldOffsetAttribute(0)]
			public float f;
			
			[FieldOffsetAttribute(0)]
			public uint ui;
			
			[FieldOffsetAttribute(0)]
			public byte b0;
			
			[FieldOffsetAttribute(1)]
			public byte b1;
			
			[FieldOffsetAttribute(2)]
			public byte b2;
			
			[FieldOffsetAttribute(3)]
			public byte b3;
		}
	
		[StructLayoutAttribute(LayoutKind.Explicit)]
		private struct Convert64
		{
			[FieldOffsetAttribute(0)]
			public double d;
			
			[FieldOffsetAttribute(0)]
			public long l;
			
			[FieldOffsetAttribute(0)]
			public ulong ul;
			
			[FieldOffsetAttribute(0)]
			public byte b0;
			
			[FieldOffsetAttribute(1)]
			public byte b1;
			
			[FieldOffsetAttribute(2)]
			public byte b2;
			
			[FieldOffsetAttribute(3)]
			public byte b3;
		
			[FieldOffsetAttribute(4)]
			public byte b4;
			
			[FieldOffsetAttribute(5)]
			public byte b5;
			
			[FieldOffsetAttribute(6)]
			public byte b6;
			
			[FieldOffsetAttribute(7)]
			public byte b7;
		}
		
		static readonly bool SwappedWordsInDouble = DoubleWordsAreSwapped ();
		public static readonly bool IsLittleEndian = AmILittleEndian ();

		static bool AmILittleEndian ()
		{
			// binary representations of 1.0:
			// big endian: 3f f0 00 00 00 00 00 00
			// little endian: 00 00 00 00 00 00 f0 3f
			// arm fpa little endian: 00 00 f0 3f 00 00 00 00
			Convert64 c = new Convert64 ();
			c.d = 1.0;
			return c.b0 == 0;
		}

		static bool DoubleWordsAreSwapped ()
		{
			// binary representations of 1.0:
			// big endian: 3f f0 00 00 00 00 00 00
			// little endian: 00 00 00 00 00 00 f0 3f
			// arm fpa little endian: 00 00 f0 3f 00 00 00 00
			Convert64 c = new Convert64 ();
			c.d = 1.0;
			return c.b2 == 0xf0;
		}

		public static long DoubleToInt64Bits (double value)
		{
			Convert64 c = new Convert64 ();
			c.d = value;
			return c.l;
		}

		public static double Int64BitsToDouble (long value)
		{
			Convert64 c = new Convert64 ();
			c.l = value;
			return c.d;
		}

		internal static double InternalInt64BitsToDouble (long value)
		{
			return SwappableToDouble (GetBytes (value), 0);
		}

		public static byte[] GetBytes (bool value)
		{
			return value ? new byte[] { 1 } : new byte[] { 0 };
		}

		public static byte[] GetBytes (char value)
		{
			Convert16 c = new Convert16 ();
			c.c = value;
			return new byte[] { c.b0, c.b1 };
		}

		public static byte[] GetBytes (short value)
		{
			Convert16 c = new Convert16 ();
			c.s = value;
			return new byte[] { c.b0, c.b1 };
		}

		public static byte[] GetBytes (int value)
		{
			Convert32 c = new Convert32 ();
			c.i = value;
			return new byte[] { c.b0, c.b1, c.b2, c.b3 };
		}

		public static byte[] GetBytes (long value)
		{
			Convert64 c = new Convert64 ();
			c.l = value;
			return new byte[] { c.b0, c.b1, c.b2, c.b3, c.b4, c.b5, c.b6, c.b7 };
		}

		[CLSCompliant (false)]
		public static byte[] GetBytes (ushort value)
		{
			Convert16 c = new Convert16 ();
			c.us = value;
			return new byte[] { c.b0, c.b1 };
		}

		[CLSCompliant (false)]
		public static byte[] GetBytes (uint value)
		{
			Convert32 c = new Convert32 ();
			c.ui = value;
			return new byte[] { c.b0, c.b1, c.b2, c.b3 };
		}

		[CLSCompliant (false)]
		public static byte[] GetBytes (ulong value)
		{
			Convert64 c = new Convert64 ();
			c.ul = value;
			return new byte[] { c.b0, c.b1, c.b2, c.b3, c.b4, c.b5, c.b6, c.b7 };
		}

		public static byte[] GetBytes (float value)
		{
			Convert32 c = new Convert32 ();
			c.f = value;
			return new byte[] { c.b0, c.b1, c.b2, c.b3 };
		}

		public static byte[] GetBytes (double value)
		{
			Convert64 c = new Convert64 ();
			c.d = value;
			
			if (SwappedWordsInDouble) {
				return new byte[] { c.b4, c.b5, c.b6, c.b7, c.b0, c.b1, c.b2, c.b3 };
			} else {
				return new byte[] { c.b0, c.b1, c.b2, c.b3, c.b4, c.b5, c.b6, c.b7 };
			}
		}

		private static void CheckArguments (byte[] src, int start_index, int count)
		{
			if (src == null)
#if NET_2_0
				throw new ArgumentNullException ("value");
#else
				throw new ArgumentNullException ("byteArray");
#endif

			if (start_index < 0 || (start_index > src.Length - 1))
				throw new ArgumentOutOfRangeException ("startIndex", "Index was"
					+ " out of range. Must be non-negative and less than the"
					+ " size of the collection.");

			// avoid integer overflow (with large pos/neg start_index values)
			if (src.Length - count < start_index)
				throw new ArgumentException ("Destination array is not long"
					+ " enough to copy all the items in the collection."
					+ " Check array index and length.");
		}
		
		static void PutBytes16 (ref Convert16 c, byte[] src, int start_index)
		{
			CheckArguments (src, start_index, 2);
			c.b0 = src[start_index];
			c.b1 = src[start_index + 1];
		}
		static void PutBytes32 (ref Convert32 c, byte[] src, int start_index)
		{
			CheckArguments (src, start_index, 4);
			c.b0 = src[start_index];
			c.b1 = src[start_index + 1];
			c.b2 = src[start_index + 2];
			c.b3 = src[start_index + 3];
		}
		static void PutBytes64 (ref Convert64 c, byte[] src, int start_index)
		{
			CheckArguments (src, start_index, 8);
			c.b0 = src[start_index];
			c.b1 = src[start_index + 1];
			c.b2 = src[start_index + 2];
			c.b3 = src[start_index + 3];
			c.b4 = src[start_index + 4];
			c.b5 = src[start_index + 5];
			c.b6 = src[start_index + 6];
			c.b7 = src[start_index + 7];
		}

		public static bool ToBoolean (byte[] value, int startIndex)
		{
			if (value == null) 
				throw new ArgumentNullException ("value");

			if (startIndex < 0 || (startIndex > value.Length - 1))
				throw new ArgumentOutOfRangeException ("startIndex", "Index was"
					+ " out of range. Must be non-negative and less than the"
					+ " size of the collection.");

			if (value [startIndex] != 0)
				return true;
			
			return false;
		}

		public static char ToChar (byte[] value, int startIndex)
		{
			Convert16 c = new Convert16 ();
			
			PutBytes16 (ref c, value, startIndex);
			
			return c.c;
		}

		public static short ToInt16 (byte[] value, int startIndex)
		{
			Convert16 c = new Convert16 ();
			
			PutBytes16 (ref c, value, startIndex);
			
			return c.s;
		}

		public static int ToInt32 (byte[] value, int startIndex)
		{
			Convert32 c = new Convert32 ();
			
			PutBytes32 (ref c, value, startIndex);
			
			return c.i;
		}

		public static long ToInt64 (byte[] value, int startIndex)
		{
			Convert64 c = new Convert64();
			
			PutBytes64 (ref c, value, startIndex);
			
			return c.l;
		}

		[CLSCompliant (false)]
		public static ushort ToUInt16 (byte[] value, int startIndex)
		{
			Convert16 c = new Convert16 ();
			
			PutBytes16 (ref c, value, startIndex);
			
			return c.us;
		}

		[CLSCompliant (false)]
		public static uint ToUInt32 (byte[] value, int startIndex)
		{
			Convert32 c = new Convert32 ();
			
			PutBytes32 (ref c, value, startIndex);
			
			return c.ui;
		}

		[CLSCompliant (false)]
		public static ulong ToUInt64 (byte[] value, int startIndex)
		{
			Convert64 c = new Convert64 ();
			
			PutBytes64 (ref c, value, startIndex);
			
			return c.ul;
		}

		public static float ToSingle (byte[] value, int startIndex)
		{
			Convert32 c = new Convert32 ();
			
			PutBytes32 (ref c, value, startIndex);
			
			return c.f;
		}

		public static double ToDouble (byte[] value, int startIndex)
		{
			Convert64 c = new Convert64 ();

			if (SwappedWordsInDouble) {
				if (value == null)
					throw new ArgumentNullException ("value");

				if (startIndex < 0 || (startIndex > value.Length - 1))
					throw new ArgumentOutOfRangeException ("startIndex", "Index was"
						+ " out of range. Must be non-negative and less than the"
						+ " size of the collection.");

				// avoid integer overflow (with large pos/neg start_index values)
				if (value.Length - 8 < startIndex)
					throw new ArgumentException ("Destination array is not long"
						+ " enough to copy all the items in the collection."
						+ " Check array index and length.");
				
				c.b0 = value [startIndex + 4];
				c.b1 = value [startIndex + 5];
				c.b2 = value [startIndex + 6];
				c.b3 = value [startIndex + 7];
				c.b4 = value [startIndex + 0];
				c.b5 = value [startIndex + 1];
				c.b6 = value [startIndex + 2];
				c.b7 = value [startIndex + 3];

				return c.d;
			}
			
			PutBytes64 (ref c, value, startIndex);
			return c.d;
		}

		internal static double SwappableToDouble (byte[] value, int startIndex)
		{
			Convert64 c = new Convert64 ();

			if (SwappedWordsInDouble) {
				if (value == null)
					throw new ArgumentNullException ("value");

				if (startIndex < 0 || (startIndex > value.Length - 1))
					throw new ArgumentOutOfRangeException ("startIndex", "Index was"
						+ " out of range. Must be non-negative and less than the"
						+ " size of the collection.");

				// avoid integer overflow (with large pos/neg start_index values)
				if (value.Length - 8 < startIndex)
					throw new ArgumentException ("Destination array is not long"
						+ " enough to copy all the items in the collection."
						+ " Check array index and length.");

				c.b0 = value [startIndex + 4];
				c.b1 = value [startIndex + 5];
				c.b2 = value [startIndex + 6];
				c.b3 = value [startIndex + 7];
				c.b4 = value [startIndex + 0];
				c.b5 = value [startIndex + 1];
				c.b6 = value [startIndex + 2];
				c.b7 = value [startIndex + 3];

				return c.d;
			} else if (!IsLittleEndian) {
				if (value == null)
					throw new ArgumentNullException ("value");

				if (startIndex < 0 || (startIndex > value.Length - 1))
					throw new ArgumentOutOfRangeException ("startIndex", "Index was"
						+ " out of range. Must be non-negative and less than the"
						+ " size of the collection.");

				// avoid integer overflow (with large pos/neg start_index values)
				if (value.Length - 8 < startIndex)
					throw new ArgumentException ("Destination array is not long"
						+ " enough to copy all the items in the collection."
						+ " Check array index and length.");

				c.b0 = value [startIndex + 7];
				c.b1 = value [startIndex + 6];
				c.b2 = value [startIndex + 5];
				c.b3 = value [startIndex + 4];
				c.b4 = value [startIndex + 3];
				c.b5 = value [startIndex + 2];
				c.b6 = value [startIndex + 1];
				c.b7 = value [startIndex + 0];

				return c.d;
			}

			PutBytes64 (ref c, value, startIndex);

			return c.d;
		}
		
		public static string ToString (byte[] value)
		{
			if (value == null)
				throw new ArgumentNullException ("value");

			return ToString (value, 0, value.Length);
		}

		public static string ToString (byte[] value, int startIndex)
		{
			if (value == null)
				throw new ArgumentNullException ("value");

			return ToString (value, startIndex, value.Length - startIndex);
		}

		public static string ToString (byte[] value, int startIndex, int length)
		{
			if (value == null)
				throw new ArgumentNullException ("byteArray");

			// The 4th and last clause (start_index >= value.Length)
			// was added as a small fix to a very obscure bug.
			// It makes a small difference when start_index is
			// outside the range and length==0. 
			if (startIndex < 0 || startIndex >= value.Length) {
#if NET_2_0
				// special (but valid) case (e.g. new byte [0])
				if ((startIndex == 0) && (value.Length == 0))
					return String.Empty;
#endif
				throw new ArgumentOutOfRangeException ("startIndex", "Index was"
					+ " out of range. Must be non-negative and less than the"
					+ " size of the collection.");
			}

			if (length < 0)
				throw new ArgumentOutOfRangeException ("length",
					"Value must be positive.");

			// note: re-ordered to avoid possible integer overflow
			if (startIndex > value.Length - length)
				throw new ArgumentException ("startIndex + length > value.Length");

			if (length == 0)
				return string.Empty;

			StringBuilder builder = new StringBuilder(length * 3 - 1);
			int end = startIndex + length;

			for (int i = startIndex; i < end; i++) {
				if (i > startIndex)
					builder.Append('-');
				
				char high = (char)((value[i] >> 4) & 0x0f);
				char low = (char)(value[i] & 0x0f);

				if (high < 10) 
					high += '0';
				else {
					high -= (char) 10;
					high += 'A';
				}

				if (low < 10)
					low += '0';
				else {
					low -= (char) 10;
					low += 'A';
				}
				builder.Append(high);
				builder.Append(low);
			}

			return builder.ToString ();
		}
	}
}

using System;
using System.Text;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
namespace Test
{
	public class MainClass
	{
		static void Main (string[] args)
		{
			while (true)
			{
				byte[] val = new byte[] { 5,6,2,1,6,4,3,6,8,6,4,2,4,6};
				long start = Environment.TickCount;
				for (long i=0; i < 50000000; i++)
					Test.BitConverter.ToInt64 (val, 0);
				Console.WriteLine ("New: {0}", Environment.TickCount - start);
				
				start = Environment.TickCount;
				for (long i=0; i < 50000000; i++)
					System.BitConverter.ToInt64 (val, 0);
				Console.WriteLine ("Old: {0}", Environment.TickCount - start);
			}
		}
	}
}
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to