Rune
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text.Encodings.Web;
namespace System.Text
{
internal readonly struct Rune : IEquatable<System.Text.Rune>
{
private const int MaxUtf16CharsPerRune = 2;
private const char HighSurrogateStart = '�';
private const char LowSurrogateStart = '�';
private const int HighSurrogateRange = 1023;
private readonly uint _value;
public bool IsAscii => System.Text.UnicodeUtility.IsAsciiCodePoint(_value);
public bool IsBmp => System.Text.UnicodeUtility.IsBmpCodePoint(_value);
public static System.Text.Rune ReplacementChar => UnsafeCreate(65533);
public int Utf16SequenceLength => System.Text.UnicodeUtility.GetUtf16SequenceLength(_value);
public int Value => (int)_value;
public Rune(uint value)
{
if (!System.Text.UnicodeUtility.IsValidUnicodeScalar(value))
System.Text.Encodings.Web.ThrowHelper.ThrowArgumentOutOfRangeException(System.Text.Encodings.Web.ExceptionArgument.value);
_value = value;
}
public Rune(int value)
{
this = new System.Text.Rune((uint)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 IsControl(System.Text.Rune value)
{
return (uint)((int)(value._value + 1) & -129) <= 32;
}
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 (1 < (uint)source.Length) {
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;
uint num2;
if ((uint)num < (uint)source.Length) {
num2 = source[num];
if (System.Text.UnicodeUtility.IsAsciiCodePoint(num2))
goto IL_0021;
if (System.Text.UnicodeUtility.IsInRangeInclusive(num2, 194, 244)) {
num2 = num2 - 194 << 6;
num++;
if ((uint)num >= (uint)source.Length)
goto IL_0163;
int num3 = (sbyte)source[num];
if (num3 < -64) {
num2 = (uint)((int)num2 + num3);
num2 += 128;
num2 += 128;
if (num2 < 2048)
goto IL_0021;
if (System.Text.UnicodeUtility.IsInRangeInclusive(num2, 2080, 3343) && !System.Text.UnicodeUtility.IsInRangeInclusive(num2, 2912, 2943) && !System.Text.UnicodeUtility.IsInRangeInclusive(num2, 3072, 3087)) {
num++;
if ((uint)num >= (uint)source.Length)
goto IL_0163;
num3 = (sbyte)source[num];
if (num3 < -64) {
num2 <<= 6;
num2 = (uint)((int)num2 + num3);
num2 += 128;
num2 -= 131072;
if (num2 > 65535) {
num++;
if ((uint)num >= (uint)source.Length)
goto IL_0163;
num3 = (sbyte)source[num];
if (num3 >= -64)
goto IL_0153;
num2 <<= 6;
num2 = (uint)((int)num2 + num3);
num2 += 128;
num2 -= 4194304;
}
goto IL_0021;
}
}
}
} else
num = 1;
goto IL_0153;
}
goto IL_0163;
IL_0021:
bytesConsumed = num + 1;
result = UnsafeCreate(num2);
return OperationStatus.Done;
IL_0153:
bytesConsumed = num;
result = ReplacementChar;
return OperationStatus.InvalidData;
IL_0163:
bytesConsumed = num;
result = ReplacementChar;
return OperationStatus.NeedMoreData;
}
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 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 bool TryEncodeToUtf16(Span<char> destination, out int charsWritten)
{
if (destination.Length >= 1) {
if (IsBmp) {
destination[0] = (char)_value;
charsWritten = 1;
return true;
}
if (destination.Length >= 2) {
System.Text.UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar(_value, out destination[0], out destination[1]);
charsWritten = 2;
return true;
}
}
charsWritten = 0;
return false;
}
public bool TryEncodeToUtf8(Span<byte> destination, out int bytesWritten)
{
if (destination.Length >= 1) {
if (IsAscii) {
destination[0] = (byte)_value;
bytesWritten = 1;
return true;
}
if (destination.Length >= 2) {
if (_value <= 2047) {
destination[0] = (byte)(_value + 12288 >> 6);
destination[1] = (byte)((_value & 63) + 128);
bytesWritten = 2;
return true;
}
if (destination.Length >= 3) {
if (_value <= 65535) {
destination[0] = (byte)(_value + 917504 >> 12);
destination[1] = (byte)(((_value & 4032) >> 6) + 128);
destination[2] = (byte)((_value & 63) + 128);
bytesWritten = 3;
return true;
}
if (destination.Length >= 4) {
destination[0] = (byte)(_value + 62914560 >> 18);
destination[1] = (byte)(((_value & 258048) >> 12) + 128);
destination[2] = (byte)(((_value & 4032) >> 6) + 128);
destination[3] = (byte)((_value & 63) + 128);
bytesWritten = 4;
return true;
}
}
}
}
bytesWritten = 0;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static System.Text.Rune UnsafeCreate(uint scalarValue)
{
return new System.Text.Rune(scalarValue, false);
}
}
}