5 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
6 // Miguel de Icaza (miguel@ximian.com)
7 // Jackson Harper (jackson@ximian.com)
9 // (C) Ximian, Inc. http://www.ximian.com
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
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.
39 using System.Globalization;
40 using System.Runtime.CompilerServices;
42 using System.Runtime.InteropServices;
50 public struct Char : IComparable, IConvertible, IComparable <char>, IEquatable <char>
52 public struct Char : IComparable, IConvertible
55 public const char MaxValue = (char) 0xffff;
56 public const char MinValue = (char) 0;
58 internal char m_value;
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);
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;
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);
82 public int CompareTo (object v)
87 if (!(v is System.Char))
88 throw new ArgumentException (Locale.GetText ("Value is not a System.Char"));
100 public override bool Equals (object o)
105 return ((char) o) == m_value;
109 public int CompareTo (char value)
111 if (m_value == value)
120 public static string ConvertFromUtf32 (int utf32)
122 if (utf32 < 0 || utf32 > 0x10FFFF)
123 throw new ArgumentOutOfRangeException ("utf32", "The argument must be from 0 to 0x10FFFF.");
124 if (0xD800 <= utf32 && utf32 <= 0xDFFF)
125 throw new ArgumentOutOfRangeException ("utf32", "The argument must not be in surrogate pair range.");
127 return new string ((char) utf32, 1);
130 new char [] {(char) ((utf32 >> 10) + 0xD800),
131 (char) (utf32 % 0x0400 + 0xDC00)});
134 public static int ConvertToUtf32 (char highSurrogate, char lowSurrogate)
136 if (highSurrogate < 0xD800 || 0xDBFF < highSurrogate)
137 throw new ArgumentOutOfRangeException ("highSurrogate");
138 if (lowSurrogate < 0xDC00 || 0xDFFF < lowSurrogate)
139 throw new ArgumentOutOfRangeException ("lowSurrogate");
141 return 0x10000 + ((highSurrogate - 0xD800) << 10) + (lowSurrogate - 0xDC00);
144 public static int ConvertToUtf32 (string s, int index)
147 throw new ArgumentNullException ("s");
148 if (index < 0 || index >= s.Length)
149 throw new ArgumentOutOfRangeException ("index");
150 if (!Char.IsSurrogate (s [index]))
152 if (!Char.IsHighSurrogate (s [index])
153 || index == s.Length - 1
154 || !Char.IsLowSurrogate (s [index + 1]))
155 throw new ArgumentException (String.Format ("The string contains invalid surrogate pair character at {0}", index));
156 return ConvertToUtf32 (s [index], s [index + 1]);
159 public bool Equals (char value)
161 return m_value == value;
164 public static bool IsSurrogatePair (char high, char low)
166 return '\uD800' <= high && high <= '\uDBFF'
167 && '\uDC00' <= low && low <= '\uDFFF';
170 public static bool IsSurrogatePair (string s, int index)
173 throw new ArgumentNullException ("s");
174 if (index < 0 || index >= s.Length)
175 throw new ArgumentOutOfRangeException ("index");
176 return index + 1 < s.Length && IsSurrogatePair (s [index], s [index + 1]);
180 public override int GetHashCode ()
185 public static double GetNumericValue (char c)
187 if (c > (char)0x3289) {
188 if (c >= (char)0xFF10 && c <= (char)0xFF19)
189 return (c - 0xFF10); // Numbers 0-9
191 // Default not set data
196 return numeric_data_values [numeric_data [c]];
202 public static double GetNumericValue (string str, int index)
205 throw new ArgumentNullException ("str");
207 if (index < 0 || index >= str.Length)
208 throw new ArgumentOutOfRangeException (Locale.GetText (
209 "The value of index is less than zero, or greater than or equal to the length of str."));
211 return GetNumericValue (str[index]);
214 public static UnicodeCategory GetUnicodeCategory (char c)
217 return (UnicodeCategory)(category_data [c]);
221 public static UnicodeCategory GetUnicodeCategory (string str, int index)
224 throw new ArgumentNullException ("str");
226 if (index < 0 || index >= str.Length)
227 throw new ArgumentOutOfRangeException (Locale.GetText (
228 "The value of index is less than zero, or greater than or equal to the length of str."));
230 return GetUnicodeCategory (str[index]);
233 public static bool IsControl (char c)
236 return (category_data [c] == (byte)UnicodeCategory.Control);
240 public static bool IsControl (string str, int index)
243 throw new ArgumentNullException ("str");
245 if (index < 0 || index >= str.Length)
246 throw new ArgumentOutOfRangeException (Locale.GetText (
247 "The value of index is less than zero, or greater than or equal to the length of str."));
249 return IsControl (str[index]);
252 public static bool IsDigit (char c)
255 return (category_data [c] == (byte)UnicodeCategory.DecimalDigitNumber);
259 public static bool IsDigit (string str, int index)
262 throw new ArgumentNullException ("str");
264 if (index < 0 || index >= str.Length)
265 throw new ArgumentOutOfRangeException (Locale.GetText (
266 "The value of index is less than zero, or greater than or equal to the length of str."));
268 return IsDigit (str[index]);
272 public static bool IsHighSurrogate (char c)
274 return c >= '\uD800' && c <= '\uDBFF';
277 public static bool IsHighSurrogate (string s, int index)
280 throw new ArgumentNullException ("s");
282 if (index < 0 || index >= s.Length)
283 throw new ArgumentOutOfRangeException ("index");
285 return IsHighSurrogate (s [index]);
289 public static bool IsLetter (char c)
292 UnicodeCategory Category = (UnicodeCategory)category_data [c];
294 case UnicodeCategory.UppercaseLetter:
295 case UnicodeCategory.LowercaseLetter:
296 case UnicodeCategory.TitlecaseLetter:
297 case UnicodeCategory.ModifierLetter:
298 case UnicodeCategory.OtherLetter:
306 public static bool IsLetter (string str, int index)
309 throw new ArgumentNullException ("str");
311 if (index < 0 || index >= str.Length)
312 throw new ArgumentOutOfRangeException (Locale.GetText (
313 "The value of index is less than zero, or greater than or equal to the length of str."));
315 return IsLetter (str[index]);
318 public static bool IsLetterOrDigit (char c)
321 UnicodeCategory Category = (UnicodeCategory)category_data [c];
323 case UnicodeCategory.DecimalDigitNumber:
324 case UnicodeCategory.UppercaseLetter:
325 case UnicodeCategory.LowercaseLetter:
326 case UnicodeCategory.TitlecaseLetter:
327 case UnicodeCategory.ModifierLetter:
328 case UnicodeCategory.OtherLetter:
336 public static bool IsLetterOrDigit (string str, int index)
339 throw new ArgumentNullException ("str");
341 if (index < 0 || index >= str.Length)
342 throw new ArgumentOutOfRangeException (Locale.GetText (
343 "The value of index is less than zero, or greater than or equal to the length of str."));
345 return IsLetterOrDigit (str[index]);
348 public static bool IsLower (char c)
351 return (category_data [c] == (byte)UnicodeCategory.LowercaseLetter);
355 public static bool IsLower (string str, int index)
358 throw new ArgumentNullException ("str");
360 if (index < 0 || index >= str.Length)
361 throw new ArgumentOutOfRangeException (Locale.GetText (
362 "The value of index is less than zero, or greater than or equal to the length of str."));
364 return IsLower (str[index]);
368 public static bool IsLowSurrogate (char c)
370 return c >= '\uDC00' && c <= '\uDFFF';
373 public static bool IsLowSurrogate (string s, int index)
376 throw new ArgumentNullException ("s");
378 if (index < 0 || index >= s.Length)
379 throw new ArgumentOutOfRangeException ("index");
381 return IsLowSurrogate (s [index]);
385 public static bool IsNumber (char c)
388 UnicodeCategory Category = (UnicodeCategory)category_data [c];
390 case UnicodeCategory.DecimalDigitNumber:
391 case UnicodeCategory.LetterNumber:
392 case UnicodeCategory.OtherNumber:
400 public static bool IsNumber (string str, int index)
403 throw new ArgumentNullException ("str");
405 if (index < 0 || index >= str.Length)
406 throw new ArgumentOutOfRangeException (Locale.GetText (
407 "The value of index is less than zero, or greater than or equal to the length of str."));
409 return IsNumber (str[index]);
412 public static bool IsPunctuation (char c)
415 UnicodeCategory Category = (UnicodeCategory)category_data [c];
417 case UnicodeCategory.ConnectorPunctuation:
418 case UnicodeCategory.DashPunctuation:
419 case UnicodeCategory.OpenPunctuation:
420 case UnicodeCategory.ClosePunctuation:
421 case UnicodeCategory.InitialQuotePunctuation:
422 case UnicodeCategory.FinalQuotePunctuation:
423 case UnicodeCategory.OtherPunctuation:
431 public static bool IsPunctuation (string str, int index)
434 throw new ArgumentNullException ("str");
436 if (index < 0 || index >= str.Length)
437 throw new ArgumentOutOfRangeException (Locale.GetText (
438 "The value of index is less than zero, or greater than or equal to the length of str."));
440 return IsPunctuation (str[index]);
443 public static bool IsSeparator (char c)
446 UnicodeCategory Category = (UnicodeCategory)category_data [c];
448 case UnicodeCategory.SpaceSeparator:
449 case UnicodeCategory.LineSeparator:
450 case UnicodeCategory.ParagraphSeparator:
458 public static bool IsSeparator (string str, int index)
461 throw new ArgumentNullException ("str");
463 if (index < 0 || index >= str.Length)
464 throw new ArgumentOutOfRangeException (Locale.GetText (
465 "The value of index is less than zero, or greater than or equal to the length of str."));
467 return IsSeparator (str[index]);
470 public static bool IsSurrogate (char c)
473 return (category_data [c] == (byte)UnicodeCategory.Surrogate);
477 public static bool IsSurrogate (string str, int index)
480 throw new ArgumentNullException ("str");
482 if (index < 0 || index >= str.Length)
483 throw new ArgumentOutOfRangeException (Locale.GetText (
484 "The value of index is less than zero, or greater than or equal to the length of str."));
486 return IsSurrogate (str[index]);
489 public static bool IsSymbol (char c)
492 UnicodeCategory Category = (UnicodeCategory)category_data [c];
494 case UnicodeCategory.MathSymbol:
495 case UnicodeCategory.CurrencySymbol:
496 case UnicodeCategory.ModifierSymbol:
497 case UnicodeCategory.OtherSymbol:
505 public static bool IsSymbol (string str, int index)
508 throw new ArgumentNullException ("str");
510 if (index < 0 || index >= str.Length)
511 throw new ArgumentOutOfRangeException (Locale.GetText (
512 "The value of index is less than zero, or greater than or equal to the length of str."));
514 return IsSymbol (str[index]);
517 public static bool IsUpper (char c)
520 return (category_data [c] == (byte)UnicodeCategory.UppercaseLetter);
524 public static bool IsUpper (string str, int index)
527 throw new ArgumentNullException ("str");
529 if (index < 0 || index >= str.Length)
530 throw new ArgumentOutOfRangeException (Locale.GetText (
531 "The value of index is less than zero, or greater than or equal to the length of str."));
533 return IsUpper (str[index]);
536 public static bool IsWhiteSpace (char c)
539 if (category_data [c] == (byte)UnicodeCategory.SpaceSeparator)
548 case (char)0x85: // NEL
549 case (char)0x2028: // Line Separator
550 case (char)0x2029: // Paragraph Separator
552 case (char)0x205F: // Medium Mathematical Space
561 public static bool IsWhiteSpace (string str, int index)
564 throw new ArgumentNullException ("str");
566 if (index < 0 || index >= str.Length)
567 throw new ArgumentOutOfRangeException (Locale.GetText (
568 "The value of index is less than zero, or greater than or equal to the length of str."));
570 return IsWhiteSpace (str[index]);
574 public static bool TryParse (string s, out char result)
576 if (s == null || s.Length != 1) {
586 public static char Parse (string str)
589 throw new ArgumentNullException ("str");
592 throw new FormatException ("string contains more than one character.");
597 public static char ToLower (char c)
599 return ToLower (c, CultureInfo.CurrentCulture);
603 public static char ToLowerInvariant (char c)
605 internal static char ToLowerInvariant (char c)
609 if (c <= ((char)0x24cf))
610 return (char) to_lower_data_low [c];
611 if (c >= ((char)0xff21))
612 return (char) to_lower_data_high[c - 0xff21];
617 public static char ToLower (char c, CultureInfo culture)
620 throw new ArgumentNullException ("culture");
621 if (culture.LCID == 0x007F) // Invariant
622 return ToLowerInvariant (c);
624 return culture.TextInfo.ToLower (c);
627 public static char ToUpper (char c)
629 return ToUpper (c, CultureInfo.CurrentCulture);
633 public static char ToUpperInvariant (char c)
635 internal static char ToUpperInvariant (char c)
639 if (c <= ((char)0x24e9))
640 return (char) to_upper_data_low [c];
641 if (c >= ((char)0xff21))
642 return (char) to_upper_data_high [c - 0xff21];
647 public static char ToUpper (char c, CultureInfo culture)
650 throw new ArgumentNullException ("culture");
651 if (culture.LCID == 0x007F) // Invariant
652 return ToUpperInvariant (c);
654 return culture.TextInfo.ToUpper (c);
657 public override string ToString ()
659 // LAMESPEC: ECMA draft lists this as returning ToString (null),
660 // However it doesn't list another ToString() method.
661 return new String (m_value, 1);
664 public static string ToString(char c)
666 return new String (c, 1);
669 public string ToString (IFormatProvider fp)
671 // LAMESPEC: ECMA draft doesn't say Char implements IFormattable
672 return new String (m_value, 1);
675 // =========== IConvertible Methods =========== //
677 public TypeCode GetTypeCode ()
679 return TypeCode.Char;
682 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
684 return System.Convert.ToType(m_value, conversionType, provider);
687 bool IConvertible.ToBoolean (IFormatProvider provider)
689 throw new InvalidCastException();
692 byte IConvertible.ToByte (IFormatProvider provider)
694 return System.Convert.ToByte(m_value);
697 char IConvertible.ToChar (IFormatProvider provider)
702 DateTime IConvertible.ToDateTime (IFormatProvider provider)
704 throw new InvalidCastException();
707 decimal IConvertible.ToDecimal (IFormatProvider provider)
709 throw new InvalidCastException();
712 double IConvertible.ToDouble (IFormatProvider provider)
714 throw new InvalidCastException();
717 short IConvertible.ToInt16 (IFormatProvider provider)
719 return System.Convert.ToInt16(m_value);
722 int IConvertible.ToInt32 (IFormatProvider provider)
724 return System.Convert.ToInt32(m_value);
727 long IConvertible.ToInt64 (IFormatProvider provider)
729 return System.Convert.ToInt64(m_value);
732 sbyte IConvertible.ToSByte (IFormatProvider provider)
734 return System.Convert.ToSByte(m_value);
737 float IConvertible.ToSingle (IFormatProvider provider)
739 throw new InvalidCastException();
742 ushort IConvertible.ToUInt16 (IFormatProvider provider)
744 return System.Convert.ToUInt16(m_value);
747 uint IConvertible.ToUInt32 (IFormatProvider provider)
749 return System.Convert.ToUInt32(m_value);
752 ulong IConvertible.ToUInt64 (IFormatProvider provider)
754 return System.Convert.ToUInt64(m_value);