Skip to content

Commit b6736b0

Browse files
Merge pull request #2418 from gfoidl/fixed-improvements
Improvements around `fixed`
2 parents bab277c + f65122b commit b6736b0

File tree

11 files changed

+39
-85
lines changed

11 files changed

+39
-85
lines changed

src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public static float Compress(float channel)
167167
[MethodImpl(MethodImplOptions.AggressiveInlining)]
168168
private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
169169
{
170-
fixed (float* tablePointer = &table[0])
170+
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
171171
{
172172
var scale = Vector256.Create((float)Scale);
173173
Vector256<float> zero = Vector256<float>.Zero;
@@ -199,7 +199,7 @@ private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
199199
[MethodImpl(MethodImplOptions.AggressiveInlining)]
200200
private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table)
201201
{
202-
fixed (float* tablePointer = &table[0])
202+
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
203203
{
204204
Vector4 zero = Vector4.Zero;
205205
var scale = new Vector4(Scale);

src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
1515
/// 8x8 matrix of <see cref="short"/> coefficients.
1616
/// </summary>
1717
// ReSharper disable once InconsistentNaming
18-
[StructLayout(LayoutKind.Explicit)]
19-
internal unsafe partial struct Block8x8
18+
[StructLayout(LayoutKind.Explicit, Size = 2 * Size)]
19+
internal partial struct Block8x8
2020
{
2121
/// <summary>
2222
/// A number of scalar coefficients in a <see cref="Block8x8F"/>
2323
/// </summary>
2424
public const int Size = 64;
2525

26-
#pragma warning disable IDE0051 // Remove unused private member
27-
/// <summary>
28-
/// A placeholder buffer so the actual struct occupies exactly 64 * 2 bytes.
29-
/// </summary>
30-
/// <remarks>
31-
/// This is not used directly in the code.
32-
/// </remarks>
33-
[FieldOffset(0)]
34-
private fixed short data[Size];
35-
#pragma warning restore IDE0051
36-
3726
/// <summary>
3827
/// Gets or sets a <see cref="short"/> value at the given index
3928
/// </summary>
@@ -74,9 +63,10 @@ public short this[int idx]
7463

7564
public static Block8x8 Load(Span<short> data)
7665
{
77-
Unsafe.SkipInit(out Block8x8 result);
78-
result.LoadFrom(data);
79-
return result;
66+
DebugGuard.MustBeGreaterThanOrEqualTo(data.Length, Size, "data is too small");
67+
68+
ref byte src = ref Unsafe.As<short, byte>(ref MemoryMarshal.GetReference(data));
69+
return Unsafe.ReadUnaligned<Block8x8>(ref src);
8070
}
8171

8272
/// <summary>
@@ -104,9 +94,10 @@ public short[] ToArray()
10494
/// </summary>
10595
public void CopyTo(Span<short> destination)
10696
{
107-
ref byte selfRef = ref Unsafe.As<Block8x8, byte>(ref this);
108-
ref byte destRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<short, byte>(destination));
109-
Unsafe.CopyBlockUnaligned(ref destRef, ref selfRef, Size * sizeof(short));
97+
DebugGuard.MustBeGreaterThanOrEqualTo(destination.Length, Size, "destination is too small");
98+
99+
ref byte destRef = ref Unsafe.As<short, byte>(ref MemoryMarshal.GetReference(destination));
100+
Unsafe.WriteUnaligned(ref destRef, this);
110101
}
111102

112103
/// <summary>
@@ -135,19 +126,6 @@ public void LoadFrom(ReadOnlySpan<byte> source)
135126
}
136127
}
137128

138-
/// <summary>
139-
/// Load raw 16bit integers from source.
140-
/// </summary>
141-
/// <param name="source">Source</param>
142-
[MethodImpl(InliningOptions.ShortMethod)]
143-
public void LoadFrom(Span<short> source)
144-
{
145-
ref byte sourceRef = ref Unsafe.As<short, byte>(ref MemoryMarshal.GetReference(source));
146-
ref byte destRef = ref Unsafe.As<Block8x8, byte>(ref this);
147-
148-
Unsafe.CopyBlockUnaligned(ref destRef, ref sourceRef, Size * sizeof(short));
149-
}
150-
151129
/// <summary>
152130
/// Cast and copy <see cref="Size"/> <see cref="int"/>-s from the beginning of 'source' span.
153131
/// </summary>

src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,24 +101,17 @@ internal float this[nuint idx]
101101
set => this[((uint)y * 8) + (uint)x] = value;
102102
}
103103

104-
public static Block8x8F Load(Span<float> data)
105-
{
106-
Block8x8F result = default;
107-
result.LoadFrom(data);
108-
return result;
109-
}
110-
111104
/// <summary>
112105
/// Load raw 32bit floating point data from source.
113106
/// </summary>
114-
/// <param name="source">Source</param>
107+
/// <param name="data">Source</param>
115108
[MethodImpl(InliningOptions.ShortMethod)]
116-
public void LoadFrom(Span<float> source)
109+
public static Block8x8F Load(Span<float> data)
117110
{
118-
ref byte s = ref Unsafe.As<float, byte>(ref MemoryMarshal.GetReference(source));
119-
ref byte d = ref Unsafe.As<Block8x8F, byte>(ref this);
111+
DebugGuard.MustBeGreaterThanOrEqualTo(data.Length, Size, "data is too small");
120112

121-
Unsafe.CopyBlock(ref d, ref s, Size * sizeof(float));
113+
ref byte src = ref Unsafe.As<float, byte>(ref MemoryMarshal.GetReference(data));
114+
return Unsafe.ReadUnaligned<Block8x8F>(ref src);
122115
}
123116

124117
/// <summary>
@@ -144,10 +137,10 @@ public unsafe void LoadFrom(Span<int> source)
144137
[MethodImpl(InliningOptions.ShortMethod)]
145138
public unsafe void ScaledCopyTo(float[] dest)
146139
{
147-
fixed (void* ptr = &this.V0L)
148-
{
149-
Marshal.Copy((IntPtr)ptr, dest, 0, Size);
150-
}
140+
DebugGuard.MustBeGreaterThanOrEqualTo(dest.Length, Size, "dest is too small");
141+
142+
ref byte destRef = ref Unsafe.As<float, byte>(ref MemoryMarshal.GetArrayDataReference(dest));
143+
Unsafe.WriteUnaligned(ref destRef, this);
151144
}
152145

153146
public float[] ToArray()

src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,8 +1474,7 @@ private static uint Select(uint a, uint b, uint c, Span<short> scratch)
14741474
{
14751475
if (Sse2.IsSupported)
14761476
{
1477-
Span<short> output = scratch;
1478-
fixed (short* p = output)
1477+
fixed (short* ptr = &MemoryMarshal.GetReference(scratch))
14791478
{
14801479
Vector128<byte> a0 = Sse2.ConvertScalarToVector128UInt32(a).AsByte();
14811480
Vector128<byte> b0 = Sse2.ConvertScalarToVector128UInt32(b).AsByte();
@@ -1489,8 +1488,8 @@ private static uint Select(uint a, uint b, uint c, Span<short> scratch)
14891488
Vector128<byte> pa = Sse2.UnpackLow(ac, Vector128<byte>.Zero); // |a - c|
14901489
Vector128<byte> pb = Sse2.UnpackLow(bc, Vector128<byte>.Zero); // |b - c|
14911490
Vector128<ushort> diff = Sse2.Subtract(pb.AsUInt16(), pa.AsUInt16());
1492-
Sse2.Store((ushort*)p, diff);
1493-
int paMinusPb = output[3] + output[2] + output[1] + output[0];
1491+
Sse2.Store((ushort*)ptr, diff);
1492+
int paMinusPb = ptr[3] + ptr[2] + ptr[1] + ptr[0];
14941493
return (paMinusPb <= 0) ? a : b;
14951494
}
14961495
}

tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_MultiplyInPlaceBlock.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ private static Block8x8F Create8x8FloatData()
2929
}
3030
}
3131

32-
var source = default(Block8x8F);
33-
source.LoadFrom(result);
34-
return source;
32+
return Block8x8F.Load(result);
3533
}
3634
}

tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ public void Load_Store_FloatArray()
9999
Times,
100100
() =>
101101
{
102-
var b = default(Block8x8F);
103-
b.LoadFrom(data);
102+
Block8x8F b = Block8x8F.Load(data);
104103
b.ScaledCopyTo(mirror);
105104
});
106105

@@ -117,8 +116,7 @@ static void RunTest()
117116
float[] expected = Create8x8FloatData();
118117
ReferenceImplementations.Transpose8x8(expected);
119118

120-
var block8x8 = default(Block8x8F);
121-
block8x8.LoadFrom(Create8x8FloatData());
119+
Block8x8F block8x8 = Block8x8F.Load(Create8x8FloatData());
122120

123121
block8x8.TransposeInplace();
124122

@@ -153,9 +151,8 @@ private static float[] Create8x8ColorCropTestData()
153151
[Fact]
154152
public void NormalizeColors()
155153
{
156-
var block = default(Block8x8F);
157154
float[] input = Create8x8ColorCropTestData();
158-
block.LoadFrom(input);
155+
Block8x8F block = Block8x8F.Load(input);
159156
this.Output.WriteLine("Input:");
160157
this.PrintLinearData(input);
161158

@@ -242,8 +239,7 @@ public void RoundInto()
242239
{
243240
float[] data = Create8x8RandomFloatData(-1000, 1000);
244241

245-
var source = default(Block8x8F);
246-
source.LoadFrom(data);
242+
Block8x8F source = Block8x8F.Load(data);
247243
var dest = default(Block8x8);
248244

249245
source.RoundInto(ref dest);

tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,7 @@ static void RunTest()
269269
short[] expected = Create8x8ShortData();
270270
ReferenceImplementations.Transpose8x8(expected);
271271

272-
var block8x8 = default(Block8x8);
273-
block8x8.LoadFrom(Create8x8ShortData());
272+
Block8x8 block8x8 = Block8x8.Load(Create8x8ShortData());
274273

275274
block8x8.TransposeInplace();
276275

tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ static void RunTest(string serialized)
114114
int seed = FeatureTestRunner.Deserialize<int>(serialized);
115115

116116
Span<float> src = Create8x8RandomFloatData(MinInputValue, MaxInputValue, seed);
117-
var srcBlock = default(Block8x8F);
118-
srcBlock.LoadFrom(src);
117+
Block8x8F srcBlock = Block8x8F.Load(src);
119118

120119
float[] expectedDest = new float[64];
121120
float[] temp = new float[64];
@@ -162,8 +161,7 @@ static void RunTest(string serialized)
162161
public void TranformIDCT_4x4(int seed)
163162
{
164163
Span<float> src = Create8x8RandomFloatData(MinInputValue, MaxInputValue, seed, 4, 4);
165-
var srcBlock = default(Block8x8F);
166-
srcBlock.LoadFrom(src);
164+
Block8x8F srcBlock = Block8x8F.Load(src);
167165

168166
float[] expectedDest = new float[64];
169167
float[] temp = new float[64];
@@ -224,8 +222,7 @@ static void AssertScaledElementEquality(Span<float> expected, Span<float> actual
224222
public void TranformIDCT_2x2(int seed)
225223
{
226224
Span<float> src = Create8x8RandomFloatData(MinInputValue, MaxInputValue, seed, 2, 2);
227-
var srcBlock = default(Block8x8F);
228-
srcBlock.LoadFrom(src);
225+
Block8x8F srcBlock = Block8x8F.Load(src);
229226

230227
float[] expectedDest = new float[64];
231228
float[] temp = new float[64];
@@ -286,8 +283,7 @@ static void AssertScaledElementEquality(Span<float> expected, Span<float> actual
286283
public void TranformIDCT_1x1(int seed)
287284
{
288285
Span<float> src = Create8x8RandomFloatData(MinInputValue, MaxInputValue, seed, 1, 1);
289-
var srcBlock = default(Block8x8F);
290-
srcBlock.LoadFrom(src);
286+
Block8x8F srcBlock = Block8x8F.Load(src);
291287

292288
float[] expectedDest = new float[64];
293289
float[] temp = new float[64];
@@ -330,8 +326,7 @@ static void RunTest(string serialized)
330326
int seed = FeatureTestRunner.Deserialize<int>(serialized);
331327

332328
Span<float> src = Create8x8RandomFloatData(MinInputValue, MaxInputValue, seed);
333-
var block = default(Block8x8F);
334-
block.LoadFrom(src);
329+
Block8x8F block = Block8x8F.Load(src);
335330

336331
float[] expectedDest = new float[64];
337332
float[] temp1 = new float[64];

tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ public void ForwardThenInverse(int seed)
2525
{
2626
float[] data = Create8x8RandomFloatData(-1000, 1000, seed);
2727

28-
var b0 = default(Block8x8F);
29-
b0.LoadFrom(data);
28+
Block8x8F b0 = Block8x8F.Load(data);
3029

3130
Block8x8F b1 = ReferenceImplementations.AccurateDCT.TransformFDCT(ref b0);
3231
Block8x8F b2 = ReferenceImplementations.AccurateDCT.TransformIDCT(ref b1);

tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ public void LLM_FDCT_IsEquivalentTo_AccurateImplementation(int seed)
7070
{
7171
float[] floatData = Create8x8RandomFloatData(-1000, 1000);
7272

73-
Block8x8F source = default;
74-
source.LoadFrom(floatData);
73+
Block8x8F source = Block8x8F.Load(floatData);
7574

7675
Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformFDCT(ref source);
7776
Block8x8F actual = ReferenceImplementations.LLM_FloatingPoint_DCT.TransformFDCT_UpscaleBy8(ref source);

0 commit comments

Comments
 (0)