From d60d4833ca111e3e2febf88cdd81f887ea163fa9 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sun, 5 Feb 2023 07:36:50 +0100 Subject: [PATCH] Reduced some allocations mostly due to boxing --- .../Color/Behaviors/DefaultColorBehavior.cs | 27 ++++++++++------- .../Color/Behaviors/IColorBehavior.cs | 8 +++++ RGB.NET.Core/Color/Color.cs | 9 +++++- RGB.NET.Core/MVVM/AbstractBindable.cs | 5 ++-- RGB.NET.Core/Positioning/Placeable.cs | 14 ++++----- RGB.NET.Core/Positioning/Point.cs | 18 ++++++----- RGB.NET.Core/Positioning/Rectangle.cs | 30 +++++++------------ RGB.NET.Core/Positioning/Rotation.cs | 2 +- RGB.NET.Core/Positioning/Scale.cs | 5 ++-- RGB.NET.Core/Positioning/Size.cs | 30 ++++++++----------- .../Textures/Sampler/AverageColorSampler.cs | 2 +- 11 files changed, 80 insertions(+), 70 deletions(-) diff --git a/RGB.NET.Core/Color/Behaviors/DefaultColorBehavior.cs b/RGB.NET.Core/Color/Behaviors/DefaultColorBehavior.cs index 6942325..baa3515 100644 --- a/RGB.NET.Core/Color/Behaviors/DefaultColorBehavior.cs +++ b/RGB.NET.Core/Color/Behaviors/DefaultColorBehavior.cs @@ -6,7 +6,7 @@ namespace RGB.NET.Core; /// /// Represents the default-behavior for the work with colors. /// -public class DefaultColorBehavior : IColorBehavior +public sealed class DefaultColorBehavior : IColorBehavior { #region Methods @@ -14,7 +14,7 @@ public class DefaultColorBehavior : IColorBehavior /// Converts the individual byte values of this to a human-readable string. /// /// A string that contains the individual byte values of this . For example "[A: 255, R: 255, G: 0, B: 0]". - public virtual string ToString(in Color color) => $"[A: {color.GetA()}, R: {color.GetR()}, G: {color.GetG()}, B: {color.GetB()}]"; + public string ToString(in Color color) => $"[A: {color.GetA()}, R: {color.GetR()}, G: {color.GetG()}, B: {color.GetB()}]"; /// /// Tests whether the specified object is a and is equivalent to this . @@ -22,28 +22,35 @@ public class DefaultColorBehavior : IColorBehavior /// The color to test. /// The object to test. /// true if is a equivalent to this ; otherwise, false. - public virtual bool Equals(in Color color, object? obj) + public bool Equals(in Color color, object? obj) { if (obj is not Color color2) return false; - - return color.A.EqualsInTolerance(color2.A) - && color.R.EqualsInTolerance(color2.R) - && color.G.EqualsInTolerance(color2.G) - && color.B.EqualsInTolerance(color2.B); + return Equals(color, color2); } + /// + /// Tests whether the specified object is a and is equivalent to this . + /// + /// The first color to test. + /// The second color to test. + /// true if equivalent to this ; otherwise, false. + public bool Equals(in Color color, in Color color2) => color.A.EqualsInTolerance(color2.A) + && color.R.EqualsInTolerance(color2.R) + && color.G.EqualsInTolerance(color2.G) + && color.B.EqualsInTolerance(color2.B); + /// /// Returns a hash code for this . /// /// An integer value that specifies the hash code for this . - public virtual int GetHashCode(in Color color) => HashCode.Combine(color.A, color.R, color.G, color.B); + public int GetHashCode(in Color color) => HashCode.Combine(color.A, color.R, color.G, color.B); /// /// Blends a over this color. /// /// The to to blend over. /// The to blend. - public virtual Color Blend(in Color baseColor, in Color blendColor) + public Color Blend(in Color baseColor, in Color blendColor) { if (blendColor.A.EqualsInTolerance(0)) return baseColor; diff --git a/RGB.NET.Core/Color/Behaviors/IColorBehavior.cs b/RGB.NET.Core/Color/Behaviors/IColorBehavior.cs index 29b6614..f365f37 100644 --- a/RGB.NET.Core/Color/Behaviors/IColorBehavior.cs +++ b/RGB.NET.Core/Color/Behaviors/IColorBehavior.cs @@ -20,6 +20,14 @@ public interface IColorBehavior /// true if is a equivalent to this ; otherwise, false. bool Equals(in Color color, object? obj); + /// + /// Tests whether the specified object is a and is equivalent to this . + /// + /// The first color to test. + /// The second color to test. + /// true if equivalent to this ; otherwise, false. + bool Equals(in Color color, in Color color2); + /// /// Returns a hash code for this . /// diff --git a/RGB.NET.Core/Color/Color.cs b/RGB.NET.Core/Color/Color.cs index ae775d3..c786502 100644 --- a/RGB.NET.Core/Color/Color.cs +++ b/RGB.NET.Core/Color/Color.cs @@ -11,7 +11,7 @@ namespace RGB.NET.Core; /// Represents an ARGB (alpha, red, green, blue) color. /// [DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")] -public readonly struct Color +public readonly struct Color : IEquatable { #region Constants @@ -196,6 +196,13 @@ public readonly struct Color /// true if is a equivalent to this ; otherwise, false. public override bool Equals(object? obj) => Behavior.Equals(this, obj); + /// + /// Tests whether the specified is equivalent to this , as defined by the current . + /// + /// The color to test. + /// true if is equivalent to this ; otherwise, false. + public bool Equals(Color other) => Behavior.Equals(this, other); + /// /// Returns a hash code for this , as defined by the current . /// diff --git a/RGB.NET.Core/MVVM/AbstractBindable.cs b/RGB.NET.Core/MVVM/AbstractBindable.cs index c58c1ae..b12f302 100644 --- a/RGB.NET.Core/MVVM/AbstractBindable.cs +++ b/RGB.NET.Core/MVVM/AbstractBindable.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.Generic; +using System.ComponentModel; using System.Runtime.CompilerServices; namespace RGB.NET.Core; @@ -28,7 +29,7 @@ public abstract class AbstractBindable : IBindable /// Value to apply. /// true if the value needs to be updated; otherweise false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected virtual bool RequiresUpdate(ref T storage, T value) => !Equals(storage, value); + protected virtual bool RequiresUpdate(ref T storage, T value) => !EqualityComparer.Default.Equals(storage, value); /// /// Checks if the property already matches the desired value and updates it if not. diff --git a/RGB.NET.Core/Positioning/Placeable.cs b/RGB.NET.Core/Positioning/Placeable.cs index 29ca551..81b6d82 100644 --- a/RGB.NET.Core/Positioning/Placeable.cs +++ b/RGB.NET.Core/Positioning/Placeable.cs @@ -211,7 +211,7 @@ public class Placeable : AbstractBindable, IPlaceable /// protected virtual void OnLocationChanged() { - LocationChanged?.Invoke(this, new EventArgs()); + LocationChanged?.Invoke(this, EventArgs.Empty); UpdateActualPlaceableData(); } @@ -220,7 +220,7 @@ public class Placeable : AbstractBindable, IPlaceable /// protected virtual void OnSizeChanged() { - SizeChanged?.Invoke(this, new EventArgs()); + SizeChanged?.Invoke(this, EventArgs.Empty); UpdateActualPlaceableData(); } @@ -229,7 +229,7 @@ public class Placeable : AbstractBindable, IPlaceable /// protected virtual void OnScaleChanged() { - ScaleChanged?.Invoke(this, new EventArgs()); + ScaleChanged?.Invoke(this, EventArgs.Empty); UpdateActualPlaceableData(); } @@ -238,24 +238,24 @@ public class Placeable : AbstractBindable, IPlaceable /// protected virtual void OnRotationChanged() { - RotationChanged?.Invoke(this, new EventArgs()); + RotationChanged?.Invoke(this, EventArgs.Empty); UpdateActualPlaceableData(); } /// /// Called when the property was changed. /// - protected virtual void OnActualLocationChanged() => ActualLocationChanged?.Invoke(this, new EventArgs()); + protected virtual void OnActualLocationChanged() => ActualLocationChanged?.Invoke(this, EventArgs.Empty); /// /// Called when the property was changed. /// - protected virtual void OnActualSizeChanged() => ActualSizeChanged?.Invoke(this, new EventArgs()); + protected virtual void OnActualSizeChanged() => ActualSizeChanged?.Invoke(this, EventArgs.Empty); /// /// Called when the property was changed. /// - protected virtual void OnBoundaryChanged() => BoundaryChanged?.Invoke(this, new EventArgs()); + protected virtual void OnBoundaryChanged() => BoundaryChanged?.Invoke(this, EventArgs.Empty); #endregion } \ No newline at end of file diff --git a/RGB.NET.Core/Positioning/Point.cs b/RGB.NET.Core/Positioning/Point.cs index e2f3d97..e92c65f 100644 --- a/RGB.NET.Core/Positioning/Point.cs +++ b/RGB.NET.Core/Positioning/Point.cs @@ -10,7 +10,7 @@ namespace RGB.NET.Core; /// Represents a point consisting of a X- and a Y-position. /// [DebuggerDisplay("[X: {X}, Y: {Y}]")] -public readonly struct Point +public readonly struct Point : IEquatable { #region Constants @@ -59,18 +59,20 @@ public readonly struct Point /// A string that contains the and of this . For example "[X: 100, Y: 20]". public override string ToString() => $"[X: {X}, Y: {Y}]"; + /// + /// Tests whether the specified is equivalent to this . + /// + /// The point to test. + /// true if is equivalent to this ; otherwise, false. + public bool Equals(Point other) => ((float.IsNaN(X) && float.IsNaN(other.X)) || X.EqualsInTolerance(other.X)) + && ((float.IsNaN(Y) && float.IsNaN(other.Y)) || Y.EqualsInTolerance(other.Y)); + /// /// Tests whether the specified object is a and is equivalent to this . /// /// The object to test. /// true if is a equivalent to this ; otherwise, false. - public override bool Equals(object? obj) - { - if (obj is not Point comparePoint) return false; - - return ((float.IsNaN(X) && float.IsNaN(comparePoint.X)) || X.EqualsInTolerance(comparePoint.X)) - && ((float.IsNaN(Y) && float.IsNaN(comparePoint.Y)) || Y.EqualsInTolerance(comparePoint.Y)); - } + public override bool Equals(object? obj) => obj is Point other && Equals(other); /// /// Returns a hash code for this . diff --git a/RGB.NET.Core/Positioning/Rectangle.cs b/RGB.NET.Core/Positioning/Rectangle.cs index a178989..456a568 100644 --- a/RGB.NET.Core/Positioning/Rectangle.cs +++ b/RGB.NET.Core/Positioning/Rectangle.cs @@ -12,7 +12,7 @@ namespace RGB.NET.Core; /// Represents a rectangle defined by it's position and it's size. /// [DebuggerDisplay("[Location: {Location}, Size: {Size}]")] -public readonly struct Rectangle +public readonly struct Rectangle : IEquatable { #region Properties & Fields @@ -172,35 +172,25 @@ public readonly struct Rectangle /// A string that contains the and of this . For example "[Location: [X: 100, Y: 10], Size: [Width: 20, Height: [40]]". public override string ToString() => $"[Location: {Location}, Size: {Size}]"; + /// + /// Tests whether the specified is equivalent to this . + /// + /// The rectangle to test. + /// true if is equivalent to this ; otherwise, false. + public bool Equals(Rectangle other) => (Location == other.Location) && (Size == other.Size); + /// /// Tests whether the specified object is a and is equivalent to this . /// /// The object to test. /// true if is a equivalent to this ; otherwise, false. - public override bool Equals(object? obj) - { - if (obj is not Rectangle compareRect) - return false; - - if (GetType() != compareRect.GetType()) - return false; - - return (Location == compareRect.Location) && (Size == compareRect.Size); - } + public override bool Equals(object? obj) => obj is Rectangle other && Equals(other); /// /// Returns a hash code for this . /// /// An integer value that specifies the hash code for this . - public override int GetHashCode() - { - unchecked - { - int hashCode = Location.GetHashCode(); - hashCode = (hashCode * 397) ^ Size.GetHashCode(); - return hashCode; - } - } + public override int GetHashCode() => HashCode.Combine(Location, Size); #endregion diff --git a/RGB.NET.Core/Positioning/Rotation.cs b/RGB.NET.Core/Positioning/Rotation.cs index 58903b7..e204b75 100644 --- a/RGB.NET.Core/Positioning/Rotation.cs +++ b/RGB.NET.Core/Positioning/Rotation.cs @@ -10,7 +10,7 @@ namespace RGB.NET.Core; /// Represents an angular rotation. /// [DebuggerDisplay("[{" + nameof(Degrees) + "}°]")] -public readonly struct Rotation +public readonly struct Rotation : IEquatable { #region Constants diff --git a/RGB.NET.Core/Positioning/Scale.cs b/RGB.NET.Core/Positioning/Scale.cs index 8c88406..973bf9c 100644 --- a/RGB.NET.Core/Positioning/Scale.cs +++ b/RGB.NET.Core/Positioning/Scale.cs @@ -1,6 +1,7 @@ // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedMember.Global +using System; using System.Diagnostics; namespace RGB.NET.Core; @@ -9,7 +10,7 @@ namespace RGB.NET.Core; /// Represents a scaling. /// [DebuggerDisplay("[Horizontal: {Horizontal}, Vertical: {Vertical}]")] -public readonly struct Scale +public readonly struct Scale : IEquatable { #region Properties & Fields @@ -67,7 +68,7 @@ public readonly struct Scale /// Returns a hash code for this . /// /// An integer value that specifies the hash code for this . - public override int GetHashCode() { unchecked { return (Horizontal.GetHashCode() * 397) ^ Vertical.GetHashCode(); } } + public override int GetHashCode() => HashCode.Combine(Horizontal, Vertical); /// /// Deconstructs the scale into the horizontal and vertical value. diff --git a/RGB.NET.Core/Positioning/Size.cs b/RGB.NET.Core/Positioning/Size.cs index daba2ff..1a9a6d6 100644 --- a/RGB.NET.Core/Positioning/Size.cs +++ b/RGB.NET.Core/Positioning/Size.cs @@ -1,6 +1,7 @@ // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedMember.Global +using System; using System.Diagnostics; namespace RGB.NET.Core; @@ -9,7 +10,7 @@ namespace RGB.NET.Core; /// Represents a size consisting of a width and a height. /// [DebuggerDisplay("[Width: {Width}, Height: {Height}]")] -public readonly struct Size +public readonly struct Size : IEquatable { #region Constants @@ -67,33 +68,26 @@ public readonly struct Size /// A string that contains the and of this . For example "[Width: 100, Height: 20]". public override string ToString() => $"[Width: {Width}, Height: {Height}]"; + /// + /// Tests whether the specified is equivalent to this . + /// + /// The size to test. + /// true if is equivalent to this ; otherwise, false. + public bool Equals(Size other) => ((float.IsNaN(Width) && float.IsNaN(other.Width)) || Width.EqualsInTolerance(other.Width)) + && ((float.IsNaN(Height) && float.IsNaN(other.Height)) || Height.EqualsInTolerance(other.Height)); + /// /// Tests whether the specified object is a and is equivalent to this . /// /// The object to test. /// true if is a equivalent to this ; otherwise, false. - public override bool Equals(object? obj) - { - if (obj is not Size size) return false; - - (float width, float height) = size; - return ((float.IsNaN(Width) && float.IsNaN(width)) || Width.EqualsInTolerance(width)) - && ((float.IsNaN(Height) && float.IsNaN(height)) || Height.EqualsInTolerance(height)); - } + public override bool Equals(object? obj) => obj is Size other && Equals(other); /// /// Returns a hash code for this . /// /// An integer value that specifies the hash code for this . - public override int GetHashCode() - { - unchecked - { - int hashCode = Width.GetHashCode(); - hashCode = (hashCode * 397) ^ Height.GetHashCode(); - return hashCode; - } - } + public override int GetHashCode() => HashCode.Combine(Width, Height); /// /// Deconstructs the size into the width and height value. diff --git a/RGB.NET.Core/Rendering/Textures/Sampler/AverageColorSampler.cs b/RGB.NET.Core/Rendering/Textures/Sampler/AverageColorSampler.cs index f93d212..d8fd006 100644 --- a/RGB.NET.Core/Rendering/Textures/Sampler/AverageColorSampler.cs +++ b/RGB.NET.Core/Rendering/Textures/Sampler/AverageColorSampler.cs @@ -10,7 +10,7 @@ namespace RGB.NET.Core; /// /// Averages all components (A, R, G, B) of the colors separately which isn't ideal in cases where multiple different colors are combined. /// -public class AverageColorSampler : ISampler +public sealed class AverageColorSampler : ISampler { #region Constants