[corlib] Optimize EqualityComparer for common value types. Fixes #18400
[mono.git] / mcs / class / corlib / System / BitConverter.cs
1 //
2 // System.BitConverter.cs
3 //
4 // Author:
5 //   Matt Kimball (matt@kimball.net)
6 //
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Text;
31
32 namespace System
33 {
34         public
35         static
36         class BitConverter
37         {
38                 public static readonly bool IsLittleEndian = AmILittleEndian ();
39
40                 static unsafe bool AmILittleEndian ()
41                 {
42                         // binary representations of 1.0:
43                         // big endian:            3f f0 00 00 00 00 00 00
44                         // little endian:         00 00 00 00 00 00 f0 3f
45                         double d = 1.0;
46                         byte *b = (byte*)&d;
47                         return (b [0] == 0);
48                 }
49
50                 public unsafe static long DoubleToInt64Bits (double value)
51                 {
52                         return *(long *) &value;
53                 }
54
55                 public unsafe static double Int64BitsToDouble (long value)
56                 {
57                         return *(double *) &value;
58                 }
59
60                 unsafe static byte[] GetBytes (byte *ptr, int count)
61                 {
62                         byte [] ret = new byte [count];
63
64                         for (int i = 0; i < count; i++) {
65                                 ret [i] = ptr [i];
66                         }
67
68                         return ret;
69                 }
70
71                 unsafe public static byte[] GetBytes (bool value)
72                 {
73                         return GetBytes ((byte *) &value, 1);
74                 }
75
76                 unsafe public static byte[] GetBytes (char value)
77                 {
78                         return GetBytes ((byte *) &value, 2);
79                 }
80
81                 unsafe public static byte[] GetBytes (short value)
82                 {
83                         return GetBytes ((byte *) &value, 2);
84                 }
85
86                 unsafe public static byte[] GetBytes (int value)
87                 {
88                         return GetBytes ((byte *) &value, 4);
89                 }
90
91                 unsafe public static byte[] GetBytes (long value)
92                 {
93                         return GetBytes ((byte *) &value, 8);
94                 }
95
96                 [CLSCompliant (false)]
97                 unsafe public static byte[] GetBytes (ushort value)
98                 {
99                         return GetBytes ((byte *) &value, 2);
100                 }
101
102                 [CLSCompliant (false)]
103                 unsafe public static byte[] GetBytes (uint value)
104                 {
105                         return GetBytes ((byte *) &value, 4);
106                 }
107
108                 [CLSCompliant (false)]
109                 unsafe public static byte[] GetBytes (ulong value)
110                 {
111                         return GetBytes ((byte *) &value, 8);
112                 }
113
114                 unsafe public static byte[] GetBytes (float value)
115                 {
116                         return GetBytes ((byte *) &value, 4);
117                 }
118
119                 unsafe public static byte[] GetBytes (double value)
120                 {
121                         return GetBytes ((byte *) &value, 8);
122                 }
123
124                 unsafe static void PutBytes (byte *dst, byte[] src, int start_index, int count)
125                 {
126                         if (src == null)
127                                 throw new ArgumentNullException ("value");
128
129                         if (start_index < 0 || (start_index > src.Length - 1))
130                                 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
131                                         + " out of range. Must be non-negative and less than the"
132                                         + " size of the collection.");
133
134                         // avoid integer overflow (with large pos/neg start_index values)
135                         if (src.Length - count < start_index)
136                                 throw new ArgumentException ("Destination array is not long"
137                                         + " enough to copy all the items in the collection."
138                                         + " Check array index and length.");
139
140                         for (int i = 0; i < count; i++)
141                                 dst[i] = src[i + start_index];
142                 }
143
144                 unsafe public static bool ToBoolean (byte[] value, int startIndex)
145                 {
146                         if (value == null) 
147                                 throw new ArgumentNullException ("value");
148
149                         if (startIndex < 0 || (startIndex > value.Length - 1))
150                                 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
151                                         + " out of range. Must be non-negative and less than the"
152                                         + " size of the collection.");
153
154                         if (value [startIndex] != 0)
155                                 return true;
156                         
157                         return false;
158                 }
159
160                 unsafe public static char ToChar (byte[] value, int startIndex)
161                 {
162                         char ret;
163
164                         PutBytes ((byte *) &ret, value, startIndex, 2);
165
166                         return ret;
167                 }
168
169                 unsafe public static short ToInt16 (byte[] value, int startIndex)
170                 {
171                         short ret;
172
173                         PutBytes ((byte *) &ret, value, startIndex, 2);
174
175                         return ret;
176                 }
177
178                 unsafe public static int ToInt32 (byte[] value, int startIndex)
179                 {
180                         int ret;
181
182                         PutBytes ((byte *) &ret, value, startIndex, 4);
183
184                         return ret;
185                 }
186
187                 unsafe public static long ToInt64 (byte[] value, int startIndex)
188                 {
189                         long ret;
190
191                         PutBytes ((byte *) &ret, value, startIndex, 8);
192
193                         return ret;
194                 }
195
196                 [CLSCompliant (false)]
197                 unsafe public static ushort ToUInt16 (byte[] value, int startIndex)
198                 {
199                         ushort ret;
200
201                         PutBytes ((byte *) &ret, value, startIndex, 2);
202
203                         return ret;
204                 }
205
206                 [CLSCompliant (false)]
207                 unsafe public static uint ToUInt32 (byte[] value, int startIndex)
208                 {
209                         uint ret;
210
211                         PutBytes ((byte *) &ret, value, startIndex, 4);
212
213                         return ret;
214                 }
215
216                 [CLSCompliant (false)]
217                 unsafe public static ulong ToUInt64 (byte[] value, int startIndex)
218                 {
219                         ulong ret;
220
221                         PutBytes ((byte *) &ret, value, startIndex, 8);
222
223                         return ret;
224                 }
225
226                 unsafe public static float ToSingle (byte[] value, int startIndex)
227                 {
228                         float ret;
229
230                         PutBytes ((byte *) &ret, value, startIndex, 4);
231
232                         return ret;
233                 }
234
235                 unsafe public static double ToDouble (byte[] value, int startIndex)
236                 {
237                         double ret;
238
239                         PutBytes ((byte *) &ret, value, startIndex, 8);
240
241                         return ret;
242                 }
243
244                 public static string ToString (byte[] value)
245                 {
246                         if (value == null)
247                                 throw new ArgumentNullException ("value");
248
249                         return ToString (value, 0, value.Length);
250                 }
251
252                 public static string ToString (byte[] value, int startIndex)
253                 {
254                         if (value == null)
255                                 throw new ArgumentNullException ("value");
256
257                         return ToString (value, startIndex, value.Length - startIndex);
258                 }
259
260                 public static string ToString (byte[] value, int startIndex, int length)
261                 {
262                         if (value == null)
263                                 throw new ArgumentNullException ("byteArray");
264
265                         // The 4th and last clause (start_index >= value.Length)
266                         // was added as a small fix to a very obscure bug.
267                         // It makes a small difference when start_index is
268                         // outside the range and length==0. 
269                         if (startIndex < 0 || startIndex >= value.Length) {
270                                 // special (but valid) case (e.g. new byte [0])
271                                 if ((startIndex == 0) && (value.Length == 0))
272                                         return String.Empty;
273                                 throw new ArgumentOutOfRangeException ("startIndex", "Index was"
274                                         + " out of range. Must be non-negative and less than the"
275                                         + " size of the collection.");
276                         }
277
278                         if (length < 0)
279                                 throw new ArgumentOutOfRangeException ("length",
280                                         "Value must be positive.");
281
282                         // note: re-ordered to avoid possible integer overflow
283                         if (startIndex > value.Length - length)
284                                 throw new ArgumentException ("startIndex + length > value.Length");
285
286                         if (length == 0)
287                                 return string.Empty;
288
289                         StringBuilder builder = new StringBuilder(length * 3 - 1);
290                         int end = startIndex + length;
291
292                         for (int i = startIndex; i < end; i++) {
293                                 if (i > startIndex)
294                                         builder.Append('-');
295                                 
296                                 char high = (char)((value[i] >> 4) & 0x0f);
297                                 char low = (char)(value[i] & 0x0f);
298
299                                 if (high < 10) 
300                                         high += '0';
301                                 else {
302                                         high -= (char) 10;
303                                         high += 'A';
304                                 }
305
306                                 if (low < 10)
307                                         low += '0';
308                                 else {
309                                         low -= (char) 10;
310                                         low += 'A';
311                                 }
312                                 builder.Append(high);
313                                 builder.Append(low);
314                         }
315
316                         return builder.ToString ();
317                 }
318         }
319 }