Removed useless [CLSCompliant(false)]
[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 // (C) 2004 Novell, Inc (http://www.novell.com)
11 //
12
13 // Note about the ToString()'s. ECMA says there's only a ToString() method, 
14 // BUT it is just a wrapper for ToString(null). However there is no other ToString
15 // in the docs. Turning to the NET framework sdk reveals that there is a 
16 // ToString(formatprovider) method, as well as a 'static ToString (char c)' method, 
17 // which appears to just be a Convert.ToString(char c) type method. ECMA also
18 // doesn't list this class as implementing IFormattable.
19
20 using System; 
21 using System.Globalization;
22 using System.Runtime.CompilerServices;
23
24 namespace System
25 {
26         [Serializable]
27         public struct Char : IComparable, IConvertible
28         {
29                 public const char MaxValue = (char) 0xffff;
30                 public const char MinValue = (char) 0;
31
32                 internal char m_value;
33
34                 static Char ()
35                 {
36                         unsafe {
37                                 GetDataTablePointers (out category_data, out numeric_data, out numeric_data_values,
38                                         out to_lower_data_low, out to_lower_data_high, out to_upper_data_low, out to_upper_data_high);
39                         }
40                 }
41
42                 private readonly unsafe static byte *category_data;
43                 private readonly unsafe static byte *numeric_data;
44                 private readonly unsafe static double *numeric_data_values;
45                 private readonly unsafe static ushort *to_lower_data_low;
46                 private readonly unsafe static ushort *to_lower_data_high;
47                 private readonly unsafe static ushort *to_upper_data_low;
48                 private readonly unsafe static ushort *to_upper_data_high;
49
50                 [MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
51                 private unsafe static extern void GetDataTablePointers (out byte *category_data,
52                                 out byte *numeric_data, out double *numeric_data_values,
53                                 out ushort *to_lower_data_low, out ushort *to_lower_data_high,
54                                 out ushort *to_upper_data_low, out ushort *to_upper_data_high);
55
56                 public int CompareTo (object v)
57                 {
58                         if (v == null)
59                                 return 1;
60                         
61                         if (!(v is System.Char))
62                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Char"));
63
64                         char xv = (char) v;
65                         if (m_value == xv)
66                                 return 0;
67
68                         if (m_value > xv)
69                                 return 1;
70                         else
71                                 return -1;
72                 }
73
74                 public override bool Equals (object o)
75                 {
76                         if (!(o is Char))
77                                 return false;
78
79                         return ((Char) o).m_value == m_value;
80                 }
81
82                 public override int GetHashCode ()
83                 {
84                         return m_value;
85                 }
86
87                 public static double GetNumericValue (char c)
88                 {
89                         if (c > (char)0x3289) {
90                                 if (c >= (char)0xFF10 && c <= (char)0xFF19)
91                                         return (c - 0xFF10); // Numbers 0-9
92
93                                 // Default not set data
94                                 return -1;
95                         }
96                         else {
97                                 unsafe {
98                                         return numeric_data_values [numeric_data [c]];
99                                 }
100                         }
101                         
102                 }
103
104                 public static double GetNumericValue (string str, int index)
105                 {
106                         if (str == null) 
107                                 throw new ArgumentNullException ("str");
108                         
109                         if (index < 0 || index >= str.Length)
110                                 throw new ArgumentOutOfRangeException (Locale.GetText (
111                                         "The value of index is less than zero, or greater than or equal to the length of str."));       
112                         
113                         return GetNumericValue (str[index]);
114                 }
115
116                 public static UnicodeCategory GetUnicodeCategory (char c)
117                 {
118                         unsafe {
119                                 return (UnicodeCategory)(category_data [c]);
120                         }
121                 }
122
123                 public static UnicodeCategory GetUnicodeCategory (string str, int index)
124                 {
125                         if (str == null) 
126                                 throw new ArgumentNullException ("str");
127                         
128                         if (index < 0 || index >= str.Length)
129                                 throw new ArgumentOutOfRangeException (Locale.GetText (
130                                         "The value of index is less than zero, or greater than or equal to the length of str."));
131                         
132                         return GetUnicodeCategory (str[index]);
133                 }
134
135                 public static bool IsControl (char c)
136                 {
137                         unsafe {
138                                 return (category_data [c] == (byte)UnicodeCategory.Control);
139                         }
140                 }
141
142                 public static bool IsControl (string str, int index)
143                 {
144                         if (str == null) 
145                                 throw new ArgumentNullException ("str");
146                         
147                         if (index < 0 || index >= str.Length)
148                                 throw new ArgumentOutOfRangeException (Locale.GetText (
149                                         "The value of index is less than zero, or greater than or equal to the length of str."));
150                         
151                         return IsControl (str[index]);
152                 }       
153
154                 public static bool IsDigit (char c)
155                 {
156                         unsafe {
157                                 return (category_data [c] == (byte)UnicodeCategory.DecimalDigitNumber);
158                         }
159                 }
160
161                 public static bool IsDigit (string str, int index)
162                 {
163                         if (str == null) 
164                                 throw new ArgumentNullException ("str");
165                         
166                         if (index < 0 || index >= str.Length)
167                                 throw new ArgumentOutOfRangeException (Locale.GetText (
168                                         "The value of index is less than zero, or greater than or equal to the length of str."));
169                         
170                         return IsDigit (str[index]);
171                 }
172
173                 public static bool IsLetter (char c)
174                 {
175                         unsafe {
176                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
177                                 switch (Category) {
178                                 case UnicodeCategory.UppercaseLetter:
179                                 case UnicodeCategory.LowercaseLetter:
180                                 case UnicodeCategory.TitlecaseLetter:
181                                 case UnicodeCategory.ModifierLetter:
182                                 case UnicodeCategory.OtherLetter:
183                                         return true;
184                                 default:
185                                         return false;
186                                 }
187                         }
188                 }
189
190                 public static bool IsLetter (string str, int index)
191                 {
192                         if (str == null) 
193                                 throw new ArgumentNullException ("str");
194                         
195                         if (index < 0 || index >= str.Length)
196                                 throw new ArgumentOutOfRangeException (Locale.GetText (
197                                         "The value of index is less than zero, or greater than or equal to the length of str."));
198                         
199                         return IsLetter (str[index]);
200                 }
201
202                 public static bool IsLetterOrDigit (char c)
203                 {
204                         unsafe {
205                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
206                                 switch (Category) {
207                                 case UnicodeCategory.DecimalDigitNumber:
208                                 case UnicodeCategory.UppercaseLetter:
209                                 case UnicodeCategory.LowercaseLetter:
210                                 case UnicodeCategory.TitlecaseLetter:
211                                 case UnicodeCategory.ModifierLetter:
212                                 case UnicodeCategory.OtherLetter:
213                                         return true;
214                                 default:
215                                         return false;
216                                 }
217                         }
218                 }
219
220                 public static bool IsLetterOrDigit (string str, int index)
221                 {
222                         if (str == null) 
223                                 throw new ArgumentNullException ("str");
224                         
225                         if (index < 0 || index >= str.Length)
226                                 throw new ArgumentOutOfRangeException (Locale.GetText (
227                                         "The value of index is less than zero, or greater than or equal to the length of str."));
228                         
229                         return IsLetterOrDigit (str[index]);
230                 }
231
232                 public static bool IsLower (char c)
233                 {
234                         unsafe {
235                                 return (category_data [c] == (byte)UnicodeCategory.LowercaseLetter);
236                         }
237                 }
238                 
239                 public static bool IsLower (string str, int index)
240                 {
241                         if (str == null) 
242                                 throw new ArgumentNullException ("str");
243                         
244                         if (index < 0 || index >= str.Length)
245                                 throw new ArgumentOutOfRangeException (Locale.GetText (
246                                         "The value of index is less than zero, or greater than or equal to the length of str."));
247                         
248                         return IsLower (str[index]);
249                 }
250
251                 public static bool IsNumber (char c)
252                 {
253                         unsafe {
254                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
255                                 switch (Category) {
256                                 case UnicodeCategory.DecimalDigitNumber:
257                                 case UnicodeCategory.LetterNumber:
258                                 case UnicodeCategory.OtherNumber:
259                                         return true;
260                                 default:
261                                         return false;
262                                 }
263                         }
264                 }
265                 
266                 public static bool IsNumber (string str, int index)
267                 {
268                         if (str == null) 
269                                 throw new ArgumentNullException ("str");
270                         
271                         if (index < 0 || index >= str.Length)
272                                 throw new ArgumentOutOfRangeException (Locale.GetText (
273                                         "The value of index is less than zero, or greater than or equal to the length of str."));
274                         
275                         return IsNumber (str[index]);
276                 }
277
278                 public static bool IsPunctuation (char c)
279                 {
280                         unsafe {
281                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
282                                 switch (Category) {
283                                 case UnicodeCategory.ConnectorPunctuation:
284                                 case UnicodeCategory.DashPunctuation:
285                                 case UnicodeCategory.OpenPunctuation:
286                                 case UnicodeCategory.ClosePunctuation:
287                                 case UnicodeCategory.InitialQuotePunctuation:
288                                 case UnicodeCategory.FinalQuotePunctuation:
289                                 case UnicodeCategory.OtherPunctuation:
290                                         return true;
291                                 default:
292                                         return false;
293                                 }
294                         }
295                 }
296                 
297                 public static bool IsPunctuation (string str, int index)
298                 {
299                         if (str == null) 
300                                 throw new ArgumentNullException ("str");
301                         
302                         if (index < 0 || index >= str.Length)
303                                 throw new ArgumentOutOfRangeException (Locale.GetText (
304                                         "The value of index is less than zero, or greater than or equal to the length of str."));
305                         
306                         return IsPunctuation (str[index]);
307                 }
308
309                 public static bool IsSeparator (char c)
310                 {
311                         unsafe {
312                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
313                                 switch (Category) {
314                                 case UnicodeCategory.SpaceSeparator:
315                                 case UnicodeCategory.LineSeparator:
316                                 case UnicodeCategory.ParagraphSeparator:
317                                         return true;
318                                 default:
319                                         return false;
320                                 }
321                         }
322                 }
323                 
324                 public static bool IsSeparator (string str, int index)
325                 {
326                         if (str == null) 
327                                 throw new ArgumentNullException ("str");
328                         
329                         if (index < 0 || index >= str.Length)
330                                 throw new ArgumentOutOfRangeException (Locale.GetText (
331                                         "The value of index is less than zero, or greater than or equal to the length of str."));
332                         
333                         return IsSeparator (str[index]);
334                 }
335
336                 public static bool IsSurrogate (char c)
337                 {
338                         unsafe {
339                                 return (category_data [c] == (byte)UnicodeCategory.Surrogate);
340                         }
341                 }
342                 
343                 public static bool IsSurrogate (string str, int index)
344                 {
345                         if (str == null) 
346                                 throw new ArgumentNullException ("str");
347                         
348                         if (index < 0 || index >= str.Length)
349                                 throw new ArgumentOutOfRangeException (Locale.GetText (
350                                         "The value of index is less than zero, or greater than or equal to the length of str."));
351                         
352                         return IsSurrogate (str[index]);
353                 }
354
355                 public static bool IsSymbol (char c)
356                 {
357                         unsafe {
358                                 UnicodeCategory Category = (UnicodeCategory)category_data [c];
359                                 switch (Category) {
360                                 case UnicodeCategory.MathSymbol:
361                                 case UnicodeCategory.CurrencySymbol:
362                                 case UnicodeCategory.ModifierSymbol:
363                                 case UnicodeCategory.OtherSymbol:
364                                         return true;
365                                 default:
366                                         return false;
367                                 }
368                         }
369                 }
370                 
371                 public static bool IsSymbol (string str, int index)
372                 {
373                         if (str == null) 
374                                 throw new ArgumentNullException ("str");
375                         
376                         if (index < 0 || index >= str.Length)
377                                 throw new ArgumentOutOfRangeException (Locale.GetText (
378                                         "The value of index is less than zero, or greater than or equal to the length of str."));
379                         
380                         return IsSymbol (str[index]);
381                 }
382
383                 public static bool IsUpper (char c)
384                 {
385                         unsafe {
386                                 return (category_data [c] == (byte)UnicodeCategory.UppercaseLetter);
387                         }
388                 }
389                 
390                 public static bool IsUpper (string str, int index)
391                 {
392                         if (str == null) 
393                                 throw new ArgumentNullException ("str");
394                         
395                         if (index < 0 || index >= str.Length)
396                                 throw new ArgumentOutOfRangeException (Locale.GetText (
397                                         "The value of index is less than zero, or greater than or equal to the length of str."));
398                         
399                         return IsUpper (str[index]);
400                 }
401
402                 public static bool IsWhiteSpace (char c)
403                 {
404                         unsafe {
405                                 if (category_data [c] == (byte)UnicodeCategory.SpaceSeparator)
406                                         return true;
407                                 
408                                 switch (c) {
409                                 case (char)0x9:
410                                 case (char)0x0a:
411                                 case (char)0x0b:
412                                 case (char)0x0c:
413                                 case (char)0x0d:
414                                 case (char)0x85: // NEL 
415                                 case (char)0x2028: // Line Separator
416                                 case (char)0x2029: // Paragraph Separator       
417                                         return true;
418                                 default:
419                                         return false;
420                                 }
421                         }
422                 }
423                 
424                 public static bool IsWhiteSpace (string str, int index)
425                 {
426                         if (str == null) 
427                                 throw new ArgumentNullException ("str");
428                         
429                         if (index < 0 || index >= str.Length)
430                                 throw new ArgumentOutOfRangeException (Locale.GetText (
431                                         "The value of index is less than zero, or greater than or equal to the length of str."));
432                         
433                         return IsWhiteSpace (str[index]);
434                 }
435
436                 public static char Parse (string str)
437                 {
438                         if (str == null) 
439                                 throw new ArgumentNullException ("str");
440
441                         if (str.Length != 1)
442                                 throw new FormatException ("string contains more than one character.");
443                         
444                         return str [0];
445                 }
446
447                 [MonoTODO ("Fix FIXME")]
448                 public static char ToLower (char c)
449                 {
450                         // FIXME: needs to call line below, but that would probably break a lot of things right now
451                         // return InternalToLower (c, CultureInfo.CurrentCulture);
452                         return ToLowerInvariant (c);
453                 }
454
455                 internal static char ToLowerInvariant (char c)
456                 {
457                         unsafe {
458                                 if (c <= ((char)0x24cf))
459                                         return (char) to_lower_data_low [c];
460                                 if (c >= ((char)0xff41))
461                                         return (char) to_lower_data_high[c - 0xff41];
462                         }
463                         return c;
464                 }
465
466                 public static char ToLower (char c, CultureInfo culture)
467                 {
468                         if (culture == null)
469                                 throw new ArgumentNullException ("culture");
470                         if (culture.LCID == 0x007F) // Invariant
471                                 return ToLowerInvariant (c);
472
473                         return InternalToLower (c, culture);
474                 }
475
476                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
477                 private static extern char InternalToLower (char c, CultureInfo culture);
478
479                 [MonoTODO ("Fix FIXME")]
480                 public static char ToUpper (char c)
481                 {
482                         // FIXME: needs to call line below, but that would probably break a lot of things right now
483                         // return InternalToUpper (c, CultureInfo.CurrentCulture);
484                         return ToUpperInvariant (c);
485                 }
486
487                 internal static char ToUpperInvariant (char c)
488                 {
489                         unsafe {
490                                 if (c <= ((char)0x24cf))
491                                         return (char) to_upper_data_low [c];
492                                 if (c >= ((char)0xff21))
493                                         return (char) to_upper_data_high [c - 0xff21];
494                         }
495                         return c;
496                 }
497
498                 public static char ToUpper (char c, CultureInfo culture)
499                 {
500                         if (culture == null)
501                                 throw new ArgumentNullException ("culture");
502                         if (culture.LCID == 0x007F) // Invariant
503                                 return ToUpperInvariant (c);
504
505                         return InternalToUpper (c, culture);
506                 }
507
508                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
509                 private static extern char InternalToUpper (char c, CultureInfo culture);
510                 
511                 public override string ToString ()
512                 {
513                         // LAMESPEC: ECMA draft lists this as returning ToString (null), 
514                         // However it doesn't list another ToString() method.
515                         return new String (m_value, 1);
516                 }
517
518                 public static string ToString(char c)
519                 {
520                         return new String (c, 1);
521                 }
522
523                 public string ToString (IFormatProvider fp)
524                 {
525                         // LAMESPEC: ECMA draft doesn't say Char implements IFormattable
526                         return new String (m_value, 1);
527                 }
528
529                 // =========== IConvertible Methods =========== //
530                 
531                 public TypeCode GetTypeCode ()
532                 {
533                         return TypeCode.Char;
534                 }         
535
536                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
537                 {
538                         return System.Convert.ToType(m_value, conversionType, provider);
539                 }
540                 
541                 bool IConvertible.ToBoolean (IFormatProvider provider)
542                 {
543                         throw new InvalidCastException();
544                 }
545                 
546                 byte IConvertible.ToByte (IFormatProvider provider)
547                 {
548                         return System.Convert.ToByte(m_value);
549                 }
550                 
551                 char IConvertible.ToChar (IFormatProvider provider)
552                 {
553                         return m_value;
554                 }
555                 
556                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
557                 {
558                         throw new InvalidCastException();
559                 }
560                 
561                 decimal IConvertible.ToDecimal (IFormatProvider provider)
562                 {
563                         throw new InvalidCastException();
564                 }
565                 
566                 double IConvertible.ToDouble (IFormatProvider provider)
567                 {
568                         throw new InvalidCastException();
569                 }
570                 
571                 short IConvertible.ToInt16 (IFormatProvider provider)
572                 {
573                         return System.Convert.ToInt16(m_value);
574                 }
575                 
576                 int IConvertible.ToInt32 (IFormatProvider provider)
577                 {
578                         return System.Convert.ToInt32(m_value);
579                 }
580                 
581                 long IConvertible.ToInt64 (IFormatProvider provider)
582                 {
583                         return System.Convert.ToInt64(m_value);
584                 }
585                 
586                 sbyte IConvertible.ToSByte (IFormatProvider provider)
587                 {
588                         return System.Convert.ToSByte(m_value);
589                 }
590                 
591                 float IConvertible.ToSingle (IFormatProvider provider)
592                 {
593                         throw new InvalidCastException();
594                 }
595                 
596                 string IConvertible.ToString (IFormatProvider provider)
597                 {
598                         return ToString(provider);
599                 }
600
601                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
602                 {
603                         return System.Convert.ToUInt16(m_value);
604                 }
605                 
606                 uint IConvertible.ToUInt32 (IFormatProvider provider)
607                 {
608                         return System.Convert.ToUInt32(m_value);
609                 }
610                 
611                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
612                 {
613                         return System.Convert.ToUInt64(m_value);
614                 }
615         }
616 }
617