-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Reduce unsafe from STJ #114154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reduce unsafe from STJ #114154
Changes from 4 commits
f3b1496
f7ad796
6d08056
839ccbd
afaad68
4b66784
e7345c8
8721350
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -113,14 +113,14 @@ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial | |
| case JsonTokenType.Number when (_converterOptions & EnumConverterOptions.AllowNumbers) != 0: | ||
| switch (s_enumTypeCode) | ||
| { | ||
| case TypeCode.Int32 when reader.TryGetInt32(out int int32): return Unsafe.As<int, T>(ref int32); | ||
| case TypeCode.UInt32 when reader.TryGetUInt32(out uint uint32): return Unsafe.As<uint, T>(ref uint32); | ||
| case TypeCode.Int64 when reader.TryGetInt64(out long int64): return Unsafe.As<long, T>(ref int64); | ||
| case TypeCode.UInt64 when reader.TryGetUInt64(out ulong uint64): return Unsafe.As<ulong, T>(ref uint64); | ||
| case TypeCode.Byte when reader.TryGetByte(out byte ubyte8): return Unsafe.As<byte, T>(ref ubyte8); | ||
| case TypeCode.SByte when reader.TryGetSByte(out sbyte byte8): return Unsafe.As<sbyte, T>(ref byte8); | ||
| case TypeCode.Int16 when reader.TryGetInt16(out short int16): return Unsafe.As<short, T>(ref int16); | ||
| case TypeCode.UInt16 when reader.TryGetUInt16(out ushort uint16): return Unsafe.As<ushort, T>(ref uint16); | ||
| case TypeCode.Int32 when reader.TryGetInt32(out int int32): return (T)(object)int32; | ||
| case TypeCode.UInt32 when reader.TryGetUInt32(out uint uint32): return (T)(object)uint32; | ||
| case TypeCode.Int64 when reader.TryGetInt64(out long int64): return (T)(object)int64; | ||
| case TypeCode.UInt64 when reader.TryGetUInt64(out ulong uint64): return (T)(object)uint64; | ||
| case TypeCode.Byte when reader.TryGetByte(out byte ubyte8): return (T)(object)ubyte8; | ||
| case TypeCode.SByte when reader.TryGetSByte(out sbyte byte8): return (T)(object)byte8; | ||
| case TypeCode.Int16 when reader.TryGetInt16(out short int16): return (T)(object)int16; | ||
| case TypeCode.UInt16 when reader.TryGetUInt16(out ushort uint16): return (T)(object)uint16; | ||
| } | ||
| break; | ||
| } | ||
|
|
@@ -350,51 +350,42 @@ private bool TryParseNamedEnum( | |
|
|
||
| private static ulong ConvertToUInt64(T value) | ||
| { | ||
| switch (s_enumTypeCode) | ||
| { | ||
| case TypeCode.Int32 or TypeCode.UInt32: return Unsafe.As<T, uint>(ref value); | ||
| case TypeCode.Int64 or TypeCode.UInt64: return Unsafe.As<T, ulong>(ref value); | ||
| case TypeCode.Int16 or TypeCode.UInt16: return Unsafe.As<T, ushort>(ref value); | ||
| default: | ||
| Debug.Assert(s_enumTypeCode is TypeCode.SByte or TypeCode.Byte); | ||
| return Unsafe.As<T, byte>(ref value); | ||
| return s_enumTypeCode switch | ||
| { | ||
| TypeCode.Int32 => (ulong)(int)(object)value, | ||
| TypeCode.UInt32 => (uint)(object)value, | ||
| TypeCode.Int64 => (ulong)(long)(object)value, | ||
| TypeCode.UInt64 => (ulong)(object)value, | ||
| TypeCode.Int16 => (ulong)(short)(object)value, | ||
| TypeCode.UInt16 => (ushort)(object)value, | ||
| TypeCode.SByte => (ulong)(sbyte)(object)value, | ||
| _ => (byte)(object)value | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous code was asserting in the drain, and you're not. If a new TypeCode were to be introduced, is the exception that comes out of this cast going to be useful enough?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
if a new type code is added, the default will throw an InvalidCastException? we can only unbox byte out of a boxed byte-enum. |
||
| }; | ||
| } | ||
|
|
||
| private static long ConvertToInt64(T value) | ||
| { | ||
| Debug.Assert(s_isSignedEnum); | ||
| switch (s_enumTypeCode) | ||
| { | ||
| case TypeCode.Int32: return Unsafe.As<T, int>(ref value); | ||
| case TypeCode.Int64: return Unsafe.As<T, long>(ref value); | ||
| case TypeCode.Int16: return Unsafe.As<T, short>(ref value); | ||
| default: | ||
| Debug.Assert(s_enumTypeCode is TypeCode.SByte); | ||
| return Unsafe.As<T, sbyte>(ref value); | ||
| return s_enumTypeCode switch | ||
| { | ||
| TypeCode.Int32 => (int)(object)value, | ||
| TypeCode.Int64 => (long)(object)value, | ||
| TypeCode.Int16 => (short)(object)value, | ||
| _ => (sbyte)(object)value, | ||
|
stephentoub marked this conversation as resolved.
|
||
| }; | ||
| } | ||
|
|
||
| private static T ConvertFromUInt64(ulong value) | ||
| { | ||
| switch (s_enumTypeCode) | ||
| { | ||
| case TypeCode.Int32 or TypeCode.UInt32: | ||
| uint uintValue = (uint)value; | ||
| return Unsafe.As<uint, T>(ref uintValue); | ||
|
|
||
| case TypeCode.Int64 or TypeCode.UInt64: | ||
| ulong ulongValue = value; | ||
| return Unsafe.As<ulong, T>(ref ulongValue); | ||
|
|
||
| case TypeCode.Int16 or TypeCode.UInt16: | ||
| ushort ushortValue = (ushort)value; | ||
| return Unsafe.As<ushort, T>(ref ushortValue); | ||
|
|
||
| default: | ||
| Debug.Assert(s_enumTypeCode is TypeCode.SByte or TypeCode.Byte); | ||
| byte byteValue = (byte)value; | ||
| return Unsafe.As<byte, T>(ref byteValue); | ||
| return s_enumTypeCode switch | ||
| { | ||
| TypeCode.Int32 => (T)(object)(int)value, | ||
| TypeCode.UInt32 => (T)(object)(uint)value, | ||
| TypeCode.Int64 => (T)(object)(long)value, | ||
| TypeCode.UInt64 => (T)(object)value, | ||
| TypeCode.Int16 => (T)(object)(short)value, | ||
| TypeCode.UInt16 => (T)(object)(ushort)value, | ||
| TypeCode.SByte => (T)(object)(sbyte)value, | ||
| _ => (T)(object)(byte)value | ||
| }; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1543,7 +1543,11 @@ private static RegexCharClass ParseRecursive(string charClass, int start) | |
| public static string OneToStringClass(char c) | ||
| => CharsToStringClass([c]); | ||
|
|
||
| internal static unsafe string CharsToStringClass(ReadOnlySpan<char> chars) | ||
| internal static | ||
| #if !NET | ||
| unsafe | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method is safe for callers. Move this
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ended up duplicating code since netfx needs unsafe context in two places |
||
| #endif | ||
| string CharsToStringClass(ReadOnlySpan<char> chars) | ||
| { | ||
| #if DEBUG | ||
| // Make sure they're all sorted with no duplicates | ||
|
|
@@ -1594,18 +1598,20 @@ internal static unsafe string CharsToStringClass(ReadOnlySpan<char> chars) | |
| ReadOnlySpan<char> tmpChars = chars; // avoid address exposing the span and impacting the other code in the method that uses it | ||
| return | ||
| #if NET | ||
| string | ||
| string.Create(SetStartIndex + count, tmpChars, static (span, chars) => | ||
| #else | ||
| StringExtensions | ||
| StringExtensions.Create(SetStartIndex + count, (IntPtr)(&tmpChars), static (span, charsPtr) => | ||
| #endif | ||
| .Create(SetStartIndex + count, (IntPtr)(&tmpChars), static (span, charsPtr) => | ||
| { | ||
| // Fill in the set string | ||
| span[FlagsIndex] = (char)0; | ||
| span[SetLengthIndex] = (char)(span.Length - SetStartIndex); | ||
| span[CategoryLengthIndex] = (char)0; | ||
| int i = SetStartIndex; | ||
| foreach (char c in *(ReadOnlySpan<char>*)charsPtr) | ||
| #if !NET | ||
| ReadOnlySpan<char> chars = *(ReadOnlySpan<char>*)charsPtr; | ||
| #endif | ||
| foreach (char c in chars) | ||
| { | ||
| span[i++] = c; | ||
| if (c != LastChar) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.