Skip to content

Commit ff752a2

Browse files
Sequential layout plus faster equality checks.
1 parent b458ff2 commit ff752a2

File tree

14 files changed

+142
-102
lines changed

14 files changed

+142
-102
lines changed

src/ImageSharp/ColorProfiles/CieLab.cs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

910
/// <summary>
1011
/// Represents a CIE L*a*b* 1976 color.
1112
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
1213
/// </summary>
14+
[StructLayout(LayoutKind.Sequential)]
1315
public readonly struct CieLab : IProfileConnectingSpace<CieLab, CieXyz>
1416
{
1517
/// <summary>
@@ -80,20 +82,6 @@ public CieLab(Vector3 vector)
8082
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8183
public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right);
8284

83-
/// <inheritdoc/>
84-
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B);
85-
86-
/// <inheritdoc/>
87-
public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
88-
89-
/// <inheritdoc/>
90-
public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other);
91-
92-
/// <inheritdoc/>
93-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
94-
public bool Equals(CieLab other)
95-
=> new Vector3(this.L, this.A, this.B) == new Vector3(other.L, other.A, other.B);
96-
9785
/// <inheritdoc/>
9886
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9987
public static CieLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
@@ -171,4 +159,20 @@ public static void ToProfileConnectionSpace(ColorConversionOptions options, Read
171159
/// <inheritdoc/>
172160
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
173161
=> ChromaticAdaptionWhitePointSource.WhitePoint;
162+
163+
/// <inheritdoc/>
164+
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B);
165+
166+
/// <inheritdoc/>
167+
public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
168+
169+
/// <inheritdoc/>
170+
public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other);
171+
172+
/// <inheritdoc/>
173+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
174+
public bool Equals(CieLab other)
175+
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
176+
177+
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLab, Vector3>(ref Unsafe.AsRef(in this));
174178
}

src/ImageSharp/ColorProfiles/CieLch.cs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

910
/// <summary>
1011
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color.
1112
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC"/>
1213
/// </summary>
14+
[StructLayout(LayoutKind.Sequential)]
1315
public readonly struct CieLch : IColorProfile<CieLch, CieLab>
1416
{
1517
private static readonly Vector3 Min = new(0, -200, 0);
@@ -80,22 +82,6 @@ public CieLch(Vector3 vector)
8082
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8183
public static bool operator !=(CieLch left, CieLch right) => !left.Equals(right);
8284

83-
/// <inheritdoc/>
84-
public override int GetHashCode()
85-
=> HashCode.Combine(this.L, this.C, this.H);
86-
87-
/// <inheritdoc/>
88-
public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
89-
90-
/// <inheritdoc/>
91-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
92-
public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other);
93-
94-
/// <inheritdoc/>
95-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
96-
public bool Equals(CieLch other)
97-
=> new Vector3(this.L, this.C, this.H) == new Vector3(other.L, other.C, other.H);
98-
9985
/// <inheritdoc/>
10086
public static CieLch FromProfileConnectingSpace(ColorConversionOptions options, in CieLab source)
10187
{
@@ -159,4 +145,22 @@ public static void ToProfileConnectionSpace(ColorConversionOptions options, Read
159145
/// <inheritdoc/>
160146
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
161147
=> ChromaticAdaptionWhitePointSource.WhitePoint;
148+
149+
/// <inheritdoc/>
150+
public override int GetHashCode()
151+
=> HashCode.Combine(this.L, this.C, this.H);
152+
153+
/// <inheritdoc/>
154+
public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
155+
156+
/// <inheritdoc/>
157+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
158+
public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other);
159+
160+
/// <inheritdoc/>
161+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
162+
public bool Equals(CieLch other)
163+
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
164+
165+
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLch, Vector3>(ref Unsafe.AsRef(in this));
162166
}

src/ImageSharp/ColorProfiles/CieLchuv.cs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

910
/// <summary>
1011
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color.
1112
/// <see href="https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC"/>
1213
/// </summary>
14+
[StructLayout(LayoutKind.Sequential)]
1315
public readonly struct CieLchuv : IColorProfile<CieLchuv, CieXyz>
1416
{
1517
private static readonly Vector3 Min = new(0, -200, 0);
@@ -159,25 +161,7 @@ public override bool Equals(object? obj)
159161
/// <inheritdoc/>
160162
[MethodImpl(MethodImplOptions.AggressiveInlining)]
161163
public bool Equals(CieLchuv other)
162-
=> new Vector3(this.L, this.C, this.H) == new Vector3(other.L, other.C, other.H);
164+
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
163165

164-
/// <summary>
165-
/// Computes the saturation of the color (chroma normalized by lightness)
166-
/// </summary>
167-
/// <remarks>
168-
/// A value ranging from 0 to 100.
169-
/// </remarks>
170-
/// <returns>The <see cref="float"/></returns>
171-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
172-
public float Saturation()
173-
{
174-
float result = 100 * (this.C / this.L);
175-
176-
if (float.IsNaN(result))
177-
{
178-
return 0;
179-
}
180-
181-
return result;
182-
}
166+
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLchuv, Vector3>(ref Unsafe.AsRef(in this));
183167
}

src/ImageSharp/ColorProfiles/CieLuv.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

@@ -12,6 +13,7 @@ namespace SixLabors.ImageSharp.ColorProfiles;
1213
/// attempted perceptual uniformity
1314
/// <see href="https://en.wikipedia.org/wiki/CIELUV"/>
1415
/// </summary>
16+
[StructLayout(LayoutKind.Sequential)]
1517
public readonly struct CieLuv : IColorProfile<CieLuv, CieXyz>
1618
{
1719
/// <summary>
@@ -205,7 +207,9 @@ public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSo
205207
/// <inheritdoc/>
206208
[MethodImpl(MethodImplOptions.AggressiveInlining)]
207209
public bool Equals(CieLuv other)
208-
=> new Vector3(this.L, this.U, this.V) == new Vector3(other.L, other.U, other.V);
210+
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
211+
212+
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLuv, Vector3>(ref Unsafe.AsRef(in this));
209213

210214
[MethodImpl(MethodImplOptions.AggressiveInlining)]
211215
private static double ComputeU(in CieXyz source)

src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

7-
// ReSharper disable CompareOfFloatsByEqualityOperator
88
namespace SixLabors.ImageSharp.ColorProfiles;
99

1010
/// <summary>
1111
/// Represents the coordinates of CIEXY chromaticity space.
1212
/// </summary>
13+
[StructLayout(LayoutKind.Sequential)]
1314
public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromaticityCoordinates>
1415
{
1516
/// <summary>
@@ -80,5 +81,7 @@ public override bool Equals(object? obj)
8081
/// <inheritdoc/>
8182
[MethodImpl(InliningOptions.ShortMethod)]
8283
public bool Equals(CieXyChromaticityCoordinates other)
83-
=> new Vector2(this.X, this.Y) == new Vector2(other.X, other.Y);
84+
=> this.AsVector2Unsafe() == other.AsVector2Unsafe();
85+
86+
private Vector2 AsVector2Unsafe() => Unsafe.As<CieXyChromaticityCoordinates, Vector2>(ref Unsafe.AsRef(in this));
8487
}

src/ImageSharp/ColorProfiles/CieXyy.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

910
/// <summary>
1011
/// Represents an CIE xyY 1931 color
1112
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space"/>
1213
/// </summary>
14+
[StructLayout(LayoutKind.Sequential)]
1315
public readonly struct CieXyy : IColorProfile<CieXyy, CieXyz>
1416
{
1517
/// <summary>
@@ -150,5 +152,7 @@ public override string ToString()
150152
/// <inheritdoc/>
151153
[MethodImpl(MethodImplOptions.AggressiveInlining)]
152154
public bool Equals(CieXyy other)
153-
=> new Vector3(this.X, this.Y, this.Yl) == new Vector3(other.X, other.Y, other.Yl);
155+
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
156+
157+
private Vector3 AsVector3Unsafe() => Unsafe.As<CieXyy, Vector3>(ref Unsafe.AsRef(in this));
154158
}

src/ImageSharp/ColorProfiles/CieXyz.cs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

910
/// <summary>
1011
/// Represents an CIE XYZ 1931 color
1112
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space#Definition_of_the_CIE_XYZ_color_space"/>
1213
/// </summary>
14+
[StructLayout(LayoutKind.Sequential)]
1315
public readonly struct CieXyz : IProfileConnectingSpace<CieXyz, CieXyz>
1416
{
1517
/// <summary>
@@ -86,20 +88,6 @@ public CieXyz(Vector3 vector)
8688
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8789
public Vector3 ToVector3() => new(this.X, this.Y, this.Z);
8890

89-
/// <inheritdoc/>
90-
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z);
91-
92-
/// <inheritdoc/>
93-
public override string ToString() => FormattableString.Invariant($"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})");
94-
95-
/// <inheritdoc/>
96-
public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other);
97-
98-
/// <inheritdoc/>
99-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
100-
public bool Equals(CieXyz other)
101-
=> new Vector3(this.X, this.Y, this.Z) == new Vector3(other.X, other.Y, other.Z);
102-
10391
/// <inheritdoc/>
10492
public static CieXyz FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
10593
=> new(source.X, source.Y, source.Z);
@@ -124,4 +112,20 @@ public static void ToProfileConnectionSpace(ColorConversionOptions options, Read
124112

125113
/// <inheritdoc/>
126114
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint;
115+
116+
/// <inheritdoc/>
117+
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z);
118+
119+
/// <inheritdoc/>
120+
public override string ToString() => FormattableString.Invariant($"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})");
121+
122+
/// <inheritdoc/>
123+
public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other);
124+
125+
/// <inheritdoc/>
126+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
127+
public bool Equals(CieXyz other)
128+
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
129+
130+
private Vector3 AsVector3Unsafe() => Unsafe.As<CieXyz, Vector3>(ref Unsafe.AsRef(in this));
127131
}

src/ImageSharp/ColorProfiles/Cmyk.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

910
/// <summary>
1011
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
1112
/// </summary>
13+
[StructLayout(LayoutKind.Sequential)]
1214
public readonly struct Cmyk : IColorProfile<Cmyk, Rgb>
1315
{
1416
private static readonly Vector4 Min = Vector4.Zero;
@@ -157,5 +159,7 @@ public override bool Equals(object? obj)
157159
/// <inheritdoc/>
158160
[MethodImpl(MethodImplOptions.AggressiveInlining)]
159161
public bool Equals(Cmyk other)
160-
=> new Vector4(this.C, this.M, this.Y, this.K) == new Vector4(other.C, other.M, other.Y, other.K);
162+
=> this.AsVector4Unsafe() == other.AsVector4Unsafe();
163+
164+
private Vector4 AsVector4Unsafe() => Unsafe.As<Cmyk, Vector4>(ref Unsafe.AsRef(in this));
161165
}

src/ImageSharp/ColorProfiles/Hsl.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

910
/// <summary>
1011
/// Represents a Hsl (hue, saturation, lightness) color.
1112
/// </summary>
13+
[StructLayout(LayoutKind.Sequential)]
1214
public readonly struct Hsl : IColorProfile<Hsl, Rgb>
1315
{
1416
private static readonly Vector3 Min = Vector3.Zero;
@@ -200,7 +202,9 @@ public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSo
200202
/// <inheritdoc/>
201203
[MethodImpl(MethodImplOptions.AggressiveInlining)]
202204
public bool Equals(Hsl other)
203-
=> new Vector3(this.H, this.S, this.L) == new Vector3(other.H, other.S, other.L);
205+
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
206+
207+
private Vector3 AsVector3Unsafe() => Unsafe.As<Hsl, Vector3>(ref Unsafe.AsRef(in this));
204208

205209
[MethodImpl(MethodImplOptions.AggressiveInlining)]
206210
private static float GetColorComponent(float first, float second, float third)

src/ImageSharp/ColorProfiles/Hsv.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
using System.Numerics;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
67

78
namespace SixLabors.ImageSharp.ColorProfiles;
89

910
/// <summary>
1011
/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness).
1112
/// </summary>
13+
[StructLayout(LayoutKind.Sequential)]
1214
public readonly struct Hsv : IColorProfile<Hsv, Rgb>
1315
{
1416
private static readonly Vector3 Min = Vector3.Zero;
@@ -223,5 +225,7 @@ public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSo
223225
/// <inheritdoc/>
224226
[MethodImpl(MethodImplOptions.AggressiveInlining)]
225227
public bool Equals(Hsv other)
226-
=> new Vector3(this.H, this.S, this.V) == new Vector3(other.H, other.S, other.V);
228+
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
229+
230+
private Vector3 AsVector3Unsafe() => Unsafe.As<Hsv, Vector3>(ref Unsafe.AsRef(in this));
227231
}

0 commit comments

Comments
 (0)