diff --git a/src/MaterialEditor.Core.Studio/Core.MaterialEditor.SceneController.cs b/src/MaterialEditor.Core.Studio/Core.MaterialEditor.SceneController.cs
index 2438e56c..95659603 100644
--- a/src/MaterialEditor.Core.Studio/Core.MaterialEditor.SceneController.cs
+++ b/src/MaterialEditor.Core.Studio/Core.MaterialEditor.SceneController.cs
@@ -672,7 +672,7 @@ internal static int SetAndGetTextureID(byte[] textureBytes)
{
int highestID = 0;
foreach (var tex in TextureDictionary)
- if (tex.Value.Data.SequenceEqual(textureBytes))
+ if (Utility.SequenceEqualFast(tex.Value.Data,textureBytes))
return tex.Key;
else if (tex.Key > highestID)
highestID = tex.Key;
diff --git a/src/MaterialEditor.Core/Core.MaterialEditor.CharaController.cs b/src/MaterialEditor.Core/Core.MaterialEditor.CharaController.cs
index 943c5cf6..b8d4bc8b 100644
--- a/src/MaterialEditor.Core/Core.MaterialEditor.CharaController.cs
+++ b/src/MaterialEditor.Core/Core.MaterialEditor.CharaController.cs
@@ -855,7 +855,7 @@ private int SetAndGetTextureID(byte[] textureBytes)
{
int highestID = 0;
foreach (var tex in TextureDictionary)
- if (tex.Value.Data.SequenceEqual(textureBytes))
+ if (Utility.SequenceEqualFast(tex.Value.Data,textureBytes))
return tex.Key;
else if (tex.Key > highestID)
highestID = tex.Key;
diff --git a/src/Shared.TextureContainer/Shared.TextureContainerManager.cs b/src/Shared.TextureContainer/Shared.TextureContainerManager.cs
index b05d9dae..58b10106 100644
--- a/src/Shared.TextureContainer/Shared.TextureContainerManager.cs
+++ b/src/Shared.TextureContainer/Shared.TextureContainerManager.cs
@@ -41,20 +41,18 @@ public TextureKey(byte[] data, TextureFormat format = TextureFormat.ARGB32, bool
public override bool Equals(object obj)
{
- if (obj is TextureKey)
+ if (obj is TextureKey other)
{
- var other = (TextureKey)obj;
-
- return
- other.hash == hash &&
+ return other.hash == hash &&
other.format == format &&
other.mipmaps == mipmaps &&
- other.data.SequenceEqual(data);
+ Utility.SequenceEqualFast(other.data, data);
}
return false;
}
+
public override int GetHashCode()
{
return hash;
diff --git a/src/Shared/Shared.Utility.cs b/src/Shared/Shared.Utility.cs
new file mode 100644
index 00000000..6fdbe4de
--- /dev/null
+++ b/src/Shared/Shared.Utility.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace KK_Plugins
+{
+ internal class Utility
+ {
+
+ ///
+ /// Compares two byte arrays for equality in a high-performance manner using unsafe code.
+ ///
+ /// The first byte array to compare.
+ /// The second byte array to compare.
+ /// True if the byte arrays are equal, false otherwise.
+ static public bool SequenceEqualFast(byte[] a, byte[] b)
+ {
+ // Check if both references are the same, if so, return true.
+ if (System.Object.ReferenceEquals(a, b))
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ int bytes = a.Length;
+
+ if (bytes != b.Length)
+ return false;
+
+ if (bytes <= 0)
+ return true;
+
+ unsafe
+ {
+ // Fix the memory locations of the arrays to prevent the garbage collector from moving them.
+ fixed (byte* pA = &a[0])
+ fixed (byte* pB = &b[0])
+ {
+ int offset = 0;
+
+ // If both pointers are 8-byte aligned, use 64-bit comparison.
+ if (((int)pA & 7) == 0 && ((int)pB & 7) == 0 && bytes >= 32)
+ {
+ offset = bytes & ~31; // Round down to the nearest multiple of 32.
+
+ byte* pA_ = pA;
+ byte* pB_ = pB;
+ byte* pALast = pA + offset;
+
+ do
+ {
+ if (*(ulong*)pA_ != *(ulong*)pB_)
+ goto NotEquals;
+
+ pA_ += 8;
+ pB_ += 8;
+
+ if (*(ulong*)pA_ != *(ulong*)pB_)
+ goto NotEquals;
+
+ pA_ += 8;
+ pB_ += 8;
+
+ if (*(ulong*)pA_ != *(ulong*)pB_)
+ goto NotEquals;
+
+ pA_ += 8;
+ pB_ += 8;
+
+ if (*(ulong*)pA_ != *(ulong*)pB_)
+ goto NotEquals;
+
+ pA_ += 8;
+ pB_ += 8;
+ }
+ while (pA_ != pALast);
+ }
+ // If both pointers are 4-byte aligned, use 32-bit comparison.
+ else if (((int)pA & 3) == 0 && ((int)pB & 3) == 0 && bytes >= 16)
+ {
+ offset = bytes & ~15; // Round down to the nearest multiple of 16.
+
+ byte* pA_ = pA;
+ byte* pB_ = pB;
+ byte* pALast = pA + offset;
+
+ do
+ {
+ if (*(uint*)pA_ != *(uint*)pB_)
+ goto NotEquals;
+
+ pA_ += 4;
+ pB_ += 4;
+
+ if (*(uint*)pA_ != *(uint*)pB_)
+ goto NotEquals;
+
+ pA_ += 4;
+ pB_ += 4;
+
+ if (*(uint*)pA_ != *(uint*)pB_)
+ goto NotEquals;
+
+ pA_ += 4;
+ pB_ += 4;
+
+ if (*(uint*)pA_ != *(uint*)pB_)
+ goto NotEquals;
+
+ pA_ += 4;
+ pB_ += 4;
+ }
+ while (pA_ != pALast);
+ }
+
+ // Compare remaining bytes one by one.
+ for (int i = offset; i < bytes; ++i)
+ if (pA[i] != pB[i])
+ goto NotEquals;
+ }
+ }
+
+ return true;
+
+NotEquals:
+ // Return false indicating arrays are not equal.
+ // Note: Using a return statement in the loop can potentially degrade performance due to the generated binary code,
+ return false;
+ }
+ }
+}
diff --git a/src/Shared/Shared.projitems b/src/Shared/Shared.projitems
index 06660f8b..806939b0 100644
--- a/src/Shared/Shared.projitems
+++ b/src/Shared/Shared.projitems
@@ -15,5 +15,6 @@
+
\ No newline at end of file