Char.cs: Implemented IsHighSurrogate and IsLowSurrogate methods.
[mono.git] / mcs / class / corlib / System / Char.cs
1 //
2 // System.Char.cs
3 //
4 // Authors:
5 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
6 //   Miguel de Icaza (miguel@ximian.com)
7 //   Jackson Harper (jackson@ximian.com)
8 //
9 // (C) Ximian, Inc.  http://www.ximian.com
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 // Note about the ToString()'s. ECMA says there's only a ToString() method, 
33 // BUT it is just a wrapper for ToString(null). However there is no other ToString
34 // in the docs. Turning to the NET framework sdk reveals that there is a 
35 // ToString(formatprovider) method, as well as a 'static ToString (char c)' method, 
36 // which appears to just be a Convert.ToString(char c) type method. ECMA also
37 // doesn't list this class as implementing IFormattable.
38
39 using System.Globalization;
40 using System.Runtime.CompilerServices;
41 #if NET_2_0
42 using System.Runtime.InteropServices;
43 #endif
44
45 namespace System
46 {
47         [Serializable]
48 #if NET_2_0
49         [ComVisible (true)]
50         public struct Char : IComparable, IConvertible, IComparable <char>, IEquatable <char>
51 #else
52         public struct Char : IComparable, IConvertible
53 #endif
54         {
55                 public const char MaxValue = (char) 0xffff;
56                 public const char MinValue = (char) 0;
57
58                 internal char m_value;
59
60                 static Char ()
61                 {
62                         unsafe {
63                                 GetDataTablePointers (out category_data, out numeric_data, out numeric_data_values,
64                                         out to_lower_data_low, out to_lower_data_high, out to_upper_data_low, out to_upper_data_high);
65                         }
66                 }
67
68                 private readonly unsafe static byte *category_data;
69                 private readonly unsafe static byte *numeric_data;
70                 private readonly unsafe static double *numeric_data_values;
71                 private readonly unsafe static ushort *to_lower_data_low;
72                 private readonly unsafe static ushort *to_lower_data_high;
73                 private readonly unsafe static ushort *to_upper_data_low;
74                 private readonly unsafe static ushort *to_upper_data_high;
75
76                 [MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
77                 private unsafe static extern void GetDataTablePointers (out byte *category_data,
78                                 out byte *numeric_data, out double *numeric_data_values,
79                                 out ushort *to_lower_data_low, out ushort *to_lower_data_high,
80                                 out ushort *to_upper_data_low, out ushort *to_upper_data_high);
81
82                 public int CompareTo (object v)
83                 {
84                         if (v == null)
85                                 return 1;
86                         
87                         if (!(v is System.Char))
88                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Char"));
89
90                         char xv = (char) v;
91                         if (m_value == xv)
92                                 return 0;
93
94                         if (m_value > xv)
95                                 return 1;
96                         else
97                                 return -1;
98                 }
99
100                 public override bool Equals (object o)
101                 {
102                         if (!(o is Char))
103                                 return false;
104
105                         return ((char) o) == m_value;
106                 }
107
108 #if NET_2_0
109                 public int CompareTo (char value)
110                 {
111                         if (m_value == value)
112                                 return 0;
113
114                         if (m_value > value)
115                                 return 1;
116                         else
117                                 return -1;
118                 }
119
120                 public bool Equals (char value)
121                 {
122                         return m_value == value;
123                 }
124 #endif
125
126                 public override int GetHashCode ()
127                 {
128                         return m_value;
129                 }
130
131                 public static double GetNumericValue (char c)
132                 {
133                         if (c > (char)0x3289) {
134                                 if (c >= (char)0xFF10 && c <= (char)0xFF19)
135                                         return (c - 0xFF10); // Numbers 0-9
136
137                                 // Default not set data
138                                 return -1;
139                         }
140                         else {
141                                 unsafe {
142                                         return numeric_data_values [numeric_data [c]];
143                                 }
144                         }
145                         
146                 }
147
148                 public static double GetNumericValue (string str, int index)
149                 {
150                         if (str == null) 
151                                 throw new ArgumentNullException ("str");
152                         
153                         if (index < 0 || index >= str.Length)
154                                 throw new ArgumentOutOfRangeException (Locale.GetText (
155                                         "The value of index is less than zero, or greater than or equal to the length of str."));       
156                         
157                         return GetNumericValue (str[index]);
158                 }
159
160                 public static UnicodeCategory GetUnicodeCategory (char c)
161                 {
162                         unsafe {
163                                 return (UnicodeCategory)(category_data [c]);
164                         }
165                 }
166
167                 public static UnicodeCategory GetUnicodeCategory (string str, int index)
168                 {
169                         if (str == null) 
170                                 throw new ArgumentNullException ("str");
171                         
172                         if (index < 0 || index >= str.Length)
173                                 throw new ArgumentOutOfRangeException (Locale.GetText (
174                                         "The value of index is less than zero, or greater than or equal to the length of str."));
175                         
176                         return GetUnicodeCategory (str[index]);
177                 }
178
179                 public static bool IsControl (char c)
180                 {
181                         unsafe {
182                                 return (category_data [c] == (byte)UnicodeCategory.Control);
183                         }
184                 }
185
186                 public static bool IsControl (string str, int index)
187                 {
188                         if (str == null) 
189                                 throw new ArgumentNullException ("str");
190                         
191                         if (index < 0 || index >= str.Length)
192                                 throw new ArgumentOutOfRangeException (Locale.GetText (
193                                         "The value of index is less than zero, or greater than or equal to the length of str."));
194                         
195                         return IsControl (str[index]);
196                 }       
197
198                 public static bool IsDigit (char c)
199                 {
200                         unsafe {
201                                 return (category_data [c] == (byte)UnicodeCategory.DecimalDigitNumber);
202                         }
203                 }
204
205                 public static bool IsDigit (string str, int index)
206                 {
207                         if (str == null) 
208                                 throw new ArgumentNullException ("str");
209                         
210                         if (index < 0 || index >= str.Length)
211                                 throw new ArgumentOutOfRangeException (Locale.GetText (
212                                         "The value of index is less than zero, or greater than or equal to the length of str."));
213                         
214                         return IsDigit (str[index]);
215                 }
216
217 #if NET_2_0
218                 public static bool IsHighSurrogate (char c)
219                 {
220                         return c >= '\uD800' && c <= '\uDBFF';
221                 }
222
223                 public static bool IsHighSurrogate (string s, int index)
224                 {
225                         if (s == null) 
226                                 throw new ArgumentNullException ("s");
227                         
228                         if (index < 0 || index >= s.Length)
229                                 throw new ArgumentOutOfRangeException ("index");
230                         
231                         return IsHighSurrogate (s [index]);
232                 }
233 #endif
234
235                 public static bool IsLetter (char c)
236                 {
237                         unsafe {
238                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
239                                 switch (Category) {
240                                 case UnicodeCategory.UppercaseLetter:
241                                 case UnicodeCategory.LowercaseLetter:
242                                 case UnicodeCategory.TitlecaseLetter:
243                                 case UnicodeCategory.ModifierLetter:
244                                 case UnicodeCategory.OtherLetter:
245                                         return true;
246                                 default:
247                                         return false;
248                                 }
249                         }
250                 }
251
252                 public static bool IsLetter (string str, int index)
253                 {
254                         if (str == null) 
255                                 throw new ArgumentNullException ("str");
256                         
257                         if (index < 0 || index >= str.Length)
258                                 throw new ArgumentOutOfRangeException (Locale.GetText (
259                                         "The value of index is less than zero, or greater than or equal to the length of str."));
260                         
261                         return IsLetter (str[index]);
262                 }
263
264                 public static bool IsLetterOrDigit (char c)
265                 {
266                         unsafe {
267                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
268                                 switch (Category) {
269                                 case UnicodeCategory.DecimalDigitNumber:
270                                 case UnicodeCategory.UppercaseLetter:
271                                 case UnicodeCategory.LowercaseLetter:
272                                 case UnicodeCategory.TitlecaseLetter:
273                                 case UnicodeCategory.ModifierLetter:
274                                 case UnicodeCategory.OtherLetter:
275                                         return true;
276                                 default:
277                                         return false;
278                                 }
279                         }
280                 }
281
282                 public static bool IsLetterOrDigit (string str, int index)
283                 {
284                         if (str == null) 
285                                 throw new ArgumentNullException ("str");
286                         
287                         if (index < 0 || index >= str.Length)
288                                 throw new ArgumentOutOfRangeException (Locale.GetText (
289                                         "The value of index is less than zero, or greater than or equal to the length of str."));
290                         
291                         return IsLetterOrDigit (str[index]);
292                 }
293
294                 public static bool IsLower (char c)
295                 {
296                         unsafe {
297                                 return (category_data [c] == (byte)UnicodeCategory.LowercaseLetter);
298                         }
299                 }
300                 
301                 public static bool IsLower (string str, int index)
302                 {
303                         if (str == null) 
304                                 throw new ArgumentNullException ("str");
305                         
306                         if (index < 0 || index >= str.Length)
307                                 throw new ArgumentOutOfRangeException (Locale.GetText (
308                                         "The value of index is less than zero, or greater than or equal to the length of str."));
309                         
310                         return IsLower (str[index]);
311                 }
312
313 #if NET_2_0
314                 public static bool IsLowSurrogate (char c)
315                 {
316                         return c >= '\uDC00' && c <= '\uDFFF';
317                 }
318
319                 public static bool IsLowSurrogate (string s, int index)
320                 {
321                         if (s == null) 
322                                 throw new ArgumentNullException ("s");
323                         
324                         if (index < 0 || index >= s.Length)
325                                 throw new ArgumentOutOfRangeException ("index");
326                         
327                         return IsLowSurrogate (s [index]);
328                 }
329 #endif
330
331                 public static bool IsNumber (char c)
332                 {
333                         unsafe {
334                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
335                                 switch (Category) {
336                                 case UnicodeCategory.DecimalDigitNumber:
337                                 case UnicodeCategory.LetterNumber:
338                                 case UnicodeCategory.OtherNumber:
339                                         return true;
340                                 default:
341                                         return false;
342                                 }
343                         }
344                 }
345                 
346                 public static bool IsNumber (string str, int index)
347                 {
348                         if (str == null) 
349                                 throw new ArgumentNullException ("str");
350                         
351                         if (index < 0 || index >= str.Length)
352                                 throw new ArgumentOutOfRangeException (Locale.GetText (
353                                         "The value of index is less than zero, or greater than or equal to the length of str."));
354                         
355                         return IsNumber (str[index]);
356                 }
357
358                 public static bool IsPunctuation (char c)
359                 {
360                         unsafe {
361                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
362                                 switch (Category) {
363                                 case UnicodeCategory.ConnectorPunctuation:
364                                 case UnicodeCategory.DashPunctuation:
365                                 case UnicodeCategory.OpenPunctuation:
366                                 case UnicodeCategory.ClosePunctuation:
367                                 case UnicodeCategory.InitialQuotePunctuation:
368                                 case UnicodeCategory.FinalQuotePunctuation:
369                                 case UnicodeCategory.OtherPunctuation:
370                                         return true;
371                                 default:
372                                         return false;
373                                 }
374                         }
375                 }
376                 
377                 public static bool IsPunctuation (string str, int index)
378                 {
379                         if (str == null) 
380                                 throw new ArgumentNullException ("str");
381                         
382                         if (index < 0 || index >= str.Length)
383                                 throw new ArgumentOutOfRangeException (Locale.GetText (
384                                         "The value of index is less than zero, or greater than or equal to the length of str."));
385                         
386                         return IsPunctuation (str[index]);
387                 }
388
389                 public static bool IsSeparator (char c)
390                 {
391                         unsafe {
392                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
393                                 switch (Category) {
394                                 case UnicodeCategory.SpaceSeparator:
395                                 case UnicodeCategory.LineSeparator:
396                                 case UnicodeCategory.ParagraphSeparator:
397                                         return true;
398                                 default:
399                                         return false;
400                                 }
401                         }
402                 }
403                 
404                 public static bool IsSeparator (string str, int index)
405                 {
406                         if (str == null) 
407                                 throw new ArgumentNullException ("str");
408                         
409                         if (index < 0 || index >= str.Length)
410                                 throw new ArgumentOutOfRangeException (Locale.GetText (
411                                         "The value of index is less than zero, or greater than or equal to the length of str."));
412                         
413                         return IsSeparator (str[index]);
414                 }
415
416                 public static bool IsSurrogate (char c)
417                 {
418                         unsafe {
419                                 return (category_data [c] == (byte)UnicodeCategory.Surrogate);
420                         }
421                 }
422                 
423                 public static bool IsSurrogate (string str, int index)
424                 {
425                         if (str == null) 
426                                 throw new ArgumentNullException ("str");
427                         
428                         if (index < 0 || index >= str.Length)
429                                 throw new ArgumentOutOfRangeException (Locale.GetText (
430                                         "The value of index is less than zero, or greater than or equal to the length of str."));
431                         
432                         return IsSurrogate (str[index]);
433                 }
434
435                 public static bool IsSymbol (char c)
436                 {
437                         unsafe {
438                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
439                                 switch (Category) {
440                                 case UnicodeCategory.MathSymbol:
441                                 case UnicodeCategory.CurrencySymbol:
442                                 case UnicodeCategory.ModifierSymbol:
443                                 case UnicodeCategory.OtherSymbol:
444                                         return true;
445                                 default:
446                                         return false;
447                                 }
448                         }
449                 }
450                 
451                 public static bool IsSymbol (string str, int index)
452                 {
453                         if (str == null) 
454                                 throw new ArgumentNullException ("str");
455                         
456                         if (index < 0 || index >= str.Length)
457                                 throw new ArgumentOutOfRangeException (Locale.GetText (
458                                         "The value of index is less than zero, or greater than or equal to the length of str."));
459                         
460                         return IsSymbol (str[index]);
461                 }
462
463                 public static bool IsUpper (char c)
464                 {
465                         unsafe {
466                                 return (category_data [c] == (byte)UnicodeCategory.UppercaseLetter);
467                         }
468                 }
469                 
470                 public static bool IsUpper (string str, int index)
471                 {
472                         if (str == null) 
473                                 throw new ArgumentNullException ("str");
474                         
475                         if (index < 0 || index >= str.Length)
476                                 throw new ArgumentOutOfRangeException (Locale.GetText (
477                                         "The value of index is less than zero, or greater than or equal to the length of str."));
478                         
479                         return IsUpper (str[index]);
480                 }
481
482                 public static bool IsWhiteSpace (char c)
483                 {
484                         unsafe {
485                                 if (category_data [c] == (byte)UnicodeCategory.SpaceSeparator)
486                                         return true;
487                                 
488                                 switch (c) {
489                                 case (char)0x9:
490                                 case (char)0x0a:
491                                 case (char)0x0b:
492                                 case (char)0x0c:
493                                 case (char)0x0d:
494                                 case (char)0x85: // NEL 
495                                 case (char)0x2028: // Line Separator
496                                 case (char)0x2029: // Paragraph Separator
497 #if NET_2_0
498                                 case (char)0x205F: // Medium Mathematical Space
499 #endif
500                                         return true;
501                                 default:
502                                         return false;
503                                 }
504                         }
505                 }
506                 
507                 public static bool IsWhiteSpace (string str, int index)
508                 {
509                         if (str == null) 
510                                 throw new ArgumentNullException ("str");
511                         
512                         if (index < 0 || index >= str.Length)
513                                 throw new ArgumentOutOfRangeException (Locale.GetText (
514                                         "The value of index is less than zero, or greater than or equal to the length of str."));
515                         
516                         return IsWhiteSpace (str[index]);
517                 }
518
519                 public static char Parse (string str)
520                 {
521                         if (str == null) 
522                                 throw new ArgumentNullException ("str");
523
524                         if (str.Length != 1)
525                                 throw new FormatException ("string contains more than one character.");
526                         
527                         return str [0];
528                 }
529
530                 public static char ToLower (char c)
531                 {
532                         return ToLower (c, CultureInfo.CurrentCulture);
533                 }
534
535 #if NET_2_0
536                 public static char ToLowerInvariant (char c)
537 #else
538                 internal static char ToLowerInvariant (char c)
539 #endif
540                 {
541                         unsafe {
542                                 if (c <= ((char)0x24cf))
543                                         return (char) to_lower_data_low [c];
544                                 if (c >= ((char)0xff21))
545                                         return (char) to_lower_data_high[c - 0xff21];
546                         }
547                         return c;
548                 }
549
550                 public static char ToLower (char c, CultureInfo culture)
551                 {
552                         if (culture == null)
553                                 throw new ArgumentNullException ("culture");
554                         if (culture.LCID == 0x007F) // Invariant
555                                 return ToLowerInvariant (c);
556
557                         return culture.TextInfo.ToLower (c);
558                 }
559
560                 public static char ToUpper (char c)
561                 {
562                         return ToUpper (c, CultureInfo.CurrentCulture);
563                 }
564
565 #if NET_2_0
566                 public static char ToUpperInvariant (char c)
567 #else
568                 internal static char ToUpperInvariant (char c)
569 #endif
570                 {
571                         unsafe {
572                                 if (c <= ((char)0x24e9))
573                                         return (char) to_upper_data_low [c];
574                                 if (c >= ((char)0xff21))
575                                         return (char) to_upper_data_high [c - 0xff21];
576                         }
577                         return c;
578                 }
579
580                 public static char ToUpper (char c, CultureInfo culture)
581                 {
582                         if (culture == null)
583                                 throw new ArgumentNullException ("culture");
584                         if (culture.LCID == 0x007F) // Invariant
585                                 return ToUpperInvariant (c);
586
587                         return culture.TextInfo.ToUpper (c);
588                 }
589                 
590                 public override string ToString ()
591                 {
592                         // LAMESPEC: ECMA draft lists this as returning ToString (null), 
593                         // However it doesn't list another ToString() method.
594                         return new String (m_value, 1);
595                 }
596
597                 public static string ToString(char c)
598                 {
599                         return new String (c, 1);
600                 }
601
602                 public string ToString (IFormatProvider fp)
603                 {
604                         // LAMESPEC: ECMA draft doesn't say Char implements IFormattable
605                         return new String (m_value, 1);
606                 }
607
608                 // =========== IConvertible Methods =========== //
609                 
610                 public TypeCode GetTypeCode ()
611                 {
612                         return TypeCode.Char;
613                 }         
614
615                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
616                 {
617                         return System.Convert.ToType(m_value, conversionType, provider);
618                 }
619                 
620                 bool IConvertible.ToBoolean (IFormatProvider provider)
621                 {
622                         throw new InvalidCastException();
623                 }
624                 
625                 byte IConvertible.ToByte (IFormatProvider provider)
626                 {
627                         return System.Convert.ToByte(m_value);
628                 }
629                 
630                 char IConvertible.ToChar (IFormatProvider provider)
631                 {
632                         return m_value;
633                 }
634                 
635                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
636                 {
637                         throw new InvalidCastException();
638                 }
639                 
640                 decimal IConvertible.ToDecimal (IFormatProvider provider)
641                 {
642                         throw new InvalidCastException();
643                 }
644                 
645                 double IConvertible.ToDouble (IFormatProvider provider)
646                 {
647                         throw new InvalidCastException();
648                 }
649                 
650                 short IConvertible.ToInt16 (IFormatProvider provider)
651                 {
652                         return System.Convert.ToInt16(m_value);
653                 }
654                 
655                 int IConvertible.ToInt32 (IFormatProvider provider)
656                 {
657                         return System.Convert.ToInt32(m_value);
658                 }
659                 
660                 long IConvertible.ToInt64 (IFormatProvider provider)
661                 {
662                         return System.Convert.ToInt64(m_value);
663                 }
664                 
665                 sbyte IConvertible.ToSByte (IFormatProvider provider)
666                 {
667                         return System.Convert.ToSByte(m_value);
668                 }
669                 
670                 float IConvertible.ToSingle (IFormatProvider provider)
671                 {
672                         throw new InvalidCastException();
673                 }
674                 
675                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
676                 {
677                         return System.Convert.ToUInt16(m_value);
678                 }
679                 
680                 uint IConvertible.ToUInt32 (IFormatProvider provider)
681                 {
682                         return System.Convert.ToUInt32(m_value);
683                 }
684                 
685                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
686                 {
687                         return System.Convert.ToUInt64(m_value);
688                 }
689         }
690 }
691