<PackageReference Include="System.Text.Encodings.Web" Version="10.0.0-preview.1.25080.5" />

Rune

using System.Buffers; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Text.Unicode; namespace System.Text { [DebuggerDisplay("{DebuggerDisplay,nq}")] internal readonly struct Rune : IComparable, IComparable<System.Text.Rune>, IEquatable<System.Text.Rune> { internal const int MaxUtf16CharsPerRune = 2; internal const int MaxUtf8BytesPerRune = 4; private const char HighSurrogateStart = '�'; private const char LowSurrogateStart = '�'; private const int HighSurrogateRange = 1023; private const byte IsWhiteSpaceFlag = 128; private const byte IsLetterOrDigitFlag = 64; private const byte UnicodeCategoryMask = 31; private readonly uint _value; private unsafe static ReadOnlySpan<byte> AsciiCharInfo => new ReadOnlySpan<byte>(&global::<PrivateImplementationDetails>.2F3EFC9595514E83DED03093C4F3E3C781A650E1AAB8CA350537CD1A47E1EE8E, 128); private string DebuggerDisplay => FormattableString.Invariant(FormattableStringFactory.Create("U+{0:X4} '{1}'", _value, IsValid(_value) ? ToString() : "�")); public bool IsAscii => System.Text.UnicodeUtility.IsAsciiCodePoint(_value); public bool IsBmp => System.Text.UnicodeUtility.IsBmpCodePoint(_value); public int Plane => System.Text.UnicodeUtility.GetPlane(_value); public static System.Text.Rune ReplacementChar => UnsafeCreate(65533); public int Utf16SequenceLength => System.Text.UnicodeUtility.GetUtf16SequenceLength(_value); public int Utf8SequenceLength => System.Text.UnicodeUtility.GetUtf8SequenceLength(_value); public int Value => (int)_value; public Rune(char ch) { if (System.Text.UnicodeUtility.IsSurrogateCodePoint(ch)) System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.ch); _value = ch; } public Rune(char highSurrogate, char lowSurrogate) { this = new System.Text.Rune((uint)char.ConvertToUtf32(highSurrogate, lowSurrogate), false); } public Rune(int value) { this = new System.Text.Rune((uint)value); } [CLSCompliant(false)] public Rune(uint value) { if (!System.Text.UnicodeUtility.IsValidUnicodeScalar(value)) System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.value); _value = value; } private Rune(uint scalarValue, bool _) { _value = scalarValue; } public static bool operator ==(System.Text.Rune left, System.Text.Rune right) { return left._value == right._value; } public static bool operator !=(System.Text.Rune left, System.Text.Rune right) { return left._value != right._value; } public static bool operator <(System.Text.Rune left, System.Text.Rune right) { return left._value < right._value; } public static bool operator <=(System.Text.Rune left, System.Text.Rune right) { return left._value <= right._value; } public static bool operator >(System.Text.Rune left, System.Text.Rune right) { return left._value > right._value; } public static bool operator >=(System.Text.Rune left, System.Text.Rune right) { return left._value >= right._value; } public static explicit operator System.Text.Rune(char ch) { return new System.Text.Rune(ch); } public static explicit operator System.Text.Rune(uint value) { return new System.Text.Rune(value); } public static explicit operator System.Text.Rune(int value) { return new System.Text.Rune(value); } private unsafe static System.Text.Rune ChangeCaseCultureAware(System.Text.Rune rune, CultureInfo culture, bool toUpper) { Span<char> span = new Span<char>(stackalloc byte[4], 2); Span<char> destination = new Span<char>(stackalloc byte[4], 2); int length = rune.EncodeToUtf16(span); span = span.Slice(0, length); destination = destination.Slice(0, length); if (toUpper) span.ToUpper(destination, culture); else span.ToLower(destination, culture); if (rune.IsBmp) return UnsafeCreate(destination[0]); return UnsafeCreate(System.Text.UnicodeUtility.GetScalarFromUtf16SurrogatePair(destination[0], destination[1])); } public int CompareTo(System.Text.Rune other) { return Value - other.Value; } public static OperationStatus DecodeFromUtf16(ReadOnlySpan<char> source, out System.Text.Rune result, out int charsConsumed) { if (!source.IsEmpty) { char c = source[0]; if (TryCreate(c, out result)) { charsConsumed = 1; return OperationStatus.Done; } if (source.Length > 1) { char lowSurrogate = source[1]; if (TryCreate(c, lowSurrogate, out result)) { charsConsumed = 2; return OperationStatus.Done; } } else if (char.IsHighSurrogate(c)) { goto IL_004c; } charsConsumed = 1; result = ReplacementChar; return OperationStatus.InvalidData; } goto IL_004c; IL_004c: charsConsumed = source.Length; result = ReplacementChar; return OperationStatus.NeedMoreData; } public static OperationStatus DecodeFromUtf8(ReadOnlySpan<byte> source, out System.Text.Rune result, out int bytesConsumed) { int num = 0; if (source.IsEmpty) goto IL_0153; uint num2 = source[0]; if (System.Text.UnicodeUtility.IsAsciiCodePoint(num2)) { bytesConsumed = 1; result = UnsafeCreate(num2); return OperationStatus.Done; } num = 1; if (System.Text.UnicodeUtility.IsInRangeInclusive(num2, 194, 244)) { num2 = num2 - 194 << 6; if (source.Length <= 1) goto IL_0153; int num3 = (sbyte)source[1]; if (num3 < -64) { num2 = (uint)((int)num2 + num3); num2 += 128; num2 += 128; if (num2 < 2048) goto IL_0140; if (System.Text.UnicodeUtility.IsInRangeInclusive(num2, 2080, 3343) && !System.Text.UnicodeUtility.IsInRangeInclusive(num2, 2912, 2943) && !System.Text.UnicodeUtility.IsInRangeInclusive(num2, 3072, 3087)) { num = 2; if (source.Length <= 2) goto IL_0153; num3 = (sbyte)source[2]; if (num3 < -64) { num2 <<= 6; num2 = (uint)((int)num2 + num3); num2 += 128; num2 -= 131072; if (num2 > 65535) { num = 3; if (source.Length <= 3) goto IL_0153; num3 = (sbyte)source[3]; if (num3 >= -64) goto IL_0163; num2 <<= 6; num2 = (uint)((int)num2 + num3); num2 += 128; num2 -= 4194304; } goto IL_0140; } } } } goto IL_0163; IL_0140: bytesConsumed = num + 1; result = UnsafeCreate(num2); return OperationStatus.Done; IL_0163: bytesConsumed = num; result = ReplacementChar; return OperationStatus.InvalidData; IL_0153: bytesConsumed = num; result = ReplacementChar; return OperationStatus.NeedMoreData; } public static OperationStatus DecodeLastFromUtf16(ReadOnlySpan<char> source, out System.Text.Rune result, out int charsConsumed) { int num = source.Length - 1; if ((uint)num < (uint)source.Length) { char c = source[num]; if (TryCreate(c, out result)) { charsConsumed = 1; return OperationStatus.Done; } if (char.IsLowSurrogate(c)) { num--; if ((uint)num < (uint)source.Length && TryCreate(source[num], c, out result)) { charsConsumed = 2; return OperationStatus.Done; } charsConsumed = 1; result = ReplacementChar; return OperationStatus.InvalidData; } } charsConsumed = (int)((uint)(-source.Length) >> 31); result = ReplacementChar; return OperationStatus.NeedMoreData; } public static OperationStatus DecodeLastFromUtf8(ReadOnlySpan<byte> source, out System.Text.Rune value, out int bytesConsumed) { int num = source.Length - 1; if ((uint)num < (uint)source.Length) { uint num2 = source[num]; if (System.Text.UnicodeUtility.IsAsciiCodePoint(num2)) { bytesConsumed = 1; value = UnsafeCreate(num2); return OperationStatus.Done; } if (((byte)num2 & 64) != 0) return DecodeFromUtf8(source.Slice(num), out value, out bytesConsumed); int num3 = 3; OperationStatus result2; System.Text.Rune result; int bytesConsumed2; while (true) { if (num3 > 0) { num--; if ((uint)num < (uint)source.Length) { if ((sbyte)source[num] < -64) { num3--; continue; } source = source.Slice(num); result2 = DecodeFromUtf8(source, out result, out bytesConsumed2); if (bytesConsumed2 == source.Length) break; } } value = ReplacementChar; bytesConsumed = 1; return OperationStatus.InvalidData; } bytesConsumed = bytesConsumed2; value = result; return result2; } value = ReplacementChar; bytesConsumed = 0; return OperationStatus.NeedMoreData; } public int EncodeToUtf16(Span<char> destination) { if (!TryEncodeToUtf16(destination, out int charsWritten)) System.ThrowHelper.ThrowArgumentException_DestinationTooShort(); return charsWritten; } public int EncodeToUtf8(Span<byte> destination) { if (!TryEncodeToUtf8(destination, out int bytesWritten)) System.ThrowHelper.ThrowArgumentException_DestinationTooShort(); return bytesWritten; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] object obj) { if (obj is System.Text.Rune) { System.Text.Rune other = (System.Text.Rune)obj; return Equals(other); } return false; } public bool Equals(System.Text.Rune other) { return this == other; } public override int GetHashCode() { return Value; } public static System.Text.Rune GetRuneAt(string input, int index) { int num = ReadRuneFromString(input, index); if (num < 0) System.ThrowHelper.ThrowArgumentException_CannotExtractScalar(System.ExceptionArgument.index); return UnsafeCreate((uint)num); } public static bool IsValid(int value) { return IsValid((uint)value); } [CLSCompliant(false)] public static bool IsValid(uint value) { return System.Text.UnicodeUtility.IsValidUnicodeScalar(value); } internal static int ReadFirstRuneFromUtf16Buffer(ReadOnlySpan<char> input) { if (input.IsEmpty) return -1; uint num = input[0]; if (System.Text.UnicodeUtility.IsSurrogateCodePoint(num)) { if (!System.Text.UnicodeUtility.IsHighSurrogateCodePoint(num)) return -1; if (input.Length <= 1) return -1; uint num2 = input[1]; if (!System.Text.UnicodeUtility.IsLowSurrogateCodePoint(num2)) return -1; num = System.Text.UnicodeUtility.GetScalarFromUtf16SurrogatePair(num, num2); } return (int)num; } private static int ReadRuneFromString(string input, int index) { if (input == null) System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.input); if ((uint)index >= (uint)input.Length) System.ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessException(); uint num = input[index]; if (System.Text.UnicodeUtility.IsSurrogateCodePoint(num)) { if (!System.Text.UnicodeUtility.IsHighSurrogateCodePoint(num)) return -1; index++; if ((uint)index >= (uint)input.Length) return -1; uint num2 = input[index]; if (!System.Text.UnicodeUtility.IsLowSurrogateCodePoint(num2)) return -1; num = System.Text.UnicodeUtility.GetScalarFromUtf16SurrogatePair(num, num2); } return (int)num; } public unsafe override string ToString() { if (IsBmp) return ((char)(ushort)_value).ToString(); Span<char> span = new Span<char>(stackalloc byte[4], 2); System.Text.UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar(_value, out span[0], out span[1]); return span.ToString(); } public static bool TryCreate(char ch, out System.Text.Rune result) { if (!System.Text.UnicodeUtility.IsSurrogateCodePoint(ch)) { result = UnsafeCreate(ch); return true; } result = default(System.Text.Rune); return false; } public static bool TryCreate(char highSurrogate, char lowSurrogate, out System.Text.Rune result) { uint num = (uint)(highSurrogate - 55296); uint num2 = (uint)(lowSurrogate - 56320); if ((num | num2) <= 1023) { result = UnsafeCreate((uint)((int)(num << 10) + (lowSurrogate - 56320) + 65536)); return true; } result = default(System.Text.Rune); return false; } public static bool TryCreate(int value, out System.Text.Rune result) { return TryCreate((uint)value, out result); } [CLSCompliant(false)] public static bool TryCreate(uint value, out System.Text.Rune result) { if (System.Text.UnicodeUtility.IsValidUnicodeScalar(value)) { result = UnsafeCreate(value); return true; } result = default(System.Text.Rune); return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryEncodeToUtf16(Span<char> destination, out int charsWritten) { return TryEncodeToUtf16(this, destination, out charsWritten); } private static bool TryEncodeToUtf16(System.Text.Rune value, Span<char> destination, out int charsWritten) { if (!destination.IsEmpty) { if (value.IsBmp) { destination[0] = (char)value._value; charsWritten = 1; return true; } if (destination.Length > 1) { System.Text.UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar(value._value, out destination[0], out destination[1]); charsWritten = 2; return true; } } charsWritten = 0; return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryEncodeToUtf8(Span<byte> destination, out int bytesWritten) { return TryEncodeToUtf8(this, destination, out bytesWritten); } private static bool TryEncodeToUtf8(System.Text.Rune value, Span<byte> destination, out int bytesWritten) { if (!destination.IsEmpty) { if (value.IsAscii) { destination[0] = (byte)value._value; bytesWritten = 1; return true; } if (destination.Length > 1) { if ((long)value.Value <= 2047) { destination[0] = (byte)(value._value + 12288 >> 6); destination[1] = (byte)((value._value & 63) + 128); bytesWritten = 2; return true; } if (destination.Length > 2) { if ((long)value.Value <= 65535) { destination[0] = (byte)(value._value + 917504 >> 12); destination[1] = (byte)(((value._value & 4032) >> 6) + 128); destination[2] = (byte)((value._value & 63) + 128); bytesWritten = 3; return true; } if (destination.Length > 3) { destination[0] = (byte)(value._value + 62914560 >> 18); destination[1] = (byte)(((value._value & 258048) >> 12) + 128); destination[2] = (byte)(((value._value & 4032) >> 6) + 128); destination[3] = (byte)((value._value & 63) + 128); bytesWritten = 4; return true; } } } } bytesWritten = 0; return false; } public static bool TryGetRuneAt(string input, int index, out System.Text.Rune value) { int num = ReadRuneFromString(input, index); if (num >= 0) { value = UnsafeCreate((uint)num); return true; } value = default(System.Text.Rune); return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static System.Text.Rune UnsafeCreate(uint scalarValue) { return new System.Text.Rune(scalarValue, false); } public static double GetNumericValue(System.Text.Rune value) { if (value.IsAscii) { uint num = value._value - 48; if (num > 9) return -1; return (double)num; } if (value.IsBmp) return CharUnicodeInfo.GetNumericValue((char)value._value); return CharUnicodeInfo.GetNumericValue(value.ToString(), 0); } public static UnicodeCategory GetUnicodeCategory(System.Text.Rune value) { if (value.IsAscii) return (UnicodeCategory)(AsciiCharInfo[value.Value] & 31); return GetUnicodeCategoryNonAscii(value); } private static UnicodeCategory GetUnicodeCategoryNonAscii(System.Text.Rune value) { if (value.IsBmp) return CharUnicodeInfo.GetUnicodeCategory((char)value._value); return CharUnicodeInfo.GetUnicodeCategory(value.ToString(), 0); } private static bool IsCategoryLetter(UnicodeCategory category) { return System.Text.UnicodeUtility.IsInRangeInclusive((uint)category, 0, 4); } private static bool IsCategoryLetterOrDecimalDigit(UnicodeCategory category) { if (!System.Text.UnicodeUtility.IsInRangeInclusive((uint)category, 0, 4)) return category == UnicodeCategory.DecimalDigitNumber; return true; } private static bool IsCategoryNumber(UnicodeCategory category) { return System.Text.UnicodeUtility.IsInRangeInclusive((uint)category, 8, 10); } private static bool IsCategoryPunctuation(UnicodeCategory category) { return System.Text.UnicodeUtility.IsInRangeInclusive((uint)category, 18, 24); } private static bool IsCategorySeparator(UnicodeCategory category) { return System.Text.UnicodeUtility.IsInRangeInclusive((uint)category, 11, 13); } private static bool IsCategorySymbol(UnicodeCategory category) { return System.Text.UnicodeUtility.IsInRangeInclusive((uint)category, 25, 28); } public static bool IsControl(System.Text.Rune value) { return (uint)((int)(value._value + 1) & -129) <= 32; } public static bool IsDigit(System.Text.Rune value) { if (value.IsAscii) return System.Text.UnicodeUtility.IsInRangeInclusive(value._value, 48, 57); return GetUnicodeCategoryNonAscii(value) == UnicodeCategory.DecimalDigitNumber; } public static bool IsLetter(System.Text.Rune value) { if (value.IsAscii) return (uint)((int)(value._value - 65) & -33) <= 25; return IsCategoryLetter(GetUnicodeCategoryNonAscii(value)); } public static bool IsLetterOrDigit(System.Text.Rune value) { if (value.IsAscii) return (AsciiCharInfo[value.Value] & 64) != 0; return IsCategoryLetterOrDecimalDigit(GetUnicodeCategoryNonAscii(value)); } public static bool IsLower(System.Text.Rune value) { if (value.IsAscii) return System.Text.UnicodeUtility.IsInRangeInclusive(value._value, 97, 122); return GetUnicodeCategoryNonAscii(value) == UnicodeCategory.LowercaseLetter; } public static bool IsNumber(System.Text.Rune value) { if (value.IsAscii) return System.Text.UnicodeUtility.IsInRangeInclusive(value._value, 48, 57); return IsCategoryNumber(GetUnicodeCategoryNonAscii(value)); } public static bool IsPunctuation(System.Text.Rune value) { return IsCategoryPunctuation(GetUnicodeCategory(value)); } public static bool IsSeparator(System.Text.Rune value) { return IsCategorySeparator(GetUnicodeCategory(value)); } public static bool IsSymbol(System.Text.Rune value) { return IsCategorySymbol(GetUnicodeCategory(value)); } public static bool IsUpper(System.Text.Rune value) { if (value.IsAscii) return System.Text.UnicodeUtility.IsInRangeInclusive(value._value, 65, 90); return GetUnicodeCategoryNonAscii(value) == UnicodeCategory.UppercaseLetter; } public static bool IsWhiteSpace(System.Text.Rune value) { if (value.IsAscii) return (AsciiCharInfo[value.Value] & 128) != 0; if (value.IsBmp) return char.IsWhiteSpace((char)value._value); return false; } public static System.Text.Rune ToLower(System.Text.Rune value, CultureInfo culture) { if (culture == null) System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.culture); return ChangeCaseCultureAware(value, culture, false); } public static System.Text.Rune ToLowerInvariant(System.Text.Rune value) { if (value.IsAscii) return UnsafeCreate(System.Text.Unicode.Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(value._value)); return ChangeCaseCultureAware(value, CultureInfo.InvariantCulture, false); } public static System.Text.Rune ToUpper(System.Text.Rune value, CultureInfo culture) { if (culture == null) System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.culture); return ChangeCaseCultureAware(value, culture, true); } public static System.Text.Rune ToUpperInvariant(System.Text.Rune value) { if (value.IsAscii) return UnsafeCreate(System.Text.Unicode.Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(value._value)); return ChangeCaseCultureAware(value, CultureInfo.InvariantCulture, true); } int IComparable.CompareTo(object obj) { if (obj == null) return 1; if (obj is System.Text.Rune) { System.Text.Rune other = (System.Text.Rune)obj; return CompareTo(other); } throw new ArgumentException(System.SR.Arg_MustBeRune); } } }