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;
41 using System.Runtime.InteropServices;
47 public struct Char : IComparable, IConvertible, IComparable <char>, IEquatable <char>
49 public const char MaxValue = (char) 0xffff;
50 public const char MinValue = (char) 0;
52 internal char m_value;
57 GetDataTablePointers (CategoryDataVersion,
58 out category_data, out category_astral_index, out numeric_data,
59 out numeric_data_values, out to_lower_data_low, out to_lower_data_high,
60 out to_upper_data_low, out to_upper_data_high);
61 category_check_pair = category_astral_index != null
62 ? (byte)UnicodeCategory.Surrogate
67 private readonly unsafe static byte *category_data;
68 private readonly unsafe static ushort *category_astral_index;
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 // UnicodeCategory.Surrogate if astral plane
77 // categories are available, 0xff otherwise.
78 private readonly static byte category_check_pair;
81 private const int CategoryDataVersion = 4;
83 private const int CategoryDataVersion = 2;
86 [MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
87 private unsafe static extern void GetDataTablePointers (int category_data_version,
88 out byte *category_data, out ushort *category_astral_index, out byte *numeric_data,
89 out double *numeric_data_values, out ushort *to_lower_data_low, out ushort *to_lower_data_high,
90 out ushort *to_upper_data_low, out ushort *to_upper_data_high);
92 public int CompareTo (object value)
97 if (!(value is System.Char))
98 throw new ArgumentException (Locale.GetText ("Value is not a System.Char"));
100 char xv = (char) value;
110 public override bool Equals (object obj)
115 return ((char) obj) == m_value;
118 public int CompareTo (char value)
120 if (m_value == value)
129 public static string ConvertFromUtf32 (int utf32)
131 if (utf32 < 0 || utf32 > 0x10FFFF)
132 throw new ArgumentOutOfRangeException ("utf32", "The argument must be from 0 to 0x10FFFF.");
133 if (0xD800 <= utf32 && utf32 <= 0xDFFF)
134 throw new ArgumentOutOfRangeException ("utf32", "The argument must not be in surrogate pair range.");
136 return new string ((char) utf32, 1);
139 new char [] {(char) ((utf32 >> 10) + 0xD800),
140 (char) (utf32 % 0x0400 + 0xDC00)});
143 public static int ConvertToUtf32 (char highSurrogate, char lowSurrogate)
145 if (highSurrogate < 0xD800 || 0xDBFF < highSurrogate)
146 throw new ArgumentOutOfRangeException ("highSurrogate");
147 if (lowSurrogate < 0xDC00 || 0xDFFF < lowSurrogate)
148 throw new ArgumentOutOfRangeException ("lowSurrogate");
150 return 0x10000 + ((highSurrogate - 0xD800) << 10) + (lowSurrogate - 0xDC00);
153 public static int ConvertToUtf32 (string s, int index)
155 CheckParameter (s, index);
157 if (!Char.IsSurrogate (s [index]))
159 if (!Char.IsHighSurrogate (s [index])
160 || index == s.Length - 1
161 || !Char.IsLowSurrogate (s [index + 1]))
162 throw new ArgumentException (String.Format ("The string contains invalid surrogate pair character at {0}", index));
163 return ConvertToUtf32 (s [index], s [index + 1]);
166 public bool Equals (char obj)
168 return m_value == obj;
171 public static bool IsSurrogatePair (char highSurrogate, char lowSurrogate)
173 return '\uD800' <= highSurrogate && highSurrogate <= '\uDBFF'
174 && '\uDC00' <= lowSurrogate && lowSurrogate <= '\uDFFF';
177 public static bool IsSurrogatePair (string s, int index)
179 CheckParameter (s, index);
180 return index + 1 < s.Length && IsSurrogatePair (s [index], s [index + 1]);
183 public override int GetHashCode ()
188 public static double GetNumericValue (char c)
190 if (c > (char)0x3289) {
191 if (c >= (char)0xFF10 && c <= (char)0xFF19)
192 return (c - 0xFF10); // Numbers 0-9
194 // Default not set data
199 return numeric_data_values [numeric_data [c]];
205 public static double GetNumericValue (string s, int index)
207 CheckParameter (s, index);
208 return GetNumericValue (s[index]);
211 public static UnicodeCategory GetUnicodeCategory (char c)
214 return (UnicodeCategory)(category_data [c]);
218 public static UnicodeCategory GetUnicodeCategory (string s, int index)
220 CheckParameter (s, index);
221 UnicodeCategory c = GetUnicodeCategory (s [index]);
223 if ((byte)c == category_check_pair &&
224 IsSurrogatePair (s, index)) {
225 int u = ConvertToUtf32 (s [index], s [index + 1]);
227 // ConvertToUtf32 guarantees 0x10000 <= u <= 0x10ffff
228 int x = (category_astral_index [(u - 0x10000) >> 8] << 8) + (u & 0xff);
230 c = (UnicodeCategory)category_data [x];
237 public static bool IsControl (char c)
240 return (category_data [c] == (byte)UnicodeCategory.Control);
244 public static bool IsControl (string s, int index)
246 CheckParameter (s, index);
247 return IsControl (s[index]);
250 public static bool IsDigit (char c)
253 return (category_data [c] == (byte)UnicodeCategory.DecimalDigitNumber);
257 public static bool IsDigit (string s, int index)
259 CheckParameter (s, index);
260 return IsDigit (s[index]);
263 public static bool IsHighSurrogate (char c)
265 return c >= '\uD800' && c <= '\uDBFF';
268 public static bool IsHighSurrogate (string s, int index)
270 CheckParameter (s, index);
271 return IsHighSurrogate (s [index]);
274 public static bool IsLetter (char c)
277 return category_data [c] <= ((byte)UnicodeCategory.OtherLetter);
281 public static bool IsLetter (string s, int index)
283 CheckParameter (s, index);
284 return IsLetter (s[index]);
287 public static bool IsLetterOrDigit (char c)
290 int category = category_data [c];
291 return (category <= ((int)UnicodeCategory.OtherLetter) ||
292 category == ((int)UnicodeCategory.DecimalDigitNumber));
296 public static bool IsLetterOrDigit (string s, int index)
298 CheckParameter (s, index);
299 return IsLetterOrDigit (s[index]);
302 public static bool IsLower (char c)
305 return (category_data [c] == (byte)UnicodeCategory.LowercaseLetter);
309 public static bool IsLower (string s, int index)
311 CheckParameter (s, index);
312 return IsLower (s[index]);
315 public static bool IsLowSurrogate (char c)
317 return c >= '\uDC00' && c <= '\uDFFF';
320 public static bool IsLowSurrogate (string s, int index)
322 CheckParameter (s, index);
323 return IsLowSurrogate (s [index]);
326 public static bool IsNumber (char c)
329 int category = category_data [c];
330 return (category >= ((int)UnicodeCategory.DecimalDigitNumber) &&
331 category <= ((int)UnicodeCategory.OtherNumber));
335 public static bool IsNumber (string s, int index)
337 CheckParameter (s, index);
338 return IsNumber (s[index]);
341 public static bool IsPunctuation (char c)
344 int category = category_data [c];
345 return (category >= ((int)UnicodeCategory.ConnectorPunctuation) &&
346 category <= ((int)UnicodeCategory.OtherPunctuation));
350 public static bool IsPunctuation (string s, int index)
352 CheckParameter (s, index);
353 return IsPunctuation (s[index]);
356 public static bool IsSeparator (char c)
359 int category = category_data [c];
360 return (category >= ((int)UnicodeCategory.SpaceSeparator) &&
361 category <= ((int)UnicodeCategory.ParagraphSeparator));
365 public static bool IsSeparator (string s, int index)
367 CheckParameter (s, index);
368 return IsSeparator (s[index]);
371 public static bool IsSurrogate (char c)
374 return (category_data [c] == (byte)UnicodeCategory.Surrogate);
378 public static bool IsSurrogate (string s, int index)
380 CheckParameter (s, index);
381 return IsSurrogate (s[index]);
384 public static bool IsSymbol (char c)
387 int category = category_data [c];
388 return (category >= ((int)UnicodeCategory.MathSymbol) &&
389 category <= ((int)UnicodeCategory.OtherSymbol));
393 public static bool IsSymbol (string s, int index)
395 CheckParameter (s, index);
396 return IsSymbol (s[index]);
399 public static bool IsUpper (char c)
402 return (category_data [c] == (byte)UnicodeCategory.UppercaseLetter);
406 public static bool IsUpper (string s, int index)
408 CheckParameter (s, index);
409 return IsUpper (s[index]);
412 public static bool IsWhiteSpace (char c)
415 return c == 0x20 || c >= 0x09 && c <= 0x0d || c == 0x85 || c == 0xA0;
418 int category = category_data [c];
419 return category > (int) UnicodeCategory.OtherNumber && category <= (int) UnicodeCategory.ParagraphSeparator;
423 public static bool IsWhiteSpace (string s, int index)
425 CheckParameter (s, index);
426 return IsWhiteSpace (s[index]);
429 private static void CheckParameter (string s, int index)
432 throw new ArgumentNullException ("s");
434 if (index < 0 || index >= s.Length)
435 throw new ArgumentOutOfRangeException (
436 Locale.GetText ("The value of index is less than zero, or greater than or equal to the length of s."));
439 public static bool TryParse (string s, out char result)
441 if (s == null || s.Length != 1) {
450 public static char Parse (string s)
453 throw new ArgumentNullException ("s");
456 throw new FormatException (Locale.GetText ("s contains more than one character."));
461 public static char ToLower (char c)
463 // CurrentCulture is never null or Invariant
464 return CultureInfo.CurrentCulture.TextInfo.ToLower (c);
467 public static char ToLowerInvariant (char c)
470 if (c <= ((char)0x24cf))
471 return (char) to_lower_data_low [c];
472 if (c >= ((char)0xff21))
473 return (char) to_lower_data_high[c - 0xff21];
478 public static char ToLower (char c, CultureInfo culture)
481 throw new ArgumentNullException ("culture");
482 if (culture.LCID == 0x007F) // Invariant
483 return ToLowerInvariant (c);
485 return culture.TextInfo.ToLower (c);
488 public static char ToUpper (char c)
490 // CurrentCulture is never null or Invariant
491 return CultureInfo.CurrentCulture.TextInfo.ToUpper (c);
494 public static char ToUpperInvariant (char c)
497 if (c <= ((char)0x24e9))
498 return (char) to_upper_data_low [c];
499 if (c >= ((char)0xff21))
500 return (char) to_upper_data_high [c - 0xff21];
505 public static char ToUpper (char c, CultureInfo culture)
508 throw new ArgumentNullException ("culture");
509 if (culture.LCID == 0x007F) // Invariant
510 return ToUpperInvariant (c);
512 return culture.TextInfo.ToUpper (c);
515 public override string ToString ()
517 return new String (m_value, 1);
520 public static string ToString (char c)
522 return new String (c, 1);
525 public string ToString (IFormatProvider provider)
527 return new String (m_value, 1);
530 // =========== IConvertible Methods =========== //
532 public TypeCode GetTypeCode ()
534 return TypeCode.Char;
537 object IConvertible.ToType (Type targetType, IFormatProvider provider)
539 if (targetType == null)
540 throw new ArgumentNullException ("targetType");
541 return System.Convert.ToType (m_value, targetType, provider, false);
544 bool IConvertible.ToBoolean (IFormatProvider provider)
546 throw new InvalidCastException ();
549 byte IConvertible.ToByte (IFormatProvider provider)
551 return System.Convert.ToByte (m_value);
554 char IConvertible.ToChar (IFormatProvider provider)
559 DateTime IConvertible.ToDateTime (IFormatProvider provider)
561 throw new InvalidCastException ();
564 decimal IConvertible.ToDecimal (IFormatProvider provider)
566 throw new InvalidCastException ();
569 double IConvertible.ToDouble (IFormatProvider provider)
571 throw new InvalidCastException ();
574 short IConvertible.ToInt16 (IFormatProvider provider)
576 return System.Convert.ToInt16 (m_value);
579 int IConvertible.ToInt32 (IFormatProvider provider)
581 return System.Convert.ToInt32 (m_value);
584 long IConvertible.ToInt64 (IFormatProvider provider)
586 return System.Convert.ToInt64 (m_value);
589 sbyte IConvertible.ToSByte (IFormatProvider provider)
591 return System.Convert.ToSByte (m_value);
594 float IConvertible.ToSingle (IFormatProvider provider)
596 throw new InvalidCastException ();
599 ushort IConvertible.ToUInt16 (IFormatProvider provider)
601 return System.Convert.ToUInt16 (m_value);
604 uint IConvertible.ToUInt32 (IFormatProvider provider)
606 return System.Convert.ToUInt32 (m_value);
609 ulong IConvertible.ToUInt64 (IFormatProvider provider)
611 return System.Convert.ToUInt64 (m_value);