Skip to content

Commit 2b3e604

Browse files
authored
Merge pull request #511 from CommunityToolkit/dev/use-language-unsafe
Replace Unsafe.SizeOf<T>() with sizeof(T)
2 parents 2edbb0a + 3bbfe6c commit 2b3e604

File tree

19 files changed

+44
-48
lines changed

19 files changed

+44
-48
lines changed

build/Community.Toolkit.Common.props

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
2323
<LangVersion>11.0</LangVersion>
2424
<Nullable>enable</Nullable>
25+
26+
<!--
27+
Suppress ref safety warnings in unsafe contexts (see https://github.com/dotnet/csharplang/issues/6476).
28+
This is used eg. to replace Unsafe.SizeOf<T>() calls with just sizeof(T). The warning is not necessary
29+
since in order to use these APIs the caller already has to be in an unsafe context.
30+
-->
31+
<NoWarn>$(NoWarn);CS8500</NoWarn>
2532
</PropertyGroup>
2633

2734
<PropertyGroup>

src/CommunityToolkit.Diagnostics/Extensions/ValueTypeExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static class ValueTypeExtensions
4444
public static unsafe string ToHexString<T>(this T value)
4545
where T : unmanaged
4646
{
47-
int sizeOfT = Unsafe.SizeOf<T>();
47+
int sizeOfT = sizeof(T);
4848
int bufferSize = (2 * sizeOfT) + 2;
4949
char* p = stackalloc char[bufferSize];
5050

src/CommunityToolkit.Diagnostics/Guard.String.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System;
66
using System.Diagnostics.CodeAnalysis;
7-
using System.IO;
87
using System.Runtime.CompilerServices;
98

109
#pragma warning disable CS8777

src/CommunityToolkit.HighPerformance/Buffers/Internals/ArrayMemoryManager{TFrom,TTo}.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ public override Span<TTo> GetSpan()
7070
/// <inheritdoc/>
7171
public override unsafe MemoryHandle Pin(int elementIndex = 0)
7272
{
73-
if ((uint)elementIndex >= (uint)(this.length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>()))
73+
if ((uint)elementIndex >= (uint)(this.length * sizeof(TFrom) / sizeof(TTo)))
7474
{
7575
ThrowArgumentOutOfRangeExceptionForInvalidIndex();
7676
}
7777

78-
int bytePrefix = this.offset * Unsafe.SizeOf<TFrom>();
79-
int byteSuffix = elementIndex * Unsafe.SizeOf<TTo>();
78+
int bytePrefix = this.offset * sizeof(TFrom);
79+
int byteSuffix = elementIndex * sizeof(TTo);
8080
int byteOffset = bytePrefix + byteSuffix;
8181

8282
GCHandle handle = GCHandle.Alloc(this.array, GCHandleType.Pinned);

src/CommunityToolkit.HighPerformance/Buffers/Internals/ProxyMemoryManager{TFrom,TTo}.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System;
66
using System.Buffers;
7-
using System.Runtime.CompilerServices;
87
using System.Runtime.InteropServices;
98
using CommunityToolkit.HighPerformance.Buffers.Internals.Interfaces;
109
using RuntimeHelpers = CommunityToolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
@@ -57,17 +56,17 @@ public override Span<TTo> GetSpan()
5756
}
5857

5958
/// <inheritdoc/>
60-
public override MemoryHandle Pin(int elementIndex = 0)
59+
public override unsafe MemoryHandle Pin(int elementIndex = 0)
6160
{
62-
if ((uint)elementIndex >= (uint)(this.length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>()))
61+
if ((uint)elementIndex >= (uint)(this.length * sizeof(TFrom) / sizeof(TTo)))
6362
{
6463
ThrowArgumentExceptionForInvalidIndex();
6564
}
6665

67-
int bytePrefix = this.offset * Unsafe.SizeOf<TFrom>();
68-
int byteSuffix = elementIndex * Unsafe.SizeOf<TTo>();
66+
int bytePrefix = this.offset * sizeof(TFrom);
67+
int byteSuffix = elementIndex * sizeof(TTo);
6968
int byteOffset = bytePrefix + byteSuffix;
70-
int shiftedOffset = Math.DivRem(byteOffset, Unsafe.SizeOf<TFrom>(), out int remainder);
69+
int shiftedOffset = Math.DivRem(byteOffset, sizeof(TFrom), out int remainder);
7170

7271
if (remainder != 0)
7372
{

src/CommunityToolkit.HighPerformance/Buffers/Internals/StringMemoryManager{TTo}.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ public override Span<TTo> GetSpan()
6666
/// <inheritdoc/>
6767
public override unsafe MemoryHandle Pin(int elementIndex = 0)
6868
{
69-
if ((uint)elementIndex >= (uint)(this.length * Unsafe.SizeOf<char>() / Unsafe.SizeOf<TTo>()))
69+
if ((uint)elementIndex >= (uint)(this.length * sizeof(char) / sizeof(TTo)))
7070
{
7171
ThrowArgumentOutOfRangeExceptionForInvalidIndex();
7272
}
7373

74-
int bytePrefix = this.offset * Unsafe.SizeOf<char>();
75-
int byteSuffix = elementIndex * Unsafe.SizeOf<TTo>();
74+
int bytePrefix = this.offset * sizeof(char);
75+
int byteSuffix = elementIndex * sizeof(TTo);
7676
int byteOffset = bytePrefix + byteSuffix;
7777

7878
GCHandle handle = GCHandle.Alloc(this.text, GCHandleType.Pinned);

src/CommunityToolkit.HighPerformance/Extensions/IBufferWriterExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ public static Stream AsStream(this IBufferWriter<byte> writer)
4545
/// <param name="writer">The target <see cref="IBufferWriter{T}"/> instance to write to.</param>
4646
/// <param name="value">The input value to write to <paramref name="writer"/>.</param>
4747
/// <exception cref="ArgumentException">Thrown if <paramref name="writer"/> reaches the end.</exception>
48-
public static void Write<T>(this IBufferWriter<byte> writer, T value)
48+
public static unsafe void Write<T>(this IBufferWriter<byte> writer, T value)
4949
where T : unmanaged
5050
{
51-
int length = Unsafe.SizeOf<T>();
51+
int length = sizeof(T);
5252
Span<byte> span = writer.GetSpan(1);
5353

5454
if (span.Length < length)

src/CommunityToolkit.HighPerformance/Extensions/ReadOnlySpanExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,13 @@ public static ReadOnlySpan2D<T> AsSpan2D<T>(this ReadOnlySpan<T> span, int offse
210210
/// <param name="value">The reference to the target item to get the index for.</param>
211211
/// <returns>The index of <paramref name="value"/> within <paramref name="span"/>, or <c>-1</c>.</returns>
212212
[MethodImpl(MethodImplOptions.AggressiveInlining)]
213-
public static int IndexOf<T>(this ReadOnlySpan<T> span, in T value)
213+
public static unsafe int IndexOf<T>(this ReadOnlySpan<T> span, in T value)
214214
{
215215
ref T r0 = ref MemoryMarshal.GetReference(span);
216216
ref T r1 = ref Unsafe.AsRef(value);
217217
IntPtr byteOffset = Unsafe.ByteOffset(ref r0, ref r1);
218218

219-
nint elementOffset = byteOffset / (nint)(uint)Unsafe.SizeOf<T>();
219+
nint elementOffset = byteOffset / (nint)(uint)sizeof(T);
220220

221221
if ((nuint)elementOffset >= (uint)span.Length)
222222
{

src/CommunityToolkit.HighPerformance/Extensions/SpanExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,12 @@ public static Span<TTo> Cast<TFrom, TTo>(this Span<TFrom> span)
148148
/// <param name="value">The reference to the target item to get the index for.</param>
149149
/// <returns>The index of <paramref name="value"/> within <paramref name="span"/>, or <c>-1</c>.</returns>
150150
[MethodImpl(MethodImplOptions.AggressiveInlining)]
151-
public static int IndexOf<T>(this Span<T> span, ref T value)
151+
public static unsafe int IndexOf<T>(this Span<T> span, ref T value)
152152
{
153153
ref T r0 = ref MemoryMarshal.GetReference(span);
154154
IntPtr byteOffset = Unsafe.ByteOffset(ref r0, ref value);
155155

156-
nint elementOffset = byteOffset / (nint)(uint)Unsafe.SizeOf<T>();
156+
nint elementOffset = byteOffset / (nint)(uint)sizeof(T);
157157

158158
if ((nuint)elementOffset >= (uint)span.Length)
159159
{

src/CommunityToolkit.HighPerformance/Extensions/StreamExtensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,12 @@ public static void Write(this Stream stream, ReadOnlySpan<byte> buffer)
202202
#if NETSTANDARD2_1_OR_GREATER
203203
[MethodImpl(MethodImplOptions.AggressiveInlining)]
204204
#endif
205-
public static T Read<T>(this Stream stream)
205+
public static unsafe T Read<T>(this Stream stream)
206206
where T : unmanaged
207207
{
208208
#if NETSTANDARD2_1_OR_GREATER
209209
T result = default;
210-
int length = Unsafe.SizeOf<T>();
210+
int length = sizeof(T);
211211

212212
unsafe
213213
{
@@ -219,7 +219,7 @@ public static T Read<T>(this Stream stream)
219219

220220
return result;
221221
#else
222-
int length = Unsafe.SizeOf<T>();
222+
int length = sizeof(T);
223223
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
224224

225225
try
@@ -247,19 +247,19 @@ public static T Read<T>(this Stream stream)
247247
#if NETSTANDARD2_1_OR_GREATER
248248
[MethodImpl(MethodImplOptions.AggressiveInlining)]
249249
#endif
250-
public static void Write<T>(this Stream stream, in T value)
250+
public static unsafe void Write<T>(this Stream stream, in T value)
251251
where T : unmanaged
252252
{
253253
#if NETSTANDARD2_1_OR_GREATER
254254
ref T r0 = ref Unsafe.AsRef(value);
255255
ref byte r1 = ref Unsafe.As<T, byte>(ref r0);
256-
int length = Unsafe.SizeOf<T>();
256+
int length = sizeof(T);
257257

258258
ReadOnlySpan<byte> span = MemoryMarshal.CreateReadOnlySpan(ref r1, length);
259259

260260
stream.Write(span);
261261
#else
262-
int length = Unsafe.SizeOf<T>();
262+
int length = sizeof(T);
263263
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
264264

265265
try

src/CommunityToolkit.HighPerformance/Helpers/HashCode{T}.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public static int Combine(ReadOnlySpan<T> span)
5050
/// <returns>The hash code for the input <see cref="ReadOnlySpan{T}"/> instance</returns>
5151
/// <remarks>The returned hash code is not processed through <see cref="HashCode"/> APIs.</remarks>
5252
[MethodImpl(MethodImplOptions.AggressiveInlining)]
53-
internal static int CombineValues(ReadOnlySpan<T> span)
53+
internal static unsafe int CombineValues(ReadOnlySpan<T> span)
5454
{
5555
ref T r0 = ref MemoryMarshal.GetReference(span);
5656

@@ -70,7 +70,7 @@ internal static int CombineValues(ReadOnlySpan<T> span)
7070
// process. In that case it will just compute the byte size as a 32 bit
7171
// multiplication with overflow, which is guaranteed never to happen anyway.
7272
ref byte rb = ref Unsafe.As<T, byte>(ref r0);
73-
nint length = (nint)((uint)span.Length * (uint)Unsafe.SizeOf<T>());
73+
nint length = (nint)((uint)span.Length * (uint)sizeof(T));
7474

7575
return SpanHelper.GetDjb2LikeByteHash(ref rb, length);
7676
}

src/CommunityToolkit.HighPerformance/Memory/Memory2D{T}.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ public Span2D<T> Span
657657
/// are negative or not within the bounds that are valid for the current instance.
658658
/// </exception>
659659
/// <returns>A new <see cref="Memory2D{T}"/> instance representing a slice of the current one.</returns>
660-
public Memory2D<T> Slice(int row, int column, int height, int width)
660+
public unsafe Memory2D<T> Slice(int row, int column, int height, int width)
661661
{
662662
if ((uint)row >= Height)
663663
{
@@ -682,7 +682,7 @@ public Memory2D<T> Slice(int row, int column, int height, int width)
682682
int shift = ((this.width + this.pitch) * row) + column;
683683
int pitch = this.pitch + (this.width - width);
684684

685-
IntPtr offset = this.offset + (shift * Unsafe.SizeOf<T>());
685+
IntPtr offset = this.offset + (shift * sizeof(T));
686686

687687
return new(this.instance!, offset, height, width, pitch);
688688
}

src/CommunityToolkit.HighPerformance/Memory/ReadOnlyMemory2D{T}.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ public ReadOnlySpan2D<T> Span
670670
/// are negative or not within the bounds that are valid for the current instance.
671671
/// </exception>
672672
/// <returns>A new <see cref="ReadOnlyMemory2D{T}"/> instance representing a slice of the current one.</returns>
673-
public ReadOnlyMemory2D<T> Slice(int row, int column, int height, int width)
673+
public unsafe ReadOnlyMemory2D<T> Slice(int row, int column, int height, int width)
674674
{
675675
if ((uint)row >= Height)
676676
{
@@ -695,7 +695,7 @@ public ReadOnlyMemory2D<T> Slice(int row, int column, int height, int width)
695695
int shift = ((this.width + this.pitch) * row) + column;
696696
int pitch = this.pitch + (this.width - width);
697697

698-
IntPtr offset = this.offset + (shift * Unsafe.SizeOf<T>());
698+
IntPtr offset = this.offset + (shift * sizeof(T));
699699

700700
return new(this.instance!, offset, height, width, pitch);
701701
}

src/CommunityToolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ public ref T DangerousGetReferenceAt(int i, int j)
801801
/// are negative or not within the bounds that are valid for the current instance.
802802
/// </exception>
803803
/// <returns>A new <see cref="ReadOnlySpan2D{T}"/> instance representing a slice of the current one.</returns>
804-
public ReadOnlySpan2D<T> Slice(int row, int column, int height, int width)
804+
public unsafe ReadOnlySpan2D<T> Slice(int row, int column, int height, int width)
805805
{
806806
if ((uint)row >= Height)
807807
{
@@ -831,7 +831,7 @@ public ReadOnlySpan2D<T> Slice(int row, int column, int height, int width)
831831

832832
return new(in r0, height, width, pitch);
833833
#else
834-
IntPtr offset = this.offset + (shift * (nint)(uint)Unsafe.SizeOf<T>());
834+
IntPtr offset = this.offset + (shift * (nint)(uint)sizeof(T));
835835

836836
return new(this.instance, offset, height, width, pitch);
837837
#endif

src/CommunityToolkit.HighPerformance/Memory/Span2D{T}.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ public ref T DangerousGetReferenceAt(int i, int j)
957957
/// are negative or not within the bounds that are valid for the current instance.
958958
/// </exception>
959959
/// <returns>A new <see cref="Span2D{T}"/> instance representing a slice of the current one.</returns>
960-
public Span2D<T> Slice(int row, int column, int height, int width)
960+
public unsafe Span2D<T> Slice(int row, int column, int height, int width)
961961
{
962962
if ((uint)row >= Height)
963963
{
@@ -987,7 +987,7 @@ public Span2D<T> Slice(int row, int column, int height, int width)
987987

988988
return new(ref r0, height, width, pitch);
989989
#else
990-
IntPtr offset = this.Offset + (shift * (nint)(uint)Unsafe.SizeOf<T>());
990+
IntPtr offset = this.Offset + (shift * (nint)(uint)sizeof(T));
991991

992992
return new(this.Instance, offset, height, width, pitch);
993993
#endif

src/CommunityToolkit.Mvvm/Messaging/IMessengerExtensions.Observables.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6-
using System.Diagnostics.CodeAnalysis;
7-
using System.Linq;
8-
using System.Linq.Expressions;
9-
using System.Reflection;
10-
using System.Runtime.CompilerServices;
11-
using CommunityToolkit.Mvvm.Messaging.Internals;
126

137
namespace CommunityToolkit.Mvvm.Messaging;
148

tests/CommunityToolkit.HighPerformance.UnitTests/Buffers/Internals/UnmanagedSpanOwner.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System;
66
using System.Buffers;
7-
using System.Runtime.CompilerServices;
87
using System.Runtime.InteropServices;
98

109
namespace CommunityToolkit.HighPerformance.UnitTests.Buffers.Internals;
@@ -32,7 +31,7 @@ internal sealed unsafe class UnmanagedSpanOwner<T> : MemoryManager<T>
3231
/// <param name="size">The size of the buffer to rent.</param>
3332
public UnmanagedSpanOwner(int size)
3433
{
35-
this.ptr = Marshal.AllocHGlobal(size * Unsafe.SizeOf<T>());
34+
this.ptr = Marshal.AllocHGlobal(size * sizeof(T));
3635
this.length = size;
3736
}
3837

tests/CommunityToolkit.HighPerformance.UnitTests/Extensions/Test_IBufferWriterExtensions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using System.Buffers;
88
#endif
99
using System.IO;
10-
using System.Runtime.CompilerServices;
1110
using CommunityToolkit.HighPerformance.Buffers;
1211
using Microsoft.VisualStudio.TestTools.UnitTesting;
1312

@@ -17,7 +16,7 @@ namespace CommunityToolkit.HighPerformance.UnitTests.Extensions;
1716
public class Test_IBufferWriterExtensions
1817
{
1918
[TestMethod]
20-
public void Test_IBufferWriterExtensions_WriteReadOverBytes()
19+
public unsafe void Test_IBufferWriterExtensions_WriteReadOverBytes()
2120
{
2221
ArrayPoolBufferWriter<byte> writer = new();
2322

@@ -33,7 +32,7 @@ public void Test_IBufferWriterExtensions_WriteReadOverBytes()
3332
writer.Write(d);
3433
writer.Write(guid);
3534

36-
int count = sizeof(byte) + sizeof(char) + sizeof(float) + sizeof(double) + Unsafe.SizeOf<Guid>();
35+
int count = sizeof(byte) + sizeof(char) + sizeof(float) + sizeof(double) + sizeof(Guid);
3736

3837
Assert.AreEqual(count, writer.WrittenCount);
3938

tests/CommunityToolkit.Mvvm.UnitTests/Test_RelayCommandAttribute.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System.Reflection;
99
using System.Threading;
1010
using System.Threading.Tasks;
11-
using System.Windows.Input;
1211
using CommunityToolkit.Mvvm.ComponentModel;
1312
using CommunityToolkit.Mvvm.Input;
1413
using Microsoft.VisualStudio.TestTools.UnitTesting;

0 commit comments

Comments
 (0)