From ae4d816ebd180f51f73725467e8da451430b1d28 Mon Sep 17 00:00:00 2001 From: Maximilian Kalimon Date: Mon, 9 Aug 2021 06:44:19 +0200 Subject: [PATCH] v1.1 ### Additions - Added "SIMD_MinMax" functions to all types and contiguous Unity.Collections containers - Added a "Comparison" enum that is used in "IndexOf", "Contains" and "Count" algorithms, giving the caller a choice to express primitive where clauses, like "index of first x where x > 9000" ### Improvements - Substantially improved performance and reduced code size of "SIMD_Count" functions for all types (and added caller-site optimization options - see below) - "SIMD_Count" functions now have a TypeCode parameter "returnType" (set to the most inefficient - "TypeCode.UInt64" - by default) (unless the underlying type is exactly 64 bits wide), which can be overwritten for (s)byte and (u)short containers, in order to enable optimizations - Slightly improved performance of "SIMD_Contains" functions for all types - Improved performance of "SIMD_Min" and "SIMD_Max" functions for very small arrays for all types ### Changes - API BREAKING CHANGE: "SIMD_Count" extension methods now return ints (...since native collections "only" hold up to int.MaxValue elements) - API BREAKING CHANGE: Any call-sites which explicity declared an array traversal order before ("SIMD_Contains" and/or "SIMD_IndexOf") now require either an explicit "Comparison.EqualTo" parameter or a "traversalOrder:" named parameter declaration --- AssemblyInfo.cs | 4 +- Runtime/Algorithms/Contains.cs | 3680 ++++++++++++--- Runtime/Algorithms/Count.cs | 7029 +++++++++++++++++++++++------ Runtime/Algorithms/IndexOf.cs | 4573 ++++++++++++++++--- Runtime/Algorithms/Maximum.cs | 1109 ++--- Runtime/Algorithms/MinMax.cs | 3796 ++++++++++++++++ Runtime/Algorithms/Minimum.cs | 1102 +++-- Runtime/Enums/BitwiseOperation.cs | 12 +- Runtime/Enums/Comparison.cs | 20 + Runtime/Helpers/Compare.cs | 1059 +++++ Runtime/Helpers/Fallback.cs | 24 + Runtime/Helpers/PartialVectors.cs | 117 + Runtime/Helpers/SummationRange.cs | 12 +- Tests/AssemblyInfo.cs | 1 - Tests/Editor/CONSTANTS.cs | 8 - Tests/Editor/Contains.cs | 1808 +++++++- Tests/Editor/Count.cs | 2368 +++++++++- Tests/Editor/CountBits.cs | 82 +- Tests/Editor/Helpers.cs | 36 + Tests/Editor/IndexOfFIrst.cs | 4743 ++++++++++++++++++- Tests/Editor/IndexOfLast.cs | 4748 ++++++++++++++++++- Tests/Editor/Maximum.cs | 191 +- Tests/Editor/MinMax.cs | 167 + Tests/Editor/Minimum.cs | 191 +- Tests/Editor/ShouldMask.cs | 470 ++ Tests/Editor/Sum.cs | 100 +- manifest.json | 6 +- package.json | 2 +- 28 files changed, 32831 insertions(+), 4627 deletions(-) create mode 100644 Runtime/Algorithms/MinMax.cs create mode 100644 Runtime/Enums/Comparison.cs create mode 100644 Runtime/Helpers/Compare.cs create mode 100644 Runtime/Helpers/Fallback.cs create mode 100644 Runtime/Helpers/PartialVectors.cs delete mode 100644 Tests/Editor/CONSTANTS.cs create mode 100644 Tests/Editor/Helpers.cs create mode 100644 Tests/Editor/MinMax.cs create mode 100644 Tests/Editor/ShouldMask.cs diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs index 5b704db..e97b4a2 100644 --- a/AssemblyInfo.cs +++ b/AssemblyInfo.cs @@ -28,5 +28,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion("1.0.1.0")] -[assembly: AssemblyFileVersion("1.0.1.0")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/Runtime/Algorithms/Contains.cs b/Runtime/Algorithms/Contains.cs index 78fc28a..59fecaa 100644 --- a/Runtime/Algorithms/Contains.cs +++ b/Runtime/Algorithms/Contains.cs @@ -29,7 +29,7 @@ public static bool SIMD_Contains(bool* ptr, long length, bool value, TraversalOr } } #endif - return SIMD_Contains((byte*)ptr, length, *(byte*)&value, traversalOrder); + return SIMD_Contains((byte*)ptr, length, *(byte*)&value, Comparison.EqualTo, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -100,7 +100,7 @@ public static bool SIMD_Contains(this NativeSlice array, int index, int nu [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(byte* ptr, long length, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); @@ -113,44 +113,59 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr while (Hint.Likely(length >= 32)) { - int mask = Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi8(broadcast, Avx.mm256_loadu_si256(ptr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != -1)) + { + return true; + } } else { - ptr_v256++; - length -= 32; + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + ptr_v256++; + length -= 32; } if (Hint.Likely((int)length >= 16)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256))); - - if (Hint.Unlikely(mask != 0)) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } } else { - length -= 16; - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 16; + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); } else { } - v128 cmp = default(v128); if (Hint.Likely((int)length >= 8)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -159,24 +174,32 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } } else { - length -= 8; - ptr_v256 = (v256*)((long*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 8; + ptr_v256 = (v256*)((long*)ptr_v256 + 1); } else { } if (Hint.Likely((int)length >= 4)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)ptr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -185,24 +208,32 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } } else { - length -= 4; - ptr_v256 = (v256*)((int*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 4; + ptr_v256 = (v256*)((int*)ptr_v256 + 1); } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -211,22 +242,30 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b0011)) + { + return true; + } } else { - length -= 2; - ptr_v256 = (v256*)((short*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 2; + ptr_v256 = (v256*)((short*)ptr_v256 + 1); } else { } if (Hint.Likely(length != 0)) { - return *(byte*)ptr_v256 == value; + return Compare.Bytes(*(byte*)ptr_v256, value, where); } else { } @@ -240,25 +279,33 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr while (Hint.Likely(length >= 16)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.loadu_si128(ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.loadu_si128(ptr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } } else { - ptr_v128++; - length -= 16; + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + ptr_v128++; + length -= 16; } if (Hint.Likely((int)length >= 8)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -267,24 +314,32 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } } else { - length -= 8; - ptr_v128 = (v128*)((long*)ptr_v128 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 8; + ptr_v128 = (v128*)((long*)ptr_v128 + 1); } else { } if (Hint.Likely((int)length >= 4)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi32_si128(*(int*)ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -293,24 +348,32 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } } else { - length -= 4; - ptr_v128 = (v128*)((int*)ptr_v128 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 4; + ptr_v128 = (v128*)((int*)ptr_v128 + 1); } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.insert_epi16(default(v128), *(short*)ptr_v128, 0))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.insert_epi16(default(v128), *(short*)ptr_v128, 0), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -319,22 +382,30 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b0011)) + { + return true; + } } else { - length -= 2; - ptr_v128 = (v128*)((short*)ptr_v128 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 2; + ptr_v128 = (v128*)((short*)ptr_v128 + 1); } else { } if (Hint.Likely(length != 0)) { - return *(byte*)ptr_v128 == value; + return Compare.Bytes(*(byte*)ptr_v128, value, where); } else { } @@ -345,7 +416,7 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.Bytes(ptr[i], value, where)) { return true; } @@ -365,34 +436,52 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi8(broadcast, Avx.mm256_loadu_si256(endPtr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.Bytes256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) { endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)endPtr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -401,20 +490,29 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 4)) { endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -423,20 +521,29 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 2)) { endPtr_v256 = (v256*)((ushort*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(ushort*)endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(ushort*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -445,23 +552,28 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b0011)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((byte*)endPtr_v256 - 1); - if (*(byte*)endPtr_v256 == value) - { - return true; - } - else { } + return Compare.Bytes(*(byte*)endPtr_v256, value, where); } else { } @@ -476,21 +588,30 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.loadu_si128(endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) { endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi64x_si128(*(long*)endPtr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -499,20 +620,29 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 4)) { endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi32_si128(*(int*)endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -521,20 +651,29 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 2)) { endPtr_v128 = (v128*)((ushort*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi32_si128(*(ushort*)endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(ushort*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -543,23 +682,28 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b0011)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((byte*)endPtr_v128 - 1); - if (*(byte*)endPtr_v128 == value) - { - return true; - } - else { } + return Compare.Bytes(*(byte*)endPtr_v128, value, where); } else { } @@ -572,7 +716,7 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr while (length >= 0) { - if (ptr[length] == value) + if (Compare.Bytes(ptr[length], value, where)) { return true; } @@ -588,74 +732,74 @@ public static bool SIMD_Contains(byte* ptr, long length, byte value, TraversalOr } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(ushort* ptr, long length, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); @@ -668,42 +812,58 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers while (Hint.Likely(length >= 16)) { - int mask = Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi16(broadcast, Avx.mm256_loadu_si256(ptr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != -1)) + { + return true; + } } else { - ptr_v256++; - length -= 16; + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + ptr_v256++; + length -= 16; } if (Hint.Likely((int)length >= 8)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } } else { - length -= 8; - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 8; + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); } else { } if (Hint.Likely((int)length >= 4)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -712,24 +872,32 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } } else { - length -= 4; - ptr_v256 = (v256*)((long*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 4; + ptr_v256 = (v256*)((long*)ptr_v256 + 1); } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)ptr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -738,22 +906,30 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } } else { - length -= 2; - ptr_v256 = (v256*)((int*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 2; + ptr_v256 = (v256*)((int*)ptr_v256 + 1); } else { } if (Hint.Likely(length != 0)) { - return *(ushort*)ptr_v256 == value; + return Compare.UShorts(*(ushort*)ptr_v256, value, where); } else { } @@ -767,25 +943,33 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers while (Hint.Likely(length >= 8)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.loadu_si128(ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.loadu_si128(ptr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } } else { - ptr_v128++; - length -= 8; + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + ptr_v128++; + length -= 8; } if (Hint.Likely((int)length >= 4)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -794,24 +978,32 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } } else { - length -= 4; - ptr_v128 = (v128*)((long*)ptr_v128 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 4; + ptr_v128 = (v128*)((long*)ptr_v128 + 1); } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi32_si128(*(int*)ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -820,22 +1012,30 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } } else { - length -= 2; - ptr_v128 = (v128*)((int*)ptr_v128 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 2; + ptr_v128 = (v128*)((int*)ptr_v128 + 1); } else { } if (Hint.Likely(length != 0)) { - return *(ushort*)ptr_v128 == value; + return Compare.UShorts(*(ushort*)ptr_v128, value, where); } else { } @@ -846,7 +1046,7 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.UShorts(ptr[i], value, where)) { return true; } @@ -866,34 +1066,52 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi16(broadcast, Avx.mm256_loadu_si256(endPtr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.UShorts256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) { endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)endPtr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -902,20 +1120,29 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 4)) { endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -924,23 +1151,28 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((ushort*)endPtr_v256 - 1); - if (*(ushort*)endPtr_v256 == value) - { - return true; - } - else { } + return Compare.UShorts(*(ushort*)endPtr_v256, value, where); } else { } @@ -955,21 +1187,30 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.loadu_si128(endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) { endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi64x_si128(*(long*)endPtr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -978,20 +1219,29 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 4)) { endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi32_si128(*(int*)endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -1000,23 +1250,28 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((ushort*)endPtr_v128 - 1); - if (*(ushort*)endPtr_v128 == value) - { - return true; - } - else { } + return Compare.UShorts(*(ushort*)endPtr_v128, value, where); } else { } @@ -1029,7 +1284,7 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers while (length >= 0) { - if (ptr[length] == value) + if (Compare.UShorts(ptr[length], value, where)) { return true; } @@ -1045,74 +1300,74 @@ public static bool SIMD_Contains(ushort* ptr, long length, ushort value, Travers } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(uint* ptr, long length, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(uint* ptr, long length, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); @@ -1125,66 +1380,90 @@ public static bool SIMD_Contains(uint* ptr, long length, uint value, TraversalOr while (Hint.Likely(length >= 8)) { - int mask = Avx.mm256_movemask_ps(Avx2.mm256_cmpeq_epi32(broadcast, Avx.mm256_loadu_si256(ptr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != -1)) + { + return true; + } } else { - ptr_v256++; - length -= 8; + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + ptr_v256++; + length -= 8; } if (Hint.Likely((int)length >= 4)) { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256))); + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } } else { - length -= 4; - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 4; + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } else { - mask &= 0b0011; + mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } } else { - length -= 2; - ptr_v256 = (v256*)((long*)ptr_v256 + 1); + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + length -= 2; + ptr_v256 = (v256*)((long*)ptr_v256 + 1); } else { } if (Hint.Likely(length != 0)) { - return *(uint*)ptr_v256 == value; + return Compare.UInts(*(uint*)ptr_v256, value, where); } else { } @@ -1198,49 +1477,105 @@ public static bool SIMD_Contains(uint* ptr, long length, uint value, TraversalOr while (Hint.Likely(length >= 4)) { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.loadu_si128(ptr_v128))); - - if (Hint.Unlikely(mask != 0)) - { - return true; + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } } else { - ptr_v128++; - length -= 4; - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + ptr_v128++; + length -= 4; } if (Hint.Likely((int)length >= 2)) { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } else { - mask &= 0b0011; + mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (Sse4_1.IsSse41Supported) { - return true; + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } } else { - length -= 2; - ptr_v128 = (v128*)((long*)ptr_v128 + 1); - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + length -= 2; + ptr_v128 = (v128*)((long*)ptr_v128 + 1); } else { } if (Hint.Likely(length != 0)) { - return *(uint*)ptr_v128 == value; + return Compare.UInts(*(uint*)ptr_v128, value, where); } else { } @@ -1251,7 +1586,7 @@ public static bool SIMD_Contains(uint* ptr, long length, uint value, TraversalOr { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.UInts(ptr[i], value, where)) { return true; } @@ -1271,59 +1606,82 @@ public static bool SIMD_Contains(uint* ptr, long length, uint value, TraversalOr while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx.mm256_movemask_ps(Avx2.mm256_cmpeq_epi32(broadcast, Avx.mm256_loadu_si256(endPtr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.UInts256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) { endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)endPtr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } else { - mask &= 0b0011; + mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - return true; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((uint*)endPtr_v256 - 1); - if (*(uint*)endPtr_v256 == value) - { - return true; - } - else { } + return Compare.UInts(*(uint*)endPtr_v256, value, where); } else { } @@ -1338,46 +1696,100 @@ public static bool SIMD_Contains(uint* ptr, long length, uint value, TraversalOr while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.loadu_si128(endPtr_v128))); - - if (Hint.Unlikely(mask != 0)) + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { - return true; + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } } - else { } } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) { endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.cvtsi64x_si128(*(long*)endPtr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } else { - mask &= 0b0011; + mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (Sse4_1.IsSse41Supported) { - return true; + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } } - else { } } else { } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((uint*)endPtr_v128 - 1); - - if (*(uint*)endPtr_v128 == value) - { - return true; - } - else { } + + return Compare.UInts(*(uint*)endPtr_v128, value, where); } else { } @@ -1390,7 +1802,7 @@ public static bool SIMD_Contains(uint* ptr, long length, uint value, TraversalOr while (length >= 0) { - if (ptr[length] == value) + if (Compare.UInts(ptr[length], value, where)) { return true; } @@ -1406,74 +1818,74 @@ public static bool SIMD_Contains(uint* ptr, long length, uint value, TraversalOr } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(ulong* ptr, long length, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(ulong* ptr, long length, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); @@ -1486,81 +1898,159 @@ public static bool SIMD_Contains(ulong* ptr, long length, ulong value, Traversal while (Hint.Likely(length >= 4)) { - int mask = Avx.mm256_movemask_pd(Avx2.mm256_cmpeq_epi64(broadcast, Avx.mm256_loadu_si256(ptr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - return true; + if (Hint.Unlikely(mask != -1)) + { + return true; + } } else { - ptr_v256++; - length -= 4; + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + ptr_v256++; + length -= 4; } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_pd(Sse4_1.cmpeq_epi64(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256))); + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } } else { - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 2; + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 2; } else { } if (Hint.Likely(length != 0)) { - return *(ulong*)ptr_v256 == value; + return Compare.ULongs(*(ulong*)ptr_v256, value, where); } else { } return false; } - else if (Sse4_1.IsSse41Supported) + else if (Sse4_2.IsSse42Supported) { v128 broadcast = Sse2.set1_epi64x((long)value); v128* ptr_v128 = (v128*)ptr; while (Hint.Likely(length >= 2)) { - int mask = Sse2.movemask_pd(Sse4_1.cmpeq_epi64(broadcast, Sse2.loadu_si128(ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(ptr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } } else { - ptr_v128++; - length -= 2; + if (Hint.Unlikely(mask != 0)) + { + return true; + } } + + ptr_v128++; + length -= 2; } if (Hint.Likely(length != 0)) { - return *(ulong*)ptr_v128 == value; + return Compare.ULongs(*(ulong*)ptr_v128, value, where); } else { } return false; } + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x((long)value); + v128* ptr_v128 = (v128*)ptr; + + while (Hint.Likely(length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + ptr_v128++; + length -= 2; + } + + + if (Hint.Likely(length != 0)) + { + return Compare.ULongs(*(ulong*)ptr_v128, value, where); + } + else { } + + + return false; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.ULongs(ptr[i], value, where)) + { + return true; + } + else continue; + } + + return false; + } + } else { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.ULongs(ptr[i], value, where)) { return true; } @@ -1580,44 +2070,58 @@ public static bool SIMD_Contains(ulong* ptr, long length, ulong value, Traversal while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx.mm256_movemask_pd(Avx2.mm256_cmpeq_epi64(broadcast, Avx.mm256_loadu_si256(endPtr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.ULongs256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - return true; + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse2.movemask_pd(Sse4_1.cmpeq_epi64(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((ulong*)endPtr_v256 - 1); - if (*(ulong*)endPtr_v256 == value) - { - return true; - } - else { } + return Compare.ULongs(*(ulong*)endPtr_v256, value, where); } else { } return false; } - else if (Sse4_1.IsSse41Supported) + else if (Sse4_2.IsSse42Supported) { v128 broadcast = Sse2.set1_epi64x((long)value); v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL @@ -1625,29 +2129,92 @@ public static bool SIMD_Contains(ulong* ptr, long length, ulong value, Traversal while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse2.movemask_pd(Sse4_1.cmpeq_epi64(broadcast, Sse2.loadu_si128(endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - return true; + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } } - else { } } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((ulong*)endPtr_v128 - 1); - if (*(ulong*)endPtr_v128 == value) + return Compare.ULongs(*(ulong*)endPtr_v128, value, where); + } + else { } + + + return false; + } + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x((long)value); + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { - return true; + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((ulong*)endPtr_v128 - 1); + + return Compare.ULongs(*(ulong*)endPtr_v128, value, where); } else { } + + + return false; } - else { } + else + { + length--; + while (length >= 0) + { + if (Compare.ULongs(ptr[length], value, where)) + { + return true; + } + else + { + length--; + } + } - return false; + return false; + } } else { @@ -1655,7 +2222,7 @@ public static bool SIMD_Contains(ulong* ptr, long length, ulong value, Traversal while (length >= 0) { - if (ptr[length] == value) + if (Compare.ULongs(ptr[length], value, where)) { return true; } @@ -1671,374 +2238,2199 @@ public static bool SIMD_Contains(ulong* ptr, long length, ulong value, Traversal } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(sbyte* ptr, long length, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(sbyte* ptr, long length, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); - return SIMD_Contains((byte*)ptr, length, (byte)value); + if (traversalOrder == TraversalOrder.Ascending) + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi8((byte)value); + v256* ptr_v256 = (v256*)ptr; + + while (Hint.Likely(length >= 32)) + { + int mask = Avx2.mm256_movemask_epi8(Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + ptr_v256++; + length -= 32; + } + + + if (Hint.Likely((int)length >= 16)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 16; + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + } + else { } + + v128 cmp = default(v128); + + if (Hint.Likely((int)length >= 8)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 8; + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + } + else { } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 4; + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b0011)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 2; + ptr_v256 = (v256*)((short*)ptr_v256 + 1); + } + else { } + + + if (Hint.Likely(length != 0)) + { + return Compare.SBytes(*(sbyte*)ptr_v256, value, where); + } + else { } + + + return false; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi8(value); + v128* ptr_v128 = (v128*)ptr; + + while (Hint.Likely(length >= 16)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + ptr_v128++; + length -= 16; + } + + + if (Hint.Likely((int)length >= 8)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 8; + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + } + else { } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 4; + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.insert_epi16(default(v128), *(short*)ptr_v128, 0), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b0011)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 2; + ptr_v128 = (v128*)((short*)ptr_v128 + 1); + } + else { } + + + if (Hint.Likely(length != 0)) + { + return Compare.SBytes(*(sbyte*)ptr_v128, value, where); + } + else { } + + + return false; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.SBytes(ptr[i], value, where)) + { + return true; + } + else continue; + } + + return false; + } + } + else + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi8((byte)value); + v256* endPtr_v256 = (v256*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) + { + endPtr_v256--; + int mask = Avx2.mm256_movemask_epi8(Compare.SBytes256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) + { + endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) + { + endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 4)) + { + endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 2)) + { + endPtr_v256 = (v256*)((ushort*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(ushort*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b0011)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) + { + endPtr_v256 = (v256*)((sbyte*)endPtr_v256 - 1); + + return Compare.SBytes(*(sbyte*)endPtr_v256, value, where); + } + else { } + + + return false; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi8(value); + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 4)) + { + endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 2)) + { + endPtr_v128 = (v128*)((ushort*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(ushort*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b0011)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((sbyte*)endPtr_v128 - 1); + + return Compare.SBytes(*(sbyte*)endPtr_v128, value, where); + } + else { } + + + return false; + } + else + { + length--; + + while (length >= 0) + { + if (Compare.SBytes(ptr[length], value, where)) + { + return true; + } + else + { + length--; + } + } + + return false; + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeArray array, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeArray array, int index, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeList array, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeList array, int index, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeSlice array, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeSlice array, int index, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(short* ptr, long length, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsNonNegative(length); + + if (traversalOrder == TraversalOrder.Ascending) + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi16(value); + v256* ptr_v256 = (v256*)ptr; + + while (Hint.Likely(length >= 16)) + { + int mask = Avx2.mm256_movemask_epi8(Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + ptr_v256++; + length -= 16; + } + + + if (Hint.Likely((int)length >= 8)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 8; + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + } + else { } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 4; + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 2; + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + } + else { } + + + if (Hint.Likely(length != 0)) + { + return Compare.Shorts(*(short*)ptr_v256, value, where); + } + else { } + + + return false; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi16(value); + v128* ptr_v128 = (v128*)ptr; + + while (Hint.Likely(length >= 8)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + ptr_v128++; + length -= 8; + } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 4; + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 2; + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + } + else { } + + + if (Hint.Likely(length != 0)) + { + return Compare.Shorts(*(short*)ptr_v128, value, where); + } + else { } + + + return false; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.Shorts(ptr[i], value, where)) + { + return true; + } + else continue; + } + + return false; + } + } + else + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi16(value); + v256* endPtr_v256 = (v256*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) + { + endPtr_v256--; + int mask = Avx2.mm256_movemask_epi8(Compare.Shorts256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) + { + endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) + { + endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 4)) + { + endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) + { + endPtr_v256 = (v256*)((short*)endPtr_v256 - 1); + + return Compare.Shorts(*(short*)endPtr_v256, value, where); + } + else { } + + + return false; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi16(value); + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 4)) + { + endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((short*)endPtr_v128 - 1); + + return Compare.Shorts(*(short*)endPtr_v128, value, where); + } + else { } + + + return false; + } + else + { + length--; + + while (length >= 0) + { + if (Compare.Shorts(ptr[length], value, where)) + { + return true; + } + else + { + length--; + } + } + + return false; + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeArray array, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeArray array, int index, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeList array, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeList array, int index, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeSlice array, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeSlice array, int index, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool SIMD_Contains(int* ptr, long length, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsNonNegative(length); + + if (traversalOrder == TraversalOrder.Ascending) + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi32(value); + v256* ptr_v256 = (v256*)ptr; + + while (Hint.Likely(length >= 8)) + { + int mask = Avx2.mm256_movemask_epi8(Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + ptr_v256++; + length -= 8; + } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 4; + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 2; + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + } + else { } + + + if (Hint.Likely(length != 0)) + { + return Compare.Ints(*(int*)ptr_v256, value, where); + } + else { } + + + return false; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi32(value); + v128* ptr_v128 = (v128*)ptr; + + while (Hint.Likely(length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + ptr_v128++; + length -= 4; + } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + + length -= 2; + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + } + else { } + + + if (Hint.Likely(length != 0)) + { + return Compare.Ints(*(int*)ptr_v128, value, where); + } + else { } + + + return false; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.Ints(ptr[i], value, where)) + { + return true; + } + else continue; + } + + return false; + } + } + else + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi32(value); + v256* endPtr_v256 = (v256*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) + { + endPtr_v256--; + int mask = Avx2.mm256_movemask_epi8(Compare.Ints256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) + { + endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) + { + endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) + { + endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); + + return Compare.Ints(*(int*)endPtr_v256, value, where); + } + else { } + + + return false; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi32(value); + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); + + return Compare.Ints(*(int*)endPtr_v128, value, where); + } + else { } + + + return false; + } + else + { + length--; + + while (length >= 0) + { + if (Compare.Ints(ptr[length], value, where)) + { + return true; + } + else + { + length--; + } + } + + return false; + } + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(short* ptr, long length, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(long* ptr, long length, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); - return SIMD_Contains((ushort*)ptr, length, (ushort)value); - } + if (traversalOrder == TraversalOrder.Ascending) + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi64x(value); + v256* ptr_v256 = (v256*)ptr; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + while (Hint.Likely(length >= 4)) + { + int mask = Avx2.mm256_movemask_epi8(Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + ptr_v256++; + length -= 4; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 2; + } + else { } - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + if (Hint.Likely(length != 0)) + { + return Compare.Longs(*(long*)ptr_v256, value, where); + } + else { } - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + return false; + } + else if (Sse4_2.IsSse42Supported) + { + v128 broadcast = Sse2.set1_epi64x(value); + v128* ptr_v128 = (v128*)ptr; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + while (Hint.Likely(length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(ptr_v128), broadcast, where)); - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + ptr_v128++; + length -= 2; + } - return SIMD_Contains((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + if (Hint.Likely(length != 0)) + { + return Compare.Longs(*(long*)ptr_v128, value, where); + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(int* ptr, long length, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsNonNegative(length); - return SIMD_Contains((uint*)ptr, length, (uint)value); - } + return false; + } + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x(value); + v128* ptr_v128 = (v128*)ptr; + + while (Hint.Likely(length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + ptr_v128++; + length -= 2; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + if (Hint.Likely(length != 0)) + { + return Compare.Longs(*(long*)ptr_v128, value, where); + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + return false; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.Longs(ptr[i], value, where)) + { + return true; + } + else continue; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + return false; + } + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.Longs(ptr[i], value, where)) + { + return true; + } + else continue; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + return false; + } + } + else + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi64x(value); + v256* endPtr_v256 = (v256*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) + { + endPtr_v256--; + int mask = Avx2.mm256_movemask_epi8(Compare.Longs256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) + { + endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) + { + endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + return Compare.Longs(*(long*)endPtr_v256, value, where); + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + return false; + } + else if (Sse4_2.IsSse42Supported) + { + v128 broadcast = Sse2.set1_epi64x(value); + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(long* ptr, long length, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsNonNegative(length); + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - return SIMD_Contains((ulong*)ptr, length, (ulong)value); + return Compare.Longs(*(long*)endPtr_v128, value, where); + } + else { } + + + return false; + } + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x(value); + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + return true; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + return true; + } + } + } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + + return Compare.Longs(*(long*)endPtr_v128, value, where); + } + else { } + + + return false; + } + else + { + length--; + + while (length >= 0) + { + if (Compare.Longs(ptr[length], value, where)) + { + return true; + } + else + { + length--; + } + } + + return false; + } + } + else + { + length--; + + while (length >= 0) + { + if (Compare.Longs(ptr[length], value, where)) + { + return true; + } + else + { + length--; + } + } + + return false; + } + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(float* ptr, long length, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(float* ptr, long length, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); Assert.IsFalse(math.isnan(value)); @@ -2052,7 +4444,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal while (Hint.Likely(length >= 8)) { - int mask = Avx.mm256_movemask_ps(Avx.mm256_cmp_ps(broadcast, Avx.mm256_loadu_ps(ptr_v256), (int)Avx.CMP.EQ_OQ)); + int mask = Avx.mm256_movemask_ps(Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256), broadcast, where)); if (Hint.Unlikely(mask != 0)) { @@ -2068,7 +4460,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal if (Hint.Likely((int)length >= 4)) { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castps256_ps128(broadcast), Sse.loadu_ps(ptr_v256))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(ptr_v256), Avx.mm256_castps256_ps128(broadcast), where)); if (Hint.Unlikely(mask != 0)) { @@ -2085,9 +4477,9 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal if (Hint.Likely((int)length >= 2)) { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castps256_ps128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castps256_ps128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -2111,7 +4503,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal if (Hint.Likely(length != 0)) { - return *(float*)ptr_v256 == value; + return Compare.Floats(*(float*)ptr_v256, value, where); } else { } @@ -2125,7 +4517,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal while (Hint.Likely(length >= 4)) { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse.loadu_ps(ptr_v128))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(ptr_v128), broadcast, where)); if (Hint.Unlikely(mask != 0)) { @@ -2141,9 +4533,9 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal if (Hint.Likely((int)length >= 2)) { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -2167,7 +4559,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal if (Hint.Likely(length != 0)) { - return *(float*)ptr_v128 == value; + return Compare.Floats(*(float*)ptr_v128, value, where); } else { } @@ -2178,7 +4570,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.Floats(ptr[i], value, where)) { return true; } @@ -2198,7 +4590,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx.mm256_movemask_ps(Avx.mm256_cmp_ps(broadcast, Avx.mm256_loadu_ps(endPtr_v256), (int)Avx.CMP.EQ_OQ)); + int mask = Avx.mm256_movemask_ps(Compare.Floats256(Avx.mm256_loadu_ps(endPtr_v256), broadcast, where)); if (Hint.Unlikely(mask != 0)) { @@ -2210,7 +4602,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castps256_ps128(broadcast), Sse.loadu_ps(endPtr_v256))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(endPtr_v256), Avx.mm256_castps256_ps128(broadcast), where)); if (Hint.Unlikely(mask != 0)) { @@ -2223,9 +4615,9 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) { endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castps256_ps128(broadcast), Sse2.cvtsi64x_si128(*(long*)endPtr_v256))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castps256_ps128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -2242,15 +4634,11 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((float*)endPtr_v256 - 1); - - if (*(float*)endPtr_v256 == value) - { - return true; - } - else { } + + return Compare.Floats(*(float*)endPtr_v256, value, where); } else { } @@ -2265,7 +4653,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse.loadu_ps(endPtr_v128))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(endPtr_v128), broadcast, where)); if (Hint.Unlikely(mask != 0)) { @@ -2277,9 +4665,9 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) { endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse2.cvtsi64x_si128(*(long*)endPtr_v128))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (!Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -2296,15 +4684,11 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal } else { } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((float*)endPtr_v128 - 1); - if (*(float*)endPtr_v128 == value) - { - return true; - } - else { } + return Compare.Floats(*(float*)endPtr_v128, value, where); } else { } @@ -2317,7 +4701,7 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal while (length >= 0) { - if (ptr[length] == value) + if (Compare.Floats(ptr[length], value, where)) { return true; } @@ -2333,74 +4717,74 @@ public static bool SIMD_Contains(float* ptr, long length, float value, Traversal } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(double* ptr, long length, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(double* ptr, long length, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); Assert.IsFalse(math.isnan(value)); @@ -2414,7 +4798,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers while (Hint.Likely(length >= 4)) { - int mask = Avx.mm256_movemask_pd(Avx.mm256_cmp_pd(broadcast, Avx.mm256_loadu_pd(ptr_v256), (int)Avx.CMP.EQ_OQ)); + int mask = Avx.mm256_movemask_pd(Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256), broadcast, where)); if (Hint.Unlikely(mask != 0)) { @@ -2430,7 +4814,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_pd(Sse2.cmpeq_pd(Avx.mm256_castpd256_pd128(broadcast), Sse.loadu_ps(ptr_v256))); + int mask = Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(ptr_v256), Avx.mm256_castpd256_pd128(broadcast), where)); if (Hint.Unlikely(mask != 0)) { @@ -2447,7 +4831,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers if (Hint.Likely(length != 0)) { - return *(double*)ptr_v256 == value; + return Compare.Doubles(*(double*)ptr_v256, value, where); } else { } @@ -2461,7 +4845,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers while (Hint.Likely(length >= 2)) { - int mask = Sse2.movemask_pd(Sse2.cmpeq_pd(broadcast, Sse.loadu_ps(ptr_v128))); + int mask = Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(ptr_v128), broadcast, where)); if (Hint.Unlikely(mask != 0)) { @@ -2477,7 +4861,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers if (Hint.Likely(length != 0)) { - return *(double*)ptr_v128 == value; + return Compare.Doubles(*(double*)ptr_v128, value, where); } else { } @@ -2488,7 +4872,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.Doubles(ptr[i], value, where)) { return true; } @@ -2508,7 +4892,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx.mm256_movemask_pd(Avx.mm256_cmp_pd(broadcast, Avx.mm256_loadu_pd(endPtr_v256), (int)Avx.CMP.EQ_OQ)); + int mask = Avx.mm256_movemask_pd(Compare.Doubles256(Avx.mm256_loadu_pd(endPtr_v256), broadcast, where)); if (Hint.Unlikely(mask != 0)) { @@ -2520,7 +4904,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse2.movemask_pd(Sse2.cmpeq_pd(Avx.mm256_castpd256_pd128(broadcast), Sse.loadu_ps(endPtr_v256))); + int mask = Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(endPtr_v256), Avx.mm256_castpd256_pd128(broadcast), where)); if (Hint.Unlikely(mask != 0)) { @@ -2530,15 +4914,11 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((double*)endPtr_v256 - 1); - if (*(double*)endPtr_v256 == value) - { - return true; - } - else { } + return Compare.Doubles(*(double*)endPtr_v256, value, where); } else { } @@ -2553,7 +4933,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse2.movemask_pd(Sse2.cmpeq_pd(broadcast, Sse.loadu_ps(endPtr_v128))); + int mask = Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(endPtr_v128), broadcast, where)); if (Hint.Unlikely(mask != 0)) { @@ -2562,15 +4942,11 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers else { } } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((double*)endPtr_v128 - 1); - - if (*(double*)endPtr_v128 == value) - { - return true; - } - else { } + + return Compare.Doubles(*(double*)endPtr_v128, value, where); } else { } @@ -2583,7 +4959,7 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers while (length >= 0) { - if (ptr[length] == value) + if (Compare.Doubles(ptr[length], value, where)) { return true; } @@ -2599,69 +4975,69 @@ public static bool SIMD_Contains(double* ptr, long length, double value, Travers } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeArray array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeList array, int index, int numEntries, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeList array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static bool SIMD_Contains(this NativeSlice array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return SIMD_Contains((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } } } \ No newline at end of file diff --git a/Runtime/Algorithms/Count.cs b/Runtime/Algorithms/Count.cs index c99f26f..09e896f 100644 --- a/Runtime/Algorithms/Count.cs +++ b/Runtime/Algorithms/Count.cs @@ -14,8 +14,9 @@ namespace SIMDAlgorithms unsafe public static partial class Algorithms { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(bool* ptr, long length, bool value = true) + public static ulong SIMD_Count(bool* ptr, long length, bool value, TypeCode returnType) { +Assert.IsBetween((int)returnType, (int)TypeCode.SByte, (int)TypeCode.UInt64); Assert.IsNonNegative(length); Assert.IsSafeBoolean(value); #if DEBUG @@ -28,1490 +29,2973 @@ public static ulong SIMD_Count(bool* ptr, long length, bool value = true) } } #endif - if (Avx2.IsAvx2Supported) + + switch (returnType) { - ulong originalLength = (ulong)length; - v256* ptr_v256 = (v256*)ptr; - v256 ZERO = default(v256); - v256 count0; - v256 count1; - v256 count2; - v256 count3; - v256 longs = default(v256); - - while (Hint.Likely(length >= 255 * 32 * 4)) + case TypeCode.Byte: + case TypeCode.SByte: { - count0 = default(v256); - count1 = default(v256); - count2 = default(v256); - count3 = default(v256); - - for (int i = 0; i < 255; i++) + if (Avx2.IsAvx2Supported) { - count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); - count1 = Avx2.mm256_add_epi8(count1, Avx.mm256_loadu_si256(ptr_v256++)); - count2 = Avx2.mm256_add_epi8(count2, Avx.mm256_loadu_si256(ptr_v256++)); - count3 = Avx2.mm256_add_epi8(count3, Avx.mm256_loadu_si256(ptr_v256++)); - } + ulong originalLength = (ulong)length; + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely((int)length >= 32 * 4)) + { + count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); + count1 = Avx2.mm256_add_epi8(count1, Avx.mm256_loadu_si256(ptr_v256++)); + count2 = Avx2.mm256_add_epi8(count2, Avx.mm256_loadu_si256(ptr_v256++)); + count3 = Avx2.mm256_add_epi8(count3, Avx.mm256_loadu_si256(ptr_v256++)); - v256 sad0 = Avx2.mm256_sad_epu8(count0, ZERO); - v256 sad1 = Avx2.mm256_sad_epu8(count1, ZERO); - v256 sad2 = Avx2.mm256_sad_epu8(count2, ZERO); - v256 sad3 = Avx2.mm256_sad_epu8(count3, ZERO); + length -= 32 * 4; + } - v256 csum0 = Avx2.mm256_add_epi64(sad0, sad1); - v256 csum1 = Avx2.mm256_add_epi64(sad2, sad3); - v256 csum2 = Avx2.mm256_add_epi64(csum0, csum1); - longs = Avx2.mm256_add_epi64(longs, csum2); + count0 = Avx2.mm256_add_epi8(Avx2.mm256_add_epi8(count0, count1), Avx2.mm256_add_epi8(count2, count3)); + if (Hint.Likely((int)length >= 32)) + { + count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); - length -= 255 * 32 * 4; - } + if (Hint.Likely((int)length >= 2 * 32)) + { + count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); + + if (Hint.Likely((int)length >= 3 * 32)) + { + count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); + + length -= 3 * 32; + } + else + { + length -= 2 * 32; + } + } + else + { + length -= 32; + } + } + else { } + v128 count128 = Sse2.add_epi8(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); - { - count0 = default(v256); - count1 = default(v256); - count2 = default(v256); - count3 = default(v256); + if (Hint.Likely((int)length >= 16)) + { + count128 = Sse2.add_epi8(count128, Sse2.loadu_si128(ptr_v256)); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - while (Hint.Likely((int)length >= 32 * 4)) - { - count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); - count1 = Avx2.mm256_add_epi8(count1, Avx.mm256_loadu_si256(ptr_v256++)); - count2 = Avx2.mm256_add_epi8(count2, Avx.mm256_loadu_si256(ptr_v256++)); - count3 = Avx2.mm256_add_epi8(count3, Avx.mm256_loadu_si256(ptr_v256++)); + length -= 16; + } + else { } - length -= 32 * 4; - } + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); - v256 sad0 = Avx2.mm256_sad_epu8(count0, ZERO); - v256 sad1 = Avx2.mm256_sad_epu8(count1, ZERO); - v256 sad2 = Avx2.mm256_sad_epu8(count2, ZERO); - v256 sad3 = Avx2.mm256_sad_epu8(count3, ZERO); + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.add_epi8(count128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + ptr_v256 = (v256*)((long*)ptr_v256 + 1); - v256 csum0 = Avx2.mm256_add_epi64(sad0, sad1); - v256 csum1 = Avx2.mm256_add_epi64(sad2, sad3); - v256 csum2 = Avx2.mm256_add_epi64(csum0, csum1); - longs = Avx2.mm256_add_epi64(longs, csum2); - } + length -= 8; + } + else { } + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); - if (Hint.Likely((int)length >= 32)) - { - count0 = Avx.mm256_loadu_si256(ptr_v256++); + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.add_epi8(count128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + ptr_v256 = (v256*)((int*)ptr_v256 + 1); - if (Hint.Likely((int)length >= 2 * 32)) - { - count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); + length -= 4; + } + else { } - if (Hint.Likely((int)length >= 3 * 32)) + count128 = Sse2.add_epi8(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) { - count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); - length -= 3 * 32; + count128 = Sse2.add_epi8(count128, Sse2.insert_epi16(default(v128), *(ushort*)ptr_v256, 0)); + ptr_v256 = (v256*)((ushort*)ptr_v256 + 1); + + length -= 2; + } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.bsrli_si128(count128, 1 * sizeof(byte))); + + byte countTotal = count128.Byte0; + + if (Hint.Likely(length != 0)) + { + countTotal += *(byte*)ptr_v256; + } + else { } + + + if (value == true) + { + return countTotal; } else { - length -= 2 * 32; + return (byte)(originalLength - countTotal); } } - else + else if (Sse2.IsSse2Supported) { - length -= 32; - } - - longs = Avx2.mm256_add_epi64(longs, Avx2.mm256_sad_epu8(count0, ZERO)); - } - else { } + ulong originalLength = (ulong)length; + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely((int)length >= 16 * 4)) + { + count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); + count1 = Sse2.add_epi8(count1, Sse2.loadu_si128(ptr_v128++)); + count2 = Sse2.add_epi8(count2, Sse2.loadu_si128(ptr_v128++)); + count3 = Sse2.add_epi8(count3, Sse2.loadu_si128(ptr_v128++)); + + length -= 16 * 4; + } + count0 = Sse2.add_epi8(Sse2.add_epi8(count0, count1), Sse2.add_epi8(count2, count3)); - v128 bytes; - v128 longs128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longs), Avx2.mm256_extracti128_si256(longs, 1)); + if (Hint.Likely((int)length >= 16)) + { + count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); - if (Hint.Likely((int)length >= 16)) - { - bytes = Sse2.loadu_si128(ptr_v256); - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } - length -= 16; - } - else - { - bytes = default(v128); - } + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.add_epi8(count0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + ptr_v128 = (v128*)((long*)ptr_v128 + 1); - if (Hint.Likely((int)length >= 8)) - { - bytes = Sse2.add_epi8(bytes, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); - ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; + } + else { } - length -= 8; - } - else { } + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.add_epi8(count0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + ptr_v128 = (v128*)((int*)ptr_v128 + 1); - if (Hint.Likely((int)length >= 4)) - { - bytes = Sse2.add_epi8(bytes, Sse2.cvtsi32_si128(*(int*)ptr_v256)); - ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; + } + else { } - length -= 4; - } - else { } + count0 = Sse2.add_epi8(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.add_epi8(count0, Sse2.insert_epi16(default(v128), *(ushort*)ptr_v128, 0)); + ptr_v128 = (v128*)((ushort*)ptr_v128 + 1); - if (Hint.Likely((int)length >= 2)) - { - bytes = Sse2.add_epi8(bytes, Sse2.insert_epi16(default(v128), *(ushort*)ptr_v256, 0)); - ptr_v256 = (v256*)((ushort*)ptr_v256 + 1); + length -= 2; + } + else { } - length -= 2; - } - else { } + count0 = Sse2.add_epi8(count0, Sse2.bsrli_si128(count0, 1 * sizeof(byte))); + byte countTotal = count0.Byte0; - longs128 = Sse2.add_epi64(longs128, Sse2.sad_epu8(bytes, Avx.mm256_castsi256_si128(ZERO))); - longs128 = Sse2.add_epi64(longs128, Sse2.shuffle_epi32(longs128, Sse.SHUFFLE(0, 0, 3, 2))); + if (Hint.Likely(length != 0)) + { + countTotal += *(byte*)ptr_v128; + } + else { } - ulong countTotal = longs128.ULong0; - if (Hint.Likely(length != 0)) - { - countTotal += *(byte*)ptr_v256; - } - else { } + if (value == true) + { + return countTotal; + } + else + { + return (byte)(originalLength - countTotal); + } + } + else + { + byte count = 0; + for (long i = 0; i < length; i++) + { + count += *(byte*)ptr; + ptr++; + } - if (value == true) - { - return countTotal; - } - else - { - return originalLength - countTotal; + if (value == true) + { + return count; + } + else + { + return (byte)(length - count); + } + } } - } - else if (Sse2.IsSse2Supported) - { - ulong originalLength = (ulong)length; - v128* ptr_v128 = (v128*)ptr; - v128 ZERO = default(v128); - v128 count0; - v128 count1; - v128 count2; - v128 count3; - v128 longs = default(v128); - - while (Hint.Likely(length >= 255 * 16 * 4)) + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: { - count0 = default(v128); - count1 = default(v128); - count2 = default(v128); - count3 = default(v128); - - for (int i = 0; i < 255; i++) + if (Avx2.IsAvx2Supported) { - count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); - count1 = Sse2.add_epi8(count1, Sse2.loadu_si128(ptr_v128++)); - count2 = Sse2.add_epi8(count2, Sse2.loadu_si128(ptr_v128++)); - count3 = Sse2.add_epi8(count3, Sse2.loadu_si128(ptr_v128++)); - } + ulong originalLength = (ulong)length; + v256* ptr_v256 = (v256*)ptr; + v256 ZERO = default(v256); + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 longs = default(v256); + + while (Hint.Likely(length >= 255 * 32 * 4)) + { + for (int i = 0; i < 255; i++) + { + count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); + count1 = Avx2.mm256_add_epi8(count1, Avx.mm256_loadu_si256(ptr_v256++)); + count2 = Avx2.mm256_add_epi8(count2, Avx.mm256_loadu_si256(ptr_v256++)); + count3 = Avx2.mm256_add_epi8(count3, Avx.mm256_loadu_si256(ptr_v256++)); + } + + v256 sad0 = Avx2.mm256_sad_epu8(count0, ZERO); + v256 sad1 = Avx2.mm256_sad_epu8(count1, ZERO); + v256 sad2 = Avx2.mm256_sad_epu8(count2, ZERO); + v256 sad3 = Avx2.mm256_sad_epu8(count3, ZERO); + + v256 csum0 = Avx2.mm256_add_epi64(sad0, sad1); + v256 csum1 = Avx2.mm256_add_epi64(sad2, sad3); + v256 csum2 = Avx2.mm256_add_epi64(csum0, csum1); + longs = Avx2.mm256_add_epi64(longs, csum2); + + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + + length -= 255 * 32 * 4; + } - v128 sad0 = Sse2.sad_epu8(count0, ZERO); - v128 sad1 = Sse2.sad_epu8(count1, ZERO); - v128 sad2 = Sse2.sad_epu8(count2, ZERO); - v128 sad3 = Sse2.sad_epu8(count3, ZERO); - v128 csum0 = Sse2.add_epi64(sad0, sad1); - v128 csum1 = Sse2.add_epi64(sad2, sad3); - v128 csum2 = Sse2.add_epi64(csum0, csum1); - longs = Sse2.add_epi64(longs, csum2); + while (Hint.Likely((int)length >= 32 * 4)) + { + count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); + count1 = Avx2.mm256_add_epi8(count1, Avx.mm256_loadu_si256(ptr_v256++)); + count2 = Avx2.mm256_add_epi8(count2, Avx.mm256_loadu_si256(ptr_v256++)); + count3 = Avx2.mm256_add_epi8(count3, Avx.mm256_loadu_si256(ptr_v256++)); + + length -= 32 * 4; + } + + v256 sad0_2 = Avx2.mm256_sad_epu8(count0, ZERO); + v256 sad1_2 = Avx2.mm256_sad_epu8(count1, ZERO); + v256 sad2_2 = Avx2.mm256_sad_epu8(count2, ZERO); + v256 sad3_2 = Avx2.mm256_sad_epu8(count3, ZERO); + + v256 csum0_2 = Avx2.mm256_add_epi64(sad0_2, sad1_2); + v256 csum1_2 = Avx2.mm256_add_epi64(sad2_2, sad3_2); + v256 csum2_2 = Avx2.mm256_add_epi64(csum0_2, csum1_2); + longs = Avx2.mm256_add_epi64(longs, csum2_2); + + + if (Hint.Likely((int)length >= 32)) + { + count0 = Avx.mm256_loadu_si256(ptr_v256++); + + if (Hint.Likely((int)length >= 2 * 32)) + { + count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); + + if (Hint.Likely((int)length >= 3 * 32)) + { + count0 = Avx2.mm256_add_epi8(count0, Avx.mm256_loadu_si256(ptr_v256++)); + length -= 3 * 32; + } + else + { + length -= 2 * 32; + } + } + else + { + length -= 32; + } + + longs = Avx2.mm256_add_epi64(longs, Avx2.mm256_sad_epu8(count0, ZERO)); + } + else { } + + v128 bytes; + v128 longs128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longs), Avx2.mm256_extracti128_si256(longs, 1)); - length -= 255 * 16 * 4; - } + if (Hint.Likely((int)length >= 16)) + { + bytes = Sse2.loadu_si128(ptr_v256); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 16; + } + else + { + bytes = default(v128); + } - { - count0 = default(v128); - count1 = default(v128); - count2 = default(v128); - count3 = default(v128); - - while (Hint.Likely((int)length >= 16 * 4)) - { - count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); - count1 = Sse2.add_epi8(count1, Sse2.loadu_si128(ptr_v128++)); - count2 = Sse2.add_epi8(count2, Sse2.loadu_si128(ptr_v128++)); - count3 = Sse2.add_epi8(count3, Sse2.loadu_si128(ptr_v128++)); - - length -= 16 * 4; - } - - v128 sad0 = Sse2.sad_epu8(count0, ZERO); - v128 sad1 = Sse2.sad_epu8(count1, ZERO); - v128 sad2 = Sse2.sad_epu8(count2, ZERO); - v128 sad3 = Sse2.sad_epu8(count3, ZERO); - - v128 csum0 = Sse2.add_epi64(sad0, sad1); - v128 csum1 = Sse2.add_epi64(sad2, sad3); - v128 csum2 = Sse2.add_epi64(csum0, csum1); - longs = Sse2.add_epi64(longs, csum2); - } + if (Hint.Likely((int)length >= 8)) + { + bytes = Sse2.add_epi8(bytes, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + ptr_v256 = (v256*)((long*)ptr_v256 + 1); - if (Hint.Likely((int)length >= 16)) - { - count0 = Sse2.loadu_si128(ptr_v128++); + length -= 8; + } + else { } - if (Hint.Likely((int)length >= 2 * 16)) - { - count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); - if (Hint.Likely((int)length >= 3 * 16)) + if (Hint.Likely((int)length >= 4)) { - count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); - length -= 3 * 16; + bytes = Sse2.add_epi8(bytes, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + + length -= 4; + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + bytes = Sse2.add_epi8(bytes, Sse2.insert_epi16(default(v128), *(ushort*)ptr_v256, 0)); + ptr_v256 = (v256*)((ushort*)ptr_v256 + 1); + + length -= 2; + } + else { } + + + longs128 = Sse2.add_epi64(longs128, Sse2.sad_epu8(bytes, Avx.mm256_castsi256_si128(ZERO))); + longs128 = Sse2.add_epi64(longs128, Sse2.shuffle_epi32(longs128, Sse.SHUFFLE(0, 0, 3, 2))); + + ulong countTotal = longs128.ULong0; + + if (Hint.Likely(length != 0)) + { + countTotal += *(byte*)ptr_v256; + } + else { } + + + if (value == true) + { + return countTotal; } else { - length -= 2 * 16; + return originalLength - countTotal; } } - else + else if (Sse2.IsSse2Supported) { - length -= 16; - } - - longs = Sse2.add_epi64(longs, Sse2.sad_epu8(count0, ZERO)); - } - else { } + ulong originalLength = (ulong)length; + v128* ptr_v128 = (v128*)ptr; + v128 ZERO = default(v128); + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 longs = default(v128); + + while (Hint.Likely(length >= 255 * 16 * 4)) + { + for (int i = 0; i < 255; i++) + { + count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); + count1 = Sse2.add_epi8(count1, Sse2.loadu_si128(ptr_v128++)); + count2 = Sse2.add_epi8(count2, Sse2.loadu_si128(ptr_v128++)); + count3 = Sse2.add_epi8(count3, Sse2.loadu_si128(ptr_v128++)); + } + + v128 sad0 = Sse2.sad_epu8(count0, ZERO); + v128 sad1 = Sse2.sad_epu8(count1, ZERO); + v128 sad2 = Sse2.sad_epu8(count2, ZERO); + v128 sad3 = Sse2.sad_epu8(count3, ZERO); + + v128 csum0 = Sse2.add_epi64(sad0, sad1); + v128 csum1 = Sse2.add_epi64(sad2, sad3); + v128 csum2 = Sse2.add_epi64(csum0, csum1); + longs = Sse2.add_epi64(longs, csum2); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + + length -= 255 * 16 * 4; + } - v128 bytes; + while (Hint.Likely((int)length >= 16 * 4)) + { + count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); + count1 = Sse2.add_epi8(count1, Sse2.loadu_si128(ptr_v128++)); + count2 = Sse2.add_epi8(count2, Sse2.loadu_si128(ptr_v128++)); + count3 = Sse2.add_epi8(count3, Sse2.loadu_si128(ptr_v128++)); + + length -= 16 * 4; + } + + v128 sad0_2 = Sse2.sad_epu8(count0, ZERO); + v128 sad1_2 = Sse2.sad_epu8(count1, ZERO); + v128 sad2_2 = Sse2.sad_epu8(count2, ZERO); + v128 sad3_2 = Sse2.sad_epu8(count3, ZERO); + + v128 csum0_2 = Sse2.add_epi64(sad0_2, sad1_2); + v128 csum1_2 = Sse2.add_epi64(sad2_2, sad3_2); + v128 csum2_2 = Sse2.add_epi64(csum0_2, csum1_2); + longs = Sse2.add_epi64(longs, csum2_2); + + + if (Hint.Likely((int)length >= 16)) + { + count0 = Sse2.loadu_si128(ptr_v128++); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Sse2.add_epi8(count0, Sse2.loadu_si128(ptr_v128++)); + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + + longs = Sse2.add_epi64(longs, Sse2.sad_epu8(count0, ZERO)); + } + else { } - if (Hint.Likely((int)length >= 16)) - { - bytes = Sse2.loadu_si128(ptr_v128++); - length -= 16; - } - else - { - bytes = default(v128); - } + v128 bytes; + if (Hint.Likely((int)length >= 8)) + { + bytes = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + ptr_v128 = (v128*)((long*)ptr_v128 + 1); - if (Hint.Likely((int)length >= 8)) - { - bytes = Sse2.add_epi8(bytes, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); - ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + } + else + { + bytes = default(v128); + } - length -= 8; - } - else { } + if (Hint.Likely((int)length >= 4)) + { + bytes = Sse2.add_epi8(bytes, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + ptr_v128 = (v128*)((int*)ptr_v128 + 1); - if (Hint.Likely((int)length >= 4)) - { - bytes = Sse2.add_epi8(bytes, Sse2.cvtsi32_si128(*(int*)ptr_v128)); - ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + } + else { } - length -= 4; - } - else { } + if (Hint.Likely((int)length >= 2)) + { + bytes = Sse2.add_epi8(bytes, Sse2.insert_epi16(default(v128), *(ushort*)ptr_v128, 0)); + ptr_v128 = (v128*)((ushort*)ptr_v128 + 1); - if (Hint.Likely((int)length >= 2)) - { - bytes = Sse2.add_epi8(bytes, Sse2.insert_epi16(default(v128), *(ushort*)ptr_v128, 0)); - ptr_v128 = (v128*)((ushort*)ptr_v128 + 1); + length -= 2; + } + else { } - length -= 2; - } - else { } + longs = Sse2.add_epi64(longs, Sse2.sad_epu8(bytes, ZERO)); + longs = Sse2.add_epi64(longs, Sse2.shuffle_epi32(longs, Sse.SHUFFLE(0, 0, 3, 2))); - longs = Sse2.add_epi64(longs, Sse2.sad_epu8(bytes, ZERO)); - longs = Sse2.add_epi64(longs, Sse2.shuffle_epi32(longs, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = longs.ULong0; - ulong countTotal = longs.ULong0; + if (Hint.Likely(length != 0)) + { + countTotal += *(byte*)ptr_v128; + } + else { } - if (Hint.Likely(length != 0)) - { - countTotal += *(byte*)ptr_v128; - } - else { } + if (value == true) + { + return countTotal; + } + else + { + return originalLength - countTotal; + } + } + else + { + ulong count = 0; - if (value == true) - { - return countTotal; - } - else - { - return originalLength - countTotal; - } - } - else - { - ulong count = 0; + for (long i = 0; i < length; i++) + { + count += *(byte*)ptr; + ptr++; + } - for (long i = 0; i < length; i++) - { - count += *(byte*)ptr; - ptr++; + if (value == true) + { + return count; + } + else + { + return (ulong)length - count; + } + } } - if (value == true) - { - return count; - } - else - { - return (ulong)length - count; - } + default: return 0; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, bool value = true) + public static int SIMD_Count(this NativeArray array, bool value = true, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr(), array.Length, value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, bool value = true) + public static int SIMD_Count(this NativeArray array, int index, bool value= true, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, bool value = true) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, bool value= true, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, bool value = true) + public static int SIMD_Count(this NativeList array, bool value= true, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr(), array.Length, value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, bool value = true) + public static int SIMD_Count(this NativeList array, int index, bool value= true, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, bool value = true) + public static int SIMD_Count(this NativeList array, int index, int numEntries, bool value= true, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, bool value = true) + public static int SIMD_Count(this NativeSlice array, bool value= true, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr(), array.Length, value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, bool value = true) + public static int SIMD_Count(this NativeSlice array, int index, bool value= true, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, bool value = true) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, bool value= true, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((bool*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(byte* ptr, long length, byte value) + public static ulong SIMD_Count(byte* ptr, long length, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.UInt64) { +Assert.IsBetween((int)returnType, (int)TypeCode.SByte, (int)TypeCode.UInt64); Assert.IsNonNegative(length); + + long originalLength = length; - if (Avx2.IsAvx2Supported) + switch (returnType) { - v256 broadcast = Avx.mm256_set1_epi8(value); - v256* ptr_v256 = (v256*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; - - while (Hint.Likely(length >= 128)) + case TypeCode.Byte: + case TypeCode.SByte: { - v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); - - length -= 128; + if (Avx2.IsAvx2Supported) + { + v256 ZERO = Avx.mm256_setzero_si256(); - v256 cmpeq0 = Avx2.mm256_cmpeq_epi8(broadcast, load0); - v256 cmpeq1 = Avx2.mm256_cmpeq_epi8(broadcast, load1); - v256 cmpeq2 = Avx2.mm256_cmpeq_epi8(broadcast, load2); - v256 cmpeq3 = Avx2.mm256_cmpeq_epi8(broadcast, load3); + v256 broadcast = Avx.mm256_set1_epi8(value); + v256* ptr_v256 = (v256*)ptr; - int mask0 = Avx2.mm256_movemask_epi8(cmpeq0); - int mask1 = Avx2.mm256_movemask_epi8(cmpeq1); - int mask2 = Avx2.mm256_movemask_epi8(cmpeq2); - int mask3 = Avx2.mm256_movemask_epi8(cmpeq3); + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 4 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi8(count1, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi8(count2, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi8(count3, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); + length -= 4 * 32; + } - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; - } + count0 = Avx2.mm256_add_epi8(Avx2.mm256_add_epi8(count0, count1), Avx2.mm256_add_epi8(count2, count3)); + + if (Hint.Likely((int)length >= 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 32; + } + else + { + length -= 2 * 32; + } + } + else + { + length -= 32; + } + } + else { } - countTotal = (count0 + count1) + (count2 + count3); + v128 count128 = Sse2.add_epi8(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + if (Hint.Likely((int)length >= 16)) + { + count128 = Sse2.sub_epi8(count128, Compare.Bytes128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Likely((int)length >= 32)) - { - countTotal += (uint)math.countbits(Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi8(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 16; + } + else { } - if (Hint.Likely((int)length >= 2 * 32)) - { - countTotal += (uint)math.countbits(Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi8(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); - if (Hint.Likely((int)length >= 3 * 32)) + if (Hint.Likely((int)length >= 8)) { - countTotal += (uint)math.countbits(Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi8(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); - length -= 3 * 32; + count128 = Sse2.sub_epi8(count128, Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; } - else + else { } + + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 4)) { - length -= 2 * 32; + count128 = Sse2.sub_epi8(count128, Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; } - } - else - { - length -= 32; - } - } - else { } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi8(count128, Compare.Bytes128(Sse2.insert_epi16(default(v128), *(ushort*)ptr_v256, 0), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Likely((int)length >= 16)) - { - countTotal += (uint)math.countbits(Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256)))); - - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 16; - } - else { } + ptr_v256 = (v256*)((ushort*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.bsrli_si128(count128, 1 * sizeof(byte))); + byte countTotal = count128.Byte0; + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (byte)((ulong)originalLength - 1 - countTotal); + } - if (Hint.Likely((int)length >= 8)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); + bool comparison = Compare.Bytes(*(byte*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (byte)((ulong)originalLength - countTotal); + } + } - if (Constant.IsConstantExpression(value) && value != 0) - { - ; + return countTotal; } - else + else if (Sse2.IsSse2Supported) { - mask &= 0b1111_1111; - } + v128 ZERO = Sse2.setzero_si128(); + + v128* ptr_v128 = (v128*)ptr; - countTotal += (uint)math.countbits(mask); + v128 broadcast = Sse2.set1_epi8((sbyte)value); + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); - ptr_v256 = (v256*)((long*)ptr_v256 + 1); - length -= 8; - } - else { } + while (Hint.Likely(length >= 4 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi8(count1, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi8(count2, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi8(count3, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + length -= 4 * 16; + } - if (Hint.Likely((int)length >= 4)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)ptr_v256))); + count0 = Sse2.add_epi8(Sse2.add_epi8(count0, count1), Sse2.add_epi8(count2, count3)); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; - } - else - { - mask &= 0b1111; - } + if (Hint.Likely((int)length >= 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } - countTotal += (uint)math.countbits(mask); + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); - ptr_v256 = (v256*)((int*)ptr_v256 + 1); - length -= 4; - } - else { } + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + } + else { } - if (Hint.Likely((int)length >= 2)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.insert_epi16(default(v128), *(ushort*)ptr_v256, 0))); + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.insert_epi16(ZERO, *(ushort*)ptr_v128, 0), broadcast, where)); + + ptr_v128 = (v128*)((ushort*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.bsrli_si128(count0, 1 * sizeof(byte))); + byte countTotal = count0.Byte0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (byte)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.Bytes(*(byte*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (byte)((ulong)originalLength - countTotal); + } + } + + return countTotal; } else { - mask &= 0b0011; - } + byte count = 0; - countTotal += (uint)math.countbits(mask); + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Bytes(ptr[i], value, where); + count += *(byte*)&comparison; + } - ptr_v256 = (v256*)((ushort*)ptr_v256 + 1); - length -= 2; + return count; + } } - else { } + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + { + if (Avx2.IsAvx2Supported) + { + v256 ZERO = Avx.mm256_setzero_si256(); + + v256 broadcast = Avx.mm256_set1_epi8(value); + v256* ptr_v256 = (v256*)ptr; + + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 longCount = default(v256); + + while (Hint.Likely(length >= 4 * 32 * byte.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi8(count1, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi8(count2, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi8(count3, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < byte.MaxValue)); + + length -= 4 * 32 * byte.MaxValue; + + v256 sum0 = Avx2.mm256_sad_epu8(ZERO, count0); + v256 sum1 = Avx2.mm256_sad_epu8(ZERO, count1); + v256 sum2 = Avx2.mm256_sad_epu8(ZERO, count2); + v256 sum3 = Avx2.mm256_sad_epu8(ZERO, count3); + + sum0 = Avx2.mm256_add_epi64(sum0, sum1); + sum1 = Avx2.mm256_add_epi64(sum2, sum3); + + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(sum0, sum1)); + + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } + if (Hint.Likely(length >= 4 * 32)) + { + do + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi8(count1, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi8(count2, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi8(count3, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); - if (Hint.Likely(length != 0)) - { - bool areEqual = *(byte*)ptr_v256 == value; - countTotal += *(byte*)&areEqual; - } - else { } + length -= 4 * 32; + } + while (Hint.Likely(length >= 4 * 32)); + v256 sum0 = Avx2.mm256_sad_epu8(ZERO, count0); + v256 sum1 = Avx2.mm256_sad_epu8(ZERO, count1); + v256 sum2 = Avx2.mm256_sad_epu8(ZERO, count2); + v256 sum3 = Avx2.mm256_sad_epu8(ZERO, count3); - return countTotal; - } - else if (Sse2.IsSse2Supported) - { - v128 broadcast = Sse2.set1_epi8((sbyte)value); - v128* ptr_v128 = (v128*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; + sum0 = Avx2.mm256_add_epi64(sum0, sum1); + sum1 = Avx2.mm256_add_epi64(sum2, sum3); - while (Hint.Likely(length >= 64)) - { - v128 load0 = Sse2.loadu_si128(ptr_v128++); - v128 load1 = Sse2.loadu_si128(ptr_v128++); - v128 load2 = Sse2.loadu_si128(ptr_v128++); - v128 load3 = Sse2.loadu_si128(ptr_v128++); + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(sum0, sum1)); + + count0 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely((int)length >= 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 32; + } + else + { + length -= 2 * 32; + } + } + else + { + length -= 32; + } + } + else { } - length -= 64; + v128 count128 = Sse2.add_epi8(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); - v128 cmpeq0 = Sse2.cmpeq_epi8(broadcast, load0); - v128 cmpeq1 = Sse2.cmpeq_epi8(broadcast, load1); - v128 cmpeq2 = Sse2.cmpeq_epi8(broadcast, load2); - v128 cmpeq3 = Sse2.cmpeq_epi8(broadcast, load3); + if (Hint.Likely((int)length >= 16)) + { + count128 = Sse2.sub_epi8(count128, Compare.Bytes128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - int mask0 = Sse2.movemask_epi8(cmpeq0); - int mask1 = Sse2.movemask_epi8(cmpeq1); - int mask2 = Sse2.movemask_epi8(cmpeq2); - int mask3 = Sse2.movemask_epi8(cmpeq3); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 16; + } + else { } - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; - } + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi8(count128, Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - countTotal = (count0 + count1) + (count2 + count3); + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; + } + else { } + v128 longCount128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longCount), Avx2.mm256_extracti128_si256(longCount, 1)); + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); - if (Hint.Likely((int)length >= 16)) - { - countTotal += (uint)math.countbits(Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.loadu_si128(ptr_v128++)))); + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi8(count128, Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Likely((int)length >= 2 * 16)) - { - countTotal += (uint)math.countbits(Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.loadu_si128(ptr_v128++)))); + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; + } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + longCount128 = Sse2.add_epi64(longCount128, Sse2.bsrli_si128(longCount128, 1 * sizeof(ulong))); - if (Hint.Likely((int)length >= 3 * 16)) + if (Hint.Likely((int)length >= 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.loadu_si128(ptr_v128++)))); - length -= 3 * 16; + count128 = Sse2.sub_epi8(count128, Compare.Bytes128(Sse2.insert_epi16(default(v128), *(ushort*)ptr_v256, 0), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((ushort*)ptr_v256 + 1); + length -= 2; } - else + else { } + + count128 = Sse2.add_epi8(count128, Sse2.bsrli_si128(count128, 1 * sizeof(byte))); + ulong countTotal = Sse4_1.extract_epi8(count128, 0); + countTotal += (ulong)Sse2.cvtsi128_si64x(longCount128); + + if (Hint.Likely(length != 0)) { - length -= 2 * 16; + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.Bytes(*(byte*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } } + + return countTotal; } - else + else if (Sse2.IsSse2Supported) { - length -= 16; - } - } - else { } + v128 ZERO = Sse2.setzero_si128(); + + v128* ptr_v128 = (v128*)ptr; + + v128 broadcast = Sse2.set1_epi8((sbyte)value); + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 longCount = default(v128); + + while (Hint.Likely(length >= 4 * 16 * byte.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi8(count1, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi8(count2, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi8(count3, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < byte.MaxValue)); + + length -= 4 * 16 * byte.MaxValue; + + v128 sum0 = Sse2.sad_epu8(ZERO, count0); + v128 sum1 = Sse2.sad_epu8(ZERO, count1); + v128 sum2 = Sse2.sad_epu8(ZERO, count2); + v128 sum3 = Sse2.sad_epu8(ZERO, count3); + + sum0 = Sse2.add_epi64(sum0, sum1); + sum1 = Sse2.add_epi64(sum2, sum3); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(sum0, sum1)); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + if (Hint.Likely(length >= 4 * 16)) + { + do + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi8(count1, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi8(count2, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi8(count3, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); - if (Hint.Likely((int)length >= 8)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); + length -= 4 * 16; + } + while (Hint.Likely(length >= 4 * 16)); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; - } - else - { - mask &= 0b1111_1111; - } + v128 sum0 = Sse2.sad_epu8(ZERO, count0); + v128 sum1 = Sse2.sad_epu8(ZERO, count1); + v128 sum2 = Sse2.sad_epu8(ZERO, count2); + v128 sum3 = Sse2.sad_epu8(ZERO, count3); - countTotal += (uint)math.countbits(mask); + sum0 = Sse2.add_epi64(sum0, sum1); + sum1 = Sse2.add_epi64(sum2, sum3); - ptr_v128 = (v128*)((long*)ptr_v128 + 1); - length -= 8; - } - else { } + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(sum0, sum1)); + count0 = Sse2.setzero_si128(); + } - if (Hint.Likely((int)length >= 4)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi32_si128(*(int*)ptr_v128))); + if (Hint.Likely((int)length >= 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } - if (Constant.IsConstantExpression(value) && value != 0) - { - ; - } - else - { - mask &= 0b1111; - } + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); - countTotal += (uint)math.countbits(mask); + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); - ptr_v128 = (v128*)((int*)ptr_v128 + 1); - length -= 4; - } - else { } + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + } + else { } + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); - if (Hint.Likely((int)length >= 2)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.insert_epi16(default(v128), *(ushort*)ptr_v128, 0))); + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; - } - else - { - mask &= 0b0011; - } + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + longCount = Sse2.add_epi64(longCount, Sse2.bsrli_si128(longCount, 1 * sizeof(ulong))); - countTotal += (uint)math.countbits(mask); + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi8(count0, Compare.Bytes128(Sse2.insert_epi16(ZERO, *(ushort*)ptr_v128, 0), broadcast, where)); - ptr_v128 = (v128*)((ushort*)ptr_v128 + 1); - length -= 2; - } - else { } + ptr_v128 = (v128*)((ushort*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.bsrli_si128(count0, 1 * sizeof(byte))); + ulong countTotal; + if (Sse4_1.IsSse41Supported) + { + countTotal = Sse4_1.extract_epi8(count0, 0); + countTotal += (ulong)Sse2.cvtsi128_si64x(longCount); + } + else + { + count0 = Sse2.and_si128(count0, Sse2.cvtsi32_si128(byte.MaxValue)); + longCount = Sse2.add_epi64(longCount, count0); + countTotal = (ulong)Sse2.cvtsi128_si64x(longCount); + } - if (Hint.Likely(length != 0)) - { - bool areEqual = *(byte*)ptr_v128 == value; - countTotal += *(byte*)&areEqual; - } - else { } + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + bool comparison = Compare.Bytes(*(byte*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } - return countTotal; - } - else - { - ulong count = 0; + return countTotal; + } + else + { + ulong count = 0; - for (long i = 0; i < length; i++) - { - bool areEqual = ptr[i] == value; - count += *(byte*)&areEqual; + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Bytes(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } } - return count; + default: return 0; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, byte value) + public static int SIMD_Count(this NativeArray array, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, byte value) + public static int SIMD_Count(this NativeArray array, int index, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, byte value) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, byte value) + public static int SIMD_Count(this NativeList array, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, byte value) + public static int SIMD_Count(this NativeList array, int index, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, byte value) + public static int SIMD_Count(this NativeList array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, byte value) + public static int SIMD_Count(this NativeSlice array, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, byte value) + public static int SIMD_Count(this NativeSlice array, int index, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, byte value) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(ushort* ptr, long length, ushort value) + public static ulong SIMD_Count(ushort* ptr, long length, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.UInt64) { +Assert.IsBetween((int)returnType, (int)TypeCode.SByte, (int)TypeCode.UInt64); Assert.IsNonNegative(length); - if (Avx2.IsAvx2Supported) - { - v256 broadcast = Avx.mm256_set1_epi16((short)value); - v256* ptr_v256 = (v256*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; + long originalLength = length; - while (Hint.Likely(length >= 64)) + switch (returnType) + { + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: { - v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); - - length -= 64; - - v256 cmpeq0 = Avx2.mm256_cmpeq_epi16(broadcast, load0); - v256 cmpeq1 = Avx2.mm256_cmpeq_epi16(broadcast, load1); - v256 cmpeq2 = Avx2.mm256_cmpeq_epi16(broadcast, load2); - v256 cmpeq3 = Avx2.mm256_cmpeq_epi16(broadcast, load3); - - int mask0 = Avx2.mm256_movemask_epi8(cmpeq0); - int mask1 = Avx2.mm256_movemask_epi8(cmpeq1); - int mask2 = Avx2.mm256_movemask_epi8(cmpeq2); - int mask3 = Avx2.mm256_movemask_epi8(cmpeq3); - - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); - tempCount0 >>= 1; - tempCount1 >>= 1; - tempCount2 >>= 1; - tempCount3 >>= 1; + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi16((short)value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 4 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; - } + length -= 4 * 16; + } - countTotal = (count0 + count1) + (count2 + count3); + count0 = Avx2.mm256_add_epi16(count0, count1); + count2 = Avx2.mm256_add_epi16(count2, count3); + count0 = Avx2.mm256_add_epi16(count0, count2); + if (Hint.Likely((int)length >= 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } - if (Hint.Likely((int)length >= 16)) - { - countTotal += (uint)math.countbits(Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi16(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))) >> 1; + v128 count128 = Sse2.add_epi16(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); - if (Hint.Likely((int)length >= 2 * 16)) - { - countTotal += (uint)math.countbits(Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi16(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))) >> 1; + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 8; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); - if (Hint.Likely((int)length >= 3 * 16)) + if (Hint.Likely((int)length >= 4)) { - countTotal += (uint)math.countbits(Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi16(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))) >> 1; - length -= 3 * 16; + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; } - else + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) { - length -= 2 * 16; + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + ushort countTotal = count128.UShort0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ushort)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.UShorts(*(ushort*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ushort)((ulong)originalLength - countTotal); + } + } + + return countTotal; } - else + else if (Sse2.IsSse2Supported) { - length -= 16; - } - } - else { } + v128 broadcast = Sse2.set1_epi16((short)value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely(length >= 4 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + length -= 4 * 8; + } - if (Hint.Likely((int)length >= 8)) - { - countTotal += (uint)math.countbits(Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256)))) >> 1; + count0 = Sse2.add_epi16(count0, count1); + count2 = Sse2.add_epi16(count2, count3); + count0 = Sse2.add_epi16(count0, count2); - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 8; - } - else { } + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } - if (Hint.Likely((int)length >= 4)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; - } - else - { - mask &= 0b1111_1111; - } + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); - countTotal += (uint)math.countbits(mask) >> 1; + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + else { } - ptr_v256 = (v256*)((long*)ptr_v256 + 1); - length -= 4; - } - else { } + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); - if (Hint.Likely((int)length >= 2)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)ptr_v256))); + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + ushort countTotal = count0.UShort0; + + if (Hint.Likely(length != 0)) + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ushort)((ulong)originalLength - 1 - countTotal); + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ushort)((ulong)originalLength - 1 - countTotal); + } + } + + bool comparison = Compare.UShorts(*(ushort*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ushort)((ulong)originalLength - countTotal); + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ushort)((ulong)originalLength - countTotal); + } + } + } + + return countTotal; } else { - mask &= 0b1111; - } + ushort count = 0; - countTotal += (uint)math.countbits(mask) >> 1; + for (long i = 0; i < length; i++) + { + bool comparison = Compare.UShorts(ptr[i], value, where); + count += *(byte*)&comparison; + } - ptr_v256 = (v256*)((int*)ptr_v256 + 1); - length -= 2; + return count; + } } - else { } - - if (Hint.Likely(length != 0)) + case TypeCode.Int32: + case TypeCode.UInt32: { - bool areEqual = *(ushort*)ptr_v256 == value; - countTotal += *(byte*)&areEqual; - } - else { } - + if (Avx2.IsAvx2Supported) + { + v256 ZERO = Avx.mm256_setzero_si256(); + + v256 broadcast = Avx.mm256_set1_epi16((short)value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 intCount = default(v256); + + while (Hint.Likely(length >= 4 * 16 * ushort.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < ushort.MaxValue)); + + length -= 4 * 16 * ushort.MaxValue; + + v256 intSum0 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count0, ZERO), Avx2.mm256_unpacklo_epi16(count1, ZERO)); + v256 intSum1 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count0, ZERO), Avx2.mm256_unpackhi_epi16(count1, ZERO)); + v256 intSum2 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count2, ZERO), Avx2.mm256_unpacklo_epi16(count3, ZERO)); + v256 intSum3 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count2, ZERO), Avx2.mm256_unpackhi_epi16(count3, ZERO)); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum1); + intSum2 = Avx2.mm256_add_epi32(intSum2, intSum3); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum2); + + intCount = Avx2.mm256_add_epi32(intCount, intSum0); + + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } - return countTotal; - } - else if (Sse2.IsSse2Supported) - { - v128 broadcast = Sse2.set1_epi16((short)value); - v128* ptr_v128 = (v128*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; + if (Hint.Likely(length >= 4 * 16)) + { + do + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 4 * 16; + } + while (Hint.Likely(length >= 4 * 16)); + + v256 intSum0 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count0, ZERO), Avx2.mm256_unpacklo_epi16(count1, ZERO)); + v256 intSum1 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count0, ZERO), Avx2.mm256_unpackhi_epi16(count1, ZERO)); + v256 intSum2 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count2, ZERO), Avx2.mm256_unpacklo_epi16(count3, ZERO)); + v256 intSum3 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count2, ZERO), Avx2.mm256_unpackhi_epi16(count3, ZERO)); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum1); + intSum2 = Avx2.mm256_add_epi32(intSum2, intSum3); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum2); + + intCount = Avx2.mm256_add_epi32(intCount, intSum0); + + count0 = Avx.mm256_setzero_si256(); + } - while (Hint.Likely(length >= 32)) - { - v128 load0 = Sse2.loadu_si128(ptr_v128++); - v128 load1 = Sse2.loadu_si128(ptr_v128++); - v128 load2 = Sse2.loadu_si128(ptr_v128++); - v128 load3 = Sse2.loadu_si128(ptr_v128++); - - length -= 32; - - v128 cmpeq0 = Sse2.cmpeq_epi16(broadcast, load0); - v128 cmpeq1 = Sse2.cmpeq_epi16(broadcast, load1); - v128 cmpeq2 = Sse2.cmpeq_epi16(broadcast, load2); - v128 cmpeq3 = Sse2.cmpeq_epi16(broadcast, load3); - - int mask0 = Sse2.movemask_epi8(cmpeq0); - int mask1 = Sse2.movemask_epi8(cmpeq1); - int mask2 = Sse2.movemask_epi8(cmpeq2); - int mask3 = Sse2.movemask_epi8(cmpeq3); - - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); - tempCount0 >>= 1; - tempCount1 >>= 1; - tempCount2 >>= 1; - tempCount3 >>= 1; + if (Hint.Likely((int)length >= 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; - } + v128 count128 = Sse2.add_epi16(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); - countTotal = (count0 + count1) + (count2 + count3); + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 8; + } + else { } - if (Hint.Likely((int)length >= 8)) - { - countTotal += (uint)math.countbits(Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.loadu_si128(ptr_v128++)))) >> 1; + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + v128 intCount128 = Sse2.add_epi32(Avx.mm256_castsi256_si128(intCount), Avx2.mm256_extracti128_si256(intCount, 1)); + + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + intCount128 = Sse2.add_epi32(intCount128, Sse2.bsrli_si128(intCount128, 2 * sizeof(uint))); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + count128 = Sse4_1.cvtepu16_epi32(count128); + intCount128 = Sse2.add_epi32(intCount128, Sse2.bsrli_si128(intCount128, 1 * sizeof(uint))); + uint countTotal = Sse2.add_epi32(intCount128, count128).UInt0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.UShorts(*(ushort*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } - if (Hint.Likely((int)length >= 2 * 8)) + return countTotal; + } + else if (Sse2.IsSse2Supported) { - countTotal += (uint)math.countbits(Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.loadu_si128(ptr_v128++)))) >> 1; + v128 ZERO = Sse2.setzero_si128(); + + v128 broadcast = Sse2.set1_epi16((short)value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 intCount = default(v128); + + while (Hint.Likely(length >= 4 * 8 * ushort.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < ushort.MaxValue)); + + length -= 4 * 8 * ushort.MaxValue; + + v128 intSum0 = Sse2.add_epi32(Sse2.unpacklo_epi16(count0, ZERO), Sse2.unpacklo_epi16(count1, ZERO)); + v128 intSum1 = Sse2.add_epi32(Sse2.unpackhi_epi16(count0, ZERO), Sse2.unpackhi_epi16(count1, ZERO)); + v128 intSum2 = Sse2.add_epi32(Sse2.unpacklo_epi16(count2, ZERO), Sse2.unpacklo_epi16(count3, ZERO)); + v128 intSum3 = Sse2.add_epi32(Sse2.unpackhi_epi16(count2, ZERO), Sse2.unpackhi_epi16(count3, ZERO)); + + intSum0 = Sse2.add_epi32(intSum0, intSum1); + intSum2 = Sse2.add_epi32(intSum2, intSum3); + intSum0 = Sse2.add_epi32(intSum0, intSum2); + + intCount = Sse2.add_epi32(intCount, intSum0); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + + if (Hint.Likely(length >= 4 * 8)) + { + do + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 4 * 8; + } + while (Hint.Likely(length >= 4 * 8)); + + v128 intSum0 = Sse2.add_epi32(Sse2.unpacklo_epi16(count0, ZERO), Sse2.unpacklo_epi16(count1, ZERO)); + v128 intSum1 = Sse2.add_epi32(Sse2.unpackhi_epi16(count0, ZERO), Sse2.unpackhi_epi16(count1, ZERO)); + v128 intSum2 = Sse2.add_epi32(Sse2.unpacklo_epi16(count2, ZERO), Sse2.unpacklo_epi16(count3, ZERO)); + v128 intSum3 = Sse2.add_epi32(Sse2.unpackhi_epi16(count2, ZERO), Sse2.unpackhi_epi16(count3, ZERO)); + + intSum0 = Sse2.add_epi32(intSum0, intSum1); + intSum2 = Sse2.add_epi32(intSum2, intSum3); + intSum0 = Sse2.add_epi32(intSum0, intSum2); + + intCount = Sse2.add_epi32(intCount, intSum0); + + count0 = Sse2.setzero_si128(); + } + + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + else { } - if (Hint.Likely((int)length >= 3 * 8)) + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + intCount = Sse2.add_epi32(intCount, Sse2.bsrli_si128(intCount, 2 * sizeof(uint))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Sse4_1.IsSse41Supported) { - countTotal += (uint)math.countbits(Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.loadu_si128(ptr_v128++)))) >> 1; - length -= 3 * 8; + count0 = Sse4_1.cvtepu16_epi32(count0); } else { - length -= 2 * 8; + count0 = Sse2.and_si128(count0, Sse2.cvtsi32_si128(ushort.MaxValue)); + } + + intCount = Sse2.add_epi32(intCount, Sse2.bsrli_si128(intCount, 1 * sizeof(uint))); + uint countTotal = Sse2.add_epi32(intCount, count0).UInt0; + + if (Hint.Likely(length != 0)) + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + } + + bool comparison = Compare.UShorts(*(ushort*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } } + + return countTotal; } else { - length -= 8; - } - } - else { } + uint count = 0; - if (Hint.Likely((int)length >= 4)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); + for (long i = 0; i < length; i++) + { + bool comparison = Compare.UShorts(ptr[i], value, where); + count += *(byte*)&comparison; + } - if (Constant.IsConstantExpression(value) && value != 0) - { - ; + return count; } - else + } + case TypeCode.Int64: + case TypeCode.UInt64: + { + if (Avx2.IsAvx2Supported) { - mask &= 0b1111_1111; - } + v256 ZERO = Avx.mm256_setzero_si256(); + + v256 broadcast = Avx.mm256_set1_epi16((short)value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 longCount = default(v256); + + while (Hint.Likely(length >= 4 * 16 * ushort.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < ushort.MaxValue)); + + length -= 4 * 16 * ushort.MaxValue; + + v256 intSum0 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count0, ZERO), Avx2.mm256_unpacklo_epi16(count1, ZERO)); + v256 intSum1 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count0, ZERO), Avx2.mm256_unpackhi_epi16(count1, ZERO)); + v256 intSum2 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count2, ZERO), Avx2.mm256_unpacklo_epi16(count3, ZERO)); + v256 intSum3 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count2, ZERO), Avx2.mm256_unpackhi_epi16(count3, ZERO)); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum1); + intSum2 = Avx2.mm256_add_epi32(intSum2, intSum3); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum2); + + v256 longSum = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(intSum0, ZERO), Avx2.mm256_unpackhi_epi32(intSum0, ZERO)); + longCount = Avx2.mm256_add_epi64(longCount, longSum); + + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } - countTotal += (uint)math.countbits(mask) >> 1; + if (Hint.Likely(length >= 4 * 16)) + { + do + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 4 * 16; + } + while (Hint.Likely(length >= 4 * 16)); + + v256 intSum0 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count0, ZERO), Avx2.mm256_unpacklo_epi16(count1, ZERO)); + v256 intSum1 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count0, ZERO), Avx2.mm256_unpackhi_epi16(count1, ZERO)); + v256 intSum2 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count2, ZERO), Avx2.mm256_unpacklo_epi16(count3, ZERO)); + v256 intSum3 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count2, ZERO), Avx2.mm256_unpackhi_epi16(count3, ZERO)); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum1); + intSum2 = Avx2.mm256_add_epi32(intSum2, intSum3); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum2); + + v256 longSum = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(intSum0, ZERO), Avx2.mm256_unpackhi_epi32(intSum0, ZERO)); + longCount = Avx2.mm256_add_epi64(longCount, longSum); + + count0 = Avx.mm256_setzero_si256(); + } - ptr_v128 = (v128*)((long*)ptr_v128 + 1); - length -= 4; - } - else { } + if (Hint.Likely((int)length >= 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } - if (Hint.Likely((int)length >= 2)) - { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi32_si128(*(int*)ptr_v128))); + v128 count128 = Sse2.add_epi16(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 8; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + } + else { } + + v128 longCount128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longCount), Avx2.mm256_extracti128_si256(longCount, 1)); + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi16(count128, Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + count128 = Sse4_1.cvtepu16_epi64(count128); + longCount128 = Sse2.add_epi64(longCount128, Sse2.bsrli_si128(longCount128, 1 * sizeof(ulong))); + ulong countTotal = Sse2.add_epi64(longCount128, count128).ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.UShorts(*(ushort*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + return countTotal; } - else + else if (Sse2.IsSse2Supported) { - mask &= 0b1111; - } + v128 ZERO = Sse2.setzero_si128(); - countTotal += (uint)math.countbits(mask) >> 1; + v128 broadcast = Sse2.set1_epi16((short)value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 longCount = default(v128); - ptr_v128 = (v128*)((int*)ptr_v128 + 1); - length -= 2; - } - else { } + while (Hint.Likely(length >= 4 * 8 * ushort.MaxValue)) + { + uint loopCounter = 0; - if (Hint.Likely(length != 0)) - { - bool areEqual = *(ushort*)ptr_v128 == value; - countTotal += *(byte*)&areEqual; - } - else { } + do + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + loopCounter++; + } + while (Hint.Likely(loopCounter < ushort.MaxValue)); - return countTotal; - } - else - { - ulong count = 0; + length -= 4 * 8 * ushort.MaxValue; - for (long i = 0; i < length; i++) - { - bool areEqual = ptr[i] == value; - count += *(byte*)&areEqual; + v128 intSum0 = Sse2.add_epi32(Sse2.unpacklo_epi16(count0, ZERO), Sse2.unpacklo_epi16(count1, ZERO)); + v128 intSum1 = Sse2.add_epi32(Sse2.unpackhi_epi16(count0, ZERO), Sse2.unpackhi_epi16(count1, ZERO)); + v128 intSum2 = Sse2.add_epi32(Sse2.unpacklo_epi16(count2, ZERO), Sse2.unpacklo_epi16(count3, ZERO)); + v128 intSum3 = Sse2.add_epi32(Sse2.unpackhi_epi16(count2, ZERO), Sse2.unpackhi_epi16(count3, ZERO)); + + intSum0 = Sse2.add_epi32(intSum0, intSum1); + intSum2 = Sse2.add_epi32(intSum2, intSum3); + intSum0 = Sse2.add_epi32(intSum0, intSum2); + + v128 longSum = Sse2.add_epi64(Sse2.unpacklo_epi32(intSum0, ZERO), Sse2.unpackhi_epi32(intSum0, ZERO)); + longCount = Sse2.add_epi64(longCount, longSum); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + + if (Hint.Likely(length >= 4 * 8)) + { + do + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 4 * 8; + } + while (Hint.Likely(length >= 4 * 8)); + + v128 intSum0 = Sse2.add_epi32(Sse2.unpacklo_epi16(count0, ZERO), Sse2.unpacklo_epi16(count1, ZERO)); + v128 intSum1 = Sse2.add_epi32(Sse2.unpackhi_epi16(count0, ZERO), Sse2.unpackhi_epi16(count1, ZERO)); + v128 intSum2 = Sse2.add_epi32(Sse2.unpacklo_epi16(count2, ZERO), Sse2.unpacklo_epi16(count3, ZERO)); + v128 intSum3 = Sse2.add_epi32(Sse2.unpackhi_epi16(count2, ZERO), Sse2.unpackhi_epi16(count3, ZERO)); + + intSum0 = Sse2.add_epi32(intSum0, intSum1); + intSum2 = Sse2.add_epi32(intSum2, intSum3); + intSum0 = Sse2.add_epi32(intSum0, intSum2); + + v128 longSum = Sse2.add_epi64(Sse2.unpacklo_epi32(intSum0, ZERO), Sse2.unpackhi_epi32(intSum0, ZERO)); + longCount = Sse2.add_epi64(longCount, longSum); + + count0 = Sse2.setzero_si128(); + } + + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi16(count0, Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + if (Sse4_1.IsSse41Supported) + { + count0 = Sse4_1.cvtepu16_epi64(count0); + } + else + { + count0 = Sse2.and_si128(count0, Sse2.cvtsi32_si128(ushort.MaxValue)); + } + + longCount = Sse2.add_epi64(longCount, Sse2.bsrli_si128(longCount, 1 * sizeof(ulong))); + ulong countTotal = Sse2.add_epi64(longCount, count0).ULong0; + + if (Hint.Likely(length != 0)) + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + } + + bool comparison = Compare.UShorts(*(ushort*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + } + + return countTotal; + } + else + { + ulong count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.UShorts(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } } - return count; + default: return 0; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, ushort value) + public static int SIMD_Count(this NativeArray array, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, ushort value) + public static int SIMD_Count(this NativeArray array, int index, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, ushort value) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, ushort value) + public static int SIMD_Count(this NativeList array, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, ushort value) + public static int SIMD_Count(this NativeList array, int index, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, ushort value) + public static int SIMD_Count(this NativeList array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, ushort value) + public static int SIMD_Count(this NativeSlice array, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, ushort value) + public static int SIMD_Count(this NativeSlice array, int index, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, ushort value) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(uint* ptr, long length, uint value) + public static ulong SIMD_Count(uint* ptr, long length, uint value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.UInt64) { +Assert.IsBetween((int)returnType, (int)TypeCode.SByte, (int)TypeCode.UInt64); Assert.IsNonNegative(length); - if (Avx2.IsAvx2Supported) + long originalLength = length; + + switch (returnType) { - v256 broadcast = Avx.mm256_set1_epi32((int)value); - v256* ptr_v256 = (v256*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; - - while (Hint.Likely(length >= 32)) + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: { - v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); - - length -= 32; + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi32((int)value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 32)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 32; + } - v256 cmpeq0 = Avx2.mm256_cmpeq_epi32(broadcast, load0); - v256 cmpeq1 = Avx2.mm256_cmpeq_epi32(broadcast, load1); - v256 cmpeq2 = Avx2.mm256_cmpeq_epi32(broadcast, load2); - v256 cmpeq3 = Avx2.mm256_cmpeq_epi32(broadcast, load3); + count0 = Avx2.mm256_add_epi32(Avx2.mm256_add_epi32(count0, count1), Avx2.mm256_add_epi32(count2, count3)); - int mask0 = Avx.mm256_movemask_ps(cmpeq0); - int mask1 = Avx.mm256_movemask_ps(cmpeq1); - int mask2 = Avx.mm256_movemask_ps(cmpeq2); - int mask3 = Avx.mm256_movemask_ps(cmpeq3); + if (Hint.Likely((int)length >= 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); + v128 count128 = Sse2.add_epi32(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; - } + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi32(count128, Compare.UInts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - countTotal = (count0 + count1) + (count2 + count3); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + } + else { } + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); - if (Hint.Likely((int)length >= 8)) - { - countTotal += (uint)math.countbits(Avx.mm256_movemask_ps(Avx2.mm256_cmpeq_epi32(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi32(count128, Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Likely((int)length >= 2 * 8)) - { - countTotal += (uint)math.countbits(Avx.mm256_movemask_ps(Avx2.mm256_cmpeq_epi32(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + } + else { } - if (Hint.Likely((int)length >= 3 * 8)) + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + uint countTotal = count128.UInt0; + + if (Hint.Likely(length != 0)) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_ps(Avx2.mm256_cmpeq_epi32(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); - length -= 3 * 8; + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.UInts(*(uint*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; } - else - { - length -= 2 * 8; + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } } + + return countTotal; } - else + else if (Sse2.IsSse2Supported) { - length -= 8; - } - } - else { } + v128 broadcast = Sse2.set1_epi32((int)value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely(length >= 16)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); - if (Hint.Likely((int)length >= 4)) - { - countTotal += (uint)math.countbits(Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256)))); + length -= 16; + } - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 4; - } - else { } + count0 = Sse2.add_epi32(Sse2.add_epi32(count0, count1), Sse2.add_epi32(count2, count3)); - if (Hint.Likely((int)length >= 2)) - { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + uint countTotal = count0.UInt0; + + if (Hint.Likely(length != 0)) + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + } + + bool comparison = Compare.UInts(*(uint*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } + } + + return countTotal; } else { - mask &= 0b0011; - } + uint count = 0; - countTotal += (uint)math.countbits(mask); + for (long i = 0; i < length; i++) + { + bool comparison = Compare.UInts(ptr[i], value, where); + count += *(byte*)&comparison; + } - ptr_v256 = (v256*)((long*)ptr_v256 + 1); - length -= 2; + return count; + } } - else { } - - if (Hint.Likely(length != 0)) + case TypeCode.Int64: + case TypeCode.UInt64: { - bool areEqual = *(uint*)ptr_v256 == value; - countTotal += *(byte*)&areEqual; - } - else { } + if (Avx2.IsAvx2Supported) + { + v256 ZERO = default(v256); + v256 broadcast = Avx.mm256_set1_epi32((int)value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 longCount = default(v256); - return countTotal; - } - else if (Sse2.IsSse2Supported) - { - v128 broadcast = Sse2.set1_epi32((int)value); - v128* ptr_v128 = (v128*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; + while (Hint.Likely(length >= 4L * 8 * uint.MaxValue)) + { + uint loopCounter = 0; - while (Hint.Likely(length >= 16)) - { - v128 load0 = Sse2.loadu_si128(ptr_v128++); - v128 load1 = Sse2.loadu_si128(ptr_v128++); - v128 load2 = Sse2.loadu_si128(ptr_v128++); - v128 load3 = Sse2.loadu_si128(ptr_v128++); + do + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); - length -= 16; + loopCounter++; + } + while (Hint.Likely(loopCounter < uint.MaxValue)); - v128 cmpeq0 = Sse2.cmpeq_epi32(broadcast, load0); - v128 cmpeq1 = Sse2.cmpeq_epi32(broadcast, load1); - v128 cmpeq2 = Sse2.cmpeq_epi32(broadcast, load2); - v128 cmpeq3 = Sse2.cmpeq_epi32(broadcast, load3); + v256 longSum0 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count0, ZERO), Avx2.mm256_unpacklo_epi32(count1, ZERO)); + v256 longSum1 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count0, ZERO), Avx2.mm256_unpackhi_epi32(count1, ZERO)); + v256 longSum2 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count2, ZERO), Avx2.mm256_unpacklo_epi32(count3, ZERO)); + v256 longSum3 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count2, ZERO), Avx2.mm256_unpackhi_epi32(count3, ZERO)); - int mask0 = Sse.movemask_ps(cmpeq0); - int mask1 = Sse.movemask_ps(cmpeq1); - int mask2 = Sse.movemask_ps(cmpeq2); - int mask3 = Sse.movemask_ps(cmpeq3); + length -= 4L * 8 * uint.MaxValue; - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(longSum0, longSum1), Avx2.mm256_add_epi64(longSum2, longSum3))); - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; - } + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } - countTotal = (count0 + count1) + (count2 + count3); + if (Hint.Likely(length >= 32)) + { + do + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + } + while (Hint.Likely(length >= 32)); + v256 longSum0 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count0, ZERO), Avx2.mm256_unpacklo_epi32(count1, ZERO)); + v256 longSum1 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count0, ZERO), Avx2.mm256_unpackhi_epi32(count1, ZERO)); + v256 longSum2 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count2, ZERO), Avx2.mm256_unpacklo_epi32(count3, ZERO)); + v256 longSum3 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count2, ZERO), Avx2.mm256_unpackhi_epi32(count3, ZERO)); - if (Hint.Likely((int)length >= 4)) - { - countTotal += (uint)math.countbits(Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.loadu_si128(ptr_v128++)))); + length -= 32; - if (Hint.Likely((int)length >= 2 * 4)) - { - countTotal += (uint)math.countbits(Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.loadu_si128(ptr_v128++)))); + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(longSum0, longSum1), Avx2.mm256_add_epi64(longSum2, longSum3))); - if (Hint.Likely((int)length >= 3 * 4)) + count0 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely((int)length >= 8)) { - countTotal += (uint)math.countbits(Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.loadu_si128(ptr_v128++)))); - length -= 3 * 4; + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } } - else + else { } + + v128 count128 = Sse2.add_epi32(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + v128 longCount128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longCount), Avx2.mm256_extracti128_si256(longCount, 1)); + + if (Hint.Likely((int)length >= 4)) { - length -= 2 * 4; + count128 = Sse2.sub_epi32(count128, Compare.UInts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; } - } - else - { - length -= 4; - } - } - else { } + else { } - if (Hint.Likely((int)length >= 2)) - { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + longCount128 = Sse2.add_epi64(longCount128, Sse2.bsrli_si128(longCount128, 1 * sizeof(ulong))); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi32(count128, Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + ulong countTotal = count128.UInt0 + longCount128.ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.UInts(*(uint*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + return countTotal; } - else + else if (Sse2.IsSse2Supported) { - mask &= 0b0011; - } + v128 ZERO = default(v128); - countTotal += (uint)math.countbits(mask); + v128 broadcast = Sse2.set1_epi32((int)value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 longCount = default(v128); - ptr_v128 = (v128*)((long*)ptr_v128 + 1); - length -= 2; - } - else { } + if (Hint.Likely(length >= 4L * 4 * uint.MaxValue)) + { + uint loopCounter = 0; - if (Hint.Likely(length != 0)) - { - bool areEqual = *(uint*)ptr_v128 == value; - countTotal += *(byte*)&areEqual; - } - else { } + do + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + loopCounter++; + } + while (Hint.Likely(loopCounter < uint.MaxValue)); - return countTotal; - } - else - { - ulong count = 0; + length -= 4L * 4 * uint.MaxValue; - for (long i = 0; i < length; i++) - { - bool areEqual = ptr[i] == value; - count += *(byte*)&areEqual; + v128 longSum0 = Sse2.add_epi64(Sse2.unpacklo_epi32(count0, ZERO), Sse2.unpacklo_epi32(count1, ZERO)); + v128 longSum1 = Sse2.add_epi64(Sse2.unpackhi_epi32(count0, ZERO), Sse2.unpackhi_epi32(count1, ZERO)); + v128 longSum2 = Sse2.add_epi64(Sse2.unpacklo_epi32(count2, ZERO), Sse2.unpacklo_epi32(count3, ZERO)); + v128 longSum3 = Sse2.add_epi64(Sse2.unpackhi_epi32(count2, ZERO), Sse2.unpackhi_epi32(count3, ZERO)); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(Sse2.add_epi64(longSum0, longSum1), Sse2.add_epi64(longSum2, longSum3))); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + + if (Hint.Likely(length >= 16)) + { + do + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + v128 longSum0 = Sse2.add_epi64(Sse2.unpacklo_epi32(count0, ZERO), Sse2.unpacklo_epi32(count1, ZERO)); + v128 longSum1 = Sse2.add_epi64(Sse2.unpackhi_epi32(count0, ZERO), Sse2.unpackhi_epi32(count1, ZERO)); + v128 longSum2 = Sse2.add_epi64(Sse2.unpacklo_epi32(count2, ZERO), Sse2.unpacklo_epi32(count3, ZERO)); + v128 longSum3 = Sse2.add_epi64(Sse2.unpackhi_epi32(count2, ZERO), Sse2.unpackhi_epi32(count3, ZERO)); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(Sse2.add_epi64(longSum0, longSum1), Sse2.add_epi64(longSum2, longSum3))); + + count0 = Sse2.setzero_si128(); + } + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + longCount = Sse2.bsrli_si128(longCount, 1 * sizeof(ulong)); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi32(count0, Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + ulong countTotal = count0.UInt0 + longCount.ULong0; + + if (Hint.Likely(length != 0)) + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + } + + bool comparison = Compare.UInts(*(uint*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } + } + + return countTotal; + } + else + { + ulong count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.UInts(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } } - return count; + default: return 0; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, uint value) + public static int SIMD_Count(this NativeArray array, uint value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, uint value) + public static int SIMD_Count(this NativeArray array, int index, uint value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, uint value) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, uint value) + public static int SIMD_Count(this NativeList array, uint value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, uint value) + public static int SIMD_Count(this NativeList array, int index, uint value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, uint value) + public static int SIMD_Count(this NativeList array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, uint value) + public static int SIMD_Count(this NativeSlice array, uint value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, uint value) + public static int SIMD_Count(this NativeSlice array, int index, uint value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, uint value) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(ulong* ptr, long length, ulong value) + public static ulong SIMD_Count(ulong* ptr, long length, ulong value, Comparison where = Comparison.EqualTo) { Assert.IsNonNegative(length); + long originalLength = length; + if (Avx2.IsAvx2Supported) { v256 broadcast = Avx.mm256_set1_epi64x((long)value); v256* ptr_v256 = (v256*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); while (Hint.Likely(length >= 16)) { - v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); - v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + count0 = Avx2.mm256_sub_epi64(count0, Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi64(count1, Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi64(count2, Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi64(count3, Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); length -= 16; - - v256 cmpeq0 = Avx2.mm256_cmpeq_epi64(broadcast, load0); - v256 cmpeq1 = Avx2.mm256_cmpeq_epi64(broadcast, load1); - v256 cmpeq2 = Avx2.mm256_cmpeq_epi64(broadcast, load2); - v256 cmpeq3 = Avx2.mm256_cmpeq_epi64(broadcast, load3); - - int mask0 = Avx.mm256_movemask_pd(cmpeq0); - int mask1 = Avx.mm256_movemask_pd(cmpeq1); - int mask2 = Avx.mm256_movemask_pd(cmpeq2); - int mask3 = Avx.mm256_movemask_pd(cmpeq3); - - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); - - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; } - countTotal = (count0 + count1) + (count2 + count3); - + count0 = Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(count0, count1), Avx2.mm256_add_epi64(count2, count3)); if (Hint.Likely((int)length >= 4)) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_pd(Avx2.mm256_cmpeq_epi64(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); + count0 = Avx2.mm256_sub_epi64(count0, Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); if (Hint.Likely((int)length >= 2 * 4)) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_pd(Avx2.mm256_cmpeq_epi64(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); + count0 = Avx2.mm256_sub_epi64(count0, Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); if (Hint.Likely((int)length >= 3 * 4)) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_pd(Avx2.mm256_cmpeq_epi64(broadcast, Avx.mm256_loadu_si256(ptr_v256++)))); + count0 = Avx2.mm256_sub_epi64(count0, Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + length -= 3 * 4; } else @@ -1526,79 +3010,74 @@ public static ulong SIMD_Count(ulong* ptr, long length, ulong value) } else { } + v128 count128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + if (Hint.Likely((int)length >= 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_pd(Sse4_1.cmpeq_epi64(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256)))); + count128 = Sse2.sub_epi64(count128, Compare.ULongs128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 2; } else { } + count128 = Sse2.add_epi64(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = count128.ULong0; + if (Hint.Likely(length != 0)) { - bool areEqual = *(ulong*)ptr_v256 == value; - countTotal += *(byte*)&areEqual; + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.ULongs(*(ulong*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } } - else { } return countTotal; } - else if (Sse4_1.IsSse41Supported) + else if (Sse4_2.IsSse42Supported) { v128 broadcast = Sse2.set1_epi64x((long)value); v128* ptr_v128 = (v128*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); while (Hint.Likely(length >= 8)) { - v128 load0 = Sse2.loadu_si128(ptr_v128++); - v128 load1 = Sse2.loadu_si128(ptr_v128++); - v128 load2 = Sse2.loadu_si128(ptr_v128++); - v128 load3 = Sse2.loadu_si128(ptr_v128++); - + count0 = Sse2.sub_epi64(count0, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi64(count1, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi64(count2, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi64(count3, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + length -= 8; - - v128 cmpeq0 = Sse4_1.cmpeq_epi64(broadcast, load0); - v128 cmpeq1 = Sse4_1.cmpeq_epi64(broadcast, load1); - v128 cmpeq2 = Sse4_1.cmpeq_epi64(broadcast, load2); - v128 cmpeq3 = Sse4_1.cmpeq_epi64(broadcast, load3); - - int mask0 = Sse2.movemask_pd(cmpeq0); - int mask1 = Sse2.movemask_pd(cmpeq1); - int mask2 = Sse2.movemask_pd(cmpeq2); - int mask3 = Sse2.movemask_pd(cmpeq3); - - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); - - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; } - countTotal = (count0 + count1) + (count2 + count3); - + count0 = Sse2.add_epi64(Sse2.add_epi64(count0, count1), Sse2.add_epi64(count2, count3)); if (Hint.Likely((int)length >= 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_pd(Sse4_1.cmpeq_epi64(broadcast, Sse2.loadu_si128(ptr_v128++)))); + count0 = Sse2.sub_epi64(count0, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); if (Hint.Likely((int)length >= 2 * 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_pd(Sse4_1.cmpeq_epi64(broadcast, Sse2.loadu_si128(ptr_v128++)))); + count0 = Sse2.sub_epi64(count0, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); if (Hint.Likely((int)length >= 3 * 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_pd(Sse4_1.cmpeq_epi64(broadcast, Sse2.loadu_si128(ptr_v128++)))); + count0 = Sse2.sub_epi64(count0, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + length -= 3 * 2; } else @@ -1613,24 +3092,124 @@ public static ulong SIMD_Count(ulong* ptr, long length, ulong value) } else { } + count0 = Sse2.add_epi64(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = count0.ULong0; + if (Hint.Likely(length != 0)) { - bool areEqual = *(ulong*)ptr_v128 == value; - countTotal += *(byte*)&areEqual; + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.ULongs(*(ulong*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } } - else { } return countTotal; } + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x((long)value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely(length >= 8)) + { + count0 = Sse2.sub_epi64(count0, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi64(count1, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi64(count2, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi64(count3, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 8; + } + + count0 = Sse2.add_epi64(Sse2.add_epi64(count0, count1), Sse2.add_epi64(count2, count3)); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.ULongs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 2; + } + else + { + length -= 2 * 2; + } + } + else + { + length -= 2; + } + } + else { } + + count0 = Sse2.add_epi64(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = count0.ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.ULongs(*(ulong*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + + return countTotal; + } + else + { + ulong count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.ULongs(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } + } else { ulong count = 0; for (long i = 0; i < length; i++) { - bool areEqual = ptr[i] == value; - count += *(byte*)&areEqual; + bool comparison = Compare.ULongs(ptr[i], value, where); + count += *(byte*)&comparison; } return count; @@ -1638,672 +3217,3294 @@ public static ulong SIMD_Count(ulong* ptr, long length, ulong value) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, ulong value) + public static int SIMD_Count(this NativeArray array, ulong value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, ulong value) + public static int SIMD_Count(this NativeArray array, int index, ulong value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, ulong value) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, ulong value) + public static int SIMD_Count(this NativeList array, ulong value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, ulong value) + public static int SIMD_Count(this NativeList array, int index, ulong value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, ulong value) + public static int SIMD_Count(this NativeList array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, ulong value) + public static int SIMD_Count(this NativeSlice array, ulong value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, ulong value) + public static int SIMD_Count(this NativeSlice array, int index, ulong value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, ulong value) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(sbyte* ptr, long length, sbyte value) + public static ulong SIMD_Count(sbyte* ptr, long length, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.UInt64) { +Assert.IsBetween((int)returnType, (int)TypeCode.SByte, (int)TypeCode.UInt64); Assert.IsNonNegative(length); + + long originalLength = length; - return SIMD_Count((byte*)ptr, length, (byte)value); - } + switch (returnType) + { + case TypeCode.Byte: + case TypeCode.SByte: + { + if (Avx2.IsAvx2Supported) + { + v256 ZERO = Avx.mm256_setzero_si256(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, sbyte value) - { - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value); - } + v256 broadcast = Avx.mm256_set1_epi8((byte)value); + v256* ptr_v256 = (v256*)ptr; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, sbyte value) - { -Assert.IsWithinArrayBounds(index, array.Length); + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 4 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi8(count1, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi8(count2, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi8(count3, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); - } + length -= 4 * 32; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, sbyte value) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + count0 = Avx2.mm256_add_epi8(Avx2.mm256_add_epi8(count0, count1), Avx2.mm256_add_epi8(count2, count3)); + + if (Hint.Likely((int)length >= 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 32; + } + else + { + length -= 2 * 32; + } + } + else + { + length -= 32; + } + } + else { } - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); - } + v128 count128 = Sse2.add_epi8(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, sbyte value) - { - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value); - } + if (Hint.Likely((int)length >= 16)) + { + count128 = Sse2.sub_epi8(count128, Compare.SBytes128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, sbyte value) - { -Assert.IsWithinArrayBounds(index, array.Length); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 16; + } + else { } - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); - } + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, sbyte value) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi8(count128, Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); - } + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, sbyte value) - { - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value); - } + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, sbyte value) - { -Assert.IsWithinArrayBounds(index, array.Length); + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi8(count128, Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); - } + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; + } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, sbyte value) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi8(count128, Compare.SBytes128(Sse2.insert_epi16(default(v128), *(ushort*)ptr_v256, 0), Avx.mm256_castsi256_si128(broadcast), where)); - return SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); - } + ptr_v256 = (v256*)((ushort*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.bsrli_si128(count128, 1 * sizeof(sbyte))); + byte countTotal = count128.Byte0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (byte)((ulong)originalLength - 1 - countTotal); + } + bool comparison = Compare.SBytes(*(sbyte*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (byte)((ulong)originalLength - countTotal); + } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(short* ptr, long length, short value) - { -Assert.IsNonNegative(length); + return countTotal; + } + else if (Sse2.IsSse2Supported) + { + v128 ZERO = Sse2.setzero_si128(); + + v128* ptr_v128 = (v128*)ptr; - return SIMD_Count((ushort*)ptr, length, (ushort)value); - } + v128 broadcast = Sse2.set1_epi8((sbyte)value); + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, short value) - { - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value); - } + while (Hint.Likely(length >= 4 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi8(count1, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi8(count2, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi8(count3, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, short value) - { -Assert.IsWithinArrayBounds(index, array.Length); + length -= 4 * 16; + } - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); - } + count0 = Sse2.add_epi8(Sse2.add_epi8(count0, count1), Sse2.add_epi8(count2, count3)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, short value) - { + if (Hint.Likely((int)length >= 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.insert_epi16(ZERO, *(ushort*)ptr_v128, 0), broadcast, where)); + + ptr_v128 = (v128*)((ushort*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.bsrli_si128(count0, 1 * sizeof(sbyte))); + byte countTotal = count0.Byte0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (byte)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.SBytes(*(sbyte*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (byte)((ulong)originalLength - countTotal); + } + } + + return countTotal; + } + else + { + byte count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.SBytes(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } + } + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + { + if (Avx2.IsAvx2Supported) + { + v256 ZERO = Avx.mm256_setzero_si256(); + + v256 broadcast = Avx.mm256_set1_epi8((byte)value); + v256* ptr_v256 = (v256*)ptr; + + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 longCount = default(v256); + + while (Hint.Likely(length >= 4 * 32 * byte.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi8(count1, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi8(count2, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi8(count3, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < byte.MaxValue)); + + length -= 4 * 32 * byte.MaxValue; + + v256 sum0 = Avx2.mm256_sad_epu8(ZERO, count0); + v256 sum1 = Avx2.mm256_sad_epu8(ZERO, count1); + v256 sum2 = Avx2.mm256_sad_epu8(ZERO, count2); + v256 sum3 = Avx2.mm256_sad_epu8(ZERO, count3); + + sum0 = Avx2.mm256_add_epi64(sum0, sum1); + sum1 = Avx2.mm256_add_epi64(sum2, sum3); + + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(sum0, sum1)); + + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely(length >= 4 * 32)) + { + do + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi8(count1, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi8(count2, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi8(count3, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 4 * 32; + } + while (Hint.Likely(length >= 4 * 32)); + + v256 sum0 = Avx2.mm256_sad_epu8(ZERO, count0); + v256 sum1 = Avx2.mm256_sad_epu8(ZERO, count1); + v256 sum2 = Avx2.mm256_sad_epu8(ZERO, count2); + v256 sum3 = Avx2.mm256_sad_epu8(ZERO, count3); + + sum0 = Avx2.mm256_add_epi64(sum0, sum1); + sum1 = Avx2.mm256_add_epi64(sum2, sum3); + + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(sum0, sum1)); + + count0 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely((int)length >= 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 32)) + { + count0 = Avx2.mm256_sub_epi8(count0, Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 32; + } + else + { + length -= 2 * 32; + } + } + else + { + length -= 32; + } + } + else { } + + v128 count128 = Sse2.add_epi8(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + + if (Hint.Likely((int)length >= 16)) + { + count128 = Sse2.sub_epi8(count128, Compare.SBytes128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 16; + } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi8(count128, Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; + } + else { } + + v128 longCount128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longCount), Avx2.mm256_extracti128_si256(longCount, 1)); + count128 = Sse2.add_epi8(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi8(count128, Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; + } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + longCount128 = Sse2.add_epi64(longCount128, Sse2.bsrli_si128(longCount128, 1 * sizeof(ulong))); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi8(count128, Compare.SBytes128(Sse2.insert_epi16(default(v128), *(ushort*)ptr_v256, 0), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((ushort*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi8(count128, Sse2.bsrli_si128(count128, 1 * sizeof(sbyte))); + ulong countTotal = Sse4_1.extract_epi8(count128, 0); + countTotal += (ulong)Sse2.cvtsi128_si64x(longCount128); + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.SBytes(*(sbyte*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + return countTotal; + } + else if (Sse2.IsSse2Supported) + { + v128 ZERO = Sse2.setzero_si128(); + + v128* ptr_v128 = (v128*)ptr; + + v128 broadcast = Sse2.set1_epi8((sbyte)value); + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 longCount = default(v128); + + while (Hint.Likely(length >= 4 * 16 * byte.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi8(count1, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi8(count2, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi8(count3, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < byte.MaxValue)); + + length -= 4 * 16 * byte.MaxValue; + + v128 sum0 = Sse2.sad_epu8(ZERO, count0); + v128 sum1 = Sse2.sad_epu8(ZERO, count1); + v128 sum2 = Sse2.sad_epu8(ZERO, count2); + v128 sum3 = Sse2.sad_epu8(ZERO, count3); + + sum0 = Sse2.add_epi64(sum0, sum1); + sum1 = Sse2.add_epi64(sum2, sum3); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(sum0, sum1)); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + + if (Hint.Likely(length >= 4 * 16)) + { + do + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi8(count1, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi8(count2, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi8(count3, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 4 * 16; + } + while (Hint.Likely(length >= 4 * 16)); + + v128 sum0 = Sse2.sad_epu8(ZERO, count0); + v128 sum1 = Sse2.sad_epu8(ZERO, count1); + v128 sum2 = Sse2.sad_epu8(ZERO, count2); + v128 sum3 = Sse2.sad_epu8(ZERO, count3); + + sum0 = Sse2.add_epi64(sum0, sum1); + sum1 = Sse2.add_epi64(sum2, sum3); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(sum0, sum1)); + + count0 = Sse2.setzero_si128(); + } + + if (Hint.Likely((int)length >= 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + longCount = Sse2.add_epi64(longCount, Sse2.bsrli_si128(longCount, 1 * sizeof(ulong))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi8(count0, Compare.SBytes128(Sse2.insert_epi16(ZERO, *(ushort*)ptr_v128, 0), broadcast, where)); + + ptr_v128 = (v128*)((ushort*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi8(count0, Sse2.bsrli_si128(count0, 1 * sizeof(sbyte))); + ulong countTotal; + + if (Sse4_1.IsSse41Supported) + { + countTotal = Sse4_1.extract_epi8(count0, 0); + countTotal += (ulong)Sse2.cvtsi128_si64x(longCount); + } + else + { + count0 = Sse2.and_si128(count0, Sse2.cvtsi32_si128(byte.MaxValue)); + longCount = Sse2.add_epi64(longCount, count0); + countTotal = (ulong)Sse2.cvtsi128_si64x(longCount); + } + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.SBytes(*(sbyte*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + return countTotal; + } + else + { + ulong count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.SBytes(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } + } + + default: return 0; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeArray array, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeArray array, int index, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeArray array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeList array, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeList array, int index, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeList array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeSlice array, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeSlice array, int index, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); - } + return (int)SIMD_Count((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong SIMD_Count(short* ptr, long length, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.UInt64) + { +Assert.IsBetween((int)returnType, (int)TypeCode.SByte, (int)TypeCode.UInt64); +Assert.IsNonNegative(length); + + long originalLength = length; + + switch (returnType) + { + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi16(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 4 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 4 * 16; + } + + count0 = Avx2.mm256_add_epi16(count0, count1); + count2 = Avx2.mm256_add_epi16(count2, count3); + count0 = Avx2.mm256_add_epi16(count0, count2); + + if (Hint.Likely((int)length >= 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + v128 count128 = Sse2.add_epi16(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 8; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + ushort countTotal = count128.UShort0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ushort)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.Shorts(*(short*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ushort)((ulong)originalLength - countTotal); + } + } + + return countTotal; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi16(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely(length >= 4 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 4 * 8; + } + + count0 = Sse2.add_epi16(count0, count1); + count2 = Sse2.add_epi16(count2, count3); + count0 = Sse2.add_epi16(count0, count2); + + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + ushort countTotal = count0.UShort0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ushort)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.Shorts(*(short*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ushort)((ulong)originalLength - countTotal); + } + } + + return countTotal; + } + else + { + ushort count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Shorts(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } + } + case TypeCode.Int32: + case TypeCode.UInt32: + { + if (Avx2.IsAvx2Supported) + { + v256 ZERO = Avx.mm256_setzero_si256(); + + v256 broadcast = Avx.mm256_set1_epi16(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 intCount = default(v256); + + while (Hint.Likely(length >= 4 * 16 * ushort.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < ushort.MaxValue)); + + length -= 4 * 16 * ushort.MaxValue; + + v256 intSum0 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count0, ZERO), Avx2.mm256_unpacklo_epi16(count1, ZERO)); + v256 intSum1 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count0, ZERO), Avx2.mm256_unpackhi_epi16(count1, ZERO)); + v256 intSum2 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count2, ZERO), Avx2.mm256_unpacklo_epi16(count3, ZERO)); + v256 intSum3 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count2, ZERO), Avx2.mm256_unpackhi_epi16(count3, ZERO)); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum1); + intSum2 = Avx2.mm256_add_epi32(intSum2, intSum3); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum2); + + intCount = Avx2.mm256_add_epi32(intCount, intSum0); + + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely(length >= 4 * 16)) + { + do + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 4 * 16; + } + while (Hint.Likely(length >= 4 * 16)); + + v256 intSum0 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count0, ZERO), Avx2.mm256_unpacklo_epi16(count1, ZERO)); + v256 intSum1 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count0, ZERO), Avx2.mm256_unpackhi_epi16(count1, ZERO)); + v256 intSum2 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count2, ZERO), Avx2.mm256_unpacklo_epi16(count3, ZERO)); + v256 intSum3 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count2, ZERO), Avx2.mm256_unpackhi_epi16(count3, ZERO)); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum1); + intSum2 = Avx2.mm256_add_epi32(intSum2, intSum3); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum2); + + intCount = Avx2.mm256_add_epi32(intCount, intSum0); + + count0 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely((int)length >= 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + v128 count128 = Sse2.add_epi16(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 8; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + v128 intCount128 = Sse2.add_epi32(Avx.mm256_castsi256_si128(intCount), Avx2.mm256_extracti128_si256(intCount, 1)); + + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + intCount128 = Sse2.add_epi32(intCount128, Sse2.bsrli_si128(intCount128, 2 * sizeof(uint))); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + count128 = Sse4_1.cvtepu16_epi32(count128); + intCount128 = Sse2.add_epi32(intCount128, Sse2.bsrli_si128(intCount128, 1 * sizeof(uint))); + uint countTotal = Sse2.add_epi32(intCount128, count128).UInt0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.Shorts(*(short*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } + + return countTotal; + } + else if (Sse2.IsSse2Supported) + { + v128 ZERO = Sse2.setzero_si128(); + + v128 broadcast = Sse2.set1_epi16(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 intCount = default(v128); + + while (Hint.Likely(length >= 4 * 8 * ushort.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < ushort.MaxValue)); + + length -= 4 * 8 * ushort.MaxValue; + + v128 intSum0 = Sse2.add_epi32(Sse2.unpacklo_epi16(count0, ZERO), Sse2.unpacklo_epi16(count1, ZERO)); + v128 intSum1 = Sse2.add_epi32(Sse2.unpackhi_epi16(count0, ZERO), Sse2.unpackhi_epi16(count1, ZERO)); + v128 intSum2 = Sse2.add_epi32(Sse2.unpacklo_epi16(count2, ZERO), Sse2.unpacklo_epi16(count3, ZERO)); + v128 intSum3 = Sse2.add_epi32(Sse2.unpackhi_epi16(count2, ZERO), Sse2.unpackhi_epi16(count3, ZERO)); + + intSum0 = Sse2.add_epi32(intSum0, intSum1); + intSum2 = Sse2.add_epi32(intSum2, intSum3); + intSum0 = Sse2.add_epi32(intSum0, intSum2); + + intCount = Sse2.add_epi32(intCount, intSum0); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + + if (Hint.Likely(length >= 4 * 8)) + { + do + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 4 * 8; + } + while (Hint.Likely(length >= 4 * 8)); + + v128 intSum0 = Sse2.add_epi32(Sse2.unpacklo_epi16(count0, ZERO), Sse2.unpacklo_epi16(count1, ZERO)); + v128 intSum1 = Sse2.add_epi32(Sse2.unpackhi_epi16(count0, ZERO), Sse2.unpackhi_epi16(count1, ZERO)); + v128 intSum2 = Sse2.add_epi32(Sse2.unpacklo_epi16(count2, ZERO), Sse2.unpacklo_epi16(count3, ZERO)); + v128 intSum3 = Sse2.add_epi32(Sse2.unpackhi_epi16(count2, ZERO), Sse2.unpackhi_epi16(count3, ZERO)); + + intSum0 = Sse2.add_epi32(intSum0, intSum1); + intSum2 = Sse2.add_epi32(intSum2, intSum3); + intSum0 = Sse2.add_epi32(intSum0, intSum2); + + intCount = Sse2.add_epi32(intCount, intSum0); + + count0 = Sse2.setzero_si128(); + } + + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + intCount = Sse2.add_epi32(intCount, Sse2.bsrli_si128(intCount, 2 * sizeof(uint))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Sse4_1.IsSse41Supported) + { + count0 = Sse4_1.cvtepu16_epi32(count0); + } + else + { + count0 = Sse2.and_si128(count0, Sse2.cvtsi32_si128(ushort.MaxValue)); + } + + intCount = Sse2.add_epi32(intCount, Sse2.bsrli_si128(intCount, 1 * sizeof(uint))); + uint countTotal = Sse2.add_epi32(intCount, count0).UInt0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.Shorts(*(short*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } + + return countTotal; + } + else + { + uint count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Shorts(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } + } + case TypeCode.Int64: + case TypeCode.UInt64: + { + if (Avx2.IsAvx2Supported) + { + v256 ZERO = Avx.mm256_setzero_si256(); + + v256 broadcast = Avx.mm256_set1_epi16(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 longCount = default(v256); + + while (Hint.Likely(length >= 4 * 16 * ushort.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < ushort.MaxValue)); + + length -= 4 * 16 * ushort.MaxValue; + + v256 intSum0 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count0, ZERO), Avx2.mm256_unpacklo_epi16(count1, ZERO)); + v256 intSum1 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count0, ZERO), Avx2.mm256_unpackhi_epi16(count1, ZERO)); + v256 intSum2 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count2, ZERO), Avx2.mm256_unpacklo_epi16(count3, ZERO)); + v256 intSum3 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count2, ZERO), Avx2.mm256_unpackhi_epi16(count3, ZERO)); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum1); + intSum2 = Avx2.mm256_add_epi32(intSum2, intSum3); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum2); + + v256 longSum = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(intSum0, ZERO), Avx2.mm256_unpackhi_epi32(intSum0, ZERO)); + longCount = Avx2.mm256_add_epi64(longCount, longSum); + + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely(length >= 4 * 16)) + { + do + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi16(count1, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi16(count2, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi16(count3, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 4 * 16; + } + while (Hint.Likely(length >= 4 * 16)); + + v256 intSum0 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count0, ZERO), Avx2.mm256_unpacklo_epi16(count1, ZERO)); + v256 intSum1 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count0, ZERO), Avx2.mm256_unpackhi_epi16(count1, ZERO)); + v256 intSum2 = Avx2.mm256_add_epi32(Avx2.mm256_unpacklo_epi16(count2, ZERO), Avx2.mm256_unpacklo_epi16(count3, ZERO)); + v256 intSum3 = Avx2.mm256_add_epi32(Avx2.mm256_unpackhi_epi16(count2, ZERO), Avx2.mm256_unpackhi_epi16(count3, ZERO)); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum1); + intSum2 = Avx2.mm256_add_epi32(intSum2, intSum3); + intSum0 = Avx2.mm256_add_epi32(intSum0, intSum2); + + v256 longSum = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(intSum0, ZERO), Avx2.mm256_unpackhi_epi32(intSum0, ZERO)); + longCount = Avx2.mm256_add_epi64(longCount, longSum); + + count0 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely((int)length >= 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 16)) + { + count0 = Avx2.mm256_sub_epi16(count0, Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + v128 count128 = Sse2.add_epi16(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + + if (Hint.Likely((int)length >= 8)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 8; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + } + else { } + + v128 longCount128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longCount), Avx2.mm256_extracti128_si256(longCount, 1)); + count128 = Sse2.add_epi16(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi16(count128, Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi16(count128, Sse2.shufflelo_epi16(count128, Sse.SHUFFLE(0, 0, 0, 1))); + count128 = Sse4_1.cvtepu16_epi64(count128); + longCount128 = Sse2.add_epi64(longCount128, Sse2.bsrli_si128(longCount128, 1 * sizeof(ulong))); + ulong countTotal = Sse2.add_epi64(longCount128, count128).ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.Shorts(*(short*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + return countTotal; + } + else if (Sse2.IsSse2Supported) + { + v128 ZERO = Sse2.setzero_si128(); + + v128 broadcast = Sse2.set1_epi16(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 longCount = default(v128); + + while (Hint.Likely(length >= 4 * 8 * ushort.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < ushort.MaxValue)); + + length -= 4 * 8 * ushort.MaxValue; + + v128 intSum0 = Sse2.add_epi32(Sse2.unpacklo_epi16(count0, ZERO), Sse2.unpacklo_epi16(count1, ZERO)); + v128 intSum1 = Sse2.add_epi32(Sse2.unpackhi_epi16(count0, ZERO), Sse2.unpackhi_epi16(count1, ZERO)); + v128 intSum2 = Sse2.add_epi32(Sse2.unpacklo_epi16(count2, ZERO), Sse2.unpacklo_epi16(count3, ZERO)); + v128 intSum3 = Sse2.add_epi32(Sse2.unpackhi_epi16(count2, ZERO), Sse2.unpackhi_epi16(count3, ZERO)); + + intSum0 = Sse2.add_epi32(intSum0, intSum1); + intSum2 = Sse2.add_epi32(intSum2, intSum3); + intSum0 = Sse2.add_epi32(intSum0, intSum2); + + v128 longSum = Sse2.add_epi64(Sse2.unpacklo_epi32(intSum0, ZERO), Sse2.unpackhi_epi32(intSum0, ZERO)); + longCount = Sse2.add_epi64(longCount, longSum); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + + if (Hint.Likely(length >= 4 * 8)) + { + do + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi16(count1, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi16(count2, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi16(count3, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 4 * 8; + } + while (Hint.Likely(length >= 4 * 8)); + + v128 intSum0 = Sse2.add_epi32(Sse2.unpacklo_epi16(count0, ZERO), Sse2.unpacklo_epi16(count1, ZERO)); + v128 intSum1 = Sse2.add_epi32(Sse2.unpackhi_epi16(count0, ZERO), Sse2.unpackhi_epi16(count1, ZERO)); + v128 intSum2 = Sse2.add_epi32(Sse2.unpacklo_epi16(count2, ZERO), Sse2.unpacklo_epi16(count3, ZERO)); + v128 intSum3 = Sse2.add_epi32(Sse2.unpackhi_epi16(count2, ZERO), Sse2.unpackhi_epi16(count3, ZERO)); + + intSum0 = Sse2.add_epi32(intSum0, intSum1); + intSum2 = Sse2.add_epi32(intSum2, intSum3); + intSum0 = Sse2.add_epi32(intSum0, intSum2); + + v128 longSum = Sse2.add_epi64(Sse2.unpacklo_epi32(intSum0, ZERO), Sse2.unpackhi_epi32(intSum0, ZERO)); + longCount = Sse2.add_epi64(longCount, longSum); + + count0 = Sse2.setzero_si128(); + } + + if (Hint.Likely((int)length >= 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi16(count0, Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi16(count0, Sse2.shufflelo_epi16(count0, Sse.SHUFFLE(0, 0, 0, 1))); + if (Sse4_1.IsSse41Supported) + { + count0 = Sse4_1.cvtepu16_epi64(count0); + } + else + { + count0 = Sse2.and_si128(count0, Sse2.cvtsi32_si128(ushort.MaxValue)); + } + + longCount = Sse2.add_epi64(longCount, Sse2.bsrli_si128(longCount, 1 * sizeof(ulong))); + ulong countTotal = Sse2.add_epi64(longCount, count0).ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.Shorts(*(short*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + return countTotal; + } + else + { + ulong count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Shorts(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } + } + + default: return 0; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeArray array, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeArray array, int index, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeArray array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeList array, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeList array, int index, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeList array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeSlice array, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeSlice array, int index, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, returnType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.Int32) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, returnType); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong SIMD_Count(int* ptr, long length, int value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.UInt64) + { +Assert.IsBetween((int)returnType, (int)TypeCode.SByte, (int)TypeCode.UInt64); +Assert.IsNonNegative(length); + + long originalLength = length; + + switch (returnType) + { + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi32(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 32)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 32; + } + + count0 = Avx2.mm256_add_epi32(Avx2.mm256_add_epi32(count0, count1), Avx2.mm256_add_epi32(count2, count3)); + + if (Hint.Likely((int)length >= 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + v128 count128 = Sse2.add_epi32(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi32(count128, Compare.Ints128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + } + else { } + + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi32(count128, Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + uint countTotal = count128.UInt0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } + + bool comparison = Compare.Ints(*(int*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } + + return countTotal; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi32(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely(length >= 16)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 16; + } + + count0 = Sse2.add_epi32(Sse2.add_epi32(count0, count1), Sse2.add_epi32(count2, count3)); + + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + uint countTotal = count0.UInt0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - 1 - countTotal); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, short value) - { - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value); - } + bool comparison = Compare.Ints(*(int*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (uint)((ulong)originalLength - countTotal); + } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, short value) - { -Assert.IsWithinArrayBounds(index, array.Length); + return countTotal; + } + else + { + uint count = 0; - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); - } + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Ints(ptr[i], value, where); + count += *(byte*)&comparison; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, short value) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + return count; + } + } + case TypeCode.Int64: + case TypeCode.UInt64: + { + if (Avx2.IsAvx2Supported) + { + v256 ZERO = default(v256); - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); - } + v256 broadcast = Avx.mm256_set1_epi32(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 longCount = default(v256); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, short value) - { - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value); - } + while (Hint.Likely(length >= 4L * 8 * uint.MaxValue)) + { + uint loopCounter = 0; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, short value) - { -Assert.IsWithinArrayBounds(index, array.Length); + do + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); - } + loopCounter++; + } + while (Hint.Likely(loopCounter < uint.MaxValue)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, short value) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + v256 longSum0 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count0, ZERO), Avx2.mm256_unpacklo_epi32(count1, ZERO)); + v256 longSum1 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count0, ZERO), Avx2.mm256_unpackhi_epi32(count1, ZERO)); + v256 longSum2 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count2, ZERO), Avx2.mm256_unpacklo_epi32(count3, ZERO)); + v256 longSum3 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count2, ZERO), Avx2.mm256_unpackhi_epi32(count3, ZERO)); - return SIMD_Count((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); - } + length -= 4L * 8 * uint.MaxValue; + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(longSum0, longSum1), Avx2.mm256_add_epi64(longSum2, longSum3))); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(int* ptr, long length, int value) - { -Assert.IsNonNegative(length); + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely(length >= 32)) + { + do + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + } + while (Hint.Likely(length >= 32)); + + v256 longSum0 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count0, ZERO), Avx2.mm256_unpacklo_epi32(count1, ZERO)); + v256 longSum1 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count0, ZERO), Avx2.mm256_unpackhi_epi32(count1, ZERO)); + v256 longSum2 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count2, ZERO), Avx2.mm256_unpacklo_epi32(count3, ZERO)); + v256 longSum3 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count2, ZERO), Avx2.mm256_unpackhi_epi32(count3, ZERO)); + + length -= 32; + + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(longSum0, longSum1), Avx2.mm256_add_epi64(longSum2, longSum3))); + + count0 = Avx.mm256_setzero_si256(); + } + + if (Hint.Likely((int)length >= 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + v128 count128 = Sse2.add_epi32(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + v128 longCount128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longCount), Avx2.mm256_extracti128_si256(longCount, 1)); + + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi32(count128, Compare.Ints128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + } + else { } + + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + longCount128 = Sse2.add_epi64(longCount128, Sse2.bsrli_si128(longCount128, 1 * sizeof(ulong))); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi32(count128, Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + ulong countTotal = count128.UInt0 + longCount128.ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.Ints(*(int*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + return countTotal; + } + else if (Sse2.IsSse2Supported) + { + v128 ZERO = default(v128); + + v128 broadcast = Sse2.set1_epi32(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 longCount = default(v128); + + if (Hint.Likely(length >= 4L * 4 * uint.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < uint.MaxValue)); + + length -= 4L * 4 * uint.MaxValue; + + v128 longSum0 = Sse2.add_epi64(Sse2.unpacklo_epi32(count0, ZERO), Sse2.unpacklo_epi32(count1, ZERO)); + v128 longSum1 = Sse2.add_epi64(Sse2.unpackhi_epi32(count0, ZERO), Sse2.unpackhi_epi32(count1, ZERO)); + v128 longSum2 = Sse2.add_epi64(Sse2.unpacklo_epi32(count2, ZERO), Sse2.unpacklo_epi32(count3, ZERO)); + v128 longSum3 = Sse2.add_epi64(Sse2.unpackhi_epi32(count2, ZERO), Sse2.unpackhi_epi32(count3, ZERO)); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(Sse2.add_epi64(longSum0, longSum1), Sse2.add_epi64(longSum2, longSum3))); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + + if (Hint.Likely(length >= 16)) + { + do + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + v128 longSum0 = Sse2.add_epi64(Sse2.unpacklo_epi32(count0, ZERO), Sse2.unpacklo_epi32(count1, ZERO)); + v128 longSum1 = Sse2.add_epi64(Sse2.unpackhi_epi32(count0, ZERO), Sse2.unpackhi_epi32(count1, ZERO)); + v128 longSum2 = Sse2.add_epi64(Sse2.unpacklo_epi32(count2, ZERO), Sse2.unpacklo_epi32(count3, ZERO)); + v128 longSum3 = Sse2.add_epi64(Sse2.unpackhi_epi32(count2, ZERO), Sse2.unpackhi_epi32(count3, ZERO)); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(Sse2.add_epi64(longSum0, longSum1), Sse2.add_epi64(longSum2, longSum3))); + + count0 = Sse2.setzero_si128(); + } + + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + longCount = Sse2.bsrli_si128(longCount, 1 * sizeof(ulong)); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi32(count0, Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + ulong countTotal = count0.UInt0 + longCount.ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.Ints(*(int*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + return countTotal; + } + else + { + ulong count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Ints(ptr[i], value, where); + count += *(byte*)&comparison; + } - return SIMD_Count((uint*)ptr, length, (uint)value); + return count; + } + } + + default: return 0; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int value) + public static int SIMD_Count(this NativeArray array, int value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int value) + public static int SIMD_Count(this NativeArray array, int index, int value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, int value) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int value) + public static int SIMD_Count(this NativeList array, int value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int value) + public static int SIMD_Count(this NativeList array, int index, int value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, int value) + public static int SIMD_Count(this NativeList array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int value) + public static int SIMD_Count(this NativeSlice array, int value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int value) + public static int SIMD_Count(this NativeSlice array, int index, int value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, int value) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(long* ptr, long length, long value) - { -Assert.IsNonNegative(length); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong SIMD_Count(long* ptr, long length, long value, Comparison where = Comparison.EqualTo) + { +Assert.IsNonNegative(length); + + long originalLength = length; + + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi64x(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 16)) + { + count0 = Avx2.mm256_sub_epi64(count0, Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi64(count1, Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi64(count2, Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi64(count3, Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 16; + } + + count0 = Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(count0, count1), Avx2.mm256_add_epi64(count2, count3)); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Avx2.mm256_sub_epi64(count0, Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 4)) + { + count0 = Avx2.mm256_sub_epi64(count0, Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 4)) + { + count0 = Avx2.mm256_sub_epi64(count0, Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + v128 count128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi64(count128, Compare.Longs128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi64(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = count128.ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.Longs(*(long*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + + return countTotal; + } + else if (Sse4_2.IsSse42Supported) + { + v128 broadcast = Sse2.set1_epi64x(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely(length >= 8)) + { + count0 = Sse2.sub_epi64(count0, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi64(count1, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi64(count2, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi64(count3, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 8; + } + + count0 = Sse2.add_epi64(Sse2.add_epi64(count0, count1), Sse2.add_epi64(count2, count3)); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 2; + } + else + { + length -= 2 * 2; + } + } + else + { + length -= 2; + } + } + else { } + + count0 = Sse2.add_epi64(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = count0.ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.Longs(*(long*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + + return countTotal; + } + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely(length >= 8)) + { + count0 = Sse2.sub_epi64(count0, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi64(count1, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi64(count2, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi64(count3, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 8; + } + + count0 = Sse2.add_epi64(Sse2.add_epi64(count0, count1), Sse2.add_epi64(count2, count3)); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 2)) + { + count0 = Sse2.sub_epi64(count0, Compare.Longs128(Sse2.loadu_si128(ptr_v128++), broadcast, where)); + + length -= 3 * 2; + } + else + { + length -= 2 * 2; + } + } + else + { + length -= 2; + } + } + else { } + + count0 = Sse2.add_epi64(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = count0.ULong0; + + if (Hint.Likely(length != 0)) + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - 1 - countTotal; + } + + bool comparison = Compare.Longs(*(long*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else + { + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + countTotal = (ulong)originalLength - countTotal; + } + } + + + return countTotal; + } + else + { + ulong count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Longs(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } + } + else + { + ulong count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Longs(ptr[i], value, where); + count += *(byte*)&comparison; + } - return SIMD_Count((ulong*)ptr, length, (ulong)value); + return count; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, long value) + public static int SIMD_Count(this NativeArray array, long value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, long value) + public static int SIMD_Count(this NativeArray array, int index, long value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, long value) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, long value) + public static int SIMD_Count(this NativeList array, long value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, long value) + public static int SIMD_Count(this NativeList array, int index, long value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, long value) + public static int SIMD_Count(this NativeList array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, long value) + public static int SIMD_Count(this NativeSlice array, long value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, long value) + public static int SIMD_Count(this NativeSlice array, int index, long value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, long value) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(float* ptr, long length, float value) + public static ulong SIMD_Count(float* ptr, long length, float value, Comparison where = Comparison.EqualTo, TypeCode returnType = TypeCode.UInt64) { +Assert.IsBetween((int)returnType, (int)TypeCode.SByte, (int)TypeCode.UInt64); Assert.IsNonNegative(length); Assert.IsFalse(math.isnan(value)); - if (Avx.IsAvxSupported) + switch (returnType) { - v256 broadcast = Avx.mm256_set1_ps(value); - v256* ptr_v256 = (v256*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; - - while (Hint.Likely(length >= 32)) + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: { - v256 load0 = Avx.mm256_loadu_ps(ptr_v256++); - v256 load1 = Avx.mm256_loadu_ps(ptr_v256++); - v256 load2 = Avx.mm256_loadu_ps(ptr_v256++); - v256 load3 = Avx.mm256_loadu_ps(ptr_v256++); + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_ps(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 32)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + + length -= 32; + } - length -= 32; + count0 = Avx2.mm256_add_epi32(Avx2.mm256_add_epi32(count0, count1), Avx2.mm256_add_epi32(count2, count3)); - v256 cmpeq0 = Avx.mm256_cmp_ps(broadcast, load0, (int)Avx.CMP.EQ_OQ); - v256 cmpeq1 = Avx.mm256_cmp_ps(broadcast, load1, (int)Avx.CMP.EQ_OQ); - v256 cmpeq2 = Avx.mm256_cmp_ps(broadcast, load2, (int)Avx.CMP.EQ_OQ); - v256 cmpeq3 = Avx.mm256_cmp_ps(broadcast, load3, (int)Avx.CMP.EQ_OQ); + if (Hint.Likely((int)length >= 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } - int mask0 = Avx.mm256_movemask_ps(cmpeq0); - int mask1 = Avx.mm256_movemask_ps(cmpeq1); - int mask2 = Avx.mm256_movemask_ps(cmpeq2); - int mask3 = Avx.mm256_movemask_ps(cmpeq3); + v128 count128 = Sse2.add_epi32(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi32(count128, Compare.Floats128(Sse.loadu_ps(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; - } + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + } + else { } - countTotal = (count0 + count1) + (count2 + count3); + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi32(count128, Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Likely((int)length >= 8)) - { - countTotal += (uint)math.countbits(Avx.mm256_movemask_ps(Avx.mm256_cmp_ps(broadcast, Avx.mm256_loadu_si256(ptr_v256++), (int)Avx.CMP.EQ_OQ))); + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + } + else { } + + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + uint countTotal = count128.UInt0; + + if (Hint.Likely(length != 0)) + { + bool comparison = Compare.Floats(*(float*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else { } - if (Hint.Likely((int)length >= 2 * 8)) + + return countTotal; + } + else if (Avx.IsAvxSupported) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_ps(Avx.mm256_cmp_ps(broadcast, Avx.mm256_loadu_si256(ptr_v256++), (int)Avx.CMP.EQ_OQ))); + goto case TypeCode.UInt64; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse.set1_ps(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + + while (Hint.Likely(length >= 16)) + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + length -= 16; + } - if (Hint.Likely((int)length >= 3 * 8)) + count0 = Sse2.add_epi32(Sse2.add_epi32(count0, count1), Sse2.add_epi32(count2, count3)); + + if (Hint.Likely((int)length >= 4)) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_ps(Avx.mm256_cmp_ps(broadcast, Avx.mm256_loadu_si256(ptr_v256++), (int)Avx.CMP.EQ_OQ))); - length -= 3 * 8; + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } } - else + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + uint countTotal = count0.UInt0; + + if (Hint.Likely(length != 0)) { - length -= 2 * 8; + bool comparison = Compare.Floats(*(float*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; } + else { } + + + return countTotal; } else { - length -= 8; + uint count = 0; + + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Floats(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; } } - else { } + case TypeCode.Int64: + case TypeCode.UInt64: + { + if (Avx2.IsAvx2Supported) + { + v256 ZERO = default(v256); + v256 broadcast = Avx.mm256_set1_ps(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + v256 longCount = default(v256); - if (Hint.Likely((int)length >= 4)) - { - countTotal += (uint)math.countbits(Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castsi256_si128(broadcast), Sse.loadu_ps(ptr_v256)))); - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 4; - } - else { } + if (Hint.Likely(length >= 4L * 8 * uint.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < uint.MaxValue)); + + length -= 4L * 8 * uint.MaxValue; + + v256 longSum0 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count0, ZERO), Avx2.mm256_unpacklo_epi32(count1, ZERO)); + v256 longSum1 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count0, ZERO), Avx2.mm256_unpackhi_epi32(count1, ZERO)); + v256 longSum2 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count2, ZERO), Avx2.mm256_unpacklo_epi32(count3, ZERO)); + v256 longSum3 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count2, ZERO), Avx2.mm256_unpackhi_epi32(count3, ZERO)); + + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(longSum0, longSum1), Avx2.mm256_add_epi64(longSum2, longSum3))); + + count0 = Avx.mm256_setzero_si256(); + count1 = Avx.mm256_setzero_si256(); + count2 = Avx.mm256_setzero_si256(); + count3 = Avx.mm256_setzero_si256(); + } - if (Hint.Likely((int)length >= 2)) - { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); + if (Hint.Likely(length >= 32)) + { + do + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi32(count1, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi32(count2, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi32(count3, Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256++), broadcast, where)); + + length -= 32; + } + while (Hint.Likely(length >= 32)); + + v256 longSum0 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count0, ZERO), Avx2.mm256_unpacklo_epi32(count1, ZERO)); + v256 longSum1 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count0, ZERO), Avx2.mm256_unpackhi_epi32(count1, ZERO)); + v256 longSum2 = Avx2.mm256_add_epi64(Avx2.mm256_unpacklo_epi32(count2, ZERO), Avx2.mm256_unpacklo_epi32(count3, ZERO)); + v256 longSum3 = Avx2.mm256_add_epi64(Avx2.mm256_unpackhi_epi32(count2, ZERO), Avx2.mm256_unpackhi_epi32(count3, ZERO)); + + longCount = Avx2.mm256_add_epi64(longCount, Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(longSum0, longSum1), Avx2.mm256_add_epi64(longSum2, longSum3))); + + count0 = Avx.mm256_setzero_si256(); + } - if (Constant.IsConstantExpression(value) && value != 0) - { - ; - } - else - { - mask &= 0b0011; - } + if (Hint.Likely((int)length >= 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + count0 = Avx2.mm256_sub_epi32(count0, Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } - countTotal += (uint)math.countbits(mask); + v128 count128 = Sse2.add_epi32(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + v128 longCount128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(longCount), Avx2.mm256_extracti128_si256(longCount, 1)); - ptr_v256 = (v256*)((long*)ptr_v256 + 1); - length -= 2; - } - else { } + if (Hint.Likely((int)length >= 4)) + { + count128 = Sse2.sub_epi32(count128, Compare.Floats128(Sse.loadu_ps(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Likely(length != 0)) - { - bool areEqual = *(float*)ptr_v256 == value; - countTotal += *(byte*)&areEqual; - } - else { } + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + } + else { } + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + longCount128 = Sse2.add_epi64(longCount128, Sse2.bsrli_si128(longCount128, 1 * sizeof(ulong))); - return countTotal; - } - else if (Sse2.IsSse2Supported) - { - v128 broadcast = Sse.set1_ps(value); - v128* ptr_v128 = (v128*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi32(count128, Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - while (Hint.Likely(length >= 16)) - { - v128 load0 = Sse.loadu_ps(ptr_v128++); - v128 load1 = Sse.loadu_ps(ptr_v128++); - v128 load2 = Sse.loadu_ps(ptr_v128++); - v128 load3 = Sse.loadu_ps(ptr_v128++); + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + } + else { } - length -= 16; + count128 = Sse2.add_epi32(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 0, 1))); + ulong countTotal = count128.UInt0 + longCount128.ULong0; + + if (Hint.Likely(length != 0)) + { + bool comparison = Compare.Floats(*(float*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else { } - v128 cmpeq0 = Sse.cmpeq_ps(broadcast, load0); - v128 cmpeq1 = Sse.cmpeq_ps(broadcast, load1); - v128 cmpeq2 = Sse.cmpeq_ps(broadcast, load2); - v128 cmpeq3 = Sse.cmpeq_ps(broadcast, load3); - int mask0 = Sse.movemask_ps(cmpeq0); - int mask1 = Sse.movemask_ps(cmpeq1); - int mask2 = Sse.movemask_ps(cmpeq2); - int mask3 = Sse.movemask_ps(cmpeq3); + return countTotal; + } + if (Avx.IsAvxSupported) + { + v256 broadcast = Avx.mm256_set1_ps(value); + v256* ptr_v256 = (v256*)ptr; + ulong count0 = 0; + ulong count1 = 0; + ulong count2 = 0; + ulong count3 = 0; + ulong countTotal = 0; + + while (Hint.Likely(length >= 32)) + { + v256 load0 = Avx.mm256_loadu_ps(ptr_v256++); + v256 load1 = Avx.mm256_loadu_ps(ptr_v256++); + v256 load2 = Avx.mm256_loadu_ps(ptr_v256++); + v256 load3 = Avx.mm256_loadu_ps(ptr_v256++); + + length -= 32; + + v256 cmpeq0 = Compare.Floats256(load0, broadcast, where); + v256 cmpeq1 = Compare.Floats256(load1, broadcast, where); + v256 cmpeq2 = Compare.Floats256(load2, broadcast, where); + v256 cmpeq3 = Compare.Floats256(load3, broadcast, where); + + int mask0 = Avx.mm256_movemask_ps(cmpeq0); + int mask1 = Avx.mm256_movemask_ps(cmpeq1); + int mask2 = Avx.mm256_movemask_ps(cmpeq2); + int mask3 = Avx.mm256_movemask_ps(cmpeq3); + + int tempCount0 = Popcnt.popcnt_u32((uint)mask0); + int tempCount1 = Popcnt.popcnt_u32((uint)mask1); + int tempCount2 = Popcnt.popcnt_u32((uint)mask2); + int tempCount3 = Popcnt.popcnt_u32((uint)mask3); + + count0 += (uint)tempCount0; + count1 += (uint)tempCount1; + count2 += (uint)tempCount2; + count3 += (uint)tempCount3; + } - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); + countTotal = (count0 + count1) + (count2 + count3); - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; - } - countTotal = (count0 + count1) + (count2 + count3); + if (Hint.Likely((int)length >= 8)) + { + countTotal += (uint)Popcnt.popcnt_u32((uint)Avx.mm256_movemask_ps(Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where))); + + if (Hint.Likely((int)length >= 2 * 8)) + { + countTotal += (uint)Popcnt.popcnt_u32((uint)Avx.mm256_movemask_ps(Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where))); + + if (Hint.Likely((int)length >= 3 * 8)) + { + countTotal += (uint)Popcnt.popcnt_u32((uint)Avx.mm256_movemask_ps(Compare.Floats256(Avx.mm256_loadu_si256(ptr_v256++), broadcast, where))); + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } - if (Hint.Likely((int)length >= 4)) - { - countTotal += (uint)math.countbits(Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse.loadu_ps(ptr_v128++)))); + if (Hint.Likely((int)length >= 4)) + { + countTotal += (uint)Popcnt.popcnt_u32((uint)Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where))); - if (Hint.Likely((int)length >= 2 * 4)) - { - countTotal += (uint)math.countbits(Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse.loadu_ps(ptr_v128++)))); + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + } + else { } - if (Hint.Likely((int)length >= 3 * 4)) + if (Hint.Likely((int)length >= 2)) { - countTotal += (uint)math.countbits(Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse.loadu_ps(ptr_v128++)))); - length -= 3 * 4; + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } + + countTotal += (uint)Popcnt.popcnt_u32((uint)mask); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; } - else + else { } + + if (Hint.Likely(length != 0)) { - length -= 2 * 4; + bool comparison = Compare.Floats(*(float*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; } - } - else - { - length -= 4; - } - } - else { } + else { } - if (Hint.Likely((int)length >= 2)) - { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); - if (Constant.IsConstantExpression(value) && value != 0) - { - ; + return countTotal; } - else + else if (Sse2.IsSse2Supported) { - mask &= 0b0011; - } + v128 ZERO = default(v128); - countTotal += (uint)math.countbits(mask); + v128 broadcast = Sse.set1_ps(value); + v128* ptr_v128 = (v128*)ptr; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); + v128 longCount = default(v128); - ptr_v128 = (v128*)((long*)ptr_v128 + 1); - length -= 2; - } - else { } - if (Hint.Likely(length != 0)) - { - bool areEqual = *(float*)ptr_v128 == value; - countTotal += *(byte*)&areEqual; - } - else { } + if (Hint.Likely(length >= 4L * 4 * uint.MaxValue)) + { + uint loopCounter = 0; + + do + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + loopCounter++; + } + while (Hint.Likely(loopCounter < uint.MaxValue)); + + length -= 4L * 4 * uint.MaxValue; + + v128 longSum0 = Sse2.add_epi64(Sse2.unpacklo_epi32(count0, ZERO), Sse2.unpacklo_epi32(count1, ZERO)); + v128 longSum1 = Sse2.add_epi64(Sse2.unpackhi_epi32(count0, ZERO), Sse2.unpackhi_epi32(count1, ZERO)); + v128 longSum2 = Sse2.add_epi64(Sse2.unpacklo_epi32(count2, ZERO), Sse2.unpacklo_epi32(count3, ZERO)); + v128 longSum3 = Sse2.add_epi64(Sse2.unpackhi_epi32(count2, ZERO), Sse2.unpackhi_epi32(count3, ZERO)); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(Sse2.add_epi64(longSum0, longSum1), Sse2.add_epi64(longSum2, longSum3))); + + count0 = Sse2.setzero_si128(); + count1 = Sse2.setzero_si128(); + count2 = Sse2.setzero_si128(); + count3 = Sse2.setzero_si128(); + } + + if (Hint.Likely(length >= 16)) + { + do + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi32(count1, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi32(count2, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi32(count3, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + v128 longSum0 = Sse2.add_epi64(Sse2.unpacklo_epi32(count0, ZERO), Sse2.unpacklo_epi32(count1, ZERO)); + v128 longSum1 = Sse2.add_epi64(Sse2.unpackhi_epi32(count0, ZERO), Sse2.unpackhi_epi32(count1, ZERO)); + v128 longSum2 = Sse2.add_epi64(Sse2.unpacklo_epi32(count2, ZERO), Sse2.unpacklo_epi32(count3, ZERO)); + v128 longSum3 = Sse2.add_epi64(Sse2.unpackhi_epi32(count2, ZERO), Sse2.unpackhi_epi32(count3, ZERO)); + + longCount = Sse2.add_epi64(longCount, Sse2.add_epi64(Sse2.add_epi64(longSum0, longSum1), Sse2.add_epi64(longSum2, longSum3))); + + count0 = Sse2.setzero_si128(); + } + if (Hint.Likely((int)length >= 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 4)) + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } - return countTotal; - } - else - { - ulong count = 0; + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + longCount = Sse2.add_epi64(longCount, Sse2.bsrli_si128(longCount, 1 * sizeof(ulong))); - for (long i = 0; i < length; i++) - { - bool areEqual = ptr[i] == value; - count += *(byte*)&areEqual; + if (Hint.Likely((int)length >= 2)) + { + count0 = Sse2.sub_epi32(count0, Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + else { } + + count0 = Sse2.add_epi32(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 0, 1))); + ulong countTotal = count0.UInt0 + longCount.ULong0; + + if (Hint.Likely(length != 0)) + { + bool comparison = Compare.Floats(*(float*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; + } + else { } + + + return countTotal; + } + else + { + ulong count = 0; + for (long i = 0; i < length; i++) + { + bool comparison = Compare.Floats(ptr[i], value, where); + count += *(byte*)&comparison; + } + + return count; + } } - return count; + default: return 0; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, float value) + public static int SIMD_Count(this NativeArray array, float value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, float value) + public static int SIMD_Count(this NativeArray array, int index, float value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, float value) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, float value) + public static int SIMD_Count(this NativeList array, float value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, float value) + public static int SIMD_Count(this NativeList array, int index, float value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, float value) + public static int SIMD_Count(this NativeList array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, float value) + public static int SIMD_Count(this NativeSlice array, float value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, float value) + public static int SIMD_Count(this NativeSlice array, int index, float value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, float value) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, TypeCode.Int32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(double* ptr, long length, double value) + public static ulong SIMD_Count(double* ptr, long length, double value, Comparison where = Comparison.EqualTo) { Assert.IsNonNegative(length); Assert.IsFalse(math.isnan(value)); - if (Avx.IsAvxSupported) + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_pd(value); + v256* ptr_v256 = (v256*)ptr; + v256 count0 = default(v256); + v256 count1 = default(v256); + v256 count2 = default(v256); + v256 count3 = default(v256); + + while (Hint.Likely(length >= 16)) + { + count0 = Avx2.mm256_sub_epi64(count0, Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where)); + count1 = Avx2.mm256_sub_epi64(count1, Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where)); + count2 = Avx2.mm256_sub_epi64(count2, Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where)); + count3 = Avx2.mm256_sub_epi64(count3, Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where)); + + length -= 16; + } + + count0 = Avx2.mm256_add_epi64(Avx2.mm256_add_epi64(count0, count1), Avx2.mm256_add_epi64(count2, count3)); + + if (Hint.Likely((int)length >= 4)) + { + count0 = Avx2.mm256_sub_epi64(count0, Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 2 * 4)) + { + count0 = Avx2.mm256_sub_epi64(count0, Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where)); + + if (Hint.Likely((int)length >= 3 * 4)) + { + count0 = Avx2.mm256_sub_epi64(count0, Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where)); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + v128 count128 = Sse2.add_epi64(Avx.mm256_castsi256_si128(count0), Avx2.mm256_extracti128_si256(count0, 1)); + + if (Hint.Likely((int)length >= 2)) + { + count128 = Sse2.sub_epi64(count128, Compare.Doubles128(Sse.loadu_ps(ptr_v256), Avx.mm256_castpd256_pd128(broadcast), where)); + + length -= 2; + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + } + else { } + + count128 = Sse2.add_epi64(count128, Sse2.shuffle_epi32(count128, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = count128.ULong0; + + if (Hint.Likely(length != 0)) + { + bool comparison = Compare.Doubles(*(double*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; + } + else { } + + + return countTotal; + } + else if (Avx.IsAvxSupported) { v256 broadcast = Avx.mm256_set1_pd(value); v256* ptr_v256 = (v256*)ptr; @@ -2322,20 +6523,20 @@ public static ulong SIMD_Count(double* ptr, long length, double value) length -= 16; - v256 cmpeq0 = Avx.mm256_cmp_pd(broadcast, load0, (int)Avx.CMP.EQ_OQ); - v256 cmpeq1 = Avx.mm256_cmp_pd(broadcast, load1, (int)Avx.CMP.EQ_OQ); - v256 cmpeq2 = Avx.mm256_cmp_pd(broadcast, load2, (int)Avx.CMP.EQ_OQ); - v256 cmpeq3 = Avx.mm256_cmp_pd(broadcast, load3, (int)Avx.CMP.EQ_OQ); + v256 cmpeq0 = Compare.Doubles256(load0, broadcast, where); + v256 cmpeq1 = Compare.Doubles256(load1, broadcast, where); + v256 cmpeq2 = Compare.Doubles256(load2, broadcast, where); + v256 cmpeq3 = Compare.Doubles256(load3, broadcast, where); int mask0 = Avx.mm256_movemask_pd(cmpeq0); int mask1 = Avx.mm256_movemask_pd(cmpeq1); int mask2 = Avx.mm256_movemask_pd(cmpeq2); int mask3 = Avx.mm256_movemask_pd(cmpeq3); - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); + int tempCount0 = Popcnt.popcnt_u32((uint)mask0); + int tempCount1 = Popcnt.popcnt_u32((uint)mask1); + int tempCount2 = Popcnt.popcnt_u32((uint)mask2); + int tempCount3 = Popcnt.popcnt_u32((uint)mask3); count0 += (uint)tempCount0; count1 += (uint)tempCount1; @@ -2348,15 +6549,15 @@ public static ulong SIMD_Count(double* ptr, long length, double value) if (Hint.Likely((int)length >= 4)) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_pd(Avx.mm256_cmp_pd(broadcast, Avx.mm256_loadu_pd(ptr_v256++), (int)Avx.CMP.EQ_OQ))); + countTotal += (uint)Popcnt.popcnt_u32((uint)Avx.mm256_movemask_pd(Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where))); if (Hint.Likely((int)length >= 2 * 4)) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_pd(Avx.mm256_cmp_pd(broadcast, Avx.mm256_loadu_pd(ptr_v256++), (int)Avx.CMP.EQ_OQ))); + countTotal += (uint)Popcnt.popcnt_u32((uint)Avx.mm256_movemask_pd(Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where))); if (Hint.Likely((int)length >= 3 * 4)) { - countTotal += (uint)math.countbits(Avx.mm256_movemask_pd(Avx.mm256_cmp_pd(broadcast, Avx.mm256_loadu_pd(ptr_v256++), (int)Avx.CMP.EQ_OQ))); + countTotal += (uint)Popcnt.popcnt_u32((uint)Avx.mm256_movemask_pd(Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256++), broadcast, where))); length -= 3 * 4; } else @@ -2373,7 +6574,7 @@ public static ulong SIMD_Count(double* ptr, long length, double value) if (Hint.Likely((int)length >= 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_pd(Sse2.cmpeq_pd(Avx.mm256_castpd256_pd128(broadcast), Sse.loadu_ps(ptr_v256)))); + countTotal += (uint)Popcnt.popcnt_u32((uint)Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(ptr_v256), Avx.mm256_castpd256_pd128(broadcast), where))); length -= 2; ptr_v256 = (v256*)((v128*)ptr_v256 + 1); @@ -2382,8 +6583,8 @@ public static ulong SIMD_Count(double* ptr, long length, double value) if (Hint.Likely(length != 0)) { - bool areEqual = *(double*)ptr_v256 == value; - countTotal += *(byte*)&areEqual; + bool comparison = Compare.Doubles(*(double*)ptr_v256, value, where); + countTotal += *(byte*)&comparison; } else { } @@ -2394,56 +6595,35 @@ public static ulong SIMD_Count(double* ptr, long length, double value) { v128 broadcast = Sse2.set1_pd(value); v128* ptr_v128 = (v128*)ptr; - ulong count0 = 0; - ulong count1 = 0; - ulong count2 = 0; - ulong count3 = 0; - ulong countTotal = 0; + v128 count0 = default(v128); + v128 count1 = default(v128); + v128 count2 = default(v128); + v128 count3 = default(v128); while (Hint.Likely(length >= 8)) { - v128 load0 = Sse.loadu_ps(ptr_v128++); - v128 load1 = Sse.loadu_ps(ptr_v128++); - v128 load2 = Sse.loadu_ps(ptr_v128++); - v128 load3 = Sse.loadu_ps(ptr_v128++); - + count0 = Sse2.sub_epi64(count0, Compare.Doubles128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count1 = Sse2.sub_epi64(count1, Compare.Doubles128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count2 = Sse2.sub_epi64(count2, Compare.Doubles128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + count3 = Sse2.sub_epi64(count3, Compare.Doubles128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + length -= 8; - - v128 cmpeq0 = Sse2.cmpeq_pd(broadcast, load0); - v128 cmpeq1 = Sse2.cmpeq_pd(broadcast, load1); - v128 cmpeq2 = Sse2.cmpeq_pd(broadcast, load2); - v128 cmpeq3 = Sse2.cmpeq_pd(broadcast, load3); - - int mask0 = Sse2.movemask_pd(cmpeq0); - int mask1 = Sse2.movemask_pd(cmpeq1); - int mask2 = Sse2.movemask_pd(cmpeq2); - int mask3 = Sse2.movemask_pd(cmpeq3); - - int tempCount0 = math.countbits(mask0); - int tempCount1 = math.countbits(mask1); - int tempCount2 = math.countbits(mask2); - int tempCount3 = math.countbits(mask3); - - count0 += (uint)tempCount0; - count1 += (uint)tempCount1; - count2 += (uint)tempCount2; - count3 += (uint)tempCount3; } - countTotal = (count0 + count1) + (count2 + count3); - + count0 = Sse2.add_epi64(Sse2.add_epi64(count0, count1), Sse2.add_epi64(count2, count3)); if (Hint.Likely((int)length >= 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_pd(Sse2.cmpeq_pd(broadcast, Sse.loadu_ps(ptr_v128++)))); + count0 = Sse2.sub_epi64(count0, Compare.Doubles128(Sse.loadu_ps(ptr_v128++), broadcast, where)); if (Hint.Likely((int)length >= 2 * 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_pd(Sse2.cmpeq_pd(broadcast, Sse.loadu_ps(ptr_v128++)))); + count0 = Sse2.sub_epi64(count0, Compare.Doubles128(Sse.loadu_ps(ptr_v128++), broadcast, where)); if (Hint.Likely((int)length >= 3 * 2)) { - countTotal += (uint)math.countbits(Sse2.movemask_pd(Sse2.cmpeq_pd(broadcast, Sse.loadu_ps(ptr_v128++)))); + count0 = Sse2.sub_epi64(count0, Compare.Doubles128(Sse.loadu_ps(ptr_v128++), broadcast, where)); + length -= 3 * 2; } else @@ -2458,10 +6638,13 @@ public static ulong SIMD_Count(double* ptr, long length, double value) } else { } + count0 = Sse2.add_epi64(count0, Sse2.shuffle_epi32(count0, Sse.SHUFFLE(0, 0, 3, 2))); + ulong countTotal = count0.ULong0; + if (Hint.Likely(length != 0)) { - bool areEqual = *(double*)ptr_v128 == value; - countTotal += *(byte*)&areEqual; + bool comparison = Compare.Doubles(*(double*)ptr_v128, value, where); + countTotal += *(byte*)&comparison; } else { } @@ -2474,8 +6657,8 @@ public static ulong SIMD_Count(double* ptr, long length, double value) for (long i = 0; i < length; i++) { - bool areEqual = ptr[i] == value; - count += *(byte*)&areEqual; + bool comparison = Compare.Doubles(ptr[i], value, where); + count += *(byte*)&comparison; } return count; @@ -2483,69 +6666,69 @@ public static ulong SIMD_Count(double* ptr, long length, double value) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, double value) + public static int SIMD_Count(this NativeArray array, double value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, double value) + public static int SIMD_Count(this NativeArray array, int index, double value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeArray array, int index, int numEntries, double value) + public static int SIMD_Count(this NativeArray array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, double value) + public static int SIMD_Count(this NativeList array, double value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, double value) + public static int SIMD_Count(this NativeList array, int index, double value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeList array, int index, int numEntries, double value) + public static int SIMD_Count(this NativeList array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, double value) + public static int SIMD_Count(this NativeSlice array, double value, Comparison where = Comparison.EqualTo) { - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, double value) + public static int SIMD_Count(this NativeSlice array, int index, double value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index, array.Length); - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SIMD_Count(this NativeSlice array, int index, int numEntries, double value) + public static int SIMD_Count(this NativeSlice array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value); + return (int)SIMD_Count((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where); } } } \ No newline at end of file diff --git a/Runtime/Algorithms/IndexOf.cs b/Runtime/Algorithms/IndexOf.cs index 6bced2c..837e96e 100644 --- a/Runtime/Algorithms/IndexOf.cs +++ b/Runtime/Algorithms/IndexOf.cs @@ -29,7 +29,7 @@ public static long SIMD_IndexOf(bool* ptr, long length, bool value, TraversalOrd } } #endif - return SIMD_IndexOf((byte*)ptr, length, *(byte*)&value, traversalOrder); + return SIMD_IndexOf((byte*)ptr, length, *(byte*)&value, Comparison.EqualTo, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -100,7 +100,7 @@ public static int SIMD_IndexOf(this NativeSlice array, int index, int numE [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static long SIMD_IndexOf(byte* ptr, long length, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); @@ -115,37 +115,63 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd while (Hint.Likely(length >= 32)) { - int mask = Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi8(broadcast, Avx.mm256_loadu_si256(ptr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.Bytes256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != -1)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v256++; - length -= 32; - index += 32; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v256++; + length -= 32; + index += 32; } if (Hint.Likely((int)length >= 16)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 16; - index += 16; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 16; + index += 16; } else { } @@ -154,9 +180,9 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd if (Hint.Likely((int)length >= 8)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -165,26 +191,39 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v256 = (v256*)((long*)ptr_v256 + 1); - length -= 8; - index += 8; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; + index += 8; } else { } if (Hint.Likely((int)length >= 4)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)ptr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -193,26 +232,39 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v256 = (v256*)((int*)ptr_v256 + 1); - length -= 4; - index += 4; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; + index += 4; } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -221,25 +273,35 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - bool onlyTheSecondIsEqualToValue = mask == 2; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; - goto Found; + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } } else { - ptr_v256 = (v256*)((short*)ptr_v256 + 1); - length -= 2; - index += 2; - } + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v256 = (v256*)((short*)ptr_v256 + 1); + length -= 2; + index += 2; } else { } if (Hint.Likely(length != 0)) { - if (*(byte*)ptr_v256 == value) + if (Compare.Bytes(*(byte*)ptr_v256, value, where)) { result = index; goto Found; @@ -261,27 +323,40 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd while (Hint.Likely(length >= 16)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.loadu_si128(ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.loadu_si128(ptr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v128++; - length -= 16; - index += 16; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v128++; + length -= 16; + index += 16; } if (Hint.Likely((int)length >= 8)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -290,26 +365,39 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v128 = (v128*)((long*)ptr_v128 + 1); - length -= 8; - index += 8; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + index += 8; } else { } if (Hint.Likely((int)length >= 4)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi32_si128(*(int*)ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -318,26 +406,39 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v128 = (v128*)((int*)ptr_v128 + 1); - length -= 4; - index += 4; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + index += 4; } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.insert_epi16(default(v128), *(short*)ptr_v128, 0))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.insert_epi16(default(v128), *(short*)ptr_v128, 0), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -346,25 +447,35 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - bool onlyTheSecondIsEqualToValue = mask == 2; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; - goto Found; + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } } else { - ptr_v128 = (v128*)((short*)ptr_v128 + 1); - length -= 2; - index += 2; + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } } + + ptr_v128 = (v128*)((short*)ptr_v128 + 1); + length -= 2; + index += 2; } else { } if (Hint.Likely(length != 0)) { - if (*(byte*)ptr_v128 == value) + if (Compare.Bytes(*(byte*)ptr_v128, value, where)) { result = index; goto Found; @@ -381,7 +492,7 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.Bytes(ptr[i], value, where)) { return i; } @@ -403,42 +514,68 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi8(broadcast, Avx.mm256_loadu_si256(endPtr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.Bytes256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(~mask); + + if (Hint.Unlikely(mask != -1)) + { + result = index - nonHitsWithOffset; + goto Found; + } } else { - index -= 32; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index - nonHitsWithOffset; + goto Found; + } } + + index -= 32; } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 16) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0xFFFF ^ mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = (index + 16) - nonHitsWithOffset; + goto Found; + } } else { - index -= 16; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 16) - nonHitsWithOffset; + goto Found; + } } + + index -= 16; } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) { endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -447,24 +584,37 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 24) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } } else { - index -= 8; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } } + + index -= 8; } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 4)) { endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -473,14 +623,25 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 28) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } } else { - index -= 4; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } } } else { } @@ -488,9 +649,9 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 2)) { endPtr_v256 = (v256*)((ushort*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(ushort*)endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(ushort*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -499,26 +660,34 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - bool onlyTheFirstIsEqualToValue = mask == 1; - result = index - *(byte*)&onlyTheFirstIsEqualToValue; - goto Found; + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } else { - index -= 2; + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((byte*)endPtr_v256 - 1); - if (*(byte*)endPtr_v256 == value) + if (Compare.Bytes(*(byte*)endPtr_v256, value, where)) { - result = index; + result = 0; } else { } } @@ -538,25 +707,38 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.loadu_si128(endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 16) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0xFFFF ^ mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = (index + 16) - nonHitsWithOffset; + goto Found; + } } else { - index -= 16; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 16) - nonHitsWithOffset; + goto Found; + } } + + index -= 16; } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) { endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi64x_si128(*(long*)endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -565,24 +747,37 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 24) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } } else { - index -= 8; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } } + + index -= 8; } else { } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 4)) { endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi32_si128(*(int*)endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(int*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -591,14 +786,25 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 28) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } } else { - index -= 4; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } } } else { } @@ -606,9 +812,9 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 2)) { endPtr_v128 = (v128*)((ushort*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi8(broadcast, Sse2.cvtsi32_si128(*(ushort*)endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.Bytes128(Sse2.cvtsi32_si128(*(ushort*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -617,26 +823,34 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - bool onlyTheFirstIsEqualToValue = mask == 1; - result = index - *(byte*)&onlyTheFirstIsEqualToValue; - goto Found; + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } else { - index -= 2; + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } } else { } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((byte*)endPtr_v128 - 1); - if (*(byte*)endPtr_v128 == value) + if (Compare.Bytes(*(byte*)endPtr_v128, value, where)) { - result = index; + result = 0; goto Found; } else { } @@ -653,7 +867,7 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd while (i >= 0) { - if (ptr[i] == value) + if (Compare.Bytes(ptr[i], value, where)) { goto Found; } @@ -670,74 +884,74 @@ public static long SIMD_IndexOf(byte* ptr, long length, byte value, TraversalOrd } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, byte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, byte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); @@ -752,46 +966,70 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa while (Hint.Likely(length >= 16)) { - int mask = Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi16(broadcast, Avx.mm256_loadu_si256(ptr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.UShorts256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + (math.tzcnt(mask) >> 1); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != -1)) + { + result = index + (nonHits >> 1); + goto Found; + } } else { - ptr_v256++; - length -= 16; - index += 16; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } } + + ptr_v256++; + length -= 16; + index += 16; } if (Hint.Likely((int)length >= 8)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + (math.tzcnt(mask) >> 1); - goto Found; + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = index + (math.tzcnt(~mask) >> 1); + goto Found; + } } else { - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 8; - index += 8; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 8; + index += 8; } else { } if (Hint.Likely((int)length >= 4)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -800,26 +1038,39 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + (math.tzcnt(mask) >> 1); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + (nonHits >> 1); + goto Found; + } } else { - ptr_v256 = (v256*)((long*)ptr_v256 + 1); - length -= 4; - index += 4; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } } + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + index += 4; } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)ptr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -828,25 +1079,35 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - bool onlyTheSecondIsEqualToValue = mask == 0b1100; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; - goto Found; + if (Hint.Unlikely(mask != 0b1111)) + { + bool onlyTheSecond = mask == 0b0011; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } } else { - ptr_v256 = (v256*)((int*)ptr_v256 + 1); - length -= 2; - index += 2; - } + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b1100; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + index += 2; } else { } if (Hint.Likely(length != 0)) { - if (*(ushort*)ptr_v256 == value) + if (Compare.UShorts(*(ushort*)ptr_v256, value, where)) { result = index; goto Found; @@ -868,27 +1129,40 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa while (Hint.Likely(length >= 8)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.loadu_si128(ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.loadu_si128(ptr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + (math.tzcnt(mask) >> 1); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = index + (nonHits >> 1); + goto Found; + } } else { - ptr_v128++; - length -= 8; - index += 8; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } } + + ptr_v128++; + length -= 8; + index += 8; } if (Hint.Likely((int)length >= 4)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -897,26 +1171,39 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + (math.tzcnt(mask) >> 1); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + (nonHits >> 1); + goto Found; + } } else { - ptr_v128 = (v128*)((long*)ptr_v128 + 1); - length -= 4; - index += 4; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } } + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + index += 4; } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi32_si128(*(int*)ptr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -925,25 +1212,35 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - bool onlyTheSecondIsEqualToValue = mask == 0b1100; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; - goto Found; + if (Hint.Unlikely(mask != 0b1111)) + { + bool onlyTheSecond = mask == 0b0011; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } } else { - ptr_v128 = (v128*)((int*)ptr_v128 + 1); - length -= 2; - index += 2; - } + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b1100; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + index += 2; } else { } if (Hint.Likely(length != 0)) { - if (*(ushort*)ptr_v128 == value) + if (Compare.UShorts(*(ushort*)ptr_v128, value, where)) { result = index; goto Found; @@ -960,7 +1257,7 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.UShorts(ptr[i], value, where)) { return i; } @@ -982,42 +1279,66 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx2.mm256_movemask_epi8(Avx2.mm256_cmpeq_epi16(broadcast, Avx.mm256_loadu_si256(endPtr_v256))); + int mask = Avx2.mm256_movemask_epi8(Compare.UShorts256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index - (math.lzcnt(mask) >> 1); - goto Found; + if (Hint.Unlikely(mask != -1)) + { + result = index - (math.lzcnt(~mask) >> 1); + goto Found; + } } else { - index -= 16; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index - (nonHitsWithOffset >> 1); + goto Found; + } } + + index -= 16; } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 8) - (math.lzcnt(mask) >> 1); - goto Found; + long nonHitsWithOffset = math.lzcnt(0xFFFF ^ mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = (index + 8) - (nonHitsWithOffset >> 1); + goto Found; + } } else { - index -= 8; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 8) - (nonHitsWithOffset >> 1); + goto Found; + } } + + index -= 8; } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) { endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -1026,14 +1347,25 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 12) - (math.lzcnt(mask) >> 1); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 12) - (nonHitsWithOffset >> 1); + goto Found; + } } else { - index -= 4; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 12) - (nonHitsWithOffset >> 1); + goto Found; + } } } else { } @@ -1041,9 +1373,9 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 4)) { endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi32_si128(*(int*)endPtr_v256))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -1052,25 +1384,34 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 14) - (math.lzcnt(mask) >> 1); - goto Found; + if (Hint.Unlikely(mask != 0b1111)) + { + bool onlyTheSecond = mask == 0b0011; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } else { - index -= 2; + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheFirst = mask == 0b1100; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheFirst; + goto Found; + } } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((ushort*)endPtr_v256 - 1); - if (*(ushort*)endPtr_v256 == value) + if (Compare.UShorts(*(ushort*)endPtr_v256, value, where)) { - result = index; + result = 0; } else { } } @@ -1090,25 +1431,38 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.loadu_si128(endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 8) - (math.lzcnt(mask) >> 1); - goto Found; + long nonHitsWithOffset = math.lzcnt(0xFFFF ^ mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = (index + 8) - (nonHitsWithOffset >> 1); + goto Found; + } } else { - index -= 8; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 8) - (nonHitsWithOffset >> 1); + goto Found; + } } + + index -= 8; } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) { endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi64x_si128(*(long*)endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -1117,14 +1471,25 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 12) - (math.lzcnt(mask) >> 1); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 12) - (nonHitsWithOffset >> 1); + goto Found; + } } else { - index -= 4; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 12) - (nonHitsWithOffset >> 1); + goto Found; + } } } else { } @@ -1132,9 +1497,9 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 4)) { endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); - int mask = Sse2.movemask_epi8(Sse2.cmpeq_epi16(broadcast, Sse2.cvtsi32_si128(*(int*)endPtr_v128))); + int mask = Sse2.movemask_epi8(Compare.UShorts128(Sse2.cvtsi32_si128(*(int*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -1143,25 +1508,34 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa mask &= 0b1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 14) - (math.lzcnt(mask) >> 1); - goto Found; + if (Hint.Unlikely(mask != 0b1111)) + { + bool onlyTheSecond = mask == 0b0011; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } else { - index -= 2; + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b1100; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } } else { } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((ushort*)endPtr_v128 - 1); - if (*(ushort*)endPtr_v128 == value) + if (Compare.UShorts(*(ushort*)endPtr_v128, value, where)) { - result = index; + result = 0; goto Found; } else { } @@ -1178,7 +1552,7 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa while (i >= 0) { - if (ptr[i] == value) + if (Compare.UShorts(ptr[i], value, where)) { goto Found; } @@ -1195,74 +1569,74 @@ public static long SIMD_IndexOf(ushort* ptr, long length, ushort value, Traversa } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, ushort value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, ushort value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static long SIMD_IndexOf(uint* ptr, long length, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); @@ -1277,46 +1651,72 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd while (Hint.Likely(length >= 8)) { - int mask = Avx.mm256_movemask_ps(Avx2.mm256_cmpeq_epi32(broadcast, Avx.mm256_loadu_si256(ptr_v256))); + int mask = Avx.mm256_movemask_ps(Compare.UInts256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v256++; - length -= 8; - index += 8; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v256++; + length -= 8; + index += 8; } if (Hint.Likely((int)length >= 4)) { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256))); + int mask = Sse.movemask_ps(Compare.UInts128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 4; - index += 4; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + index += 4; } else { } if (Hint.Likely((int)length >= 2)) { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); + int mask = Sse.movemask_ps(Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -1325,25 +1725,35 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd mask &= 0b0011; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - bool onlyTheSecondIsEqualToValue = mask == 2; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; - goto Found; + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } } else { - ptr_v256 = (v256*)((long*)ptr_v256 + 1); - length -= 2; - index += 2; - } + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + index += 2; } else { } if (Hint.Likely(length != 0)) { - if (*(uint*)ptr_v256 == value) + if (Compare.UInts(*(uint*)ptr_v256, value, where)) { result = index; goto Found; @@ -1365,54 +1775,127 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd while (Hint.Likely(length >= 4)) { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.loadu_si128(ptr_v128))); - - if (Hint.Unlikely(mask != 0)) - { - result = index + math.tzcnt(mask); - goto Found; + int mask = Sse.movemask_ps(Compare.UInts128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } } else { - ptr_v128++; - length -= 4; - index += 4; - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + } + + ptr_v128++; + length -= 4; + index += 4; } if (Hint.Likely((int)length >= 2)) { - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } else { - mask &= 0b0011; + mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) - { - bool onlyTheSecondIsEqualToValue = mask == 2; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; - goto Found; + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } } else { - ptr_v128 = (v128*)((long*)ptr_v128 + 1); - length -= 2; - index += 2; - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + } + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + index += 2; } else { } if (Hint.Likely(length != 0)) { - if (*(uint*)ptr_v128 == value) + if (Compare.UInts(*(uint*)ptr_v128, value, where)) { result = index; goto Found; @@ -1429,7 +1912,7 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.UInts(ptr[i], value, where)) { return i; } @@ -1451,32 +1934,56 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx.mm256_movemask_ps(Avx2.mm256_cmpeq_epi32(broadcast, Avx.mm256_loadu_si256(endPtr_v256))); + int mask = Avx.mm256_movemask_ps(Compare.UInts256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 24) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } } else { - index -= 8; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } } + + index -= 8; } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(endPtr_v256))); + int mask = Sse.movemask_ps(Compare.UInts128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 28) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } } else { - index -= 4; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } } } else { } @@ -1484,36 +1991,45 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) { endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(Avx.mm256_castsi256_si128(broadcast), Sse2.cvtsi64x_si128(*(long*)endPtr_v256))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } else { - mask &= 0b0011; + mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo) { - result = (index + 30) - math.lzcnt(mask); - goto Found; + if (Hint.Unlikely(mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } else { - index -= 2; + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((uint*)endPtr_v256 - 1); - if (*(uint*)endPtr_v256 == value) + if (Compare.UInts(*(uint*)endPtr_v256, value, where)) { - result = index; + result = 0; } else { } } @@ -1533,52 +2049,124 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.loadu_si128(endPtr_v128))); - - if (Hint.Unlikely(mask != 0)) - { - result = (index + 28) - math.lzcnt(mask); - goto Found; + int mask = Sse.movemask_ps(Compare.UInts128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } } else { - index -= 4; - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + } + + index -= 4; } if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) { endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - int mask = Sse.movemask_ps(Sse2.cmpeq_epi32(broadcast, Sse2.cvtsi64x_si128(*(long*)endPtr_v128))); - - if (Constant.IsConstantExpression(value) && value != 0) + int mask = Sse2.movemask_epi8(Compare.UInts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } else { - mask &= 0b0011; + mask &= 0b1111_1111; } - if (Hint.Unlikely(mask != 0)) - { - result = (index + 30) - math.lzcnt(mask); - goto Found; + if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } } else { - index -= 2; + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely((byte)mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } } } else { } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((uint*)endPtr_v128 - 1); - if (*(uint*)endPtr_v128 == value) + if (Compare.UInts(*(uint*)endPtr_v128, value, where)) { - result = index; + result = 0; goto Found; } else { } @@ -1595,7 +2183,7 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd while (i >= 0) { - if (ptr[i] == value) + if (Compare.UInts(ptr[i], value, where)) { goto Found; } @@ -1612,74 +2200,74 @@ public static long SIMD_IndexOf(uint* ptr, long length, uint value, TraversalOrd } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, uint value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, uint value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); @@ -1694,45 +2282,68 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO while (Hint.Likely(length >= 4)) { - int mask = Avx.mm256_movemask_pd(Avx2.mm256_cmpeq_epi64(broadcast, Avx.mm256_loadu_si256(ptr_v256))); + int mask = Avx.mm256_movemask_pd(Compare.ULongs256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - if (Hint.Unlikely(mask != 0)) + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } } else { - ptr_v256++; - length -= 4; - index += 4; + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } } + + ptr_v256++; + length -= 4; + index += 4; } if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_pd(Sse4_1.cmpeq_epi64(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256))); - - if (Hint.Unlikely(mask != 0)) + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - bool onlyTheSecondIsEqualToValue = mask == 2; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; - goto Found; + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheSecond = (ushort)mask == 0b1111_1111; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } } else { - ptr_v256 = (v256*)((v128*)ptr_v256 + 1); - length -= 2; - index += 2; - } + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = (ushort)mask == 0xFF00; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 2; + index += 2; } else { } if (Hint.Likely(length != 0)) { - if (*(ulong*)ptr_v256 == value) + if (Compare.ULongs(*(ulong*)ptr_v256, value, where)) { result = index; } @@ -1744,7 +2355,7 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO Found: return result; } - else if (!Sse4_1.IsSse41Supported) + else if (Sse4_2.IsSse42Supported) { v128 broadcast = Sse2.set1_epi64x((long)value); v128* ptr_v128 = (v128*)ptr; @@ -1753,25 +2364,36 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO while (Hint.Likely(length >= 2)) { - int mask = Sse2.movemask_pd(Sse4_1.cmpeq_epi64(broadcast, Sse2.loadu_si128(ptr_v128))); - - if (Hint.Unlikely(mask != 0)) + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - result = index + math.tzcnt(mask); - goto Found; + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheSecond = (ushort)mask == 0b1111_1111; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } } else { - ptr_v128++; - length -= 2; - index += 2; - } + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = (ushort)mask == 0xFF00; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v128++; + length -= 2; + index += 2; } if (Hint.Likely(length != 0)) { - if (*(ulong*)ptr_v128 == value) + if (Compare.ULongs(*(ulong*)ptr_v128, value, where)) { result = index; goto Found; @@ -1784,11 +2406,78 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO Found: return result; } + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x((long)value); + v128* ptr_v128 = (v128*)ptr; + long index = 0; + long result = -1; + + while (Hint.Likely(length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheSecond = (ushort)mask == 0b1111_1111; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = (ushort)mask == 0xFF00; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v128++; + length -= 2; + index += 2; + } + + + if (Hint.Likely(length != 0)) + { + if (Compare.ULongs(*(ulong*)ptr_v128, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.ULongs(ptr[i], value, where)) + { + return i; + } + else continue; + } + + return -1; + } + } else { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.ULongs(ptr[i], value, where)) { return i; } @@ -1810,43 +2499,65 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx.mm256_movemask_pd(Avx2.mm256_cmpeq_epi64(broadcast, Avx.mm256_loadu_si256(endPtr_v256))); - - if (Hint.Unlikely(mask != 0)) + int mask = Avx.mm256_movemask_pd(Compare.ULongs256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - result = (index + 28) - math.lzcnt(mask); - goto Found; + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } } else { - index -= 4; + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } } + + index -= 4; } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse2.movemask_pd(Sse4_1.cmpeq_epi64(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(endPtr_v256))); - - if (Hint.Unlikely(mask != 0)) + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - result = (index + 30) - math.lzcnt(mask); - goto Found; + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheSecond = (ushort)mask == 0x00FF; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } else { - index -= 2; + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = (ushort)mask == 0xFF00; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((ulong*)endPtr_v256 - 1); - if (*(ulong*)endPtr_v256 == value) + if (Compare.ULongs(*(ulong*)endPtr_v256, value, where)) { - result = index; + result = 0; } else { } } @@ -1856,7 +2567,7 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO Found: return result; } - else if (!Sse4_1.IsSse41Supported) + else if (Sse4_2.IsSse42Supported) { v128 broadcast = Sse2.set1_epi64x((long)value); long index = length - 1; @@ -1866,26 +2577,37 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse2.movemask_pd(Sse4_1.cmpeq_epi64(broadcast, Sse2.loadu_si128(endPtr_v128))); - - if (Hint.Unlikely(mask != 0)) + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) { - result = (index + 30) - math.lzcnt(mask); - goto Found; + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheFirst = (ushort)mask == 0xFF00; + result = index - *(byte*)&onlyTheFirst; + goto Found; + } } else { - index -= 2; + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheFirst = (ushort)mask == 0x00FF; + result = index - *(byte*)&onlyTheFirst; + goto Found; + } } + + index -= 2; } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((ulong*)endPtr_v128 - 1); - if (*(ulong*)endPtr_v128 == value) + if (Compare.ULongs(*(ulong*)endPtr_v128, value, where)) { - result = index; + result = 0; goto Found; } else { } @@ -1896,13 +2618,87 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO Found: return result; } + + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x((long)value); + long index = length - 1; + long result = -1; + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.ULongs128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheFirst = (ushort)mask == 0xFF00; + result = index - *(byte*)&onlyTheFirst; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheFirst = (ushort)mask == 0x00FF; + result = index - *(byte*)&onlyTheFirst; + goto Found; + } + } + + index -= 2; + } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((ulong*)endPtr_v128 - 1); + + if (Compare.ULongs(*(ulong*)endPtr_v128, value, where)) + { + result = 0; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + long i = length - 1; + + while (i >= 0) + { + if (Compare.ULongs(ptr[i], value, where)) + { + goto Found; + } + else + { + i--; + } + } + + Found: + return i; + } + } else { long i = length - 1; while (i >= 0) { - if (ptr[i] == value) + if (Compare.ULongs(ptr[i], value, where)) { goto Found; } @@ -1919,374 +2715,2658 @@ public static long SIMD_IndexOf(ulong* ptr, long length, ulong value, TraversalO } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, ulong value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, ulong value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(sbyte* ptr, long length, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static long SIMD_IndexOf(sbyte* ptr, long length, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); - return SIMD_IndexOf((byte*)ptr, length, (byte)value, traversalOrder); - } + if (traversalOrder == TraversalOrder.Ascending) + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi8((byte)value); + v256* ptr_v256 = (v256*)ptr; + long index = 0; + long result = -1; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + while (Hint.Likely(length >= 32)) + { + int mask = Avx2.mm256_movemask_epi8(Compare.SBytes256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + if (Hint.Unlikely(mask != -1)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + ptr_v256++; + length -= 32; + index += 32; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + if (Hint.Likely((int)length >= 16)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 16; + index += 16; + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + v128 cmp = default(v128); - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + if (Hint.Likely((int)length >= 8)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, sbyte value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); - return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; + index += 8; + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(short* ptr, long length, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsNonNegative(length); - return SIMD_IndexOf((ushort*)ptr, length, (ushort)value, traversalOrder); - } + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; + index += 4; + } + else { } - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0), Avx.mm256_castsi256_si128(broadcast), where)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index, array.Length); + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v256 = (v256*)((short*)ptr_v256 + 1); + length -= 2; + index += 2; + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + if (Hint.Likely(length != 0)) + { + if (Compare.SBytes(*(sbyte*)ptr_v256, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi8(value); + v128* ptr_v128 = (v128*)ptr; + long index = 0; + long result = -1; + + while (Hint.Likely(length >= 16)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v128++; + length -= 16; + index += 16; + } + + + if (Hint.Likely((int)length >= 8)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + index += 8; + } + else { } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + index += 4; + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.insert_epi16(default(v128), *(short*)ptr_v128, 0), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v128 = (v128*)((short*)ptr_v128 + 1); + length -= 2; + index += 2; + } + else { } + + + if (Hint.Likely(length != 0)) + { + if (Compare.SBytes(*(sbyte*)ptr_v128, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.SBytes(ptr[i], value, where)) + { + return i; + } + else continue; + } + + return -1; + } + } + else + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi8((byte)value); + long index = length - 1; + long result = -1; + v256* endPtr_v256 = (v256*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) + { + endPtr_v256--; + int mask = Avx2.mm256_movemask_epi8(Compare.SBytes256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(~mask); + + if (Hint.Unlikely(mask != -1)) + { + result = index - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index - nonHitsWithOffset; + goto Found; + } + } + + index -= 32; + } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) + { + endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0xFFFF ^ mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = (index + 16) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 16) - nonHitsWithOffset; + goto Found; + } + } + + index -= 16; + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) + { + endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } + } + + index -= 8; + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 4)) + { + endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 2)) + { + endPtr_v256 = (v256*)((ushort*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(ushort*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) + { + endPtr_v256 = (v256*)((byte*)endPtr_v256 - 1); + + if (Compare.SBytes(*(sbyte*)endPtr_v256, value, where)) + { + result = 0; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi8((sbyte)value); + long index = length - 1; + long result = -1; + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0xFFFF ^ mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = (index + 16) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 16) - nonHitsWithOffset; + goto Found; + } + } + + index -= 16; + } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } + } + + index -= 8; + } + else { } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 4)) + { + endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(int*)endPtr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 2)) + { + endPtr_v128 = (v128*)((ushort*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.SBytes128(Sse2.cvtsi32_si128(*(ushort*)endPtr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b0011; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b0011)) + { + bool onlyTheSecond = mask == 0b0001; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b0010; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((byte*)endPtr_v128 - 1); + + if (Compare.SBytes(*(sbyte*)endPtr_v128, value, where)) + { + result = 0; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + long i = length - 1; + + while (i >= 0) + { + if (Compare.SBytes(ptr[i], value, where)) + { + goto Found; + } + else + { + i--; + } + } + + Found: + return i; + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeArray array, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeArray array, int index, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeList array, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeList array, int index, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeSlice array, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeSlice array, int index, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, sbyte value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_IndexOf((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long SIMD_IndexOf(short* ptr, long length, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsNonNegative(length); + + if (traversalOrder == TraversalOrder.Ascending) + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi16(value); + v256* ptr_v256 = (v256*)ptr; + long index = 0; + long result = -1; + + while (Hint.Likely(length >= 16)) + { + int mask = Avx2.mm256_movemask_epi8(Compare.Shorts256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != -1)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + + ptr_v256++; + length -= 16; + index += 16; + } + + + if (Hint.Likely((int)length >= 8)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Avx.mm256_castsi256_si128(broadcast), Sse2.loadu_si128(ptr_v256), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 8; + index += 8; + } + else { } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + index += 4; + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + bool onlyTheSecond = mask == 0b0011; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b1100; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + index += 2; + } + else { } + + + if (Hint.Likely(length != 0)) + { + if (Compare.Shorts(*(short*)ptr_v256, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi16(value); + v128* ptr_v128 = (v128*)ptr; + long index = 0; + long result = -1; + + while (Hint.Likely(length >= 8)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + + ptr_v128++; + length -= 8; + index += 8; + } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + (nonHits >> 1); + goto Found; + } + } + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + index += 4; + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)ptr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + bool onlyTheSecond = mask == 0b0011; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b1100; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + index += 2; + } + else { } + + + if (Hint.Likely(length != 0)) + { + if (Compare.Shorts(*(short*)ptr_v128, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.Shorts(ptr[i], value, where)) + { + return i; + } + else continue; + } + + return -1; + } + } + else + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi16(value); + long index = length - 1; + long result = -1; + v256* endPtr_v256 = (v256*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) + { + endPtr_v256--; + int mask = Avx2.mm256_movemask_epi8(Compare.Shorts256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != -1)) + { + result = index - (math.lzcnt(~mask) >> 1); + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index - (nonHitsWithOffset >> 1); + goto Found; + } + } + + index -= 16; + } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) + { + endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0xFFFF ^ mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = (index + 8) - (nonHitsWithOffset >> 1); + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 8) - (nonHitsWithOffset >> 1); + goto Found; + } + } + + index -= 8; + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) + { + endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 12) - (nonHitsWithOffset >> 1); + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 12) - (nonHitsWithOffset >> 1); + goto Found; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 4)) + { + endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + bool onlyTheSecond = mask == 0b0011; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b1100; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) + { + endPtr_v256 = (v256*)((short*)endPtr_v256 - 1); + + if (Compare.Shorts(*(short*)endPtr_v256, value, where)) + { + result = 0; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi16(value); + long index = length - 1; + long result = -1; + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0xFFFF ^ mask); + + if (Hint.Unlikely(mask != 0xFFFF)) + { + result = (index + 8) - (nonHitsWithOffset >> 1); + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 8) - (nonHitsWithOffset >> 1); + goto Found; + } + } + + index -= 8; + } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 12) - (nonHitsWithOffset >> 1); + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 12) - (nonHitsWithOffset >> 1); + goto Found; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 4)) + { + endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.Shorts128(Sse2.cvtsi32_si128(*(int*)endPtr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111)) + { + bool onlyTheSecond = mask == 0b0011; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0b1100; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((short*)endPtr_v128 - 1); + + if (Compare.Shorts(*(short*)endPtr_v128, value, where)) + { + result = 0; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + long i = length - 1; + + while (i >= 0) + { + if (Compare.Shorts(ptr[i], value, where)) + { + goto Found; + } + else + { + i--; + } + } + + Found: + return i; + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeArray array, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeArray array, int index, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeList array, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeList array, int index, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeSlice array, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeSlice array, int index, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index, array.Length); + + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, short value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long SIMD_IndexOf(int* ptr, long length, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) + { +Assert.IsNonNegative(length); + + if (traversalOrder == TraversalOrder.Ascending) + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi32((int)value); + v256* ptr_v256 = (v256*)ptr; + long index = 0; + long result = -1; + + while (Hint.Likely(length >= 8)) + { + int mask = Avx.mm256_movemask_ps(Compare.Ints256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v256++; + length -= 8; + index += 8; + } + + + if (Hint.Likely((int)length >= 4)) + { + int mask = Sse.movemask_ps(Compare.Ints128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + index += 4; + } + else { } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + index += 2; + } + else { } + + + if (Hint.Likely(length != 0)) + { + if (Compare.Ints(*(int*)ptr_v256, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi32((int)value); + v128* ptr_v128 = (v128*)ptr; + long index = 0; + long result = -1; + + while (Hint.Likely(length >= 4)) + { + int mask = Sse.movemask_ps(Compare.Ints128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v128++; + length -= 4; + index += 4; + } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + index += 2; + } + else { } + + + if (Hint.Likely(length != 0)) + { + if (Compare.Ints(*(int*)ptr_v128, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.Ints(ptr[i], value, where)) + { + return i; + } + else continue; + } + + return -1; + } + } + else + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi32((int)value); + long index = length - 1; + long result = -1; + v256* endPtr_v256 = (v256*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) + { + endPtr_v256--; + int mask = Avx.mm256_movemask_ps(Compare.Ints256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111_1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111_1111)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 24) - nonHitsWithOffset; + goto Found; + } + } + + index -= 8; + } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) + { + endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); + int mask = Sse.movemask_ps(Compare.Ints128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + } + else { } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) + { + endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) + { + endPtr_v256 = (v256*)((int*)endPtr_v256 - 1); + + if (Compare.Ints(*(int*)endPtr_v256, value, where)) + { + result = 0; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse2.IsSse2Supported) + { + v128 broadcast = Sse2.set1_epi32((int)value); + long index = length - 1; + long result = -1; + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse.movemask_ps(Compare.Ints128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + + index -= 4; + } + + if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + int mask = Sse2.movemask_epi8(Compare.Ints128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); + + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) + { + ; + } + else + { + mask &= 0b1111_1111; + } + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0b1111_1111)) + { + bool onlyTheSecond = mask == 0x000F; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = mask == 0x00F0; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((int*)endPtr_v128 - 1); + + if (Compare.Ints(*(int*)endPtr_v128, value, where)) + { + result = 0; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + long i = length - 1; + + while (i >= 0) + { + if (Compare.Ints(ptr[i], value, where)) + { + goto Found; + } + else + { + i--; + } + } + + Found: + return i; + } + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, short value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(int* ptr, long length, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsNonNegative(length); - - return SIMD_IndexOf((uint*)ptr, length, (uint)value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, int value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); - } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static long SIMD_IndexOf(long* ptr, long length, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { -Assert.IsWithinArrayBounds(index, array.Length); +Assert.IsNonNegative(length); - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); - } + if (traversalOrder == TraversalOrder.Ascending) + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi64x(value); + v256* ptr_v256 = (v256*)ptr; + long index = 0; + long result = -1; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, int value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + while (Hint.Likely(length >= 4)) + { + int mask = Avx.mm256_movemask_pd(Compare.Longs256(Avx.mm256_loadu_si256(ptr_v256), broadcast, where)); - return (int)SIMD_IndexOf((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); - } + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHits = (uint)math.tzcnt(~mask); + if (Hint.Unlikely(mask != 0b1111)) + { + result = index + nonHits; + goto Found; + } + } + else + { + long nonHits = (uint)math.tzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = index + nonHits; + goto Found; + } + } + + ptr_v256++; + length -= 4; + index += 4; + } + + + if (Hint.Likely((int)length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheSecond = (ushort)mask == 0b1111_1111; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = (ushort)mask == 0xFF00; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 2; + index += 2; + } + else { } + + + if (Hint.Likely(length != 0)) + { + if (Compare.Longs(*(long*)ptr_v256, value, where)) + { + result = index; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse4_2.IsSse42Supported) + { + v128 broadcast = Sse2.set1_epi64x(value); + v128* ptr_v128 = (v128*)ptr; + long index = 0; + long result = -1; + + while (Hint.Likely(length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheSecond = (ushort)mask == 0b1111_1111; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = (ushort)mask == 0xFF00; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v128++; + length -= 2; + index += 2; + } + + + if (Hint.Likely(length != 0)) + { + if (Compare.Longs(*(long*)ptr_v128, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x(value); + v128* ptr_v128 = (v128*)ptr; + long index = 0; + long result = -1; + + while (Hint.Likely(length >= 2)) + { + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(ptr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheSecond = (ushort)mask == 0b1111_1111; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = (ushort)mask == 0xFF00; + result = index + *(byte*)&onlyTheSecond; + goto Found; + } + } + + ptr_v128++; + length -= 2; + index += 2; + } + + + if (Hint.Likely(length != 0)) + { + if (Compare.Longs(*(long*)ptr_v128, value, where)) + { + result = index; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.Longs(ptr[i], value, where)) + { + return i; + } + else continue; + } + + return -1; + } + } + else + { + for (long i = 0; i < length; i++) + { + if (Compare.Longs(ptr[i], value, where)) + { + return i; + } + else continue; + } + + return -1; + } + } + else + { + if (Avx2.IsAvx2Supported) + { + v256 broadcast = Avx.mm256_set1_epi64x(value); + long index = length - 1; + long result = -1; + v256* endPtr_v256 = (v256*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) + { + endPtr_v256--; + int mask = Avx.mm256_movemask_pd(Compare.Longs256(Avx.mm256_loadu_si256(endPtr_v256), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + long nonHitsWithOffset = math.lzcnt(0b1111 ^ mask); + + if (Hint.Unlikely(mask != 0b1111)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + else + { + long nonHitsWithOffset = math.lzcnt(mask); + + if (Hint.Unlikely(mask != 0)) + { + result = (index + 28) - nonHitsWithOffset; + goto Found; + } + } + + index -= 4; + } + + if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) + { + endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheSecond = (ushort)mask == 0x00FF; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheSecond = (ushort)mask == 0xFF00; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; + goto Found; + } + } + } + else { } + + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) + { + endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); + + if (Compare.Longs(*(long*)endPtr_v256, value, where)) + { + result = 0; + } + else { } + } + else { } + + + Found: + return result; + } + else if (Sse4_2.IsSse42Supported) + { + v128 broadcast = Sse2.set1_epi64x(value); + long index = length - 1; + long result = -1; + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo || where == Comparison.GreaterThanOrEqualTo || where == Comparison.LessThanOrEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheFirst = (ushort)mask == 0xFF00; + result = index - *(byte*)&onlyTheFirst; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheFirst = (ushort)mask == 0x00FF; + result = index - *(byte*)&onlyTheFirst; + goto Found; + } + } + + index -= 2; + } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + + if (Compare.Longs(*(long*)endPtr_v128, value, where)) + { + result = 0; + goto Found; + } + else { } + } + else { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(long* ptr, long length, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) - { -Assert.IsNonNegative(length); - return SIMD_IndexOf((ulong*)ptr, length, (ulong)value, traversalOrder); + Found: + return result; + } + + else if (Sse4_1.IsSse41Supported) + { + if (where == Comparison.EqualTo || where == Comparison.NotEqualTo) + { + v128 broadcast = Sse2.set1_epi64x(value); + long index = length - 1; + long result = -1; + v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL + + while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) + { + endPtr_v128--; + int mask = Sse2.movemask_epi8(Compare.Longs128(Sse2.loadu_si128(endPtr_v128), broadcast, where)); + + if (where == Comparison.NotEqualTo) + { + if (Hint.Unlikely(mask != 0xFFFF)) + { + bool onlyTheFirst = (ushort)mask == 0xFF00; + result = index - *(byte*)&onlyTheFirst; + goto Found; + } + } + else + { + if (Hint.Unlikely(mask != 0)) + { + bool onlyTheFirst = (ushort)mask == 0x00FF; + result = index - *(byte*)&onlyTheFirst; + goto Found; + } + } + + index -= 2; + } + + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) + { + endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); + + if (Compare.Longs(*(long*)endPtr_v128, value, where)) + { + result = 0; + goto Found; + } + else { } + } + else { } + + + Found: + return result; + } + else + { + long i = length - 1; + + while (i >= 0) + { + if (Compare.Longs(ptr[i], value, where)) + { + goto Found; + } + else + { + i--; + } + } + + Found: + return i; + } + } + else + { + long i = length - 1; + + while (i >= 0) + { + if (Compare.Longs(ptr[i], value, where)) + { + goto Found; + } + else + { + i--; + } + } + + Found: + return i; + } + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, long value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, long value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static long SIMD_IndexOf(float* ptr, long length, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); Assert.IsFalse(math.isnan(value)); @@ -2302,11 +5382,13 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO while (Hint.Likely(length >= 8)) { - int mask = Avx.mm256_movemask_ps(Avx.mm256_cmp_ps(broadcast, Avx.mm256_loadu_ps(ptr_v256), (int)Avx.CMP.EQ_OQ)); + int mask = Avx.mm256_movemask_ps(Compare.Floats256(Avx.mm256_loadu_ps(ptr_v256), broadcast, where)); + + long nonHits = (uint)math.tzcnt(mask); if (Hint.Unlikely(mask != 0)) { - result = index + math.tzcnt(mask); + result = index + nonHits; goto Found; } else @@ -2320,11 +5402,13 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Likely((int)length >= 4)) { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castps256_ps128(broadcast), Sse.loadu_ps(ptr_v256))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(ptr_v256), Avx.mm256_castps256_ps128(broadcast), where)); + + long nonHits = (uint)math.tzcnt(mask); if (Hint.Unlikely(mask != 0)) { - result = index + math.tzcnt(mask); + result = index + nonHits; goto Found; } else @@ -2339,9 +5423,9 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Likely((int)length >= 2)) { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castps256_ps128(broadcast), Sse2.cvtsi64x_si128(*(long*)ptr_v256))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v256), Avx.mm256_castps256_ps128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -2352,8 +5436,8 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Unlikely(mask != 0)) { - bool onlyTheSecondIsEqualToValue = mask == 2; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; goto Found; } else @@ -2368,7 +5452,7 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Likely(length != 0)) { - if (*(float*)ptr_v256 == value) + if (Compare.Floats(*(float*)ptr_v256, value, where)) { result = index; goto Found; @@ -2390,11 +5474,13 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO while (Hint.Likely(length >= 4)) { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse.loadu_ps(ptr_v128))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(ptr_v128), broadcast, where)); + + long nonHits = (uint)math.tzcnt(mask); if (Hint.Unlikely(mask != 0)) { - result = index + math.tzcnt(mask); + result = index + nonHits; goto Found; } else @@ -2408,9 +5494,9 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Likely((int)length >= 2)) { - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse2.cvtsi64x_si128(*(long*)ptr_v128))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)ptr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -2421,8 +5507,8 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Unlikely(mask != 0)) { - bool onlyTheSecondIsEqualToValue = mask == 2; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; goto Found; } else @@ -2437,7 +5523,7 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Likely(length != 0)) { - if (*(float*)ptr_v128 == value) + if (Compare.Floats(*(float*)ptr_v128, value, where)) { result = index; goto Found; @@ -2454,7 +5540,7 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.Floats(ptr[i], value, where)) { return i; } @@ -2476,11 +5562,13 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx.mm256_movemask_ps(Avx.mm256_cmp_ps(broadcast, Avx.mm256_loadu_ps(endPtr_v256), (int)Avx.CMP.EQ_OQ)); + int mask = Avx.mm256_movemask_ps(Compare.Floats256(Avx.mm256_loadu_ps(endPtr_v256), broadcast, where)); + + long nonHitsWithOffset = math.lzcnt(mask); if (Hint.Unlikely(mask != 0)) { - result = (index + 24) - math.lzcnt(mask); + result = (index + 24) - nonHitsWithOffset; goto Found; } else @@ -2492,26 +5580,24 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castsi256_si128(broadcast), Sse.loadu_ps(endPtr_v256))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(endPtr_v256), Avx.mm256_castsi256_si128(broadcast), where)); + + long nonHitsWithOffset = math.lzcnt(mask); if (Hint.Unlikely(mask != 0)) { - result = (index + 28) - math.lzcnt(mask); + result = (index + 28) - nonHitsWithOffset; goto Found; } - else - { - index -= 4; - } } else { } if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 8)) { endPtr_v256 = (v256*)((long*)endPtr_v256 - 1); - int mask = Sse.movemask_ps(Sse.cmpeq_ps(Avx.mm256_castps256_ps128(broadcast), Sse2.cvtsi64x_si128(*(long*)endPtr_v256))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)endPtr_v256), Avx.mm256_castps256_ps128(broadcast), where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -2522,23 +5608,20 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Unlikely(mask != 0)) { - result = (index + 30) - math.lzcnt(mask); + bool onlyTheSecond = mask == 0b0010; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; goto Found; } - else - { - index -= 2; - } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((float*)endPtr_v256 - 1); - if (*(float*)endPtr_v256 == value) + if (Compare.Floats(*(float*)endPtr_v256, value, where)) { - result = index; + result = 0; } else { } } @@ -2558,11 +5641,13 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse.loadu_ps(endPtr_v128))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse.loadu_ps(endPtr_v128), broadcast, where)); + + long nonHitsWithOffset = math.lzcnt(mask); if (Hint.Unlikely(mask != 0)) { - result = (index + 28) - math.lzcnt(mask); + result = (index + 28) - nonHitsWithOffset; goto Found; } else @@ -2574,9 +5659,9 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) >= 8)) { endPtr_v128 = (v128*)((long*)endPtr_v128 - 1); - int mask = Sse.movemask_ps(Sse.cmpeq_ps(broadcast, Sse2.cvtsi64x_si128(*(long*)endPtr_v128))); + int mask = Sse.movemask_ps(Compare.Floats128(Sse2.cvtsi64x_si128(*(long*)endPtr_v128), broadcast, where)); - if (Constant.IsConstantExpression(value) && value != 0) + if (Constant.IsConstantExpression(where) && !PartialVectors.ShouldMask(where, value)) { ; } @@ -2587,23 +5672,20 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO if (Hint.Unlikely(mask != 0)) { - result = (index + 30) - math.lzcnt(mask); + bool onlyTheSecond = mask == 0b0010; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; goto Found; } - else - { - index -= 2; - } } else { } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((float*)endPtr_v128 - 1); - if (*(float*)endPtr_v128 == value) + if (Compare.Floats(*(float*)endPtr_v128, value, where)) { - result = index; + result = 0; goto Found; } else { } @@ -2620,7 +5702,7 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO while (i >= 0) { - if (ptr[i] == value) + if (Compare.Floats(ptr[i], value, where)) { goto Found; } @@ -2637,74 +5719,74 @@ public static long SIMD_IndexOf(float* ptr, long length, float value, TraversalO } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, float value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, float value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SIMD_IndexOf(double* ptr, long length, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static long SIMD_IndexOf(double* ptr, long length, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsNonNegative(length); Assert.IsFalse(math.isnan(value)); @@ -2720,11 +5802,13 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa while (Hint.Likely(length >= 4)) { - int mask = Avx.mm256_movemask_pd(Avx.mm256_cmp_pd(broadcast, Avx.mm256_loadu_pd(ptr_v256), (int)Avx.CMP.EQ_OQ)); + int mask = Avx.mm256_movemask_pd(Compare.Doubles256(Avx.mm256_loadu_pd(ptr_v256), broadcast, where)); + + long nonHits = (uint)math.tzcnt(mask); if (Hint.Unlikely(mask != 0)) { - result = index + math.tzcnt(mask); + result = index + nonHits; goto Found; } else @@ -2738,12 +5822,12 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa if (Hint.Likely((int)length >= 2)) { - int mask = Sse2.movemask_pd(Sse2.cmpeq_pd(Avx.mm256_castpd256_pd128(broadcast), Sse.loadu_ps(ptr_v256))); + int mask = Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(ptr_v256), Avx.mm256_castpd256_pd128(broadcast), where)); if (Hint.Unlikely(mask != 0)) { - bool onlyTheSecondIsEqualToValue = mask == 2; - result = index + *(byte*)&onlyTheSecondIsEqualToValue; + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; goto Found; } else @@ -2758,7 +5842,7 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa if (Hint.Likely(length != 0)) { - if (*(double*)ptr_v256 == value) + if (Compare.Doubles(*(double*)ptr_v256, value, where)) { result = index; goto Found; @@ -2780,11 +5864,12 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa while (Hint.Likely(length >= 2)) { - int mask = Sse2.movemask_pd(Sse2.cmpeq_pd(broadcast, Sse.loadu_ps(ptr_v128))); + int mask = Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(ptr_v128), broadcast, where)); if (Hint.Unlikely(mask != 0)) { - result = index + math.tzcnt(mask); + bool onlyTheSecond = mask == 0b0010; + result = index + *(byte*)&onlyTheSecond; goto Found; } else @@ -2798,7 +5883,7 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa if (Hint.Likely(length != 0)) { - if (*(double*)ptr_v128 == value) + if (Compare.Doubles(*(double*)ptr_v128, value, where)) { result = index; goto Found; @@ -2815,7 +5900,7 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa { for (long i = 0; i < length; i++) { - if (ptr[i] == value) + if (Compare.Doubles(ptr[i], value, where)) { return i; } @@ -2837,11 +5922,13 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa while (Hint.Likely((long)endPtr_v256 - (long)ptr >= 32)) { endPtr_v256--; - int mask = Avx.mm256_movemask_pd(Avx.mm256_cmp_pd(broadcast, Avx.mm256_loadu_pd(endPtr_v256), (int)Avx.CMP.EQ_OQ)); + int mask = Avx.mm256_movemask_pd(Compare.Doubles256(Avx.mm256_loadu_pd(endPtr_v256), broadcast, where)); + + long nonHitsWithOffset = math.lzcnt(mask); if (Hint.Unlikely(mask != 0)) { - result = (index + 28) - math.lzcnt(mask); + result = (index + 28) - nonHitsWithOffset; goto Found; } else @@ -2853,27 +5940,24 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) >= 16)) { endPtr_v256 = (v256*)((v128*)endPtr_v256 - 1); - int mask = Sse2.movemask_pd(Sse2.cmpeq_pd(Avx.mm256_castpd256_pd128(broadcast), Sse.loadu_ps(endPtr_v256))); + int mask = Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(endPtr_v256), Avx.mm256_castpd256_pd128(broadcast), where)); if (Hint.Unlikely(mask != 0)) { - result = (index + 30) - math.lzcnt(mask); + bool onlyTheSecond = mask == 0b0010; + result = ((byte)length & (byte)1) + *(byte*)&onlyTheSecond; goto Found; } - else - { - index -= 2; - } } else { } - if (Hint.Likely((int)((long)endPtr_v256 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v256 != (long)ptr)) { endPtr_v256 = (v256*)((double*)endPtr_v256 - 1); - if (*(double*)endPtr_v256 == value) + if (Compare.Doubles(*(double*)endPtr_v256, value, where)) { - result = index; + result = 0; } else { } } @@ -2885,7 +5969,7 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa } else if (Sse2.IsSse2Supported) { - v128 broadcast = Sse2.set1_epi64x((long)value); + v128 broadcast = Sse2.set1_pd(value); long index = length - 1; long result = -1; v128* endPtr_v128 = (v128*)(ptr + length); // this points to the "element" right after the last element. THIS IS INTENTIONAL @@ -2893,11 +5977,12 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa while (Hint.Likely((long)endPtr_v128 - (long)ptr >= 16)) { endPtr_v128--; - int mask = Sse2.movemask_pd(Sse2.cmpeq_pd(broadcast, Sse.loadu_ps(endPtr_v128))); + int mask = Sse2.movemask_pd(Compare.Doubles128(Sse.loadu_ps(endPtr_v128), broadcast, where)); if (Hint.Unlikely(mask != 0)) { - result = (index + 30) - math.lzcnt(mask); + bool onlyTheFirst = mask == 0b0001; + result = index - *(byte*)&onlyTheFirst; goto Found; } else @@ -2906,13 +5991,13 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa } } - if (Hint.Likely((int)((long)endPtr_v128 - (long)ptr) != 0)) + if (Hint.Likely((long)endPtr_v128 != (long)ptr)) { endPtr_v128 = (v128*)((double*)endPtr_v128 - 1); - if (*(double*)endPtr_v128 == value) + if (Compare.Doubles(*(double*)endPtr_v128, value, where)) { - result = index; + result = 0; goto Found; } else { } @@ -2929,7 +6014,7 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa while (i >= 0) { - if (ptr[i] == value) + if (Compare.Doubles(ptr[i], value, where)) { goto Found; } @@ -2946,69 +6031,69 @@ public static long SIMD_IndexOf(double* ptr, long length, double value, Traversa } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeArray array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeList array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr(), array.Length, value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index, array.Length); - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), value, where, traversalOrder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, double value, TraversalOrder traversalOrder = TraversalOrder.Ascending) + public static int SIMD_IndexOf(this NativeSlice array, int index, int numEntries, double value, Comparison where = Comparison.EqualTo, TraversalOrder traversalOrder = TraversalOrder.Ascending) { Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); - return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, traversalOrder); + return (int)SIMD_IndexOf((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, value, where, traversalOrder); } } } \ No newline at end of file diff --git a/Runtime/Algorithms/Maximum.cs b/Runtime/Algorithms/Maximum.cs index 1a9012e..df44c7d 100644 --- a/Runtime/Algorithms/Maximum.cs +++ b/Runtime/Algorithms/Maximum.cs @@ -20,36 +20,41 @@ public static byte SIMD_Maximum(byte* ptr, long length) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi8(byte.MinValue); - v256 acc1 = Avx.mm256_set1_epi8(byte.MinValue); - v256 acc2 = Avx.mm256_set1_epi8(byte.MinValue); - v256 acc3 = Avx.mm256_set1_epi8(byte.MinValue); - - while (Hint.Likely(length >= 128)) + v256 max0 = Avx.mm256_set1_epi8(byte.MinValue); + + if (Hint.Likely(length >= 128)) { - acc0 = Avx2.mm256_max_epu8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_max_epu8(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_max_epu8(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_max_epu8(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 max1 = Avx.mm256_set1_epi8(byte.MinValue); + v256 max2 = Avx.mm256_set1_epi8(byte.MinValue); + v256 max3 = Avx.mm256_set1_epi8(byte.MinValue); - length -= 128; - } + do + { + max0 = Avx2.mm256_max_epu8(max0, Avx.mm256_loadu_si256(ptr_v256++)); + max1 = Avx2.mm256_max_epu8(max1, Avx.mm256_loadu_si256(ptr_v256++)); + max2 = Avx2.mm256_max_epu8(max2, Avx.mm256_loadu_si256(ptr_v256++)); + max3 = Avx2.mm256_max_epu8(max3, Avx.mm256_loadu_si256(ptr_v256++)); + + length -= 128; + } + while (Hint.Likely(length >= 128)); - acc0 = Avx2.mm256_max_epu8(acc0, acc1); - acc2 = Avx2.mm256_max_epu8(acc2, acc3); - acc0 = Avx2.mm256_max_epu8(acc0, acc2); + max0 = Avx2.mm256_max_epu8(max0, max1); + max2 = Avx2.mm256_max_epu8(max2, max3); + max0 = Avx2.mm256_max_epu8(max0, max2); + } if (Hint.Likely((int)length >= 32)) { - acc0 = Avx2.mm256_max_epu8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu8(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 32)) { - acc0 = Avx2.mm256_max_epu8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu8(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 32)) { - acc0 = Avx2.mm256_max_epu8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu8(max0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 32; } else @@ -64,88 +69,93 @@ public static byte SIMD_Maximum(byte* ptr, long length) } else { } - v128 acc128 = Sse2.max_epu8(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 max128 = Sse2.max_epu8(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); if (Hint.Likely((int)length >= 16)) { - acc128 = Sse2.max_epu8(acc128, Sse2.loadu_si128(ptr_v256)); + max128 = Sse2.max_epu8(max128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 16; } v128 cmp = default(v128); - acc128 = Sse2.max_epu8(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse2.max_epu8(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 8)) { - acc128 = Sse2.max_epu8(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + max128 = Sse2.max_epu8(max128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 8; } - acc128 = Sse2.max_epu8(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse2.max_epu8(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse2.max_epu8(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + max128 = Sse2.max_epu8(max128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); ptr_v256 = (v256*)((int*)ptr_v256 + 1); length -= 4; } - acc128 = Sse2.max_epu8(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + max128 = Sse2.max_epu8(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse2.max_epu8(acc128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)); + max128 = Sse2.max_epu8(max128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)); ptr_v256 = (v256*)((short*)ptr_v256 + 1); length -= 2; } - acc128 = Sse2.max_epu8(acc128, Sse2.bsrli_si128(acc128, 1 * sizeof(byte))); + max128 = Sse2.max_epu8(max128, Sse2.bsrli_si128(max128, 1 * sizeof(byte))); if (Hint.Likely(length != 0)) { - return Sse2.max_epu8(acc128, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0)).Byte0; + return Sse2.max_epu8(max128, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0)).Byte0; } else { - return acc128.Byte0; + return max128.Byte0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); - v128 acc1 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); - v128 acc2 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); - v128 acc3 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); - - while (Hint.Likely(length >= 64)) + v128 max0 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); + + if (Hint.Likely(length >= 64)) { - acc0 = Sse2.max_epu8(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Sse2.max_epu8(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Sse2.max_epu8(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Sse2.max_epu8(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 max1 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); + v128 max2 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); + v128 max3 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); - length -= 64; - } + do + { + max0 = Sse2.max_epu8(max0, Sse2.loadu_si128(ptr_v128++)); + max1 = Sse2.max_epu8(max1, Sse2.loadu_si128(ptr_v128++)); + max2 = Sse2.max_epu8(max2, Sse2.loadu_si128(ptr_v128++)); + max3 = Sse2.max_epu8(max3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Sse2.max_epu8(acc0, acc1); - acc2 = Sse2.max_epu8(acc2, acc3); - acc0 = Sse2.max_epu8(acc0, acc2); + length -= 64; + } + while (Hint.Likely(length >= 64)); + + max0 = Sse2.max_epu8(max0, max1); + max2 = Sse2.max_epu8(max2, max3); + max0 = Sse2.max_epu8(max0, max2); + } if (Hint.Likely((int)length >= 16)) { - acc0 = Sse2.max_epu8(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Sse2.max_epu8(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 16)) { - acc0 = Sse2.max_epu8(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Sse2.max_epu8(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 16)) { - acc0 = Sse2.max_epu8(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Sse2.max_epu8(max0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 16; } else @@ -161,49 +171,49 @@ public static byte SIMD_Maximum(byte* ptr, long length) else { } v128 cmp = default(v128); - acc0 = Sse2.max_epu8(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Sse2.max_epu8(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 8)) { - acc0 = Sse2.max_epu8(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + max0 = Sse2.max_epu8(max0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 8; } - acc0 = Sse2.max_epu8(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Sse2.max_epu8(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc0 = Sse2.max_epu8(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + max0 = Sse2.max_epu8(max0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); ptr_v128 = (v128*)((int*)ptr_v128 + 1); length -= 4; } - acc0 = Sse2.max_epu8(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + max0 = Sse2.max_epu8(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely((int)length >= 2)) { - acc0 = Sse2.max_epu8(acc0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)); + max0 = Sse2.max_epu8(max0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)); ptr_v128 = (v128*)((short*)ptr_v128 + 1); length -= 2; } - acc0 = Sse2.max_epu8(acc0, Sse2.bsrli_si128(acc0, 1 * sizeof(byte))); + max0 = Sse2.max_epu8(max0, Sse2.bsrli_si128(max0, 1 * sizeof(byte))); if (Hint.Likely(length != 0)) { if (Sse4_1.IsSse41Supported) { - return Sse2.max_epu8(acc0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).Byte0; + return Sse2.max_epu8(max0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).Byte0; } else { - return (byte)math.max((uint)acc0.Byte0, (uint)(*(byte*)ptr_v128)); + return Sse2.max_epu8(max0, Sse2.cvtsi32_si128(*(byte*)ptr_v128)).Byte0; } } else { - return acc0.Byte0; + return max0.Byte0; } } else @@ -314,36 +324,41 @@ static v128 Max(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); - v256 acc1 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); - v256 acc2 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); - v256 acc3 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); - - while (Hint.Likely(length >= 64)) + v256 max0 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); + + if (Hint.Likely(length >= 64)) { - acc0 = Avx2.mm256_max_epu16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_max_epu16(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_max_epu16(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_max_epu16(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 max1 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); + v256 max2 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); + v256 max3 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); - length -= 64; - } + do + { + max0 = Avx2.mm256_max_epu16(max0, Avx.mm256_loadu_si256(ptr_v256++)); + max1 = Avx2.mm256_max_epu16(max1, Avx.mm256_loadu_si256(ptr_v256++)); + max2 = Avx2.mm256_max_epu16(max2, Avx.mm256_loadu_si256(ptr_v256++)); + max3 = Avx2.mm256_max_epu16(max3, Avx.mm256_loadu_si256(ptr_v256++)); - acc0 = Avx2.mm256_max_epu16(acc0, acc1); - acc2 = Avx2.mm256_max_epu16(acc2, acc3); - acc0 = Avx2.mm256_max_epu16(acc0, acc2); + length -= 64; + } + while (Hint.Likely(length >= 64)); + + max0 = Avx2.mm256_max_epu16(max0, max1); + max2 = Avx2.mm256_max_epu16(max2, max3); + max0 = Avx2.mm256_max_epu16(max0, max2); + } if (Hint.Likely((int)length >= 16)) { - acc0 = Avx2.mm256_max_epu16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu16(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 16)) { - acc0 = Avx2.mm256_max_epu16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu16(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 16)) { - acc0 = Avx2.mm256_max_epu16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu16(max0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 16; } else @@ -358,79 +373,84 @@ static v128 Max(v128 a, v128 b) } else { } - v128 acc128 = Sse4_1.max_epu16(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 max128 = Sse4_1.max_epu16(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); if (Hint.Likely((int)length >= 8)) { - acc128 = Sse4_1.max_epu16(acc128, Sse2.loadu_si128(ptr_v256)); + max128 = Sse4_1.max_epu16(max128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 8; } v128 cmp = default(v128); - acc128 = Sse4_1.max_epu16(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse4_1.max_epu16(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse4_1.max_epu16(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + max128 = Sse4_1.max_epu16(max128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 4; } - acc128 = Sse4_1.max_epu16(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse4_1.max_epu16(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse4_1.max_epu16(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + max128 = Sse4_1.max_epu16(max128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); ptr_v256 = (v256*)((int*)ptr_v256 + 1); length -= 2; } - acc128 = Sse4_1.max_epu16(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + max128 = Sse4_1.max_epu16(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse4_1.max_epu16(acc128, Sse2.insert_epi16(cmp, *(ushort*)ptr_v256, 0)).UShort0; + return Sse4_1.max_epu16(max128, Sse2.insert_epi16(cmp, *(ushort*)ptr_v256, 0)).UShort0; } else { - return acc128.UShort0; + return max128.UShort0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); - v128 acc1 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); - v128 acc2 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); - v128 acc3 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); - - while (Hint.Likely(length >= 32)) + v128 max0 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + + if (Hint.Likely(length >= 32)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Max(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Max(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Max(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 max1 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + v128 max2 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + v128 max3 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); - length -= 32; - } + do + { + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); + max1 = Max(max1, Sse2.loadu_si128(ptr_v128++)); + max2 = Max(max2, Sse2.loadu_si128(ptr_v128++)); + max3 = Max(max3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Max(acc0, acc1); - acc2 = Max(acc2, acc3); - acc0 = Max(acc0, acc2); + length -= 32; + } + while (Hint.Likely(length >= 32)); + + max0 = Max(max0, max1); + max2 = Max(max2, max3); + max0 = Max(max0, max2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 8; } else @@ -446,42 +466,42 @@ static v128 Max(v128 a, v128 b) else { } v128 cmp = default(v128); - acc0 = Max(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc0 = Max(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + max0 = Max(max0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 4; } - acc0 = Max(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Max(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Max(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + max0 = Max(max0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); ptr_v128 = (v128*)((int*)ptr_v128 + 1); length -= 2; } - acc0 = Max(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + max0 = Max(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { if (Sse4_1.IsSse41Supported) { - return Sse4_1.max_epu16(acc0, Sse2.insert_epi16(cmp, *(ushort*)ptr_v128, 0)).UShort0; + return Sse4_1.max_epu16(max0, Sse2.insert_epi16(cmp, *(ushort*)ptr_v128, 0)).UShort0; } else { - return (ushort)math.max((uint)acc0.UShort0, *(ushort*)ptr_v128); + return (ushort)math.max((uint)max0.UShort0, *(ushort*)ptr_v128); } } else { - return acc0.UShort0; + return max0.UShort0; } } else @@ -594,36 +614,41 @@ static v128 Max(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); - v256 acc1 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); - v256 acc2 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); - v256 acc3 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); - - while (Hint.Likely(length >= 32)) + v256 max0 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); + + if (Hint.Likely(length >= 32)) { - acc0 = Avx2.mm256_max_epu32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_max_epu32(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_max_epu32(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_max_epu32(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 max1 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); + v256 max2 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); + v256 max3 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); - length -= 32; - } + do + { + max0 = Avx2.mm256_max_epu32(max0, Avx.mm256_loadu_si256(ptr_v256++)); + max1 = Avx2.mm256_max_epu32(max1, Avx.mm256_loadu_si256(ptr_v256++)); + max2 = Avx2.mm256_max_epu32(max2, Avx.mm256_loadu_si256(ptr_v256++)); + max3 = Avx2.mm256_max_epu32(max3, Avx.mm256_loadu_si256(ptr_v256++)); + + length -= 32; + } + while (Hint.Likely(length >= 32)); - acc0 = Avx2.mm256_max_epu32(acc0, acc1); - acc2 = Avx2.mm256_max_epu32(acc2, acc3); - acc0 = Avx2.mm256_max_epu32(acc0, acc2); + max0 = Avx2.mm256_max_epu32(max0, max1); + max2 = Avx2.mm256_max_epu32(max2, max3); + max0 = Avx2.mm256_max_epu32(max0, max2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Avx2.mm256_max_epu32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu32(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Avx2.mm256_max_epu32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu32(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Avx2.mm256_max_epu32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epu32(max0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 8; } else @@ -638,68 +663,73 @@ static v128 Max(v128 a, v128 b) } else { } - v128 acc128 = Sse4_1.max_epu32(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 max128 = Sse4_1.max_epu32(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse4_1.max_epu32(acc128, Sse2.loadu_si128(ptr_v256)); + max128 = Sse4_1.max_epu32(max128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 4; } - acc128 = Sse4_1.max_epu32(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse4_1.max_epu32(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse4_1.max_epu32(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + max128 = Sse4_1.max_epu32(max128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 2; } - acc128 = Sse4_1.max_epu32(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + max128 = Sse4_1.max_epu32(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse4_1.max_epu32(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)).UInt0; + return Sse4_1.max_epu32(max128, Sse2.cvtsi32_si128(*(int*)ptr_v256)).UInt0; } else { - return acc128.UInt0; + return max128.UInt0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); - v128 acc1 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); - v128 acc2 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); - v128 acc3 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); - - while (Hint.Likely(length >= 16)) + v128 max0 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + + if (Hint.Likely(length >= 16)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Max(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Max(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Max(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 max1 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + v128 max2 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + v128 max3 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); - length -= 16; - } + do + { + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); + max1 = Max(max1, Sse2.loadu_si128(ptr_v128++)); + max2 = Max(max2, Sse2.loadu_si128(ptr_v128++)); + max3 = Max(max3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Max(acc0, acc1); - acc2 = Max(acc2, acc3); - acc0 = Max(acc0, acc2); + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = Max(max0, max1); + max2 = Max(max2, max3); + max0 = Max(max0, max2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 4; } else @@ -715,32 +745,32 @@ static v128 Max(v128 a, v128 b) else { } - acc0 = Max(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Max(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + max0 = Max(max0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 2; } - acc0 = Max(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { if (Sse4_1.IsSse41Supported) { - return Max(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)).UInt0; + return Max(max0, Sse2.cvtsi32_si128(*(int*)ptr_v128)).UInt0; } else { - return Max(acc0, new v128(*(int*)ptr_v128, 0, 0, 0)).UInt0; + return math.max(max0.UInt0, *(uint*)ptr_v128); } } else { - return acc0.UInt0; + return max0.UInt0; } } else @@ -861,38 +891,43 @@ static v128 Max128(v128 a, v128 b, v128 mask) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); - v256 acc1 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); - v256 acc2 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); - v256 acc3 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); + v256 max0 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); v256 mask = Avx.mm256_set1_epi64x(1L << 63); - - while (Hint.Likely(length >= 16)) + + if (Hint.Likely(length >= 16)) { - acc0 = Max256(acc0, Avx.mm256_loadu_si256(ptr_v256++), mask); - acc1 = Max256(acc1, Avx.mm256_loadu_si256(ptr_v256++), mask); - acc2 = Max256(acc2, Avx.mm256_loadu_si256(ptr_v256++), mask); - acc3 = Max256(acc3, Avx.mm256_loadu_si256(ptr_v256++), mask); + v256 max1 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); + v256 max2 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); + v256 max3 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); - length -= 16; - } + do + { + max0 = Max256(max0, Avx.mm256_loadu_si256(ptr_v256++), mask); + max1 = Max256(max1, Avx.mm256_loadu_si256(ptr_v256++), mask); + max2 = Max256(max2, Avx.mm256_loadu_si256(ptr_v256++), mask); + max3 = Max256(max3, Avx.mm256_loadu_si256(ptr_v256++), mask); + + length -= 16; + } + while (Hint.Likely(length >= 16)); - acc0 = Max256(acc0, acc1, mask); - acc2 = Max256(acc2, acc3, mask); - acc0 = Max256(acc0, acc2, mask); + max0 = Max256(max0, max1, mask); + max2 = Max256(max2, max3, mask); + max0 = Max256(max0, max2, mask); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Max256(acc0, Avx.mm256_loadu_si256(ptr_v256++), mask); + max0 = Max256(max0, Avx.mm256_loadu_si256(ptr_v256++), mask); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Max256(acc0, Avx.mm256_loadu_si256(ptr_v256++), mask); + max0 = Max256(max0, Avx.mm256_loadu_si256(ptr_v256++), mask); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Max256(acc0, Avx.mm256_loadu_si256(ptr_v256++), mask); + max0 = Max256(max0, Avx.mm256_loadu_si256(ptr_v256++), mask); length -= 3 * 4; } else @@ -907,59 +942,64 @@ static v128 Max128(v128 a, v128 b, v128 mask) } else { } - v128 acc128 = Max128(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1), Avx.mm256_castsi256_si128(mask)); + v128 max128 = Max128(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1), Avx.mm256_castsi256_si128(mask)); if (Hint.Likely((int)length >= 2)) { - acc128 = Max128(acc128, Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(mask)); + max128 = Max128(max128, Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(mask)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 2; } if (Hint.Likely(length != 0)) { - return math.max(*(ulong*)ptr_v256, math.max(acc128.ULong0, acc128.ULong1)); + return math.max(*(ulong*)ptr_v256, math.max(max128.ULong0, max128.ULong1)); } else { - return math.max(acc128.ULong0, acc128.ULong1); + return math.max(max128.ULong0, max128.ULong1); } } else if (Sse4_2.IsSse42Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); - v128 acc1 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); - v128 acc2 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); - v128 acc3 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); + v128 max0 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); v128 mask = Sse2.set1_epi64x(1L << 63); - - while (Hint.Likely(length >= 8)) + + if (Hint.Likely(length >= 8)) { - acc0 = Max128(acc0, Sse2.loadu_si128(ptr_v128++), mask); - acc1 = Max128(acc1, Sse2.loadu_si128(ptr_v128++), mask); - acc2 = Max128(acc2, Sse2.loadu_si128(ptr_v128++), mask); - acc3 = Max128(acc3, Sse2.loadu_si128(ptr_v128++), mask); + v128 max1 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); + v128 max2 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); + v128 max3 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); - length -= 8; - } + do + { + max0 = Max128(max0, Sse2.loadu_si128(ptr_v128++), mask); + max1 = Max128(max1, Sse2.loadu_si128(ptr_v128++), mask); + max2 = Max128(max2, Sse2.loadu_si128(ptr_v128++), mask); + max3 = Max128(max3, Sse2.loadu_si128(ptr_v128++), mask); - acc0 = Max128(acc0, acc1, mask); - acc2 = Max128(acc2, acc3, mask); - acc0 = Max128(acc0, acc2, mask); + length -= 8; + } + while (Hint.Likely(length >= 8)); + + max0 = Max128(max0, max1, mask); + max2 = Max128(max2, max3, mask); + max0 = Max128(max0, max2, mask); + } if (Hint.Likely((int)length >= 2)) { - acc0 = Max128(acc0, Sse2.loadu_si128(ptr_v128++), mask); + max0 = Max128(max0, Sse2.loadu_si128(ptr_v128++), mask); if (Hint.Likely((int)length >= 2 * 2)) { - acc0 = Max128(acc0, Sse2.loadu_si128(ptr_v128++), mask); + max0 = Max128(max0, Sse2.loadu_si128(ptr_v128++), mask); if (Hint.Likely((int)length >= 3 * 2)) { - acc0 = Max128(acc0, Sse2.loadu_si128(ptr_v128++), mask); + max0 = Max128(max0, Sse2.loadu_si128(ptr_v128++), mask); length -= 3 * 2; } else @@ -976,11 +1016,11 @@ static v128 Max128(v128 a, v128 b, v128 mask) if (Hint.Likely(length != 0)) { - return math.max(*(ulong*)ptr_v128, math.max(acc0.ULong0, acc0.ULong1)); + return math.max(*(ulong*)ptr_v128, math.max(max0.ULong0, max0.ULong1)); } else { - return math.max(acc0.ULong0, acc0.ULong1); + return math.max(max0.ULong0, max0.ULong1); } } else @@ -1090,36 +1130,41 @@ static v128 Max(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); - v256 acc1 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); - v256 acc2 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); - v256 acc3 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); - - while (Hint.Likely(length >= 128)) + v256 max0 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); + + if (Hint.Likely(length >= 128)) { - acc0 = Avx2.mm256_max_epi8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_max_epi8(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_max_epi8(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_max_epi8(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 max1 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); + v256 max2 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); + v256 max3 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); - length -= 128; - } + do + { + max0 = Avx2.mm256_max_epi8(max0, Avx.mm256_loadu_si256(ptr_v256++)); + max1 = Avx2.mm256_max_epi8(max1, Avx.mm256_loadu_si256(ptr_v256++)); + max2 = Avx2.mm256_max_epi8(max2, Avx.mm256_loadu_si256(ptr_v256++)); + max3 = Avx2.mm256_max_epi8(max3, Avx.mm256_loadu_si256(ptr_v256++)); + + length -= 128; + } + while (Hint.Likely(length >= 128)); - acc0 = Avx2.mm256_max_epi8(acc0, acc1); - acc2 = Avx2.mm256_max_epi8(acc2, acc3); - acc0 = Avx2.mm256_max_epi8(acc0, acc2); + max0 = Avx2.mm256_max_epi8(max0, max1); + max2 = Avx2.mm256_max_epi8(max2, max3); + max0 = Avx2.mm256_max_epi8(max0, max2); + } if (Hint.Likely((int)length >= 32)) { - acc0 = Avx2.mm256_max_epi8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi8(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 32)) { - acc0 = Avx2.mm256_max_epi8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi8(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 32)) { - acc0 = Avx2.mm256_max_epi8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi8(max0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 32; } else @@ -1134,88 +1179,93 @@ static v128 Max(v128 a, v128 b) } else { } - v128 acc128 = Sse4_1.max_epi8(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 max128 = Sse4_1.max_epi8(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); if (Hint.Likely((int)length >= 16)) { - acc128 = Sse4_1.max_epi8(acc128, Sse2.loadu_si128(ptr_v256)); + max128 = Sse4_1.max_epi8(max128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 16; } v128 cmp = default(v128); - acc128 = Sse4_1.max_epi8(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse4_1.max_epi8(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 8)) { - acc128 = Sse4_1.max_epi8(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + max128 = Sse4_1.max_epi8(max128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 8; } - acc128 = Sse4_1.max_epi8(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse4_1.max_epi8(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse4_1.max_epi8(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + max128 = Sse4_1.max_epi8(max128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); ptr_v256 = (v256*)((int*)ptr_v256 + 1); length -= 4; } - acc128 = Sse4_1.max_epi8(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + max128 = Sse4_1.max_epi8(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse4_1.max_epi8(acc128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)); + max128 = Sse4_1.max_epi8(max128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)); ptr_v256 = (v256*)((short*)ptr_v256 + 1); length -= 2; } - acc128 = Sse4_1.max_epi8(acc128, Sse2.bsrli_si128(acc128, 1 * sizeof(sbyte))); + max128 = Sse4_1.max_epi8(max128, Sse2.bsrli_si128(max128, 1 * sizeof(sbyte))); if (Hint.Likely(length != 0)) { - return (sbyte)math.max((int)acc128.SByte0, (int)(*(sbyte*)ptr_v256)); + return Sse4_1.max_epi8(max128, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0)).SByte0; } else { - return acc128.SByte0; + return max128.SByte0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi8(sbyte.MinValue); - v128 acc1 = Sse2.set1_epi8(sbyte.MinValue); - v128 acc2 = Sse2.set1_epi8(sbyte.MinValue); - v128 acc3 = Sse2.set1_epi8(sbyte.MinValue); - - while (Hint.Likely(length >= 64)) + v128 max0 = Sse2.set1_epi8(sbyte.MinValue); + + if (Hint.Likely(length >= 64)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Max(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Max(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Max(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 max1 = Sse2.set1_epi8(sbyte.MinValue); + v128 max2 = Sse2.set1_epi8(sbyte.MinValue); + v128 max3 = Sse2.set1_epi8(sbyte.MinValue); - length -= 64; - } + do + { + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); + max1 = Max(max1, Sse2.loadu_si128(ptr_v128++)); + max2 = Max(max2, Sse2.loadu_si128(ptr_v128++)); + max3 = Max(max3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Max(acc0, acc1); - acc2 = Max(acc2, acc3); - acc0 = Max(acc0, acc2); + length -= 64; + } + while (Hint.Likely(length >= 64)); + + max0 = Max(max0, max1); + max2 = Max(max2, max3); + max0 = Max(max0, max2); + } if (Hint.Likely((int)length >= 16)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 16)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 16)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 16; } else @@ -1231,63 +1281,49 @@ static v128 Max(v128 a, v128 b) else { } v128 cmp = default(v128); - acc0 = Max(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 8)) { - if (Sse4_1.IsSse41Supported) - { - acc0 = Sse4_1.max_epi8(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); - } - else - { - acc0 = Max(acc0, new v128(*(long*)ptr_v128, 0)); - } + max0 = Max(max0, new v128(*(long*)ptr_v128, 0)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 8; } - acc0 = Sse2.max_epu8(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Max(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - if (Sse4_1.IsSse41Supported) - { - acc0 = Sse4_1.max_epi8(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); - } - else - { - acc0 = Max(acc0, new v128(*(int*)ptr_v128, 0, 0, 0)); - } + max0 = Max(max0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); ptr_v128 = (v128*)((int*)ptr_v128 + 1); length -= 4; } - acc0 = Max(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + max0 = Max(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely((int)length >= 2)) { - acc0 = Max(acc0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)); + max0 = Max(max0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)); ptr_v128 = (v128*)((short*)ptr_v128 + 1); length -= 2; } - acc0 = Max(acc0, Sse2.bsrli_si128(acc0, 1 * sizeof(sbyte))); + max0 = Max(max0, Sse2.bsrli_si128(max0, 1 * sizeof(sbyte))); if (Hint.Likely(length != 0)) { if (Sse4_1.IsSse41Supported) { - return Sse4_1.max_epi8(acc0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).SByte0; + return Sse4_1.max_epi8(max0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).SByte0; } else { - return (sbyte)math.max((int)acc0.SByte0, (int)(*(sbyte*)ptr_v128)); + return (sbyte)math.max((int)max0.SByte0, (int)(*(sbyte*)ptr_v128)); } } else { - return acc0.SByte0; + return max0.SByte0; } } else @@ -1378,36 +1414,41 @@ public static short SIMD_Maximum(short* ptr, long length) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi16(short.MinValue); - v256 acc1 = Avx.mm256_set1_epi16(short.MinValue); - v256 acc2 = Avx.mm256_set1_epi16(short.MinValue); - v256 acc3 = Avx.mm256_set1_epi16(short.MinValue); - - while (Hint.Likely(length >= 64)) + v256 max0 = Avx.mm256_set1_epi16(short.MinValue); + + if (Hint.Likely(length >= 64)) { - acc0 = Avx2.mm256_max_epi16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_max_epi16(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_max_epi16(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_max_epi16(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 max1 = Avx.mm256_set1_epi16(short.MinValue); + v256 max2 = Avx.mm256_set1_epi16(short.MinValue); + v256 max3 = Avx.mm256_set1_epi16(short.MinValue); - length -= 64; - } + do + { + max0 = Avx2.mm256_max_epi16(max0, Avx.mm256_loadu_si256(ptr_v256++)); + max1 = Avx2.mm256_max_epi16(max1, Avx.mm256_loadu_si256(ptr_v256++)); + max2 = Avx2.mm256_max_epi16(max2, Avx.mm256_loadu_si256(ptr_v256++)); + max3 = Avx2.mm256_max_epi16(max3, Avx.mm256_loadu_si256(ptr_v256++)); - acc0 = Avx2.mm256_max_epi16(acc0, acc1); - acc2 = Avx2.mm256_max_epi16(acc2, acc3); - acc0 = Avx2.mm256_max_epi16(acc0, acc2); + length -= 64; + } + while (Hint.Likely(length >= 64)); + + max0 = Avx2.mm256_max_epi16(max0, max1); + max2 = Avx2.mm256_max_epi16(max2, max3); + max0 = Avx2.mm256_max_epi16(max0, max2); + } if (Hint.Likely((int)length >= 16)) { - acc0 = Avx2.mm256_max_epi16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi16(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 16)) { - acc0 = Avx2.mm256_max_epi16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi16(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 16)) { - acc0 = Avx2.mm256_max_epi16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi16(max0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 16; } else @@ -1422,79 +1463,84 @@ public static short SIMD_Maximum(short* ptr, long length) } else { } - v128 acc128 = Sse2.max_epi16(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 max128 = Sse2.max_epi16(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); if (Hint.Likely((int)length >= 8)) { - acc128 = Sse2.max_epi16(acc128, Sse2.loadu_si128(ptr_v256)); + max128 = Sse2.max_epi16(max128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 8; } v128 cmp = default(v128); - acc128 = Sse2.max_epi16(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse2.max_epi16(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse2.max_epi16(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + max128 = Sse2.max_epi16(max128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 4; } - acc128 = Sse2.max_epi16(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse2.max_epi16(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse2.max_epi16(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + max128 = Sse2.max_epi16(max128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); ptr_v256 = (v256*)((int*)ptr_v256 + 1); length -= 2; } - acc128 = Sse2.max_epi16(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + max128 = Sse2.max_epi16(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse2.max_epi16(acc128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)).SShort0; + return Sse2.max_epi16(max128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)).SShort0; } else { - return acc128.SShort0; + return max128.SShort0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi16(short.MinValue); - v128 acc1 = Sse2.set1_epi16(short.MinValue); - v128 acc2 = Sse2.set1_epi16(short.MinValue); - v128 acc3 = Sse2.set1_epi16(short.MinValue); - - while (Hint.Likely(length >= 32)) + v128 max0 = Sse2.set1_epi16(short.MinValue); + + if (Hint.Likely(length >= 32)) { - acc0 = Sse2.max_epi16(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Sse2.max_epi16(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Sse2.max_epi16(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Sse2.max_epi16(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 max1 = Sse2.set1_epi16(short.MinValue); + v128 max2 = Sse2.set1_epi16(short.MinValue); + v128 max3 = Sse2.set1_epi16(short.MinValue); - length -= 32; - } + do + { + max0 = Sse2.max_epi16(max0, Sse2.loadu_si128(ptr_v128++)); + max1 = Sse2.max_epi16(max1, Sse2.loadu_si128(ptr_v128++)); + max2 = Sse2.max_epi16(max2, Sse2.loadu_si128(ptr_v128++)); + max3 = Sse2.max_epi16(max3, Sse2.loadu_si128(ptr_v128++)); + + length -= 32; + } + while (Hint.Likely(length >= 32)); - acc0 = Sse2.max_epi16(acc0, acc1); - acc2 = Sse2.max_epi16(acc2, acc3); - acc0 = Sse2.max_epi16(acc0, acc2); + max0 = Sse2.max_epi16(max0, max1); + max2 = Sse2.max_epi16(max2, max3); + max0 = Sse2.max_epi16(max0, max2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Sse2.max_epi16(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Sse2.max_epi16(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Sse2.max_epi16(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Sse2.max_epi16(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Sse2.max_epi16(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Sse2.max_epi16(max0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 8; } else @@ -1510,35 +1556,35 @@ public static short SIMD_Maximum(short* ptr, long length) else { } v128 cmp = default(v128); - acc0 = Sse2.max_epi16(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Sse2.max_epi16(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc0 = Sse2.max_epi16(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + max0 = Sse2.max_epi16(max0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 4; } - acc0 = Sse2.max_epi16(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Sse2.max_epi16(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Sse2.max_epi16(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + max0 = Sse2.max_epi16(max0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); ptr_v128 = (v128*)((int*)ptr_v128 + 1); length -= 2; } - acc0 = Sse2.max_epi16(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + max0 = Sse2.max_epi16(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse2.max_epi16(acc0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)).SShort0; + return Sse2.max_epi16(max0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)).SShort0; } else { - return acc0.SShort0; + return max0.SShort0; } } else @@ -1648,36 +1694,41 @@ static v128 Max(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi32(int.MinValue); - v256 acc1 = Avx.mm256_set1_epi32(int.MinValue); - v256 acc2 = Avx.mm256_set1_epi32(int.MinValue); - v256 acc3 = Avx.mm256_set1_epi32(int.MinValue); - - while (Hint.Likely(length >= 32)) + v256 max0 = Avx.mm256_set1_epi32(int.MinValue); + + if (Hint.Likely(length >= 32)) { - acc0 = Avx2.mm256_max_epi32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_max_epi32(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_max_epi32(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_max_epi32(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 max1 = Avx.mm256_set1_epi32(int.MinValue); + v256 max2 = Avx.mm256_set1_epi32(int.MinValue); + v256 max3 = Avx.mm256_set1_epi32(int.MinValue); - length -= 32; - } + do + { + max0 = Avx2.mm256_max_epi32(max0, Avx.mm256_loadu_si256(ptr_v256++)); + max1 = Avx2.mm256_max_epi32(max1, Avx.mm256_loadu_si256(ptr_v256++)); + max2 = Avx2.mm256_max_epi32(max2, Avx.mm256_loadu_si256(ptr_v256++)); + max3 = Avx2.mm256_max_epi32(max3, Avx.mm256_loadu_si256(ptr_v256++)); - acc0 = Avx2.mm256_max_epi32(acc0, acc1); - acc2 = Avx2.mm256_max_epi32(acc2, acc3); - acc0 = Avx2.mm256_max_epi32(acc0, acc2); + length -= 32; + } + while (Hint.Likely(length >= 32)); + + max0 = Avx2.mm256_max_epi32(max0, max1); + max2 = Avx2.mm256_max_epi32(max2, max3); + max0 = Avx2.mm256_max_epi32(max0, max2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Avx2.mm256_max_epi32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi32(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Avx2.mm256_max_epi32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi32(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Avx2.mm256_max_epi32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Avx2.mm256_max_epi32(max0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 8; } else @@ -1692,68 +1743,73 @@ static v128 Max(v128 a, v128 b) } else { } - v128 acc128 = Sse4_1.max_epi32(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 max128 = Sse4_1.max_epi32(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse4_1.max_epi32(acc128, Sse2.loadu_si128(ptr_v256)); + max128 = Sse4_1.max_epi32(max128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 4; } - acc128 = Sse4_1.max_epi32(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse4_1.max_epi32(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse4_1.max_epi32(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + max128 = Sse4_1.max_epi32(max128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 2; } - acc128 = Sse4_1.max_epi32(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + max128 = Sse4_1.max_epi32(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse4_1.max_epi32(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)).SInt0; + return Sse4_1.max_epi32(max128, Sse2.cvtsi32_si128(*(int*)ptr_v256)).SInt0; } else { - return acc128.SInt0; + return max128.SInt0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi32(int.MinValue); - v128 acc1 = Sse2.set1_epi32(int.MinValue); - v128 acc2 = Sse2.set1_epi32(int.MinValue); - v128 acc3 = Sse2.set1_epi32(int.MinValue); - - while (Hint.Likely(length >= 16)) + v128 max0 = Sse2.set1_epi32(int.MinValue); + + if (Hint.Likely(length >= 16)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Max(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Max(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Max(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 max1 = Sse2.set1_epi32(int.MinValue); + v128 max2 = Sse2.set1_epi32(int.MinValue); + v128 max3 = Sse2.set1_epi32(int.MinValue); - length -= 16; - } + do + { + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); + max1 = Max(max1, Sse2.loadu_si128(ptr_v128++)); + max2 = Max(max2, Sse2.loadu_si128(ptr_v128++)); + max3 = Max(max3, Sse2.loadu_si128(ptr_v128++)); + + length -= 16; + } + while (Hint.Likely(length >= 16)); - acc0 = Max(acc0, acc1); - acc2 = Max(acc2, acc3); - acc0 = Max(acc0, acc2); + max0 = Max(max0, max1); + max2 = Max(max2, max3); + max0 = Max(max0, max2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Max(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 4; } else @@ -1768,25 +1824,32 @@ static v128 Max(v128 a, v128 b) } else { } - acc0 = Max(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Max(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + max0 = Max(max0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 2; } - acc0 = Max(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Max(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)).SInt0; + if (Sse4_1.IsSse41Supported) + { + return Max(max0, Sse2.cvtsi32_si128(*(int*)ptr_v128)).SInt0; + } + else + { + return math.max(max0.SInt0, *(int*)ptr_v128); + } } else { - return acc0.SInt0; + return max0.SInt0; } } else @@ -1887,36 +1950,41 @@ static v128 Max128(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi64x(long.MinValue); - v256 acc1 = Avx.mm256_set1_epi64x(long.MinValue); - v256 acc2 = Avx.mm256_set1_epi64x(long.MinValue); - v256 acc3 = Avx.mm256_set1_epi64x(long.MinValue); - - while (Hint.Likely(length >= 16)) + v256 max0 = Avx.mm256_set1_epi64x(long.MinValue); + + if (Hint.Likely(length >= 16)) { - acc0 = Max256(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Max256(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Max256(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Max256(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 max1 = Avx.mm256_set1_epi64x(long.MinValue); + v256 max2 = Avx.mm256_set1_epi64x(long.MinValue); + v256 max3 = Avx.mm256_set1_epi64x(long.MinValue); - length -= 16; - } + do + { + max0 = Max256(max0, Avx.mm256_loadu_si256(ptr_v256++)); + max1 = Max256(max1, Avx.mm256_loadu_si256(ptr_v256++)); + max2 = Max256(max2, Avx.mm256_loadu_si256(ptr_v256++)); + max3 = Max256(max3, Avx.mm256_loadu_si256(ptr_v256++)); + + length -= 16; + } + while (Hint.Likely(length >= 16)); - acc0 = Max256(acc0, acc1); - acc2 = Max256(acc2, acc3); - acc0 = Max256(acc0, acc2); + max0 = Max256(max0, max1); + max2 = Max256(max2, max3); + max0 = Max256(max0, max2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Max256(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Max256(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Max256(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Max256(max0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Max256(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + max0 = Max256(max0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 4; } else @@ -1931,59 +1999,64 @@ static v128 Max128(v128 a, v128 b) } else { } - v128 acc128 = Max128(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 max128 = Max128(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); if (Hint.Likely((int)length >= 2)) { - acc128 = Max128(acc128, Sse2.loadu_si128(ptr_v256)); + max128 = Max128(max128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 2; } - acc128 = Max128(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Max128(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely(length != 0)) { - return math.max(acc128.SLong0, *(long*)ptr_v256); + return math.max(max128.SLong0, *(long*)ptr_v256); } else { - return acc128.SLong0; + return max128.SLong0; } } else if (Sse4_2.IsSse42Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi64x(long.MinValue); - v128 acc1 = Sse2.set1_epi64x(long.MinValue); - v128 acc2 = Sse2.set1_epi64x(long.MinValue); - v128 acc3 = Sse2.set1_epi64x(long.MinValue); - - while (Hint.Likely(length >= 8)) + v128 max0 = Sse2.set1_epi64x(long.MinValue); + + if (Hint.Likely(length >= 8)) { - acc0 = Max128(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Max128(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Max128(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Max128(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 max1 = Sse2.set1_epi64x(long.MinValue); + v128 max2 = Sse2.set1_epi64x(long.MinValue); + v128 max3 = Sse2.set1_epi64x(long.MinValue); - length -= 8; - } + do + { + max0 = Max128(max0, Sse2.loadu_si128(ptr_v128++)); + max1 = Max128(max1, Sse2.loadu_si128(ptr_v128++)); + max2 = Max128(max2, Sse2.loadu_si128(ptr_v128++)); + max3 = Max128(max3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Max128(acc0, acc1); - acc2 = Max128(acc2, acc3); - acc0 = Max128(acc0, acc2); + length -= 8; + } + while (Hint.Likely(length >= 8)); + + max0 = Max128(max0, max1); + max2 = Max128(max2, max3); + max0 = Max128(max0, max2); + } if (Hint.Likely((int)length >= 2)) { - acc0 = Max128(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max128(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 2)) { - acc0 = Max128(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max128(max0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 2)) { - acc0 = Max128(acc0, Sse2.loadu_si128(ptr_v128++)); + max0 = Max128(max0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 2; } else @@ -1998,15 +2071,15 @@ static v128 Max128(v128 a, v128 b) } else { } - acc0 = Max128(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Max128(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely(length != 0)) { - return math.max(acc0.SLong0, *(long*)ptr_v128); + return math.max(max0.SLong0, *(long*)ptr_v128); } else { - return acc0.SLong0; + return max0.SLong0; } } else @@ -2097,36 +2170,41 @@ public static float SIMD_Maximum(float* ptr, long length) if (Avx.IsAvxSupported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = new v256(float.NegativeInfinity); - v256 acc1 = new v256(float.NegativeInfinity); - v256 acc2 = new v256(float.NegativeInfinity); - v256 acc3 = new v256(float.NegativeInfinity); - - while (Hint.Likely(length >= 32)) + v256 max0 = new v256(float.NegativeInfinity); + + if (Hint.Likely(length >= 32)) { - acc0 = Avx.mm256_max_ps(acc0, Avx.mm256_loadu_ps(ptr_v256++)); - acc1 = Avx.mm256_max_ps(acc1, Avx.mm256_loadu_ps(ptr_v256++)); - acc2 = Avx.mm256_max_ps(acc2, Avx.mm256_loadu_ps(ptr_v256++)); - acc3 = Avx.mm256_max_ps(acc3, Avx.mm256_loadu_ps(ptr_v256++)); + v256 max1 = new v256(float.NegativeInfinity); + v256 max2 = new v256(float.NegativeInfinity); + v256 max3 = new v256(float.NegativeInfinity); - length -= 32; - } + do + { + max0 = Avx.mm256_max_ps(max0, Avx.mm256_loadu_ps(ptr_v256++)); + max1 = Avx.mm256_max_ps(max1, Avx.mm256_loadu_ps(ptr_v256++)); + max2 = Avx.mm256_max_ps(max2, Avx.mm256_loadu_ps(ptr_v256++)); + max3 = Avx.mm256_max_ps(max3, Avx.mm256_loadu_ps(ptr_v256++)); + + length -= 32; + } + while (Hint.Likely(length >= 32)); - acc0 = Avx.mm256_max_ps(acc0, acc1); - acc2 = Avx.mm256_max_ps(acc2, acc3); - acc0 = Avx.mm256_max_ps(acc0, acc2); + max0 = Avx.mm256_max_ps(max0, max1); + max2 = Avx.mm256_max_ps(max2, max3); + max0 = Avx.mm256_max_ps(max0, max2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Avx.mm256_max_ps(acc0, Avx.mm256_loadu_ps(ptr_v256++)); + max0 = Avx.mm256_max_ps(max0, Avx.mm256_loadu_ps(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Avx.mm256_max_ps(acc0, Avx.mm256_loadu_ps(ptr_v256++)); + max0 = Avx.mm256_max_ps(max0, Avx.mm256_loadu_ps(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Avx.mm256_max_ps(acc0, Avx.mm256_loadu_ps(ptr_v256++)); + max0 = Avx.mm256_max_ps(max0, Avx.mm256_loadu_ps(ptr_v256++)); length -= 3 * 8; } else @@ -2141,68 +2219,73 @@ public static float SIMD_Maximum(float* ptr, long length) } else { } - v128 acc128 = Sse.max_ps(Avx.mm256_castps256_ps128(acc0), Avx.mm256_extractf128_ps(acc0, 1)); + v128 max128 = Sse.max_ps(Avx.mm256_castps256_ps128(max0), Avx.mm256_extractf128_ps(max0, 1)); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse.max_ps(acc128, Sse.loadu_ps(ptr_v256)); + max128 = Sse.max_ps(max128, Sse.loadu_ps(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 4; } - acc128 = Sse.max_ps(acc128, Avx.permute_ps(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + max128 = Sse.max_ps(max128, Avx.permute_ps(max128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse.max_ps(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + max128 = Sse.max_ps(max128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 2; } - acc128 = Sse.max_ps(acc128, Avx.permute_ps(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + max128 = Sse.max_ps(max128, Avx.permute_ps(max128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - acc128 = Sse.max_ss(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + max128 = Sse.max_ss(max128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); } - return acc128.Float0; + return max128.Float0; } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = new v128(float.NegativeInfinity); - v128 acc1 = new v128(float.NegativeInfinity); - v128 acc2 = new v128(float.NegativeInfinity); - v128 acc3 = new v128(float.NegativeInfinity); - - while (Hint.Likely(length >= 16)) + v128 max0 = new v128(float.NegativeInfinity); + + if (Hint.Likely(length >= 16)) { - acc0 = Sse.max_ps(acc0, Sse.loadu_ps(ptr_v128++)); - acc1 = Sse.max_ps(acc1, Sse.loadu_ps(ptr_v128++)); - acc2 = Sse.max_ps(acc2, Sse.loadu_ps(ptr_v128++)); - acc3 = Sse.max_ps(acc3, Sse.loadu_ps(ptr_v128++)); + v128 max1 = new v128(float.NegativeInfinity); + v128 max2 = new v128(float.NegativeInfinity); + v128 max3 = new v128(float.NegativeInfinity); - length -= 16; - } + do + { + max0 = Sse.max_ps(max0, Sse.loadu_ps(ptr_v128++)); + max1 = Sse.max_ps(max1, Sse.loadu_ps(ptr_v128++)); + max2 = Sse.max_ps(max2, Sse.loadu_ps(ptr_v128++)); + max3 = Sse.max_ps(max3, Sse.loadu_ps(ptr_v128++)); - acc0 = Sse.max_ps(acc0, acc1); - acc2 = Sse.max_ps(acc2, acc3); - acc0 = Sse.max_ps(acc0, acc2); + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = Sse.max_ps(max0, max1); + max2 = Sse.max_ps(max2, max3); + max0 = Sse.max_ps(max0, max2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Sse.max_ps(acc0, Sse.loadu_ps(ptr_v128++)); + max0 = Sse.max_ps(max0, Sse.loadu_ps(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Sse.max_ps(acc0, Sse.loadu_ps(ptr_v128++)); + max0 = Sse.max_ps(max0, Sse.loadu_ps(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Sse.max_ps(acc0, Sse.loadu_ps(ptr_v128++)); + max0 = Sse.max_ps(max0, Sse.loadu_ps(ptr_v128++)); length -= 3 * 4; } else @@ -2217,24 +2300,24 @@ public static float SIMD_Maximum(float* ptr, long length) } else { } - acc0 = Sse.max_ps(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Sse.max_ps(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Sse.max_ps(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + max0 = Sse.max_ps(max0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 2; } - acc0 = Sse.max_ps(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + max0 = Sse.max_ps(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - acc0 = Sse.max_ss(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + max0 = Sse.max_ss(max0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); } - return acc0.Float0; + return max0.Float0; } else { @@ -2324,36 +2407,41 @@ public static double SIMD_Maximum(double* ptr, long length) if (Avx.IsAvxSupported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = new v256(double.NegativeInfinity); - v256 acc1 = new v256(double.NegativeInfinity); - v256 acc2 = new v256(double.NegativeInfinity); - v256 acc3 = new v256(double.NegativeInfinity); - - while (Hint.Likely(length >= 16)) + v256 max0 = new v256(double.NegativeInfinity); + + if (Hint.Likely(length >= 16)) { - acc0 = Avx.mm256_max_pd(acc0, Avx.mm256_loadu_pd(ptr_v256++)); - acc1 = Avx.mm256_max_pd(acc1, Avx.mm256_loadu_pd(ptr_v256++)); - acc2 = Avx.mm256_max_pd(acc2, Avx.mm256_loadu_pd(ptr_v256++)); - acc3 = Avx.mm256_max_pd(acc3, Avx.mm256_loadu_pd(ptr_v256++)); + v256 max1 = new v256(double.NegativeInfinity); + v256 max2 = new v256(double.NegativeInfinity); + v256 max3 = new v256(double.NegativeInfinity); - length -= 16; - } + do + { + max0 = Avx.mm256_max_pd(max0, Avx.mm256_loadu_pd(ptr_v256++)); + max1 = Avx.mm256_max_pd(max1, Avx.mm256_loadu_pd(ptr_v256++)); + max2 = Avx.mm256_max_pd(max2, Avx.mm256_loadu_pd(ptr_v256++)); + max3 = Avx.mm256_max_pd(max3, Avx.mm256_loadu_pd(ptr_v256++)); + + length -= 16; + } + while (Hint.Likely(length >= 16)); - acc0 = Avx.mm256_max_pd(acc0, acc1); - acc2 = Avx.mm256_max_pd(acc2, acc3); - acc0 = Avx.mm256_max_pd(acc0, acc2); + max0 = Avx.mm256_max_pd(max0, max1); + max2 = Avx.mm256_max_pd(max2, max3); + max0 = Avx.mm256_max_pd(max0, max2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Avx.mm256_max_pd(acc0, Avx.mm256_loadu_pd(ptr_v256++)); + max0 = Avx.mm256_max_pd(max0, Avx.mm256_loadu_pd(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Avx.mm256_max_pd(acc0, Avx.mm256_loadu_pd(ptr_v256++)); + max0 = Avx.mm256_max_pd(max0, Avx.mm256_loadu_pd(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Avx.mm256_max_pd(acc0, Avx.mm256_loadu_pd(ptr_v256++)); + max0 = Avx.mm256_max_pd(max0, Avx.mm256_loadu_pd(ptr_v256++)); length -= 3 * 4; } else @@ -2368,58 +2456,63 @@ public static double SIMD_Maximum(double* ptr, long length) } else { } - v128 acc128 = Sse2.max_pd(Avx.mm256_castpd256_pd128(acc0), Avx.mm256_extractf128_pd(acc0, 1)); + v128 max128 = Sse2.max_pd(Avx.mm256_castpd256_pd128(max0), Avx.mm256_extractf128_pd(max0, 1)); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse2.max_pd(acc128, Sse.loadu_ps(ptr_v256)); + max128 = Sse2.max_pd(max128, Sse.loadu_ps(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 2; } - acc128 = Sse2.max_pd(acc128, Avx.permute_pd(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + max128 = Sse2.max_pd(max128, Avx.permute_pd(max128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - acc128 = Sse2.max_sd(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + max128 = Sse2.max_sd(max128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); } - return acc128.Double0; + return max128.Double0; } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = new v128(double.NegativeInfinity); - v128 acc1 = new v128(double.NegativeInfinity); - v128 acc2 = new v128(double.NegativeInfinity); - v128 acc3 = new v128(double.NegativeInfinity); - - while (Hint.Likely(length >= 8)) + v128 max0 = new v128(double.NegativeInfinity); + + if (Hint.Likely(length >= 8)) { - acc0 = Sse2.max_pd(acc0, Sse.loadu_ps(ptr_v128++)); - acc1 = Sse2.max_pd(acc1, Sse.loadu_ps(ptr_v128++)); - acc2 = Sse2.max_pd(acc2, Sse.loadu_ps(ptr_v128++)); - acc3 = Sse2.max_pd(acc3, Sse.loadu_ps(ptr_v128++)); + v128 max1 = new v128(double.NegativeInfinity); + v128 max2 = new v128(double.NegativeInfinity); + v128 max3 = new v128(double.NegativeInfinity); - length -= 8; - } + do + { + max0 = Sse2.max_pd(max0, Sse.loadu_ps(ptr_v128++)); + max1 = Sse2.max_pd(max1, Sse.loadu_ps(ptr_v128++)); + max2 = Sse2.max_pd(max2, Sse.loadu_ps(ptr_v128++)); + max3 = Sse2.max_pd(max3, Sse.loadu_ps(ptr_v128++)); - acc0 = Sse2.max_pd(acc0, acc1); - acc2 = Sse2.max_pd(acc2, acc3); - acc0 = Sse2.max_pd(acc0, acc2); + length -= 8; + } + while (Hint.Likely(length >= 8)); + + max0 = Sse2.max_pd(max0, max1); + max2 = Sse2.max_pd(max2, max3); + max0 = Sse2.max_pd(max0, max2); + } if (Hint.Likely((int)length >= 2)) { - acc0 = Sse2.max_pd(acc0, Sse.loadu_ps(ptr_v128++)); + max0 = Sse2.max_pd(max0, Sse.loadu_ps(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 2)) { - acc0 = Sse2.max_pd(acc0, Sse.loadu_ps(ptr_v128++)); + max0 = Sse2.max_pd(max0, Sse.loadu_ps(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 2)) { - acc0 = Sse2.max_pd(acc0, Sse.loadu_ps(ptr_v128++)); + max0 = Sse2.max_pd(max0, Sse.loadu_ps(ptr_v128++)); length -= 3 * 2; } else @@ -2434,14 +2527,14 @@ public static double SIMD_Maximum(double* ptr, long length) } else { } - acc0 = Sse2.max_pd(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + max0 = Sse2.max_pd(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely(length != 0)) { - acc0 = Sse2.max_sd(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + max0 = Sse2.max_sd(max0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); } - return acc0.Double0; + return max0.Double0; } else { diff --git a/Runtime/Algorithms/MinMax.cs b/Runtime/Algorithms/MinMax.cs new file mode 100644 index 0000000..b301e9e --- /dev/null +++ b/Runtime/Algorithms/MinMax.cs @@ -0,0 +1,3796 @@ +using System.Runtime.CompilerServices; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Burst.Intrinsics; +using Unity.Burst.CompilerServices; +using Unity.Mathematics; +using DevTools; + +using static Unity.Burst.Intrinsics.X86; +using static SIMDAlgorithms.Fallback; + +namespace SIMDAlgorithms +{ + unsafe public static partial class Algorithms + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(byte* ptr, long length, out byte min, out byte max) + { +Assert.IsNonNegative(length); + + if (Avx2.IsAvx2Supported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = Avx.mm256_set1_epi8(byte.MinValue); + + v256 min0 = Avx.mm256_set1_epi8(byte.MaxValue); + + if (Hint.Likely(length >= 128)) + { + v256 max1 = Avx.mm256_set1_epi8(byte.MinValue); + v256 max2 = Avx.mm256_set1_epi8(byte.MinValue); + v256 max3 = Avx.mm256_set1_epi8(byte.MinValue); + + v256 min1 = Avx.mm256_set1_epi8(byte.MaxValue); + v256 min2 = Avx.mm256_set1_epi8(byte.MaxValue); + v256 min3 = Avx.mm256_set1_epi8(byte.MaxValue); + + do + { + v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu8(max0, load0); + max1 = Avx2.mm256_max_epu8(max1, load0); + max2 = Avx2.mm256_max_epu8(max2, load0); + max3 = Avx2.mm256_max_epu8(max3, load0); + + min0 = Avx2.mm256_min_epu8(min0, load0); + min1 = Avx2.mm256_min_epu8(min1, load0); + min2 = Avx2.mm256_min_epu8(min2, load0); + min3 = Avx2.mm256_min_epu8(min3, load0); + + length -= 128; + } + while (Hint.Likely(length >= 128)); + + max0 = Avx2.mm256_max_epu8(max0, max1); + max2 = Avx2.mm256_max_epu8(max2, max3); + max0 = Avx2.mm256_max_epu8(max0, max2); + + min0 = Avx2.mm256_min_epu8(min0, min1); + min2 = Avx2.mm256_min_epu8(min2, min3); + min0 = Avx2.mm256_min_epu8(min0, min2); + } + + if (Hint.Likely((int)length >= 32)) + { + v256 load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu8(max0, load); + min0 = Avx2.mm256_min_epu8(min0, load); + + if (Hint.Likely((int)length >= 2 * 32)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu8(max0, load); + min0 = Avx2.mm256_min_epu8(min0, load); + + if (Hint.Likely((int)length >= 3 * 32)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu8(max0, load); + min0 = Avx2.mm256_min_epu8(min0, load); + + length -= 3 * 32; + } + else + { + length -= 2 * 32; + } + } + else + { + length -= 32; + } + } + else { } + + v128 max128 = Sse2.max_epu8(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); + v128 min128 = Sse2.min_epu8(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); + + if (Hint.Likely((int)length >= 16)) + { + v128 load = Sse2.loadu_si128(ptr_v256); + + max128 = Sse2.max_epu8(max128, load); + min128 = Sse2.min_epu8(min128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + + length -= 16; + } + + v128 cmp = default(v128); + max128 = Sse2.max_epu8(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse2.min_epu8(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v256); + + max128 = Sse2.max_epu8(max128, load); + min128 = Sse2.min_epu8(min128, load); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; + } + + max128 = Sse2.max_epu8(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse2.min_epu8(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v256); + + max128 = Sse2.max_epu8(max128, load); + min128 = Sse2.min_epu8(min128, load); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; + } + + max128 = Sse2.max_epu8(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse2.min_epu8(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0); + + max128 = Sse2.max_epu8(max128, load); + min128 = Sse2.min_epu8(min128, load); + + ptr_v256 = (v256*)((short*)ptr_v256 + 1); + length -= 2; + } + + max128 = Sse2.max_epu8(max128, Sse2.bsrli_si128(max128, 1 * sizeof(byte))); + min128 = Sse2.min_epu8(min128, Sse2.bsrli_si128(min128, 1 * sizeof(byte))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0); + + max = Sse2.max_epu8(max128, load).Byte0; + min = Sse2.min_epu8(min128, load).Byte0; + } + else + { + max = max128.Byte0; + min = min128.Byte0; + } + } + else if (Sse2.IsSse2Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); + + v128 min0 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); + + if (Hint.Likely(length >= 64)) + { + v128 max1 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); + v128 max2 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); + v128 max3 = Sse2.set1_epi8(unchecked((sbyte)byte.MinValue)); + + v128 min1 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); + v128 min2 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); + v128 min3 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); + + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse2.max_epu8(max0, load0); + max1 = Sse2.max_epu8(max1, load1); + max2 = Sse2.max_epu8(max2, load2); + max3 = Sse2.max_epu8(max3, load3); + + min0 = Sse2.min_epu8(min0, load0); + min1 = Sse2.min_epu8(min1, load1); + min2 = Sse2.min_epu8(min2, load2); + min3 = Sse2.min_epu8(min3, load3); + + length -= 64; + } + while (Hint.Likely(length >= 64)); + + max0 = Sse2.max_epu8(max0, max1); + max2 = Sse2.max_epu8(max2, max3); + max0 = Sse2.max_epu8(max0, max2); + + min0 = Sse2.min_epu8(min0, min1); + min2 = Sse2.min_epu8(min2, min3); + min0 = Sse2.min_epu8(min0, min2); + } + + if (Hint.Likely((int)length >= 16)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse2.max_epu8(max0, load); + min0 = Sse2.min_epu8(min0, load); + + if (Hint.Likely((int)length >= 2 * 16)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse2.max_epu8(max0, load); + min0 = Sse2.min_epu8(min0, load); + + if (Hint.Likely((int)length >= 3 * 16)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse2.max_epu8(max0, load); + min0 = Sse2.min_epu8(min0, load); + length -= 3 * 16; + + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + v128 cmp = default(v128); + max0 = Sse2.max_epu8(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_epu8(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + + max0 = Sse2.max_epu8(max0, load); + min0 = Sse2.min_epu8(min0, load); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + } + + max0 = Sse2.max_epu8(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_epu8(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v128); + + max0 = Sse2.max_epu8(max0, load); + min0 = Sse2.min_epu8(min0, load); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + } + + max0 = Sse2.max_epu8(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Sse2.min_epu8(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0); + + max0 = Sse2.max_epu8(max0, load); + min0 = Sse2.min_epu8(min0, load); + + ptr_v128 = (v128*)((short*)ptr_v128 + 1); + length -= 2; + } + + max0 = Sse2.max_epu8(max0, Sse2.bsrli_si128(max0, 1 * sizeof(byte))); + min0 = Sse2.min_epu8(min0, Sse2.bsrli_si128(min0, 1 * sizeof(byte))); + + if (Hint.Likely(length != 0)) + { + if (Sse4_1.IsSse41Supported) + { + max = Sse2.max_epu8(max0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).Byte0; + min = Sse2.min_epu8(min0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).Byte0; + } + else + { + max = Sse2.max_epu8(max0,Sse2.cvtsi32_si128(*(byte*)ptr_v128)).Byte0; + min = Sse2.min_epu8(min0,Sse2.cvtsi32_si128(*(byte*)ptr_v128)).Byte0; + } + } + else + { + max = max0.Byte0; + min = min0.Byte0; + } + } + else + { + max = byte.MinValue; + min = byte.MinValue; + + for (long i = 0; i < length; i++) + { + uint cmp = (uint)ptr[i]; + + max = (byte)math.max((uint)max, cmp); + min = (byte)math.min((uint)min, cmp); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out byte min, out byte max) + { + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out byte min, out byte max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out byte min, out byte max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out byte min, out byte max) + { + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out byte min, out byte max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out byte min, out byte max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out byte min, out byte max) + { + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out byte min, out byte max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out byte min, out byte max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((byte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(ushort* ptr, long length, out ushort min, out ushort max) + { +Assert.IsNonNegative(length); + + if (Avx2.IsAvx2Supported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); + + v256 min0 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); + + if (Hint.Likely(length >= 64)) + { + v256 max1 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); + v256 max2 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); + v256 max3 = Avx.mm256_set1_epi16(unchecked((short)ushort.MinValue)); + + v256 min1 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); + v256 min2 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); + v256 min3 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); + + do + { + v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu16(max0, load0); + max1 = Avx2.mm256_max_epu16(max1, load1); + max2 = Avx2.mm256_max_epu16(max2, load2); + max3 = Avx2.mm256_max_epu16(max3, load3); + + min0 = Avx2.mm256_min_epu16(min0, load0); + min1 = Avx2.mm256_min_epu16(min1, load1); + min2 = Avx2.mm256_min_epu16(min2, load2); + min3 = Avx2.mm256_min_epu16(min3, load3); + + length -= 64; + } + while (Hint.Likely(length >= 64)); + + max0 = Avx2.mm256_max_epu16(max0, max1); + max2 = Avx2.mm256_max_epu16(max2, max3); + max0 = Avx2.mm256_max_epu16(max0, max2); + + min0 = Avx2.mm256_min_epu16(min0, min1); + min2 = Avx2.mm256_min_epu16(min2, min3); + min0 = Avx2.mm256_min_epu16(min0, min2); + } + + if (Hint.Likely((int)length >= 16)) + { + v256 load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu16(max0, load); + min0 = Avx2.mm256_min_epu16(min0, load); + + if (Hint.Likely((int)length >= 2 * 16)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu16(max0, load); + min0 = Avx2.mm256_min_epu16(min0, load); + + if (Hint.Likely((int)length >= 3 * 16)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu16(max0, load); + min0 = Avx2.mm256_min_epu16(min0, load); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + v128 max128 = Sse4_1.max_epu16(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); + v128 min128 = Sse4_1.min_epu16(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.loadu_si128(ptr_v256); + + max128 = Sse4_1.max_epu16(max128, load); + min128 = Sse4_1.min_epu16(min128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + + length -= 8; + } + + v128 cmp = default(v128); + max128 = Sse4_1.max_epu16(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epu16(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v256); + + max128 = Sse4_1.max_epu16(max128, load); + min128 = Sse4_1.min_epu16(min128, load); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + } + + max128 = Sse4_1.max_epu16(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epu16(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v256); + + max128 = Sse4_1.max_epu16(max128, load); + min128 = Sse4_1.min_epu16(min128, load); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + } + + max128 = Sse4_1.max_epu16(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse4_1.min_epu16(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.insert_epi16(cmp, *(ushort*)ptr_v256, 0); + + max = Sse4_1.max_epu16(max128, load).UShort0; + min = Sse4_1.min_epu16(min128, load).UShort0; + } + else + { + max = max128.UShort0; + min = min128.UShort0; + } + } + else if (Sse4_1.IsSse41Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + + v128 min0 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + + if (Hint.Likely(length >= 32)) + { + v128 max1 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + v128 max2 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + v128 max3 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + + v128 min1 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + v128 min2 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + v128 min3 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse4_1.max_epu16(max0, load0); + max1 = Sse4_1.max_epu16(max1, load1); + max2 = Sse4_1.max_epu16(max2, load2); + max3 = Sse4_1.max_epu16(max3, load3); + + min0 = Sse4_1.min_epu16(min0, load0); + min1 = Sse4_1.min_epu16(min1, load1); + min2 = Sse4_1.min_epu16(min2, load2); + min3 = Sse4_1.min_epu16(min3, load3); + + length -= 32; + } + while (Hint.Likely(length >= 32)); + + max0 = Sse4_1.max_epu16(max0, max1); + max2 = Sse4_1.max_epu16(max2, max3); + max0 = Sse4_1.max_epu16(max0, max2); + + min0 = Sse4_1.min_epu16(min0, min1); + min2 = Sse4_1.min_epu16(min2, min3); + min0 = Sse4_1.min_epu16(min0, min2); + } + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse4_1.max_epu16(max0, load); + min0 = Sse4_1.min_epu16(min0, load); + + if (Hint.Likely((int)length >= 2 * 8)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse4_1.max_epu16(max0, load); + min0 = Sse4_1.min_epu16(min0, load); + + if (Hint.Likely((int)length >= 3 * 8)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse4_1.max_epu16(max0, load); + min0 = Sse4_1.min_epu16(min0, load); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + v128 cmp = default(v128); + max0 = Sse4_1.max_epu16(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse4_1.min_epu16(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + + max0 = Sse4_1.max_epu16(max0, load); + min0 = Sse4_1.min_epu16(min0, load); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + + max0 = Sse4_1.max_epu16(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse4_1.min_epu16(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v128); + + max0 = Sse4_1.max_epu16(max0, load); + min0 = Sse4_1.min_epu16(min0, load); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + + max0 = Sse4_1.max_epu16(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Sse4_1.min_epu16(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.insert_epi16(cmp, *(ushort*)ptr_v128, 0); + + max = Sse4_1.max_epu16(max0, load).UShort0; + min = Sse4_1.min_epu16(min0, load).UShort0; + } + else + { + max = max0.UShort0; + min = min0.UShort0; + } + } + else if (Sse2.IsSse2Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 XOR_MASK = Sse2.set1_epi16(unchecked((short)(1 << 15))); + + v128 max0 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + + v128 min0 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + + if (Hint.Likely(length >= 32)) + { + v128 max1 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + v128 max2 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + v128 max3 = Sse2.set1_epi16(unchecked((short)ushort.MinValue)); + + v128 min1 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + v128 min2 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + v128 min3 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + load0 = Sse2.xor_si128(XOR_MASK, load0); + load1 = Sse2.xor_si128(XOR_MASK, load1); + load2 = Sse2.xor_si128(XOR_MASK, load2); + load3 = Sse2.xor_si128(XOR_MASK, load3); + + max0 = Sse2.xor_si128(XOR_MASK, max0); + max1 = Sse2.xor_si128(XOR_MASK, max1); + max2 = Sse2.xor_si128(XOR_MASK, max2); + max3 = Sse2.xor_si128(XOR_MASK, max3); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(load0, max0)); + max1 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(load1, max1)); + max2 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(load2, max2)); + max3 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(load3, max3)); + + min0 = Sse2.xor_si128(XOR_MASK, min0); + min1 = Sse2.xor_si128(XOR_MASK, min1); + min2 = Sse2.xor_si128(XOR_MASK, min2); + min3 = Sse2.xor_si128(XOR_MASK, min3); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(load0, min0)); + min1 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(load1, min1)); + min2 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(load2, min2)); + min3 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(load3, min3)); + + length -= 32; + } + while (Hint.Likely(length >= 32)); + + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(Sse2.xor_si128(XOR_MASK, max0), Sse2.xor_si128(XOR_MASK, max1))); + max2 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(Sse2.xor_si128(XOR_MASK, max2), Sse2.xor_si128(XOR_MASK, max3))); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(Sse2.xor_si128(XOR_MASK, max0), Sse2.xor_si128(XOR_MASK, max2))); + + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(Sse2.xor_si128(XOR_MASK, min0), Sse2.xor_si128(XOR_MASK, min1))); + min2 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(Sse2.xor_si128(XOR_MASK, min2), Sse2.xor_si128(XOR_MASK, min3))); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(Sse2.xor_si128(XOR_MASK, min0), Sse2.xor_si128(XOR_MASK, min2))); + } + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + load = Sse2.xor_si128(XOR_MASK, load); + + max0 = Sse2.xor_si128(XOR_MASK, max0); + min0 = Sse2.xor_si128(XOR_MASK, min0); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(max0, load)); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(min0, load)); + + if (Hint.Likely((int)length >= 2 * 8)) + { + load = Sse2.loadu_si128(ptr_v128++); + load = Sse2.xor_si128(XOR_MASK, load); + + max0 = Sse2.xor_si128(XOR_MASK, max0); + min0 = Sse2.xor_si128(XOR_MASK, min0); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(max0, load)); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(min0, load)); + + if (Hint.Likely((int)length >= 3 * 8)) + { + load = Sse2.loadu_si128(ptr_v128++); + load = Sse2.xor_si128(XOR_MASK, load); + + max0 = Sse2.xor_si128(XOR_MASK, max0); + min0 = Sse2.xor_si128(XOR_MASK, min0); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(max0, load)); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(min0, load)); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + max0 = Sse2.xor_si128(XOR_MASK, max0); + min0 = Sse2.xor_si128(XOR_MASK, min0); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2)))); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2)))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + load = Sse2.xor_si128(XOR_MASK, load); + + max0 = Sse2.xor_si128(XOR_MASK, max0); + min0 = Sse2.xor_si128(XOR_MASK, min0); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(max0, load)); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(min0, load)); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + + max0 = Sse2.xor_si128(XOR_MASK, max0); + min0 = Sse2.xor_si128(XOR_MASK, min0); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2)))); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2)))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v128); + load = Sse2.xor_si128(XOR_MASK, load); + + max0 = Sse2.xor_si128(XOR_MASK, max0); + min0 = Sse2.xor_si128(XOR_MASK, min0); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(max0, load)); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(min0, load)); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + + max0 = Sse2.xor_si128(XOR_MASK, max0); + min0 = Sse2.xor_si128(XOR_MASK, min0); + max0 = Sse2.xor_si128(XOR_MASK, Sse2.max_epi16(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1)))); + min0 = Sse2.xor_si128(XOR_MASK, Sse2.min_epi16(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1)))); + + if (Hint.Likely(length != 0)) + { + uint load = *(ushort*)ptr_v128; + + max = (ushort)math.max(max0.UShort0, load); + min = (ushort)math.min(min0.UShort0, load); + } + else + { + max = max0.UShort0; + min = min0.UShort0; + } + } + else + { + max = ushort.MinValue; + min = ushort.MaxValue; + + for (long i = 0; i < length; i++) + { + uint deref = (uint)ptr[i]; + + max = (ushort)math.max((uint)max, deref); + min = (ushort)math.min((uint)min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out ushort min, out ushort max) + { + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out ushort min, out ushort max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out ushort min, out ushort max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out ushort min, out ushort max) + { + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out ushort min, out ushort max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out ushort min, out ushort max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out ushort min, out ushort max) + { + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out ushort min, out ushort max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out ushort min, out ushort max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((ushort*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(uint* ptr, long length, out uint min, out uint max) + { +Assert.IsNonNegative(length); + + if (Avx2.IsAvx2Supported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); + + v256 min0 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); + + if (Hint.Likely(length >= 32)) + { + v256 max1 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); + v256 max2 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); + v256 max3 = Avx.mm256_set1_epi32(unchecked((int)uint.MinValue)); + + v256 min1 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); + v256 min2 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); + v256 min3 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); + + do + { + v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu32(max0, load0); + max1 = Avx2.mm256_max_epu32(max1, load1); + max2 = Avx2.mm256_max_epu32(max2, load2); + max3 = Avx2.mm256_max_epu32(max3, load3); + + min0 = Avx2.mm256_min_epu32(min0, load0); + min1 = Avx2.mm256_min_epu32(min1, load1); + min2 = Avx2.mm256_min_epu32(min2, load2); + min3 = Avx2.mm256_min_epu32(min3, load3); + + length -= 32; + } + while (Hint.Likely(length >= 32)); + + max0 = Avx2.mm256_max_epu32(max0, max1); + max2 = Avx2.mm256_max_epu32(max2, max3); + max0 = Avx2.mm256_max_epu32(max0, max2); + + min0 = Avx2.mm256_min_epu32(min0, min1); + min2 = Avx2.mm256_min_epu32(min2, min3); + min0 = Avx2.mm256_min_epu32(min0, min2); + } + + if (Hint.Likely((int)length >= 8)) + { + v256 load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu32(max0, load); + min0 = Avx2.mm256_min_epu32(min0, load); + + if (Hint.Likely((int)length >= 2 * 8)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu32(max0, load); + min0 = Avx2.mm256_min_epu32(min0, load); + + if (Hint.Likely((int)length >= 3 * 8)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epu32(max0, load); + min0 = Avx2.mm256_min_epu32(min0, load); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + v128 max128 = Sse4_1.max_epu32(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); + v128 min128 = Sse4_1.min_epu32(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.loadu_si128(ptr_v256); + + max128 = Sse4_1.max_epu32(max128, load); + min128 = Sse4_1.min_epu32(min128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + } + + max128 = Sse4_1.max_epu32(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epu32(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v256); + + max128 = Sse4_1.max_epu32(max128, load); + min128 = Sse4_1.min_epu32(min128, load); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + } + + max128 = Sse4_1.max_epu32(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse4_1.min_epu32(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v256); + + max = Sse4_1.max_epu32(max128, load).UInt0; + min = Sse4_1.min_epu32(min128, load).UInt0; + } + else + { + max = max128.UInt0; + min = min128.UInt0; + } + } + else if (Sse4_1.IsSse41Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + + v128 min0 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + + if (Hint.Likely(length >= 16)) + { + v128 max1 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + v128 max2 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + v128 max3 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + + v128 min1 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + v128 min2 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + v128 min3 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse4_1.max_epu32(max0, load0); + max1 = Sse4_1.max_epu32(max1, load1); + max2 = Sse4_1.max_epu32(max2, load2); + max3 = Sse4_1.max_epu32(max3, load3); + + min0 = Sse4_1.min_epu32(min0, load0); + min1 = Sse4_1.min_epu32(min1, load1); + min2 = Sse4_1.min_epu32(min2, load2); + min3 = Sse4_1.min_epu32(min3, load3); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = Sse4_1.max_epu32(max0, max1); + max2 = Sse4_1.max_epu32(max2, max3); + max0 = Sse4_1.max_epu32(max0, max2); + + min0 = Sse4_1.min_epu32(min0, min1); + min2 = Sse4_1.min_epu32(min2, min3); + min0 = Sse4_1.min_epu32(min0, min2); + } + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse4_1.max_epu32(max0, load); + min0 = Sse4_1.min_epu32(min0, load); + + if (Hint.Likely((int)length >= 2 * 4)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse4_1.max_epu32(max0, load); + min0 = Sse4_1.min_epu32(min0, load); + + if (Hint.Likely((int)length >= 3 * 4)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse4_1.max_epu32(max0, load); + min0 = Sse4_1.min_epu32(min0, load); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + + max0 = Sse4_1.max_epu32(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse4_1.min_epu32(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + + max0 = Sse4_1.max_epu32(max0, load); + min0 = Sse4_1.min_epu32(min0, load); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + + max0 = Sse4_1.max_epu32(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Sse4_1.min_epu32(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v128); + + max = Sse4_1.max_epu32(max0, load).UInt0; + min = Sse4_1.min_epu32(min0, load).UInt0; + } + else + { + max = max0.UInt0; + min = min0.UInt0; + } + } + else if (Sse2.IsSse2Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 XOR_MASK = Sse2.set1_epi32(unchecked((int)(1 << 31))); + + v128 max0 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + + v128 min0 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + + if (Hint.Likely(length >= 16)) + { + v128 max1 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + v128 max2 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + v128 max3 = Sse2.set1_epi32(unchecked((int)uint.MinValue)); + + v128 min1 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + v128 min2 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + v128 min3 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + v128 xor_load0 = Sse2.xor_si128(XOR_MASK, load0); + v128 xor_load1 = Sse2.xor_si128(XOR_MASK, load1); + v128 xor_load2 = Sse2.xor_si128(XOR_MASK, load2); + v128 xor_load3 = Sse2.xor_si128(XOR_MASK, load3); + + max0 = blendv_epi8_SSE2(max0, load0, Sse2.cmpgt_epi32(xor_load0, Sse2.xor_si128(XOR_MASK, max0))); + max1 = blendv_epi8_SSE2(max1, load1, Sse2.cmpgt_epi32(xor_load1, Sse2.xor_si128(XOR_MASK, max1))); + max2 = blendv_epi8_SSE2(max2, load2, Sse2.cmpgt_epi32(xor_load2, Sse2.xor_si128(XOR_MASK, max2))); + max3 = blendv_epi8_SSE2(max3, load3, Sse2.cmpgt_epi32(xor_load3, Sse2.xor_si128(XOR_MASK, max3))); + + min0 = blendv_epi8_SSE2(load0, min0, Sse2.cmpgt_epi32(xor_load0, Sse2.xor_si128(XOR_MASK, min0))); + min1 = blendv_epi8_SSE2(load1, min1, Sse2.cmpgt_epi32(xor_load1, Sse2.xor_si128(XOR_MASK, min1))); + min2 = blendv_epi8_SSE2(load2, min2, Sse2.cmpgt_epi32(xor_load2, Sse2.xor_si128(XOR_MASK, min2))); + min3 = blendv_epi8_SSE2(load3, min3, Sse2.cmpgt_epi32(xor_load3, Sse2.xor_si128(XOR_MASK, min3))); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = blendv_epi8_SSE2(max0, max1, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, max1), Sse2.xor_si128(XOR_MASK, max0))); + max2 = blendv_epi8_SSE2(max2, max3, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, max3), Sse2.xor_si128(XOR_MASK, max2))); + max0 = blendv_epi8_SSE2(max0, max2, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, max2), Sse2.xor_si128(XOR_MASK, max0))); + + min0 = blendv_epi8_SSE2(min1, min0, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, min1), Sse2.xor_si128(XOR_MASK, min0))); + min2 = blendv_epi8_SSE2(min3, min2, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, min3), Sse2.xor_si128(XOR_MASK, min2))); + min0 = blendv_epi8_SSE2(min2, min0, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, min2), Sse2.xor_si128(XOR_MASK, min0))); + } + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + v128 xor_load = Sse2.xor_si128(XOR_MASK, load); + + max0 = blendv_epi8_SSE2(max0, load, Sse2.cmpgt_epi32(xor_load, Sse2.xor_si128(XOR_MASK, max0))); + min0 = blendv_epi8_SSE2(load, min0, Sse2.cmpgt_epi32(xor_load, Sse2.xor_si128(XOR_MASK, min0))); + + if (Hint.Likely((int)length >= 2 * 4)) + { + load = Sse2.loadu_si128(ptr_v128++); + xor_load = Sse2.xor_si128(XOR_MASK, load); + + max0 = blendv_epi8_SSE2(max0, load, Sse2.cmpgt_epi32(xor_load, Sse2.xor_si128(XOR_MASK, max0))); + min0 = blendv_epi8_SSE2(load, min0, Sse2.cmpgt_epi32(xor_load, Sse2.xor_si128(XOR_MASK, min0))); + + if (Hint.Likely((int)length >= 3 * 4)) + { + load = Sse2.loadu_si128(ptr_v128++); + xor_load = Sse2.xor_si128(XOR_MASK, load); + + max0 = blendv_epi8_SSE2(max0, load, Sse2.cmpgt_epi32(xor_load, Sse2.xor_si128(XOR_MASK, max0))); + min0 = blendv_epi8_SSE2(load, min0, Sse2.cmpgt_epi32(xor_load, Sse2.xor_si128(XOR_MASK, min0))); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + v128 maxShuf = Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2)); + max0 = blendv_epi8_SSE2(max0, maxShuf, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, maxShuf), Sse2.xor_si128(XOR_MASK, max0))); + v128 minShuf = Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2)); + min0 = blendv_epi8_SSE2(minShuf, min0, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, minShuf), Sse2.xor_si128(XOR_MASK, min0))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + v128 xor_load = Sse2.xor_si128(XOR_MASK, load); + + max0 = blendv_epi8_SSE2(max0, load, Sse2.cmpgt_epi32(xor_load, Sse2.xor_si128(XOR_MASK, max0))); + min0 = blendv_epi8_SSE2(load, min0, Sse2.cmpgt_epi32(xor_load, Sse2.xor_si128(XOR_MASK, min0))); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + + maxShuf = Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 0, 1)); + max0 = blendv_epi8_SSE2(max0, maxShuf, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, maxShuf), Sse2.xor_si128(XOR_MASK, max0))); + minShuf = Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 0, 1)); + min0 = blendv_epi8_SSE2(minShuf, min0, Sse2.cmpgt_epi32(Sse2.xor_si128(XOR_MASK, minShuf), Sse2.xor_si128(XOR_MASK, min0))); + + if (Hint.Likely(length != 0)) + { + uint load = *(uint*)ptr_v128; + + max = math.max(max0.UInt0, load); + min = math.min(min0.UInt0, load); + } + else + { + max = max0.UInt0; + min = min0.UInt0; + } + } + else + { + max = uint.MinValue; + min = uint.MaxValue; + + for (long i = 0; i < length; i++) + { + uint deref = ptr[i]; + + max = math.max(max, deref); + min = math.min(min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out uint min, out uint max) + { + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out uint min, out uint max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out uint min, out uint max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out uint min, out uint max) + { + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out uint min, out uint max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out uint min, out uint max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out uint min, out uint max) + { + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out uint min, out uint max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out uint min, out uint max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((uint*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(ulong* ptr, long length, out ulong min, out ulong max) + { +Assert.IsNonNegative(length); + + if (Avx2.IsAvx2Supported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 XOR_MASK = Avx.mm256_set1_epi64x(1L << 63); + + v256 max0 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); + + v256 min0 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); + + if (Hint.Likely(length >= 16)) + { + v256 max1 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); + v256 max2 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); + v256 max3 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MinValue)); + + v256 min1 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); + v256 min2 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); + v256 min3 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); + + do + { + v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + v256 xor_load0 = Avx2.mm256_xor_si256(XOR_MASK, load0); + v256 xor_load1 = Avx2.mm256_xor_si256(XOR_MASK, load1); + v256 xor_load2 = Avx2.mm256_xor_si256(XOR_MASK, load2); + v256 xor_load3 = Avx2.mm256_xor_si256(XOR_MASK, load3); + + max0 = Avx2.mm256_blendv_epi8(max0, xor_load0, Avx2.mm256_cmpgt_epi64(xor_load0, Avx2.mm256_xor_si256(max0, XOR_MASK))); + max1 = Avx2.mm256_blendv_epi8(max1, xor_load1, Avx2.mm256_cmpgt_epi64(xor_load1, Avx2.mm256_xor_si256(max1, XOR_MASK))); + max2 = Avx2.mm256_blendv_epi8(max2, xor_load2, Avx2.mm256_cmpgt_epi64(xor_load2, Avx2.mm256_xor_si256(max2, XOR_MASK))); + max3 = Avx2.mm256_blendv_epi8(max3, xor_load3, Avx2.mm256_cmpgt_epi64(xor_load3, Avx2.mm256_xor_si256(max3, XOR_MASK))); + + min0 = Avx2.mm256_blendv_epi8(xor_load0, min0, Avx2.mm256_cmpgt_epi64(xor_load0, Avx2.mm256_xor_si256(min0, XOR_MASK))); + min1 = Avx2.mm256_blendv_epi8(xor_load1, min1, Avx2.mm256_cmpgt_epi64(xor_load1, Avx2.mm256_xor_si256(min1, XOR_MASK))); + min2 = Avx2.mm256_blendv_epi8(xor_load2, min2, Avx2.mm256_cmpgt_epi64(xor_load2, Avx2.mm256_xor_si256(min2, XOR_MASK))); + min3 = Avx2.mm256_blendv_epi8(xor_load3, min3, Avx2.mm256_cmpgt_epi64(xor_load3, Avx2.mm256_xor_si256(min3, XOR_MASK))); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = Avx2.mm256_blendv_epi8(max1, max0, Avx2.mm256_cmpgt_epi64(Avx2.mm256_xor_si256(max0, XOR_MASK), Avx2.mm256_xor_si256(max1, XOR_MASK))); + max2 = Avx2.mm256_blendv_epi8(max3, max2, Avx2.mm256_cmpgt_epi64(Avx2.mm256_xor_si256(max2, XOR_MASK), Avx2.mm256_xor_si256(max3, XOR_MASK))); + max0 = Avx2.mm256_blendv_epi8(max0, max2, Avx2.mm256_cmpgt_epi64(Avx2.mm256_xor_si256(max2, XOR_MASK), Avx2.mm256_xor_si256(max0, XOR_MASK))); + + min0 = Avx2.mm256_blendv_epi8(min0, min1, Avx2.mm256_cmpgt_epi64(Avx2.mm256_xor_si256(min0, XOR_MASK), Avx2.mm256_xor_si256(min1, XOR_MASK))); + min2 = Avx2.mm256_blendv_epi8(min2, min3, Avx2.mm256_cmpgt_epi64(Avx2.mm256_xor_si256(min2, XOR_MASK), Avx2.mm256_xor_si256(min3, XOR_MASK))); + min0 = Avx2.mm256_blendv_epi8(min2, min0, Avx2.mm256_cmpgt_epi64(Avx2.mm256_xor_si256(min2, XOR_MASK), Avx2.mm256_xor_si256(min0, XOR_MASK))); + } + + if (Hint.Likely((int)length >= 4)) + { + v256 load = Avx.mm256_loadu_si256(ptr_v256++); + v256 xor_load = Avx2.mm256_xor_si256(XOR_MASK, load); + + max0 = Avx2.mm256_blendv_epi8(max0, xor_load, Avx2.mm256_cmpgt_epi64(xor_load, Avx2.mm256_xor_si256(max0, XOR_MASK))); + min0 = Avx2.mm256_blendv_epi8(xor_load, min0, Avx2.mm256_cmpgt_epi64(xor_load, Avx2.mm256_xor_si256(min0, XOR_MASK))); + + if (Hint.Likely((int)length >= 2 * 4)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + xor_load = Avx2.mm256_xor_si256(XOR_MASK, load); + + max0 = Avx2.mm256_blendv_epi8(max0, xor_load, Avx2.mm256_cmpgt_epi64(xor_load, Avx2.mm256_xor_si256(max0, XOR_MASK))); + min0 = Avx2.mm256_blendv_epi8(xor_load, min0, Avx2.mm256_cmpgt_epi64(xor_load, Avx2.mm256_xor_si256(min0, XOR_MASK))); + + if (Hint.Likely((int)length >= 3 * 4)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + xor_load = Avx2.mm256_xor_si256(XOR_MASK, load); + + max0 = Avx2.mm256_blendv_epi8(max0, xor_load, Avx2.mm256_cmpgt_epi64(xor_load, Avx2.mm256_xor_si256(max0, XOR_MASK))); + min0 = Avx2.mm256_blendv_epi8(xor_load, min0, Avx2.mm256_cmpgt_epi64(xor_load, Avx2.mm256_xor_si256(min0, XOR_MASK))); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + v128 maxLo = Avx.mm256_castsi256_si128(max0); + v128 maxHi = Avx2.mm256_extracti128_si256(max0, 1); + v128 max128 = Sse4_1.blendv_epi8(maxHi, maxLo, Sse4_2.cmpgt_epi64(Sse2.xor_si128(Avx.mm256_castsi256_si128(XOR_MASK), maxLo), Sse2.xor_si128(Avx.mm256_castsi256_si128(XOR_MASK), maxHi))); + v128 minLo = Avx.mm256_castsi256_si128(min0); + v128 minHi = Avx2.mm256_extracti128_si256(min0, 1); + v128 min128 = Sse4_1.blendv_epi8(minLo, minHi, Sse4_2.cmpgt_epi64(Sse2.xor_si128(Avx.mm256_castsi256_si128(XOR_MASK), minLo), Sse2.xor_si128(Avx.mm256_castsi256_si128(XOR_MASK), minHi))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.loadu_si128(ptr_v256); + v128 xor_load = Sse2.xor_si128(Avx.mm256_castsi256_si128(XOR_MASK), load); + + max128 = Sse4_1.blendv_epi8(max128, load, Sse4_2.cmpgt_epi64(xor_load, Sse2.xor_si128(Avx.mm256_castsi256_si128(XOR_MASK), max128))); + min128 = Sse4_1.blendv_epi8(load, min128, Sse4_2.cmpgt_epi64(xor_load, Sse2.xor_si128(Avx.mm256_castsi256_si128(XOR_MASK), min128))); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 2; + } + + if (Hint.Likely(length != 0)) + { + ulong load = *(ulong*)ptr_v256; + + max = math.max(load, math.max(max128.ULong0, max128.ULong1)); + min = math.min(load, math.min(min128.ULong0, min128.ULong1)); + } + else + { + max = math.max(max128.ULong0, max128.ULong1); + min = math.min(min128.ULong0, min128.ULong1); + } + } + else if (Sse4_2.IsSse42Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 XOR_MASK = Sse2.set1_epi64x(1L << 63); + + v128 max0 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); + + v128 min0 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); + + if (Hint.Likely(length >= 8)) + { + v128 max1 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); + v128 max2 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); + v128 max3 = Sse2.set1_epi64x(unchecked((long)ulong.MinValue)); + + v128 min1 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); + v128 min2 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); + v128 min3 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); + + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + v128 xor_load0 = Sse2.xor_si128(XOR_MASK, load0); + v128 xor_load1 = Sse2.xor_si128(XOR_MASK, load1); + v128 xor_load2 = Sse2.xor_si128(XOR_MASK, load2); + v128 xor_load3 = Sse2.xor_si128(XOR_MASK, load3); + + max0 = Sse4_1.blendv_epi8(max0, load0, Sse4_2.cmpgt_epi64(xor_load0, Sse2.xor_si128(XOR_MASK, max0))); + max1 = Sse4_1.blendv_epi8(max1, load1, Sse4_2.cmpgt_epi64(xor_load1, Sse2.xor_si128(XOR_MASK, max1))); + max2 = Sse4_1.blendv_epi8(max2, load2, Sse4_2.cmpgt_epi64(xor_load2, Sse2.xor_si128(XOR_MASK, max2))); + max3 = Sse4_1.blendv_epi8(max3, load3, Sse4_2.cmpgt_epi64(xor_load3, Sse2.xor_si128(XOR_MASK, max3))); + + min0 = Sse4_1.blendv_epi8(load0, min0, Sse4_2.cmpgt_epi64(xor_load0, Sse2.xor_si128(XOR_MASK, min0))); + min1 = Sse4_1.blendv_epi8(load1, min1, Sse4_2.cmpgt_epi64(xor_load1, Sse2.xor_si128(XOR_MASK, min1))); + min2 = Sse4_1.blendv_epi8(load2, min2, Sse4_2.cmpgt_epi64(xor_load2, Sse2.xor_si128(XOR_MASK, min2))); + min3 = Sse4_1.blendv_epi8(load3, min3, Sse4_2.cmpgt_epi64(xor_load3, Sse2.xor_si128(XOR_MASK, min3))); + + length -= 8; + } + while (Hint.Likely(length >= 8)); + + max0 = Sse4_1.blendv_epi8(max0, max1, Sse4_2.cmpgt_epi64(Sse2.xor_si128(XOR_MASK, max1), Sse2.xor_si128(XOR_MASK, max0))); + max2 = Sse4_1.blendv_epi8(max2, max3, Sse4_2.cmpgt_epi64(Sse2.xor_si128(XOR_MASK, max3), Sse2.xor_si128(XOR_MASK, max2))); + max0 = Sse4_1.blendv_epi8(max0, max2, Sse4_2.cmpgt_epi64(Sse2.xor_si128(XOR_MASK, max2), Sse2.xor_si128(XOR_MASK, max0))); + + min0 = Sse4_1.blendv_epi8(min1, min0, Sse4_2.cmpgt_epi64(Sse2.xor_si128(XOR_MASK, min1), Sse2.xor_si128(XOR_MASK, min0))); + min2 = Sse4_1.blendv_epi8(min3, min2, Sse4_2.cmpgt_epi64(Sse2.xor_si128(XOR_MASK, min3), Sse2.xor_si128(XOR_MASK, min2))); + min0 = Sse4_1.blendv_epi8(min2, min0, Sse4_2.cmpgt_epi64(Sse2.xor_si128(XOR_MASK, min2), Sse2.xor_si128(XOR_MASK, min0))); + } + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + v128 xor_load = Sse2.xor_si128(XOR_MASK, load); + + max0 = Sse4_1.blendv_epi8(max0, load, Sse4_2.cmpgt_epi64(xor_load, Sse2.xor_si128(XOR_MASK, max0))); + min0 = Sse4_1.blendv_epi8(load, min0, Sse4_2.cmpgt_epi64(xor_load, Sse2.xor_si128(XOR_MASK, min0))); + + if (Hint.Likely((int)length >= 2 * 2)) + { + load = Sse2.loadu_si128(ptr_v128++); + xor_load = Sse2.xor_si128(XOR_MASK, load); + + max0 = Sse4_1.blendv_epi8(max0, load, Sse4_2.cmpgt_epi64(xor_load, Sse2.xor_si128(XOR_MASK, max0))); + min0 = Sse4_1.blendv_epi8(load, min0, Sse4_2.cmpgt_epi64(xor_load, Sse2.xor_si128(XOR_MASK, min0))); + + if (Hint.Likely((int)length >= 3 * 2)) + { + load = Sse2.loadu_si128(ptr_v128++); + xor_load = Sse2.xor_si128(XOR_MASK, load); + + max0 = Sse4_1.blendv_epi8(max0, load, Sse4_2.cmpgt_epi64(xor_load, Sse2.xor_si128(XOR_MASK, max0))); + min0 = Sse4_1.blendv_epi8(load, min0, Sse4_2.cmpgt_epi64(xor_load, Sse2.xor_si128(XOR_MASK, min0))); + + length -= 3 * 2; + } + else + { + length -= 2 * 2; + } + } + else + { + length -= 2; + } + } + else { } + + if (Hint.Likely(length != 0)) + { + ulong load = *(ulong*)ptr_v128; + + max = math.max(load, math.max(max0.ULong0, max0.ULong1)); + min = math.min(load, math.min(min0.ULong0, min0.ULong1)); + } + else + { + max = math.max(max0.ULong0, max0.ULong1); + min = math.min(min0.ULong0, min0.ULong1); + } + } + else + { + max = ulong.MinValue; + min = ulong.MaxValue; + + for (long i = 0; i < length; i++) + { + ulong deref = ptr[i]; + + max = math.max(max, deref); + min = math.min(min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out ulong min, out ulong max) + { + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out ulong min, out ulong max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out ulong min, out ulong max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out ulong min, out ulong max) + { + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out ulong min, out ulong max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out ulong min, out ulong max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out ulong min, out ulong max) + { + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out ulong min, out ulong max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out ulong min, out ulong max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((ulong*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(sbyte* ptr, long length, out sbyte min, out sbyte max) + { + static v128 Min(v128 a, v128 b) + { + if (Sse4_1.IsSse41Supported) + { + return Sse4_1.min_epi8(b, a); + } + else if (Sse2.IsSse2Supported) + { + v128 greaterMask = Sse2.cmpgt_epi8(a, b); + + return Sse2.or_si128(Sse2.and_si128(greaterMask, b), + Sse2.andnot_si128(greaterMask, a)); + } + else + { + return default(v128); + } + } + + static v128 Max(v128 a, v128 b) + { + if (Sse4_1.IsSse41Supported) + { + return Sse4_1.max_epi8(b, a); + } + else if (Sse2.IsSse2Supported) + { + v128 greaterMask = Sse2.cmpgt_epi8(b, a); + + return Sse2.or_si128(Sse2.and_si128(greaterMask, b), + Sse2.andnot_si128(greaterMask, a)); + } + else + { + return default(v128); + } + } + +Assert.IsNonNegative(length); + + if (Avx2.IsAvx2Supported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); + + v256 min0 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MaxValue)); + + if (Hint.Likely(length >= 128)) + { + v256 max1 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); + v256 max2 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); + v256 max3 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MinValue)); + + v256 min1 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MaxValue)); + v256 min2 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MaxValue)); + v256 min3 = Avx.mm256_set1_epi8(unchecked((byte)sbyte.MaxValue)); + + do + { + v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi8(max0, load0); + max1 = Avx2.mm256_max_epi8(max1, load1); + max2 = Avx2.mm256_max_epi8(max2, load2); + max3 = Avx2.mm256_max_epi8(max3, load3); + + min0 = Avx2.mm256_min_epi8(min0, load0); + min1 = Avx2.mm256_min_epi8(min1, load1); + min2 = Avx2.mm256_min_epi8(min2, load2); + min3 = Avx2.mm256_min_epi8(min3, load3); + + length -= 128; + } + while (Hint.Likely(length >= 128)); + + max0 = Avx2.mm256_max_epi8(max0, max1); + max2 = Avx2.mm256_max_epi8(max2, max3); + max0 = Avx2.mm256_max_epi8(max0, max2); + + min0 = Avx2.mm256_min_epi8(min0, min1); + min2 = Avx2.mm256_min_epi8(min2, min3); + min0 = Avx2.mm256_min_epi8(min0, min2); + } + + if (Hint.Likely((int)length >= 32)) + { + v256 load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi8(max0, load); + min0 = Avx2.mm256_min_epi8(min0, load); + + if (Hint.Likely((int)length >= 2 * 32)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi8(max0, load); + min0 = Avx2.mm256_min_epi8(min0, load); + + if (Hint.Likely((int)length >= 3 * 32)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi8(max0, load); + min0 = Avx2.mm256_min_epi8(min0, load); + + length -= 3 * 32; + } + else + { + length -= 2 * 32; + } + } + else + { + length -= 32; + } + } + else { } + + v128 max128 = Sse4_1.max_epi8(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); + v128 min128 = Sse4_1.min_epi8(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); + + if (Hint.Likely((int)length >= 16)) + { + v128 load = Sse2.loadu_si128(ptr_v256); + + max128 = Sse4_1.max_epi8(max128, load); + min128 = Sse4_1.min_epi8(min128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + + length -= 16; + } + + v128 cmp = default(v128); + max128 = Sse4_1.max_epi8(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epi8(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v256); + + max128 = Sse4_1.max_epi8(max128, load); + min128 = Sse4_1.min_epi8(min128, load); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 8; + } + + max128 = Sse4_1.max_epi8(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epi8(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v256); + + max128 = Sse4_1.max_epi8(max128, load); + min128 = Sse4_1.min_epi8(min128, load); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 4; + } + + max128 = Sse4_1.max_epi8(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse4_1.min_epi8(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0); + + max128 = Sse4_1.max_epi8(max128, load); + min128 = Sse4_1.min_epi8(min128, load); + + ptr_v256 = (v256*)((short*)ptr_v256 + 1); + length -= 2; + } + + max128 = Sse4_1.max_epi8(max128, Sse2.bsrli_si128(max128, 1 * sizeof(sbyte))); + min128 = Sse4_1.min_epi8(min128, Sse2.bsrli_si128(min128, 1 * sizeof(sbyte))); + + if (Hint.Likely(length != 0)) + { + max = Sse4_1.min_epi8(max128, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0)).SByte0; + min = Sse4_1.min_epi8(min128, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0)).SByte0; + } + else + { + max = max128.SByte0; + min = min128.SByte0; + } + } + else if (Sse2.IsSse2Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = Sse2.set1_epi8(sbyte.MinValue); + + v128 min0 = Sse2.set1_epi8(sbyte.MaxValue); + + if (Hint.Likely(length >= 64)) + { + v128 max1 = Sse2.set1_epi8(sbyte.MinValue); + v128 max2 = Sse2.set1_epi8(sbyte.MinValue); + v128 max3 = Sse2.set1_epi8(sbyte.MinValue); + + v128 min1 = Sse2.set1_epi8(sbyte.MaxValue); + v128 min2 = Sse2.set1_epi8(sbyte.MaxValue); + v128 min3 = Sse2.set1_epi8(sbyte.MaxValue); + + do + { + max0 = Max(max0, Sse2.loadu_si128(ptr_v128++)); + max1 = Max(max1, Sse2.loadu_si128(ptr_v128++)); + max2 = Max(max2, Sse2.loadu_si128(ptr_v128++)); + max3 = Max(max3, Sse2.loadu_si128(ptr_v128++)); + + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); + min1 = Min(min1, Sse2.loadu_si128(ptr_v128++)); + min2 = Min(min2, Sse2.loadu_si128(ptr_v128++)); + min3 = Min(min3, Sse2.loadu_si128(ptr_v128++)); + + length -= 64; + } + while (Hint.Likely(length >= 64)); + + max0 = Max(max0, max1); + max2 = Max(max2, max3); + max0 = Max(max0, max2); + + min0 = Min(min0, min1); + min2 = Min(min2, min3); + min0 = Min(min0, min2); + } + + if (Hint.Likely((int)length >= 16)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + if (Hint.Likely((int)length >= 2 * 16)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + if (Hint.Likely((int)length >= 3 * 16)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + v128 cmp = default(v128); + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + + max0 = Max(max0, load); + max0 = Max(max0, load); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 8; + } + + max0 = Max(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v128); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 4; + } + + max0 = Max(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Min(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + ptr_v128 = (v128*)((short*)ptr_v128 + 1); + length -= 2; + } + + max0 = Max(max0, Sse2.bsrli_si128(max0, 1 * sizeof(sbyte))); + min0 = Min(min0, Sse2.bsrli_si128(min0, 1 * sizeof(sbyte))); + + if (Hint.Likely(length != 0)) + { + if (Sse4_1.IsSse41Supported) + { + v128 load = Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0); + + max = Sse4_1.max_epi8(max0, load).SByte0; + min = Sse4_1.min_epi8(min0, load).SByte0; + } + else + { + max = (sbyte)math.max((int)max0.SByte0, (int)(*(sbyte*)ptr_v128)); + min = (sbyte)math.min((int)min0.SByte0, (int)(*(sbyte*)ptr_v128)); + } + } + else + { + max = max0.SByte0; + min = min0.SByte0; + } + } + else + { + max = sbyte.MinValue; + min = sbyte.MaxValue; + + for (long i = 0; i < length; i++) + { + sbyte deref = ptr[i]; + + max = (sbyte)math.max(max, deref); + min = (sbyte)math.min(min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out sbyte min, out sbyte max) + { + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out sbyte min, out sbyte max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out sbyte min, out sbyte max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out sbyte min, out sbyte max) + { + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out sbyte min, out sbyte max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out sbyte min, out sbyte max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out sbyte min, out sbyte max) + { + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out sbyte min, out sbyte max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out sbyte min, out sbyte max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((sbyte*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(short* ptr, long length, out short min, out short max) + { +Assert.IsNonNegative(length); + + if (Avx2.IsAvx2Supported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = Avx.mm256_set1_epi16(short.MinValue); + + v256 min0 = Avx.mm256_set1_epi16(short.MaxValue); + + if (Hint.Likely(length >= 64)) + { + v256 max1 = Avx.mm256_set1_epi16(short.MinValue); + v256 max2 = Avx.mm256_set1_epi16(short.MinValue); + v256 max3 = Avx.mm256_set1_epi16(short.MinValue); + + v256 min1 = Avx.mm256_set1_epi16(short.MaxValue); + v256 min2 = Avx.mm256_set1_epi16(short.MaxValue); + v256 min3 = Avx.mm256_set1_epi16(short.MaxValue); + + do + { + v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi16(max0, load0); + max1 = Avx2.mm256_max_epi16(max1, load1); + max2 = Avx2.mm256_max_epi16(max2, load2); + max3 = Avx2.mm256_max_epi16(max3, load3); + + min0 = Avx2.mm256_min_epi16(min0, load0); + min1 = Avx2.mm256_min_epi16(min1, load1); + min2 = Avx2.mm256_min_epi16(min2, load2); + min3 = Avx2.mm256_min_epi16(min3, load3); + + length -= 64; + } + while (Hint.Likely(length >= 64)); + + max0 = Avx2.mm256_max_epi16(max0, max1); + max2 = Avx2.mm256_max_epi16(max2, max3); + max0 = Avx2.mm256_max_epi16(max0, max2); + + min0 = Avx2.mm256_min_epi16(min0, min1); + min2 = Avx2.mm256_min_epi16(min2, min3); + min0 = Avx2.mm256_min_epi16(min0, min2); + } + + if (Hint.Likely((int)length >= 16)) + { + v256 load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi16(max0, load); + min0 = Avx2.mm256_min_epi16(min0, load); + + if (Hint.Likely((int)length >= 2 * 16)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi16(max0, load); + min0 = Avx2.mm256_min_epi16(min0, load); + + if (Hint.Likely((int)length >= 3 * 16)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi16(max0, load); + min0 = Avx2.mm256_min_epi16(min0, load); + + length -= 3 * 16; + } + else + { + length -= 2 * 16; + } + } + else + { + length -= 16; + } + } + else { } + + v128 max128 = Sse2.max_epi16(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); + v128 min128 = Sse2.min_epi16(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.loadu_si128(ptr_v256); + + max128 = Sse2.max_epi16(max128, load); + min128 = Sse2.min_epi16(min128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + + length -= 8; + } + + v128 cmp = default(v128); + max128 = Sse2.max_epi16(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse2.min_epi16(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v256); + + max128 = Sse2.max_epi16(max128, load); + min128 = Sse2.min_epi16(min128, load); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 4; + } + + max128 = Sse2.max_epi16(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse2.min_epi16(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v256); + + max128 = Sse2.max_epi16(max128, load); + min128 = Sse2.min_epi16(min128, load); + + ptr_v256 = (v256*)((int*)ptr_v256 + 1); + length -= 2; + } + + max128 = Sse2.max_epi16(max128, Sse2.shufflelo_epi16(max128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse2.min_epi16(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0); + + max = Sse2.max_epi16(max128, load).SShort0; + min = Sse2.min_epi16(min128, load).SShort0; + } + else + { + max = max128.SShort0; + min = min128.SShort0; + } + } + else if (Sse2.IsSse2Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = Sse2.set1_epi16(short.MinValue); + + v128 min0 = Sse2.set1_epi16(short.MaxValue); + + if (Hint.Likely(length >= 32)) + { + v128 max1 = Sse2.set1_epi16(short.MinValue); + v128 max2 = Sse2.set1_epi16(short.MinValue); + v128 max3 = Sse2.set1_epi16(short.MinValue); + + v128 min1 = Sse2.set1_epi16(short.MaxValue); + v128 min2 = Sse2.set1_epi16(short.MaxValue); + v128 min3 = Sse2.set1_epi16(short.MaxValue); + + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse2.max_epi16(max0, load0); + max1 = Sse2.max_epi16(max1, load1); + max2 = Sse2.max_epi16(max2, load2); + max3 = Sse2.max_epi16(max3, load3); + + min0 = Sse2.min_epi16(min0, load0); + min1 = Sse2.min_epi16(min1, load1); + min2 = Sse2.min_epi16(min2, load2); + min3 = Sse2.min_epi16(min3, load3); + + length -= 32; + } + while (Hint.Likely(length >= 32)); + + max0 = Sse2.max_epi16(max0, max1); + max2 = Sse2.max_epi16(max2, max3); + max0 = Sse2.max_epi16(max0, max2); + + min0 = Sse2.min_epi16(min0, min1); + min2 = Sse2.min_epi16(min2, min3); + min0 = Sse2.min_epi16(min0, min2); + } + + if (Hint.Likely((int)length >= 8)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse2.max_epi16(max0, load); + min0 = Sse2.min_epi16(min0, load); + + if (Hint.Likely((int)length >= 2 * 8)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse2.max_epi16(max0, load); + min0 = Sse2.min_epi16(min0, load); + + if (Hint.Likely((int)length >= 3 * 8)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Sse2.max_epi16(max0, load); + min0 = Sse2.min_epi16(min0, load); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + v128 cmp = default(v128); + max0 = Sse2.max_epi16(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_epi16(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + + max0 = Sse2.max_epi16(max0, load); + min0 = Sse2.min_epi16(min0, load); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 4; + } + + max0 = Sse2.max_epi16(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_epi16(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v128); + + max0 = Sse2.max_epi16(max0, load); + min0 = Sse2.min_epi16(min0, load); + + ptr_v128 = (v128*)((int*)ptr_v128 + 1); + length -= 2; + } + + max0 = Sse2.max_epi16(max0, Sse2.shufflelo_epi16(max0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Sse2.min_epi16(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0); + + max = Sse2.max_epi16(max0, load).SShort0; + min = Sse2.min_epi16(min0, load).SShort0; + } + else + { + max = max0.SShort0; + min = min0.SShort0; + } + } + else + { + max = short.MinValue; + min = short.MaxValue; + + for (long i = 0; i < length; i++) + { + short deref = ptr[i]; + + max = (short)math.max(max, deref); + min = (short)math.min(min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out short min, out short max) + { + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out short min, out short max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out short min, out short max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out short min, out short max) + { + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out short min, out short max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out short min, out short max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out short min, out short max) + { + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out short min, out short max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out short min, out short max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((short*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(int* ptr, long length, out int min, out int max) + { + static v128 Min(v128 a, v128 b) + { + if (Sse4_1.IsSse41Supported) + { + return Sse4_1.max_epi32(b, a); + } + else if (Sse2.IsSse2Supported) + { + v128 greaterMask = Sse2.cmpgt_epi32(a, b); + + return Sse2.or_si128(Sse2.and_si128(greaterMask, b), + Sse2.andnot_si128(greaterMask, a)); + } + else + { + return default(v128); + } + } + + static v128 Max(v128 a, v128 b) + { + if (Sse4_1.IsSse41Supported) + { + return Sse4_1.max_epi32(b, a); + } + else if (Sse2.IsSse2Supported) + { + v128 greaterMask = Sse2.cmpgt_epi32(b, a); + + return Sse2.or_si128(Sse2.and_si128(greaterMask, b), + Sse2.andnot_si128(greaterMask, a)); + } + else + { + return default(v128); + } + } + +Assert.IsNonNegative(length); + + if (Avx2.IsAvx2Supported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = Avx.mm256_set1_epi32(int.MinValue); + + v256 min0 = Avx.mm256_set1_epi32(int.MaxValue); + + if (Hint.Likely(length >= 32)) + { + v256 max1 = Avx.mm256_set1_epi32(int.MinValue); + v256 max2 = Avx.mm256_set1_epi32(int.MinValue); + v256 max3 = Avx.mm256_set1_epi32(int.MinValue); + + v256 min1 = Avx.mm256_set1_epi32(int.MaxValue); + v256 min2 = Avx.mm256_set1_epi32(int.MaxValue); + v256 min3 = Avx.mm256_set1_epi32(int.MaxValue); + + do + { + v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi32(max0, load0); + max1 = Avx2.mm256_max_epi32(max1, load1); + max2 = Avx2.mm256_max_epi32(max2, load2); + max3 = Avx2.mm256_max_epi32(max3, load3); + + min0 = Avx2.mm256_min_epi32(min0, load0); + min1 = Avx2.mm256_min_epi32(min1, load1); + min2 = Avx2.mm256_min_epi32(min2, load2); + min3 = Avx2.mm256_min_epi32(min3, load3); + + length -= 32; + } + while (Hint.Likely(length >= 32)); + + max0 = Avx2.mm256_max_epi32(max0, max1); + max2 = Avx2.mm256_max_epi32(max2, max3); + max0 = Avx2.mm256_max_epi32(max0, max2); + + min0 = Avx2.mm256_min_epi32(min0, min1); + min2 = Avx2.mm256_min_epi32(min2, min3); + min0 = Avx2.mm256_min_epi32(min0, min2); + } + + if (Hint.Likely((int)length >= 8)) + { + v256 load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi32(max0, load); + min0 = Avx2.mm256_min_epi32(min0, load); + + if (Hint.Likely((int)length >= 2 * 8)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi32(max0, load); + min0 = Avx2.mm256_min_epi32(min0, load); + + if (Hint.Likely((int)length >= 3 * 8)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Avx2.mm256_max_epi32(max0, load); + min0 = Avx2.mm256_min_epi32(min0, load); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + v128 max128 = Sse4_1.max_epi32(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); + v128 min128 = Sse4_1.min_epi32(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.loadu_si128(ptr_v256); + + max128 = Sse4_1.max_epi32(max128, load); + max128 = Sse4_1.max_epi32(max128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 4; + } + + max128 = Sse4_1.max_epi32(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epi32(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v256); + + max128 = Sse4_1.max_epi32(max128, load); + min128 = Sse4_1.min_epi32(min128, load); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + length -= 2; + } + + max128 = Sse4_1.max_epi32(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse4_1.min_epi32(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v256); + + max = Sse4_1.max_epi32(max128, load).SInt0; + min = Sse4_1.min_epi32(min128, load).SInt0; + } + else + { + max = max128.SInt0; + min = min128.SInt0; + } + } + else if (Sse2.IsSse2Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = Sse2.set1_epi32(int.MinValue); + + v128 min0 = Sse2.set1_epi32(int.MaxValue); + + if (Hint.Likely(length >= 16)) + { + v128 max1 = Sse2.set1_epi32(int.MinValue); + v128 max2 = Sse2.set1_epi32(int.MinValue); + v128 max3 = Sse2.set1_epi32(int.MinValue); + + v128 min1 = Sse2.set1_epi32(int.MaxValue); + v128 min2 = Sse2.set1_epi32(int.MaxValue); + v128 min3 = Sse2.set1_epi32(int.MaxValue); + + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + + max0 = Max(max0, load0); + max1 = Max(max1, load1); + max2 = Max(max2, load2); + max3 = Max(max3, load3); + + min0 = Min(min0, load0); + min1 = Min(min1, load1); + min2 = Min(min2, load2); + min3 = Min(min3, load3); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = Max(max0, max1); + max2 = Max(max2, max3); + max0 = Max(max0, max2); + + min0 = Min(min0, min1); + min2 = Min(min2, min3); + min0 = Min(min0, min2); + } + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + if (Hint.Likely((int)length >= 2 * 4)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + if (Hint.Likely((int)length >= 3 * 4)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + + max0 = Max(max0, load); + min0 = Min(min0, load); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + length -= 2; + } + + max0 = Max(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + if (Sse4_1.IsSse41Supported) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v128); + + max = Max(max0, load).SInt0; + min = Min(min0, load).SInt0; + } + else + { + int load = *(int*)ptr_v128; + + max = math.max(max0.SInt0, load); + min = math.min(min0.SInt0, load); + } + } + else + { + max = max0.SInt0; + min = min0.SInt0; + } + } + else + { + max = int.MinValue; + min = int.MaxValue; + + for (long i = 0; i < length; i++) + { + int deref = ptr[i]; + + max = math.max(max, deref); + min = math.min(min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out int min, out int max) + { + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out int min, out int max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out int min, out int max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out int min, out int max) + { + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out int min, out int max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out int min, out int max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out int min, out int max) + { + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out int min, out int max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out int min, out int max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((int*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(long* ptr, long length, out long min, out long max) + { + static v256 Min256(v256 a, v256 b) + { + return Avx2.mm256_blendv_epi8(b, a, Avx2.mm256_cmpgt_epi64(b, a)); + } + + static v128 Min128(v128 a, v128 b) + { + return Sse4_1.blendv_epi8(b, a, Sse4_2.cmpgt_epi64(b, a)); + } + + static v256 Max256(v256 a, v256 b) + { + return Avx2.mm256_blendv_epi8(a, b, Avx2.mm256_cmpgt_epi64(b, a)); + } + + static v128 Max128(v128 a, v128 b) + { + return Sse4_1.blendv_epi8(a, b, Sse4_2.cmpgt_epi64(b, a)); + } + +Assert.IsNonNegative(length); + + if (Avx2.IsAvx2Supported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = Avx.mm256_set1_epi64x(long.MinValue); + + v256 min0 = Avx.mm256_set1_epi64x(long.MaxValue); + + if (Hint.Likely(length >= 16)) + { + v256 max1 = Avx.mm256_set1_epi64x(long.MinValue); + v256 max2 = Avx.mm256_set1_epi64x(long.MinValue); + v256 max3 = Avx.mm256_set1_epi64x(long.MinValue); + + v256 min1 = Avx.mm256_set1_epi64x(long.MaxValue); + v256 min2 = Avx.mm256_set1_epi64x(long.MaxValue); + v256 min3 = Avx.mm256_set1_epi64x(long.MaxValue); + + do + { + v256 load0 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load1 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load2 = Avx.mm256_loadu_si256(ptr_v256++); + v256 load3 = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Max256(max0, load0); + max1 = Max256(max1, load1); + max2 = Max256(max2, load2); + max3 = Max256(max3, load3); + + min0 = Min256(min0, load0); + min1 = Min256(min1, load1); + min2 = Min256(min2, load2); + min3 = Min256(min3, load3); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = Max256(max0, max1); + max2 = Max256(max2, max3); + max0 = Max256(max0, max2); + + min0 = Min256(min0, min1); + min2 = Min256(min2, min3); + min0 = Min256(min0, min2); + } + + if (Hint.Likely((int)length >= 4)) + { + v256 load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Max256(max0, load); + min0 = Min256(min0, load); + + if (Hint.Likely((int)length >= 2 * 4)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Max256(max0, load); + min0 = Min256(min0, load); + + if (Hint.Likely((int)length >= 3 * 4)) + { + load = Avx.mm256_loadu_si256(ptr_v256++); + + max0 = Max256(max0, load); + min0 = Min256(min0, load); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + v128 max128 = Max128(Avx.mm256_castsi256_si128(max0), Avx2.mm256_extracti128_si256(max0, 1)); + v128 min128 = Min128(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.loadu_si128(ptr_v256); + + max128 = Max128(max128, load); + min128 = Min128(min128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + length -= 2; + } + + max128 = Max128(max128, Sse2.shuffle_epi32(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Min128(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely(length != 0)) + { + long load = *(long*)ptr_v256; + + max = math.max(max128.SLong0, load); + min = math.min(min128.SLong0, load); + } + else + { + max = max128.SLong0; + min = min128.SLong0; + } + } + else if (Sse4_2.IsSse42Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = Sse2.set1_epi64x(long.MinValue); + + v128 min0 = Sse2.set1_epi64x(long.MaxValue); + + if (Hint.Likely(length >= 8)) + { + v128 max1 = Sse2.set1_epi64x(long.MinValue); + v128 max2 = Sse2.set1_epi64x(long.MinValue); + v128 max3 = Sse2.set1_epi64x(long.MinValue); + + v128 min1 = Sse2.set1_epi64x(long.MaxValue); + v128 min2 = Sse2.set1_epi64x(long.MaxValue); + v128 min3 = Sse2.set1_epi64x(long.MaxValue); + + do + { + v128 load0 = Sse2.loadu_si128(ptr_v128++); + v128 load1 = Sse2.loadu_si128(ptr_v128++); + v128 load2 = Sse2.loadu_si128(ptr_v128++); + v128 load3 = Sse2.loadu_si128(ptr_v128++); + + max0 = Max128(max0, load0); + max1 = Max128(max1, load1); + max2 = Max128(max2, load2); + max3 = Max128(max3, load3); + + min0 = Min128(min0, load0); + min1 = Min128(min1, load1); + min2 = Min128(min2, load2); + min3 = Min128(min3, load3); + + length -= 8; + } + while (Hint.Likely(length >= 8)); + + max0 = Max128(max0, max1); + max2 = Max128(max2, max3); + max0 = Max128(max0, max2); + + min0 = Min128(min0, min1); + min2 = Min128(min2, min3); + min0 = Min128(min0, min2); + } + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max128(max0, load); + min0 = Min128(min0, load); + + if (Hint.Likely((int)length >= 2 * 2)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max128(max0, load); + min0 = Min128(min0, load); + + if (Hint.Likely((int)length >= 3 * 2)) + { + load = Sse2.loadu_si128(ptr_v128++); + + max0 = Max128(max0, load); + min0 = Min128(min0, load); + + length -= 3 * 2; + } + else + { + length -= 2 * 2; + } + } + else + { + length -= 2; + } + } + else { } + + max0 = Max128(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min128(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely(length != 0)) + { + long load = *(long*)ptr_v128; + + max = math.max(max0.SLong0, load); + min = math.min(min0.SLong0, load); + } + else + { + max = max0.SLong0; + min = min0.SLong0; + } + } + else + { + max = long.MinValue; + min = long.MaxValue; + + for (long i = 0; i < length; i++) + { + long deref = ptr[i]; + + max = math.max(max, deref); + min = math.min(min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out long min, out long max) + { + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out long min, out long max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out long min, out long max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out long min, out long max) + { + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out long min, out long max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out long min, out long max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out long min, out long max) + { + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out long min, out long max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out long min, out long max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((long*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(float* ptr, long length, out float min, out float max) + { +Assert.IsNonNegative(length); + + if (Avx.IsAvxSupported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = new v256(float.NegativeInfinity); + + v256 min0 = new v256(float.PositiveInfinity); + + if (Hint.Likely(length >= 32)) + { + v256 max1 = new v256(float.NegativeInfinity); + v256 max2 = new v256(float.NegativeInfinity); + v256 max3 = new v256(float.NegativeInfinity); + + v256 min1 = new v256(float.PositiveInfinity); + v256 min2 = new v256(float.PositiveInfinity); + v256 min3 = new v256(float.PositiveInfinity); + + do + { + v256 load0 = Avx.mm256_loadu_ps(ptr_v256++); + v256 load1 = Avx.mm256_loadu_ps(ptr_v256++); + v256 load2 = Avx.mm256_loadu_ps(ptr_v256++); + v256 load3 = Avx.mm256_loadu_ps(ptr_v256++); + + max0 = Avx.mm256_max_ps(max0, load0); + max1 = Avx.mm256_max_ps(max1, load1); + max2 = Avx.mm256_max_ps(max2, load2); + max3 = Avx.mm256_max_ps(max3, load3); + + min0 = Avx.mm256_min_ps(min0, load0); + min1 = Avx.mm256_min_ps(min1, load1); + min2 = Avx.mm256_min_ps(min2, load2); + min3 = Avx.mm256_min_ps(min3, load3); + + length -= 32; + } + while (Hint.Likely(length >= 32)); + + max0 = Avx.mm256_max_ps(max0, max1); + max2 = Avx.mm256_max_ps(max2, max3); + max0 = Avx.mm256_max_ps(max0, max2); + + min0 = Avx.mm256_min_ps(min0, min1); + min2 = Avx.mm256_min_ps(min2, min3); + min0 = Avx.mm256_min_ps(min0, min2); + } + + if (Hint.Likely((int)length >= 8)) + { + v256 load = Avx.mm256_loadu_ps(ptr_v256++); + + max0 = Avx.mm256_max_ps(max0, load); + min0 = Avx.mm256_min_ps(min0, load); + + if (Hint.Likely((int)length >= 2 * 8)) + { + load = Avx.mm256_loadu_ps(ptr_v256++); + + max0 = Avx.mm256_max_ps(max0, load); + min0 = Avx.mm256_min_ps(min0, load); + + if (Hint.Likely((int)length >= 3 * 8)) + { + load = Avx.mm256_loadu_ps(ptr_v256++); + + max0 = Avx.mm256_max_ps(max0, load); + min0 = Avx.mm256_min_ps(min0, load); + + length -= 3 * 8; + } + else + { + length -= 2 * 8; + } + } + else + { + length -= 8; + } + } + else { } + + v128 max128 = Sse.max_ps(Avx.mm256_castps256_ps128(max0), Avx.mm256_extractf128_ps(max0, 1)); + v128 min128 = Sse.min_ps(Avx.mm256_castps256_ps128(min0), Avx.mm256_extractf128_ps(min0, 1)); + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse.loadu_ps(ptr_v256); + + max128 = Sse.max_ps(max128, load); + min128 = Sse.min_ps(min128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + + length -= 4; + } + + max128 = Sse.max_ps(max128, Avx.permute_ps(max128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse.min_ps(min128, Avx.permute_ps(min128, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v256); + + max128 = Sse.max_ps(max128, load); + min128 = Sse.min_ps(min128, load); + + ptr_v256 = (v256*)((long*)ptr_v256 + 1); + + length -= 2; + } + + max128 = Sse.max_ps(max128, Avx.permute_ps(max128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse.min_ps(min128, Avx.permute_ps(min128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v256); + + max128 = Sse.max_ss(max128, load); + min128 = Sse.min_ss(min128, load); + } + + max = max128.Float0; + min = min128.Float0; + } + else if (Sse2.IsSse2Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = new v128(float.NegativeInfinity); + + v128 min0 = new v128(float.PositiveInfinity); + + if (Hint.Likely(length >= 16)) + { + v128 max1 = new v128(float.NegativeInfinity); + v128 max2 = new v128(float.NegativeInfinity); + v128 max3 = new v128(float.NegativeInfinity); + + v128 min1 = new v128(float.PositiveInfinity); + v128 min2 = new v128(float.PositiveInfinity); + v128 min3 = new v128(float.PositiveInfinity); + + do + { + v128 load0 = Sse.loadu_ps(ptr_v128++); + v128 load1 = Sse.loadu_ps(ptr_v128++); + v128 load2 = Sse.loadu_ps(ptr_v128++); + v128 load3 = Sse.loadu_ps(ptr_v128++); + + max0 = Sse.max_ps(max0, load0); + max1 = Sse.max_ps(max1, load1); + max2 = Sse.max_ps(max2, load2); + max3 = Sse.max_ps(max3, load3); + + min0 = Sse.min_ps(min0, load0); + min1 = Sse.min_ps(min1, load1); + min2 = Sse.min_ps(min2, load2); + min3 = Sse.min_ps(min3, load3); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = Sse.max_ps(max0, max1); + max2 = Sse.max_ps(max2, max3); + max0 = Sse.max_ps(max0, max2); + + min0 = Sse.min_ps(min0, min1); + min2 = Sse.min_ps(min2, min3); + min0 = Sse.min_ps(min0, min2); + } + + if (Hint.Likely((int)length >= 4)) + { + v128 load = Sse.loadu_ps(ptr_v128++); + + max0 = Sse.max_ps(max0, load); + min0 = Sse.min_ps(min0, load); + + if (Hint.Likely((int)length >= 2 * 4)) + { + load = Sse.loadu_ps(ptr_v128++); + + max0 = Sse.max_ps(max0, load); + min0 = Sse.min_ps(min0, load); + + if (Hint.Likely((int)length >= 3 * 4)) + { + load = Sse.loadu_ps(ptr_v128++); + + max0 = Sse.max_ps(max0, load); + min0 = Sse.min_ps(min0, load); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + max0 = Sse.max_ps(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse.min_ps(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + + max0 = Sse.max_ps(max0, load); + min0 = Sse.min_ps(min0, load); + + ptr_v128 = (v128*)((long*)ptr_v128 + 1); + + length -= 2; + } + + max0 = Sse.max_ps(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Sse.min_ps(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.cvtsi32_si128(*(int*)ptr_v128); + + max0 = Sse.max_ss(max0, load); + min0 = Sse.min_ss(min0, load); + } + + max = max0.Float0; + min = min0.Float0; + } + else + { + max = float.NegativeInfinity; + min = float.PositiveInfinity; + + for (long i = 0; i < length; i++) + { + float deref = ptr[i]; + + max = math.max(max, deref); + min = math.min(min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out float min, out float max) + { + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out float min, out float max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out float min, out float max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out float min, out float max) + { + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out float min, out float max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out float min, out float max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out float min, out float max) + { + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out float min, out float max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out float min, out float max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((float*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(double* ptr, long length, out double min, out double max) + { +Assert.IsNonNegative(length); + + if (Avx.IsAvxSupported) + { + v256* ptr_v256 = (v256*)ptr; + + v256 max0 = new v256(double.NegativeInfinity); + + v256 min0 = new v256(double.PositiveInfinity); + + if (Hint.Likely(length >= 16)) + { + v256 max1 = new v256(double.NegativeInfinity); + v256 max2 = new v256(double.NegativeInfinity); + v256 max3 = new v256(double.NegativeInfinity); + + v256 min1 = new v256(double.PositiveInfinity); + v256 min2 = new v256(double.PositiveInfinity); + v256 min3 = new v256(double.PositiveInfinity); + + do + { + v256 load0 = Avx.mm256_loadu_pd(ptr_v256++); + v256 load1 = Avx.mm256_loadu_pd(ptr_v256++); + v256 load2 = Avx.mm256_loadu_pd(ptr_v256++); + v256 load3 = Avx.mm256_loadu_pd(ptr_v256++); + + max0 = Avx.mm256_max_pd(max0, load0); + max1 = Avx.mm256_max_pd(max1, load1); + max2 = Avx.mm256_max_pd(max2, load2); + max3 = Avx.mm256_max_pd(max3, load3); + + min0 = Avx.mm256_min_pd(min0, load0); + min1 = Avx.mm256_min_pd(min1, load1); + min2 = Avx.mm256_min_pd(min2, load2); + min3 = Avx.mm256_min_pd(min3, load3); + + length -= 16; + } + while (Hint.Likely(length >= 16)); + + max0 = Avx.mm256_max_pd(max0, max1); + max2 = Avx.mm256_max_pd(max2, max3); + max0 = Avx.mm256_max_pd(max0, max2); + + min0 = Avx.mm256_min_pd(min0, min1); + min2 = Avx.mm256_min_pd(min2, min3); + min0 = Avx.mm256_min_pd(min0, min2); + } + + if (Hint.Likely((int)length >= 4)) + { + v256 load = Avx.mm256_loadu_pd(ptr_v256++); + + max0 = Avx.mm256_max_pd(max0, load); + min0 = Avx.mm256_min_pd(min0, load); + + if (Hint.Likely((int)length >= 2 * 4)) + { + load = Avx.mm256_loadu_pd(ptr_v256++); + + max0 = Avx.mm256_max_pd(max0, load); + min0 = Avx.mm256_min_pd(min0, load); + + if (Hint.Likely((int)length >= 3 * 4)) + { + load = Avx.mm256_loadu_pd(ptr_v256++); + + max0 = Avx.mm256_max_pd(max0, load); + min0 = Avx.mm256_min_pd(min0, load); + + length -= 3 * 4; + } + else + { + length -= 2 * 4; + } + } + else + { + length -= 4; + } + } + else { } + + v128 max128 = Sse2.max_pd(Avx.mm256_castpd256_pd128(max0), Avx.mm256_extractf128_pd(max0, 1)); + v128 min128 = Sse2.min_pd(Avx.mm256_castpd256_pd128(min0), Avx.mm256_extractf128_pd(min0, 1)); + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse.loadu_ps(ptr_v256); + + max128 = Sse2.max_pd(max128, load); + min128 = Sse2.min_pd(min128, load); + + ptr_v256 = (v256*)((v128*)ptr_v256 + 1); + + length -= 2; + } + + max128 = Sse2.max_pd(max128, Avx.permute_pd(max128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse2.min_pd(min128, Avx.permute_pd(min128, Sse.SHUFFLE(0, 0, 0, 1))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v256); + + max128 = Sse2.max_sd(max128, load); + min128 = Sse2.min_sd(min128, load); + } + + max = max128.Double0; + min = min128.Double0; + } + else if (Sse2.IsSse2Supported) + { + v128* ptr_v128 = (v128*)ptr; + + v128 max0 = new v128(double.NegativeInfinity); + + v128 min0 = new v128(double.NegativeInfinity); + + if (Hint.Likely(length >= 8)) + { + v128 max1 = new v128(double.NegativeInfinity); + v128 max2 = new v128(double.NegativeInfinity); + v128 max3 = new v128(double.NegativeInfinity); + + v128 min1 = new v128(double.NegativeInfinity); + v128 min2 = new v128(double.NegativeInfinity); + v128 min3 = new v128(double.NegativeInfinity); + + do + { + v128 load0 = Sse.loadu_ps(ptr_v128++); + v128 load1 = Sse.loadu_ps(ptr_v128++); + v128 load2 = Sse.loadu_ps(ptr_v128++); + v128 load3 = Sse.loadu_ps(ptr_v128++); + + max0 = Sse2.max_pd(max0, load0); + max1 = Sse2.max_pd(max1, load1); + max2 = Sse2.max_pd(max2, load2); + max3 = Sse2.max_pd(max3, load3); + + min0 = Sse2.min_pd(min0, load0); + min1 = Sse2.min_pd(min1, load1); + min2 = Sse2.min_pd(min2, load2); + min3 = Sse2.min_pd(min3, load3); + + length -= 8; + } + while (Hint.Likely(length >= 8)); + + max0 = Sse2.max_pd(max0, max1); + max2 = Sse2.max_pd(max2, max3); + max0 = Sse2.max_pd(max0, max2); + + min0 = Sse2.min_pd(min0, min1); + min2 = Sse2.min_pd(min2, min3); + min0 = Sse2.min_pd(min0, min2); + } + + if (Hint.Likely((int)length >= 2)) + { + v128 load = Sse.loadu_ps(ptr_v128++); + + max0 = Sse2.max_pd(max0, load); + min0 = Sse2.min_pd(min0, load); + + if (Hint.Likely((int)length >= 2 * 2)) + { + load = Sse.loadu_ps(ptr_v128++); + + max0 = Sse2.max_pd(max0, load); + min0 = Sse2.min_pd(min0, load); + + if (Hint.Likely((int)length >= 3 * 2)) + { + load = Sse.loadu_ps(ptr_v128++); + + max0 = Sse2.max_pd(max0, load); + min0 = Sse2.min_pd(min0, load); + + length -= 3 * 2; + } + else + { + length -= 2 * 2; + } + } + else + { + length -= 2; + } + } + else { } + + max0 = Sse2.max_pd(max0, Sse2.shuffle_epi32(max0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_pd(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); + + if (Hint.Likely(length != 0)) + { + v128 load = Sse2.cvtsi64x_si128(*(long*)ptr_v128); + + max0 = Sse2.max_sd(max0, load); + min0 = Sse2.min_sd(min0, load); + } + + max = max0.Double0; + min = min0.Double0; + } + else + { + max = double.NegativeInfinity; + min = double.PositiveInfinity; + + for (long i = 0; i < length; i++) + { + double deref = ptr[i]; + + max = math.max(max, deref); + min = math.min(min, deref); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, out double min, out double max) + { + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, out double min, out double max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeArray array, int index, int numEntries, out double min, out double max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, out double min, out double max) + { + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, out double min, out double max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeList array, int index, int numEntries, out double min, out double max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, out double min, out double max) + { + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr(), array.Length, out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, out double min, out double max) + { +Assert.IsWithinArrayBounds(index, array.Length); + + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr() + index, (array.Length - index), out min, out max); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SIMD_MinMax(this NativeSlice array, int index, int numEntries, out double min, out double max) + { +Assert.IsWithinArrayBounds(index + numEntries - 1, array.Length); + + SIMD_MinMax((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries, out min, out max); + } + } +} \ No newline at end of file diff --git a/Runtime/Algorithms/Minimum.cs b/Runtime/Algorithms/Minimum.cs index 130db68..a51190e 100644 --- a/Runtime/Algorithms/Minimum.cs +++ b/Runtime/Algorithms/Minimum.cs @@ -20,36 +20,41 @@ public static byte SIMD_Minimum(byte* ptr, long length) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi8(byte.MaxValue); - v256 acc1 = Avx.mm256_set1_epi8(byte.MaxValue); - v256 acc2 = Avx.mm256_set1_epi8(byte.MaxValue); - v256 acc3 = Avx.mm256_set1_epi8(byte.MaxValue); - - while (Hint.Likely(length >= 128)) + v256 min0 = Avx.mm256_set1_epi8(byte.MaxValue); + + if (Hint.Likely(length >= 128)) { - acc0 = Avx2.mm256_min_epu8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_min_epu8(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_min_epu8(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_min_epu8(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 min1 = Avx.mm256_set1_epi8(byte.MaxValue); + v256 min2 = Avx.mm256_set1_epi8(byte.MaxValue); + v256 min3 = Avx.mm256_set1_epi8(byte.MaxValue); - length -= 128; - } + do + { + min0 = Avx2.mm256_min_epu8(min0, Avx.mm256_loadu_si256(ptr_v256++)); + min1 = Avx2.mm256_min_epu8(min1, Avx.mm256_loadu_si256(ptr_v256++)); + min2 = Avx2.mm256_min_epu8(min2, Avx.mm256_loadu_si256(ptr_v256++)); + min3 = Avx2.mm256_min_epu8(min3, Avx.mm256_loadu_si256(ptr_v256++)); - acc0 = Avx2.mm256_min_epu8(acc0, acc1); - acc2 = Avx2.mm256_min_epu8(acc2, acc3); - acc0 = Avx2.mm256_min_epu8(acc0, acc2); + length -= 128; + } + while (Hint.Likely(length >= 128)); + + min0 = Avx2.mm256_min_epu8(min0, min1); + min2 = Avx2.mm256_min_epu8(min2, min3); + min0 = Avx2.mm256_min_epu8(min0, min2); + } if (Hint.Likely((int)length >= 32)) { - acc0 = Avx2.mm256_min_epu8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu8(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 32)) { - acc0 = Avx2.mm256_min_epu8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu8(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 32)) { - acc0 = Avx2.mm256_min_epu8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu8(min0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 32; } else @@ -64,88 +69,93 @@ public static byte SIMD_Minimum(byte* ptr, long length) } else { } - v128 acc128 = Sse2.min_epu8(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 min128 = Sse2.min_epu8(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); if (Hint.Likely((int)length >= 16)) { - acc128 = Sse2.min_epu8(acc128, Sse2.loadu_si128(ptr_v256)); + min128 = Sse2.min_epu8(min128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 16; } v128 cmp = default(v128); - acc128 = Sse2.min_epu8(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse2.min_epu8(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 8)) { - acc128 = Sse2.min_epu8(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + min128 = Sse2.min_epu8(min128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 8; } - acc128 = Sse2.min_epu8(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse2.min_epu8(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse2.min_epu8(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + min128 = Sse2.min_epu8(min128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); ptr_v256 = (v256*)((int*)ptr_v256 + 1); length -= 4; } - acc128 = Sse2.min_epu8(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse2.min_epu8(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse2.min_epu8(acc128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)); + min128 = Sse2.min_epu8(min128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)); ptr_v256 = (v256*)((short*)ptr_v256 + 1); length -= 2; } - acc128 = Sse2.min_epu8(acc128, Sse2.bsrli_si128(acc128, 1 * sizeof(byte))); + min128 = Sse2.min_epu8(min128, Sse2.bsrli_si128(min128, 1 * sizeof(byte))); if (Hint.Likely(length != 0)) { - return Sse2.min_epu8(acc128, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0)).Byte0; + return Sse2.min_epu8(min128, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0)).Byte0; } else { - return acc128.Byte0; + return min128.Byte0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); - v128 acc1 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); - v128 acc2 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); - v128 acc3 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); - - while (Hint.Likely(length >= 64)) + v128 min0 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); + + if (Hint.Likely(length >= 64)) { - acc0 = Sse2.min_epu8(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Sse2.min_epu8(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Sse2.min_epu8(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Sse2.min_epu8(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 min1 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); + v128 min2 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); + v128 min3 = Sse2.set1_epi8(unchecked((sbyte)byte.MaxValue)); - length -= 64; - } + do + { + min0 = Sse2.min_epu8(min0, Sse2.loadu_si128(ptr_v128++)); + min1 = Sse2.min_epu8(min1, Sse2.loadu_si128(ptr_v128++)); + min2 = Sse2.min_epu8(min2, Sse2.loadu_si128(ptr_v128++)); + min3 = Sse2.min_epu8(min3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Sse2.min_epu8(acc0, acc1); - acc2 = Sse2.min_epu8(acc2, acc3); - acc0 = Sse2.min_epu8(acc0, acc2); + length -= 64; + } + while (Hint.Likely(length >= 64)); + + min0 = Sse2.min_epu8(min0, min1); + min2 = Sse2.min_epu8(min2, min3); + min0 = Sse2.min_epu8(min0, min2); + } if (Hint.Likely((int)length >= 16)) { - acc0 = Sse2.min_epu8(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Sse2.min_epu8(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 16)) { - acc0 = Sse2.min_epu8(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Sse2.min_epu8(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 16)) { - acc0 = Sse2.min_epu8(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Sse2.min_epu8(min0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 16; } else @@ -161,51 +171,51 @@ public static byte SIMD_Minimum(byte* ptr, long length) else { } v128 cmp = default(v128); - acc0 = Sse2.min_epu8(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_epu8(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 8)) { - acc0 = Sse2.min_epu8(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + min0 = Sse2.min_epu8(min0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 8; } - acc0 = Sse2.min_epu8(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_epu8(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc0 = Sse2.min_epu8(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + min0 = Sse2.min_epu8(min0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); ptr_v128 = (v128*)((int*)ptr_v128 + 1); length -= 4; } - acc0 = Sse2.min_epu8(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Sse2.min_epu8(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely((int)length >= 2)) { - acc0 = Sse2.min_epu8(acc0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)); + min0 = Sse2.min_epu8(min0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)); ptr_v128 = (v128*)((short*)ptr_v128 + 1); length -= 2; } - acc0 = Sse2.min_epu8(acc0, Sse2.bsrli_si128(acc0, 1 * sizeof(byte))); + min0 = Sse2.min_epu8(min0, Sse2.bsrli_si128(min0, 1 * sizeof(byte))); if (Hint.Likely(length != 0)) { if (Sse4_1.IsSse41Supported) { - return Sse2.min_epu8(acc0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).Byte0; + return Sse2.min_epu8(min0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).Byte0; } else { - return (byte)math.min((uint)acc0.Byte0, (uint)(*(byte*)ptr_v128)); + return Sse2.min_epu8(min0, Sse2.cvtsi32_si128(*(byte*)ptr_v128)).Byte0; } } else { - return acc0.Byte0; + return min0.Byte0; } } else @@ -316,36 +326,41 @@ static v128 Min(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); - v256 acc1 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); - v256 acc2 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); - v256 acc3 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); - - while (Hint.Likely(length >= 64)) + v256 min0 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); + + if (Hint.Likely(length >= 64)) { - acc0 = Avx2.mm256_min_epu16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_min_epu16(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_min_epu16(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_min_epu16(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 min1 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); + v256 min2 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); + v256 min3 = Avx.mm256_set1_epi16(unchecked((short)ushort.MaxValue)); - length -= 64; - } + do + { + min0 = Avx2.mm256_min_epu16(min0, Avx.mm256_loadu_si256(ptr_v256++)); + min1 = Avx2.mm256_min_epu16(min1, Avx.mm256_loadu_si256(ptr_v256++)); + min2 = Avx2.mm256_min_epu16(min2, Avx.mm256_loadu_si256(ptr_v256++)); + min3 = Avx2.mm256_min_epu16(min3, Avx.mm256_loadu_si256(ptr_v256++)); - acc0 = Avx2.mm256_min_epu16(acc0, acc1); - acc2 = Avx2.mm256_min_epu16(acc2, acc3); - acc0 = Avx2.mm256_min_epu16(acc0, acc2); + length -= 64; + } + while (Hint.Likely(length >= 64)); + + min0 = Avx2.mm256_min_epu16(min0, min1); + min2 = Avx2.mm256_min_epu16(min2, min3); + min0 = Avx2.mm256_min_epu16(min0, min2); + } if (Hint.Likely((int)length >= 16)) { - acc0 = Avx2.mm256_min_epu16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu16(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 16)) { - acc0 = Avx2.mm256_min_epu16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu16(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 16)) { - acc0 = Avx2.mm256_min_epu16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu16(min0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 16; } else @@ -360,79 +375,84 @@ static v128 Min(v128 a, v128 b) } else { } - v128 acc128 = Sse4_1.min_epu16(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 min128 = Sse4_1.min_epu16(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); if (Hint.Likely((int)length >= 8)) { - acc128 = Sse4_1.min_epu16(acc128, Sse2.loadu_si128(ptr_v256)); + min128 = Sse4_1.min_epu16(min128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 8; } v128 cmp = default(v128); - acc128 = Sse4_1.min_epu16(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epu16(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse4_1.min_epu16(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + min128 = Sse4_1.min_epu16(min128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 4; } - acc128 = Sse4_1.min_epu16(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epu16(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse4_1.min_epu16(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + min128 = Sse4_1.min_epu16(min128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); ptr_v256 = (v256*)((int*)ptr_v256 + 1); length -= 2; } - acc128 = Sse4_1.min_epu16(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse4_1.min_epu16(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse4_1.min_epu16(acc128, Sse2.insert_epi16(cmp, *(ushort*)ptr_v256, 0)).UShort0; + return Sse4_1.min_epu16(min128, Sse2.insert_epi16(cmp, *(ushort*)ptr_v256, 0)).UShort0; } else { - return acc128.UShort0; + return min128.UShort0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); - v128 acc1 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); - v128 acc2 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); - v128 acc3 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); - - while (Hint.Likely(length >= 32)) + v128 min0 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + + if (Hint.Likely(length >= 32)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Min(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Min(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Min(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 min1 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + v128 min2 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); + v128 min3 = Sse2.set1_epi16(unchecked((short)ushort.MaxValue)); - length -= 32; - } + do + { + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); + min1 = Min(min1, Sse2.loadu_si128(ptr_v128++)); + min2 = Min(min2, Sse2.loadu_si128(ptr_v128++)); + min3 = Min(min3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Min(acc0, acc1); - acc2 = Min(acc2, acc3); - acc0 = Min(acc0, acc2); + length -= 32; + } + while (Hint.Likely(length >= 32)); + + min0 = Min(min0, min1); + min2 = Min(min2, min3); + min0 = Min(min0, min2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 8; } else @@ -448,42 +468,42 @@ static v128 Min(v128 a, v128 b) else { } v128 cmp = default(v128); - acc0 = Min(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc0 = Min(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + min0 = Min(min0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 4; } - acc0 = Min(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Min(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + min0 = Min(min0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); ptr_v128 = (v128*)((int*)ptr_v128 + 1); length -= 2; } - acc0 = Min(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Min(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { if (Sse4_1.IsSse41Supported) { - return Sse4_1.min_epu16(acc0, Sse2.insert_epi16(cmp, *(ushort*)ptr_v128, 0)).UShort0; + return Sse4_1.min_epu16(min0, Sse2.insert_epi16(cmp, *(ushort*)ptr_v128, 0)).UShort0; } else { - return (ushort)math.min((uint)acc0.UShort0, *(ushort*)ptr_v128); + return (ushort)math.min((uint)min0.UShort0, *(ushort*)ptr_v128); } } else { - return acc0.UShort0; + return min0.UShort0; } } else @@ -596,36 +616,41 @@ static v128 Min(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); - v256 acc1 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); - v256 acc2 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); - v256 acc3 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); - - while (Hint.Likely(length >= 32)) + v256 min0 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); + + if (Hint.Likely(length >= 32)) { - acc0 = Avx2.mm256_min_epu32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_min_epu32(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_min_epu32(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_min_epu32(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 min1 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); + v256 min2 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); + v256 min3 = Avx.mm256_set1_epi32(unchecked((int)uint.MaxValue)); - length -= 32; - } + do + { + min0 = Avx2.mm256_min_epu32(min0, Avx.mm256_loadu_si256(ptr_v256++)); + min1 = Avx2.mm256_min_epu32(min1, Avx.mm256_loadu_si256(ptr_v256++)); + min2 = Avx2.mm256_min_epu32(min2, Avx.mm256_loadu_si256(ptr_v256++)); + min3 = Avx2.mm256_min_epu32(min3, Avx.mm256_loadu_si256(ptr_v256++)); - acc0 = Avx2.mm256_min_epu32(acc0, acc1); - acc2 = Avx2.mm256_min_epu32(acc2, acc3); - acc0 = Avx2.mm256_min_epu32(acc0, acc2); + length -= 32; + } + while (Hint.Likely(length >= 32)); + + min0 = Avx2.mm256_min_epu32(min0, min1); + min2 = Avx2.mm256_min_epu32(min2, min3); + min0 = Avx2.mm256_min_epu32(min0, min2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Avx2.mm256_min_epu32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu32(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Avx2.mm256_min_epu32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu32(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Avx2.mm256_min_epu32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epu32(min0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 8; } else @@ -640,68 +665,73 @@ static v128 Min(v128 a, v128 b) } else { } - v128 acc128 = Sse4_1.min_epu32(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 min128 = Sse4_1.min_epu32(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse4_1.min_epu32(acc128, Sse2.loadu_si128(ptr_v256)); + min128 = Sse4_1.min_epu32(min128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 4; } - acc128 = Sse4_1.min_epu32(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epu32(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse4_1.min_epu32(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + min128 = Sse4_1.min_epu32(min128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 2; } - acc128 = Sse4_1.min_epu32(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse4_1.min_epu32(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse4_1.min_epu32(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)).UInt0; + return Sse4_1.min_epu32(min128, Sse2.cvtsi32_si128(*(int*)ptr_v256)).UInt0; } else { - return acc128.UInt0; + return min128.UInt0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); - v128 acc1 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); - v128 acc2 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); - v128 acc3 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); - - while (Hint.Likely(length >= 16)) + v128 min0 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + + if (Hint.Likely(length >= 16)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Min(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Min(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Min(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 min1 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + v128 min2 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); + v128 min3 = Sse2.set1_epi32(unchecked((int)uint.MaxValue)); - length -= 16; - } + do + { + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); + min1 = Min(min1, Sse2.loadu_si128(ptr_v128++)); + min2 = Min(min2, Sse2.loadu_si128(ptr_v128++)); + min3 = Min(min3, Sse2.loadu_si128(ptr_v128++)); + + length -= 16; + } + while (Hint.Likely(length >= 16)); - acc0 = Min(acc0, acc1); - acc2 = Min(acc2, acc3); - acc0 = Min(acc0, acc2); + min0 = Min(min0, min1); + min2 = Min(min2, min3); + min0 = Min(min0, min2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 4; } else @@ -717,25 +747,32 @@ static v128 Min(v128 a, v128 b) else { } - acc0 = Min(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Min(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + min0 = Min(min0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 2; } - acc0 = Min(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Min(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)).UInt0; + if (Sse4_1.IsSse41Supported) + { + return Min(min0, Sse2.cvtsi32_si128(*(int*)ptr_v128)).UInt0; + } + else + { + return math.min(min0.UInt0, *(uint*)ptr_v128); + } } else { - return acc0.UInt0; + return min0.UInt0; } } else @@ -856,38 +893,43 @@ static v128 Min128(v128 a, v128 b, v128 mask) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); - v256 acc1 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); - v256 acc2 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); - v256 acc3 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); + v256 min0 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); v256 mask = Avx.mm256_set1_epi64x(1L << 63); - - while (Hint.Likely(length >= 16)) + + if (Hint.Likely(length >= 16)) { - acc0 = Min256(acc0, Avx.mm256_loadu_si256(ptr_v256++), mask); - acc1 = Min256(acc1, Avx.mm256_loadu_si256(ptr_v256++), mask); - acc2 = Min256(acc2, Avx.mm256_loadu_si256(ptr_v256++), mask); - acc3 = Min256(acc3, Avx.mm256_loadu_si256(ptr_v256++), mask); + v256 min1 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); + v256 min2 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); + v256 min3 = Avx.mm256_set1_epi64x(unchecked((long)ulong.MaxValue)); - length -= 16; - } + do + { + min0 = Min256(min0, Avx.mm256_loadu_si256(ptr_v256++), mask); + min1 = Min256(min1, Avx.mm256_loadu_si256(ptr_v256++), mask); + min2 = Min256(min2, Avx.mm256_loadu_si256(ptr_v256++), mask); + min3 = Min256(min3, Avx.mm256_loadu_si256(ptr_v256++), mask); + + length -= 16; + } + while (Hint.Likely(length >= 16)); - acc0 = Min256(acc0, acc1, mask); - acc2 = Min256(acc2, acc3, mask); - acc0 = Min256(acc0, acc2, mask); + min0 = Min256(min0, min1, mask); + min2 = Min256(min2, min3, mask); + min0 = Min256(min0, min2, mask); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Min256(acc0, Avx.mm256_loadu_si256(ptr_v256++), mask); + min0 = Min256(min0, Avx.mm256_loadu_si256(ptr_v256++), mask); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Min256(acc0, Avx.mm256_loadu_si256(ptr_v256++), mask); + min0 = Min256(min0, Avx.mm256_loadu_si256(ptr_v256++), mask); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Min256(acc0, Avx.mm256_loadu_si256(ptr_v256++), mask); + min0 = Min256(min0, Avx.mm256_loadu_si256(ptr_v256++), mask); length -= 3 * 4; } else @@ -902,59 +944,64 @@ static v128 Min128(v128 a, v128 b, v128 mask) } else { } - v128 acc128 = Min128(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1), Avx.mm256_castsi256_si128(mask)); + v128 min128 = Min128(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1), Avx.mm256_castsi256_si128(mask)); if (Hint.Likely((int)length >= 2)) { - acc128 = Min128(acc128, Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(mask)); + min128 = Min128(min128, Sse2.loadu_si128(ptr_v256), Avx.mm256_castsi256_si128(mask)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 2; } if (Hint.Likely(length != 0)) { - return math.min(*(ulong*)ptr_v256, math.min(acc128.ULong0, acc128.ULong1)); + return math.min(*(ulong*)ptr_v256, math.min(min128.ULong0, min128.ULong1)); } else { - return math.min(acc128.ULong0, acc128.ULong1); + return math.min(min128.ULong0, min128.ULong1); } } else if (Sse4_2.IsSse42Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); - v128 acc1 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); - v128 acc2 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); - v128 acc3 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); + v128 min0 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); v128 mask = Sse2.set1_epi64x(1L << 63); - - while (Hint.Likely(length >= 8)) + + if (Hint.Likely(length >= 8)) { - acc0 = Min128(acc0, Sse2.loadu_si128(ptr_v128++), mask); - acc1 = Min128(acc1, Sse2.loadu_si128(ptr_v128++), mask); - acc2 = Min128(acc2, Sse2.loadu_si128(ptr_v128++), mask); - acc3 = Min128(acc3, Sse2.loadu_si128(ptr_v128++), mask); + v128 min1 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); + v128 min2 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); + v128 min3 = Sse2.set1_epi64x(unchecked((long)ulong.MaxValue)); - length -= 8; - } + do + { + min0 = Min128(min0, Sse2.loadu_si128(ptr_v128++), mask); + min1 = Min128(min1, Sse2.loadu_si128(ptr_v128++), mask); + min2 = Min128(min2, Sse2.loadu_si128(ptr_v128++), mask); + min3 = Min128(min3, Sse2.loadu_si128(ptr_v128++), mask); - acc0 = Min128(acc0, acc1, mask); - acc2 = Min128(acc2, acc3, mask); - acc0 = Min128(acc0, acc2, mask); + length -= 8; + } + while (Hint.Likely(length >= 8)); + + min0 = Min128(min0, min1, mask); + min2 = Min128(min2, min3, mask); + min0 = Min128(min0, min2, mask); + } if (Hint.Likely((int)length >= 2)) { - acc0 = Min128(acc0, Sse2.loadu_si128(ptr_v128++), mask); + min0 = Min128(min0, Sse2.loadu_si128(ptr_v128++), mask); if (Hint.Likely((int)length >= 2 * 2)) { - acc0 = Min128(acc0, Sse2.loadu_si128(ptr_v128++), mask); + min0 = Min128(min0, Sse2.loadu_si128(ptr_v128++), mask); if (Hint.Likely((int)length >= 3 * 2)) { - acc0 = Min128(acc0, Sse2.loadu_si128(ptr_v128++), mask); + min0 = Min128(min0, Sse2.loadu_si128(ptr_v128++), mask); length -= 3 * 2; } else @@ -971,11 +1018,11 @@ static v128 Min128(v128 a, v128 b, v128 mask) if (Hint.Likely(length != 0)) { - return math.min(*(ulong*)ptr_v128, math.min(acc0.ULong0, acc0.ULong1)); + return math.min(*(ulong*)ptr_v128, math.min(min0.ULong0, min0.ULong1)); } else { - return math.min(acc0.ULong0, acc0.ULong1); + return math.min(min0.ULong0, min0.ULong1); } } else @@ -1085,36 +1132,41 @@ static v128 Min(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi8((byte)sbyte.MaxValue); - v256 acc1 = Avx.mm256_set1_epi8((byte)sbyte.MaxValue); - v256 acc2 = Avx.mm256_set1_epi8((byte)sbyte.MaxValue); - v256 acc3 = Avx.mm256_set1_epi8((byte)sbyte.MaxValue); - - while (Hint.Likely(length >= 128)) + v256 min0 = Avx.mm256_set1_epi8((byte)sbyte.MaxValue); + + if (Hint.Likely(length >= 128)) { - acc0 = Avx2.mm256_min_epi8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_min_epi8(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_min_epi8(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_min_epi8(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 min1 = Avx.mm256_set1_epi8((byte)sbyte.MaxValue); + v256 min2 = Avx.mm256_set1_epi8((byte)sbyte.MaxValue); + v256 min3 = Avx.mm256_set1_epi8((byte)sbyte.MaxValue); - length -= 128; - } + do + { + min0 = Avx2.mm256_min_epi8(min0, Avx.mm256_loadu_si256(ptr_v256++)); + min1 = Avx2.mm256_min_epi8(min1, Avx.mm256_loadu_si256(ptr_v256++)); + min2 = Avx2.mm256_min_epi8(min2, Avx.mm256_loadu_si256(ptr_v256++)); + min3 = Avx2.mm256_min_epi8(min3, Avx.mm256_loadu_si256(ptr_v256++)); + + length -= 128; + } + while (Hint.Likely(length >= 128)); - acc0 = Avx2.mm256_min_epi8(acc0, acc1); - acc2 = Avx2.mm256_min_epi8(acc2, acc3); - acc0 = Avx2.mm256_min_epi8(acc0, acc2); + min0 = Avx2.mm256_min_epi8(min0, min1); + min2 = Avx2.mm256_min_epi8(min2, min3); + min0 = Avx2.mm256_min_epi8(min0, min2); + } if (Hint.Likely((int)length >= 32)) { - acc0 = Avx2.mm256_min_epi8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi8(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 32)) { - acc0 = Avx2.mm256_min_epi8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi8(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 32)) { - acc0 = Avx2.mm256_min_epi8(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi8(min0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 32; } else @@ -1129,88 +1181,93 @@ static v128 Min(v128 a, v128 b) } else { } - v128 acc128 = Sse4_1.min_epi8(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 min128 = Sse4_1.min_epi8(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); if (Hint.Likely((int)length >= 16)) { - acc128 = Sse4_1.min_epi8(acc128, Sse2.loadu_si128(ptr_v256)); + min128 = Sse4_1.min_epi8(min128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 16; } v128 cmp = default(v128); - acc128 = Sse4_1.min_epi8(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epi8(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 8)) { - acc128 = Sse4_1.min_epi8(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + min128 = Sse4_1.min_epi8(min128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 8; } - acc128 = Sse4_1.min_epi8(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epi8(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse4_1.min_epi8(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + min128 = Sse4_1.min_epi8(min128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); ptr_v256 = (v256*)((int*)ptr_v256 + 1); length -= 4; } - acc128 = Sse4_1.min_epi8(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse4_1.min_epi8(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse4_1.min_epi8(acc128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)); + min128 = Sse4_1.min_epi8(min128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)); ptr_v256 = (v256*)((short*)ptr_v256 + 1); length -= 2; } - acc128 = Sse4_1.min_epi8(acc128, Sse2.bsrli_si128(acc128, 1 * sizeof(sbyte))); + min128 = Sse4_1.min_epi8(min128, Sse2.bsrli_si128(min128, 1 * sizeof(sbyte))); if (Hint.Likely(length != 0)) { - return (sbyte)math.min((int)acc128.SByte0, (int)(*(sbyte*)ptr_v256)); + return Sse4_1.min_epi8(min128, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v256, 0)).SByte0; } else { - return acc128.SByte0; + return min128.SByte0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi8(sbyte.MaxValue); - v128 acc1 = Sse2.set1_epi8(sbyte.MaxValue); - v128 acc2 = Sse2.set1_epi8(sbyte.MaxValue); - v128 acc3 = Sse2.set1_epi8(sbyte.MaxValue); - - while (Hint.Likely(length >= 64)) + v128 min0 = Sse2.set1_epi8(sbyte.MaxValue); + + if (Hint.Likely(length >= 64)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Min(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Min(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Min(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 min1 = Sse2.set1_epi8(sbyte.MaxValue); + v128 min2 = Sse2.set1_epi8(sbyte.MaxValue); + v128 min3 = Sse2.set1_epi8(sbyte.MaxValue); - length -= 64; - } + do + { + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); + min1 = Min(min1, Sse2.loadu_si128(ptr_v128++)); + min2 = Min(min2, Sse2.loadu_si128(ptr_v128++)); + min3 = Min(min3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Min(acc0, acc1); - acc2 = Min(acc2, acc3); - acc0 = Min(acc0, acc2); + length -= 64; + } + while (Hint.Likely(length >= 64)); + + min0 = Min(min0, min1); + min2 = Min(min2, min3); + min0 = Min(min0, min2); + } if (Hint.Likely((int)length >= 16)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 16)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 16)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 16; } else @@ -1226,51 +1283,51 @@ static v128 Min(v128 a, v128 b) else { } v128 cmp = default(v128); - acc0 = Min(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 8)) { - acc0 = Min(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + min0 = Min(min0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 8; } - acc0 = Sse2.min_epu8(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc0 = Min(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + min0 = Min(min0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); ptr_v128 = (v128*)((int*)ptr_v128 + 1); length -= 4; } - acc0 = Min(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Min(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely((int)length >= 2)) { - acc0 = Min(acc0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)); + min0 = Min(min0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)); ptr_v128 = (v128*)((short*)ptr_v128 + 1); length -= 2; } - acc0 = Min(acc0, Sse2.bsrli_si128(acc0, 1 * sizeof(sbyte))); + min0 = Min(min0, Sse2.bsrli_si128(min0, 1 * sizeof(sbyte))); if (Hint.Likely(length != 0)) { if (Sse4_1.IsSse41Supported) { - return Sse4_1.min_epi8(acc0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).SByte0; + return Sse4_1.min_epi8(min0, Sse4_1.insert_epi8(cmp, *(byte*)ptr_v128, 0)).SByte0; } else { - return (sbyte)math.min((int)acc0.SByte0, (int)(*(sbyte*)ptr_v128)); + return (sbyte)math.min((int)min0.SByte0, (int)(*(sbyte*)ptr_v128)); } } else { - return acc0.SByte0; + return min0.SByte0; } } else @@ -1361,36 +1418,41 @@ public static short SIMD_Minimum(short* ptr, long length) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi16(short.MaxValue); - v256 acc1 = Avx.mm256_set1_epi16(short.MaxValue); - v256 acc2 = Avx.mm256_set1_epi16(short.MaxValue); - v256 acc3 = Avx.mm256_set1_epi16(short.MaxValue); - - while (Hint.Likely(length >= 64)) + v256 min0 = Avx.mm256_set1_epi16(short.MaxValue); + + if (Hint.Likely(length >= 64)) { - acc0 = Avx2.mm256_min_epi16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_min_epi16(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_min_epi16(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_min_epi16(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 min1 = Avx.mm256_set1_epi16(short.MaxValue); + v256 min2 = Avx.mm256_set1_epi16(short.MaxValue); + v256 min3 = Avx.mm256_set1_epi16(short.MaxValue); - length -= 64; - } + do + { + min0 = Avx2.mm256_min_epi16(min0, Avx.mm256_loadu_si256(ptr_v256++)); + min1 = Avx2.mm256_min_epi16(min1, Avx.mm256_loadu_si256(ptr_v256++)); + min2 = Avx2.mm256_min_epi16(min2, Avx.mm256_loadu_si256(ptr_v256++)); + min3 = Avx2.mm256_min_epi16(min3, Avx.mm256_loadu_si256(ptr_v256++)); - acc0 = Avx2.mm256_min_epi16(acc0, acc1); - acc2 = Avx2.mm256_min_epi16(acc2, acc3); - acc0 = Avx2.mm256_min_epi16(acc0, acc2); + length -= 64; + } + while (Hint.Likely(length >= 64)); + + min0 = Avx2.mm256_min_epi16(min0, min1); + min2 = Avx2.mm256_min_epi16(min2, min3); + min0 = Avx2.mm256_min_epi16(min0, min2); + } if (Hint.Likely((int)length >= 16)) { - acc0 = Avx2.mm256_min_epi16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi16(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 16)) { - acc0 = Avx2.mm256_min_epi16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi16(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 16)) { - acc0 = Avx2.mm256_min_epi16(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi16(min0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 16; } else @@ -1405,79 +1467,84 @@ public static short SIMD_Minimum(short* ptr, long length) } else { } - v128 acc128 = Sse2.min_epi16(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 min128 = Sse2.min_epi16(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); if (Hint.Likely((int)length >= 8)) { - acc128 = Sse2.min_epi16(acc128, Sse2.loadu_si128(ptr_v256)); + min128 = Sse2.min_epi16(min128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 8; } v128 cmp = default(v128); - acc128 = Sse2.min_epi16(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse2.min_epi16(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse2.min_epi16(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + min128 = Sse2.min_epi16(min128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 4; } - acc128 = Sse2.min_epi16(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse2.min_epi16(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse2.min_epi16(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + min128 = Sse2.min_epi16(min128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); ptr_v256 = (v256*)((int*)ptr_v256 + 1); length -= 2; } - acc128 = Sse2.min_epi16(acc128, Sse2.shufflelo_epi16(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse2.min_epi16(min128, Sse2.shufflelo_epi16(min128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse2.min_epi16(acc128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)).SShort0; + return Sse2.min_epi16(min128, Sse2.insert_epi16(cmp, *(short*)ptr_v256, 0)).SShort0; } else { - return acc128.SShort0; + return min128.SShort0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi16(short.MaxValue); - v128 acc1 = Sse2.set1_epi16(short.MaxValue); - v128 acc2 = Sse2.set1_epi16(short.MaxValue); - v128 acc3 = Sse2.set1_epi16(short.MaxValue); - - while (Hint.Likely(length >= 32)) + v128 min0 = Sse2.set1_epi16(short.MaxValue); + + if (Hint.Likely(length >= 32)) { - acc0 = Sse2.min_epi16(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Sse2.min_epi16(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Sse2.min_epi16(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Sse2.min_epi16(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 min1 = Sse2.set1_epi16(short.MaxValue); + v128 min2 = Sse2.set1_epi16(short.MaxValue); + v128 min3 = Sse2.set1_epi16(short.MaxValue); - length -= 32; - } + do + { + min0 = Sse2.min_epi16(min0, Sse2.loadu_si128(ptr_v128++)); + min1 = Sse2.min_epi16(min1, Sse2.loadu_si128(ptr_v128++)); + min2 = Sse2.min_epi16(min2, Sse2.loadu_si128(ptr_v128++)); + min3 = Sse2.min_epi16(min3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Sse2.min_epi16(acc0, acc1); - acc2 = Sse2.min_epi16(acc2, acc3); - acc0 = Sse2.min_epi16(acc0, acc2); + length -= 32; + } + while (Hint.Likely(length >= 32)); + + min0 = Sse2.min_epi16(min0, min1); + min2 = Sse2.min_epi16(min2, min3); + min0 = Sse2.min_epi16(min0, min2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Sse2.min_epi16(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Sse2.min_epi16(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Sse2.min_epi16(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Sse2.min_epi16(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Sse2.min_epi16(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Sse2.min_epi16(min0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 8; } else @@ -1493,35 +1560,35 @@ public static short SIMD_Minimum(short* ptr, long length) else { } v128 cmp = default(v128); - acc0 = Sse2.min_epi16(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_epi16(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 4)) { - acc0 = Sse2.min_epi16(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + min0 = Sse2.min_epi16(min0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 4; } - acc0 = Sse2.min_epi16(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_epi16(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Sse2.min_epi16(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + min0 = Sse2.min_epi16(min0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); ptr_v128 = (v128*)((int*)ptr_v128 + 1); length -= 2; } - acc0 = Sse2.min_epi16(acc0, Sse2.shufflelo_epi16(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Sse2.min_epi16(min0, Sse2.shufflelo_epi16(min0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse2.min_epi16(acc0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)).SShort0; + return Sse2.min_epi16(min0, Sse2.insert_epi16(cmp, *(short*)ptr_v128, 0)).SShort0; } else { - return acc0.SShort0; + return min0.SShort0; } } else @@ -1631,36 +1698,41 @@ static v128 Min(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi32(int.MaxValue); - v256 acc1 = Avx.mm256_set1_epi32(int.MaxValue); - v256 acc2 = Avx.mm256_set1_epi32(int.MaxValue); - v256 acc3 = Avx.mm256_set1_epi32(int.MaxValue); - - while (Hint.Likely(length >= 32)) + v256 min0 = Avx.mm256_set1_epi32(int.MaxValue); + + if (Hint.Likely(length >= 32)) { - acc0 = Avx2.mm256_min_epi32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Avx2.mm256_min_epi32(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Avx2.mm256_min_epi32(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Avx2.mm256_min_epi32(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 min1 = Avx.mm256_set1_epi32(int.MaxValue); + v256 min2 = Avx.mm256_set1_epi32(int.MaxValue); + v256 min3 = Avx.mm256_set1_epi32(int.MaxValue); - length -= 32; - } + do + { + min0 = Avx2.mm256_min_epi32(min0, Avx.mm256_loadu_si256(ptr_v256++)); + min1 = Avx2.mm256_min_epi32(min1, Avx.mm256_loadu_si256(ptr_v256++)); + min2 = Avx2.mm256_min_epi32(min2, Avx.mm256_loadu_si256(ptr_v256++)); + min3 = Avx2.mm256_min_epi32(min3, Avx.mm256_loadu_si256(ptr_v256++)); + + length -= 32; + } + while (Hint.Likely(length >= 32)); - acc0 = Avx2.mm256_min_epi32(acc0, acc1); - acc2 = Avx2.mm256_min_epi32(acc2, acc3); - acc0 = Avx2.mm256_min_epi32(acc0, acc2); + min0 = Avx2.mm256_min_epi32(min0, min1); + min2 = Avx2.mm256_min_epi32(min2, min3); + min0 = Avx2.mm256_min_epi32(min0, min2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Avx2.mm256_min_epi32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi32(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Avx2.mm256_min_epi32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi32(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Avx2.mm256_min_epi32(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Avx2.mm256_min_epi32(min0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 8; } else @@ -1675,68 +1747,73 @@ static v128 Min(v128 a, v128 b) } else { } - v128 acc128 = Sse4_1.min_epi32(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 min128 = Sse4_1.min_epi32(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse4_1.min_epi32(acc128, Sse2.loadu_si128(ptr_v256)); + min128 = Sse4_1.min_epi32(min128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 4; } - acc128 = Sse4_1.min_epi32(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse4_1.min_epi32(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse4_1.min_epi32(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + min128 = Sse4_1.min_epi32(min128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 2; } - acc128 = Sse4_1.min_epi32(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse4_1.min_epi32(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Sse4_1.min_epi32(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)).SInt0; + return Sse4_1.min_epi32(min128, Sse2.cvtsi32_si128(*(int*)ptr_v256)).SInt0; } else { - return acc128.SInt0; + return min128.SInt0; } } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi32(int.MaxValue); - v128 acc1 = Sse2.set1_epi32(int.MaxValue); - v128 acc2 = Sse2.set1_epi32(int.MaxValue); - v128 acc3 = Sse2.set1_epi32(int.MaxValue); - - while (Hint.Likely(length >= 16)) + v128 min0 = Sse2.set1_epi32(int.MaxValue); + + if (Hint.Likely(length >= 16)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Min(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Min(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Min(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 min1 = Sse2.set1_epi32(int.MaxValue); + v128 min2 = Sse2.set1_epi32(int.MaxValue); + v128 min3 = Sse2.set1_epi32(int.MaxValue); - length -= 16; - } + do + { + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); + min1 = Min(min1, Sse2.loadu_si128(ptr_v128++)); + min2 = Min(min2, Sse2.loadu_si128(ptr_v128++)); + min3 = Min(min3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Min(acc0, acc1); - acc2 = Min(acc2, acc3); - acc0 = Min(acc0, acc2); + length -= 16; + } + while (Hint.Likely(length >= 16)); + + min0 = Min(min0, min1); + min2 = Min(min2, min3); + min0 = Min(min0, min2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Min(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min(min0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 4; } else @@ -1751,25 +1828,32 @@ static v128 Min(v128 a, v128 b) } else { } - acc0 = Min(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Min(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + min0 = Min(min0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 2; } - acc0 = Min(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Min(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - return Min(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)).SInt0; + if (Sse4_1.IsSse41Supported) + { + return Min(min0, Sse2.cvtsi32_si128(*(int*)ptr_v128)).SInt0; + } + else + { + return math.min(min0.SInt0, *(int*)ptr_v128); + } } else { - return acc0.SInt0; + return min0.SInt0; } } else @@ -1868,36 +1952,41 @@ static v128 Min128(v128 a, v128 b) if (Avx2.IsAvx2Supported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = Avx.mm256_set1_epi64x(long.MaxValue); - v256 acc1 = Avx.mm256_set1_epi64x(long.MaxValue); - v256 acc2 = Avx.mm256_set1_epi64x(long.MaxValue); - v256 acc3 = Avx.mm256_set1_epi64x(long.MaxValue); - - while (Hint.Likely(length >= 16)) + v256 min0 = Avx.mm256_set1_epi64x(long.MaxValue); + + if (Hint.Likely(length >= 16)) { - acc0 = Min256(acc0, Avx.mm256_loadu_si256(ptr_v256++)); - acc1 = Min256(acc1, Avx.mm256_loadu_si256(ptr_v256++)); - acc2 = Min256(acc2, Avx.mm256_loadu_si256(ptr_v256++)); - acc3 = Min256(acc3, Avx.mm256_loadu_si256(ptr_v256++)); + v256 min1 = Avx.mm256_set1_epi64x(long.MaxValue); + v256 min2 = Avx.mm256_set1_epi64x(long.MaxValue); + v256 min3 = Avx.mm256_set1_epi64x(long.MaxValue); - length -= 16; - } + do + { + min0 = Min256(min0, Avx.mm256_loadu_si256(ptr_v256++)); + min1 = Min256(min1, Avx.mm256_loadu_si256(ptr_v256++)); + min2 = Min256(min2, Avx.mm256_loadu_si256(ptr_v256++)); + min3 = Min256(min3, Avx.mm256_loadu_si256(ptr_v256++)); - acc0 = Min256(acc0, acc1); - acc2 = Min256(acc2, acc3); - acc0 = Min256(acc0, acc2); + length -= 16; + } + while (Hint.Likely(length >= 16)); + + min0 = Min256(min0, min1); + min2 = Min256(min2, min3); + min0 = Min256(min0, min2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Min256(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Min256(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Min256(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Min256(min0, Avx.mm256_loadu_si256(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Min256(acc0, Avx.mm256_loadu_si256(ptr_v256++)); + min0 = Min256(min0, Avx.mm256_loadu_si256(ptr_v256++)); length -= 3 * 4; } else @@ -1912,59 +2001,64 @@ static v128 Min128(v128 a, v128 b) } else { } - v128 acc128 = Min128(Avx.mm256_castsi256_si128(acc0), Avx2.mm256_extracti128_si256(acc0, 1)); + v128 min128 = Min128(Avx.mm256_castsi256_si128(min0), Avx2.mm256_extracti128_si256(min0, 1)); if (Hint.Likely((int)length >= 2)) { - acc128 = Min128(acc128, Sse2.loadu_si128(ptr_v256)); + min128 = Min128(min128, Sse2.loadu_si128(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 2; } - acc128 = Min128(acc128, Sse2.shuffle_epi32(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Min128(min128, Sse2.shuffle_epi32(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely(length != 0)) { - return math.min(acc128.SLong0, *(long*)ptr_v256); + return math.min(min128.SLong0, *(long*)ptr_v256); } else { - return acc128.SLong0; + return min128.SLong0; } } else if (Sse4_2.IsSse42Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = Sse2.set1_epi64x(long.MaxValue); - v128 acc1 = Sse2.set1_epi64x(long.MaxValue); - v128 acc2 = Sse2.set1_epi64x(long.MaxValue); - v128 acc3 = Sse2.set1_epi64x(long.MaxValue); - - while (Hint.Likely(length >= 8)) + v128 min0 = Sse2.set1_epi64x(long.MaxValue); + + if (Hint.Likely(length >= 8)) { - acc0 = Min128(acc0, Sse2.loadu_si128(ptr_v128++)); - acc1 = Min128(acc1, Sse2.loadu_si128(ptr_v128++)); - acc2 = Min128(acc2, Sse2.loadu_si128(ptr_v128++)); - acc3 = Min128(acc3, Sse2.loadu_si128(ptr_v128++)); + v128 min1 = Sse2.set1_epi64x(long.MaxValue); + v128 min2 = Sse2.set1_epi64x(long.MaxValue); + v128 min3 = Sse2.set1_epi64x(long.MaxValue); - length -= 8; - } + do + { + min0 = Min128(min0, Sse2.loadu_si128(ptr_v128++)); + min1 = Min128(min1, Sse2.loadu_si128(ptr_v128++)); + min2 = Min128(min2, Sse2.loadu_si128(ptr_v128++)); + min3 = Min128(min3, Sse2.loadu_si128(ptr_v128++)); - acc0 = Min128(acc0, acc1); - acc2 = Min128(acc2, acc3); - acc0 = Min128(acc0, acc2); + length -= 8; + } + while (Hint.Likely(length >= 8)); + + min0 = Min128(min0, min1); + min2 = Min128(min2, min3); + min0 = Min128(min0, min2); + } if (Hint.Likely((int)length >= 2)) { - acc0 = Min128(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min128(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 2)) { - acc0 = Min128(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min128(min0, Sse2.loadu_si128(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 2)) { - acc0 = Min128(acc0, Sse2.loadu_si128(ptr_v128++)); + min0 = Min128(min0, Sse2.loadu_si128(ptr_v128++)); length -= 3 * 2; } else @@ -1979,15 +2073,15 @@ static v128 Min128(v128 a, v128 b) } else { } - acc0 = Min128(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Min128(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely(length != 0)) { - return math.min(acc0.SLong0, *(long*)ptr_v128); + return math.min(min0.SLong0, *(long*)ptr_v128); } else { - return acc0.SLong0; + return min0.SLong0; } } else @@ -2076,36 +2170,41 @@ public static float SIMD_Minimum(float* ptr, long length) if (Avx.IsAvxSupported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = new v256(float.PositiveInfinity); - v256 acc1 = new v256(float.PositiveInfinity); - v256 acc2 = new v256(float.PositiveInfinity); - v256 acc3 = new v256(float.PositiveInfinity); - - while (Hint.Likely(length >= 32)) + v256 min0 = new v256(float.PositiveInfinity); + + if (Hint.Likely(length >= 32)) { - acc0 = Avx.mm256_min_ps(acc0, Avx.mm256_loadu_ps(ptr_v256++)); - acc1 = Avx.mm256_min_ps(acc1, Avx.mm256_loadu_ps(ptr_v256++)); - acc2 = Avx.mm256_min_ps(acc2, Avx.mm256_loadu_ps(ptr_v256++)); - acc3 = Avx.mm256_min_ps(acc3, Avx.mm256_loadu_ps(ptr_v256++)); + v256 min1 = new v256(float.PositiveInfinity); + v256 min2 = new v256(float.PositiveInfinity); + v256 min3 = new v256(float.PositiveInfinity); - length -= 32; - } + do + { + min0 = Avx.mm256_min_ps(min0, Avx.mm256_loadu_ps(ptr_v256++)); + min1 = Avx.mm256_min_ps(min1, Avx.mm256_loadu_ps(ptr_v256++)); + min2 = Avx.mm256_min_ps(min2, Avx.mm256_loadu_ps(ptr_v256++)); + min3 = Avx.mm256_min_ps(min3, Avx.mm256_loadu_ps(ptr_v256++)); - acc0 = Avx.mm256_min_ps(acc0, acc1); - acc2 = Avx.mm256_min_ps(acc2, acc3); - acc0 = Avx.mm256_min_ps(acc0, acc2); + length -= 32; + } + while (Hint.Likely(length >= 32)); + + min0 = Avx.mm256_min_ps(min0, min1); + min2 = Avx.mm256_min_ps(min2, min3); + min0 = Avx.mm256_min_ps(min0, min2); + } if (Hint.Likely((int)length >= 8)) { - acc0 = Avx.mm256_min_ps(acc0, Avx.mm256_loadu_ps(ptr_v256++)); + min0 = Avx.mm256_min_ps(min0, Avx.mm256_loadu_ps(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 8)) { - acc0 = Avx.mm256_min_ps(acc0, Avx.mm256_loadu_ps(ptr_v256++)); + min0 = Avx.mm256_min_ps(min0, Avx.mm256_loadu_ps(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 8)) { - acc0 = Avx.mm256_min_ps(acc0, Avx.mm256_loadu_ps(ptr_v256++)); + min0 = Avx.mm256_min_ps(min0, Avx.mm256_loadu_ps(ptr_v256++)); length -= 3 * 8; } else @@ -2120,68 +2219,73 @@ public static float SIMD_Minimum(float* ptr, long length) } else { } - v128 acc128 = Sse.min_ps(Avx.mm256_castps256_ps128(acc0), Avx.mm256_extractf128_ps(acc0, 1)); + v128 min128 = Sse.min_ps(Avx.mm256_castps256_ps128(min0), Avx.mm256_extractf128_ps(min0, 1)); if (Hint.Likely((int)length >= 4)) { - acc128 = Sse.min_ps(acc128, Sse.loadu_ps(ptr_v256)); + min128 = Sse.min_ps(min128, Sse.loadu_ps(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 4; } - acc128 = Sse.min_ps(acc128, Avx.permute_ps(acc128, Sse.SHUFFLE(0, 0, 3, 2))); + min128 = Sse.min_ps(min128, Avx.permute_ps(min128, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse.min_ps(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + min128 = Sse.min_ps(min128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); ptr_v256 = (v256*)((long*)ptr_v256 + 1); length -= 2; } - acc128 = Sse.min_ps(acc128, Avx.permute_ps(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse.min_ps(min128, Avx.permute_ps(min128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - acc128 = Sse.min_ss(acc128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); + min128 = Sse.min_ss(min128, Sse2.cvtsi32_si128(*(int*)ptr_v256)); } - return acc128.Float0; + return min128.Float0; } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = new v128(float.PositiveInfinity); - v128 acc1 = new v128(float.PositiveInfinity); - v128 acc2 = new v128(float.PositiveInfinity); - v128 acc3 = new v128(float.PositiveInfinity); - - while (Hint.Likely(length >= 16)) + v128 min0 = new v128(float.PositiveInfinity); + + if (Hint.Likely(length >= 16)) { - acc0 = Sse.min_ps(acc0, Sse.loadu_ps(ptr_v128++)); - acc1 = Sse.min_ps(acc1, Sse.loadu_ps(ptr_v128++)); - acc2 = Sse.min_ps(acc2, Sse.loadu_ps(ptr_v128++)); - acc3 = Sse.min_ps(acc3, Sse.loadu_ps(ptr_v128++)); + v128 min1 = new v128(float.PositiveInfinity); + v128 min2 = new v128(float.PositiveInfinity); + v128 min3 = new v128(float.PositiveInfinity); - length -= 16; - } + do + { + min0 = Sse.min_ps(min0, Sse.loadu_ps(ptr_v128++)); + min1 = Sse.min_ps(min1, Sse.loadu_ps(ptr_v128++)); + min2 = Sse.min_ps(min2, Sse.loadu_ps(ptr_v128++)); + min3 = Sse.min_ps(min3, Sse.loadu_ps(ptr_v128++)); - acc0 = Sse.min_ps(acc0, acc1); - acc2 = Sse.min_ps(acc2, acc3); - acc0 = Sse.min_ps(acc0, acc2); + length -= 16; + } + while (Hint.Likely(length >= 16)); + + min0 = Sse.min_ps(min0, min1); + min2 = Sse.min_ps(min2, min3); + min0 = Sse.min_ps(min0, min2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Sse.min_ps(acc0, Sse.loadu_ps(ptr_v128++)); + min0 = Sse.min_ps(min0, Sse.loadu_ps(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Sse.min_ps(acc0, Sse.loadu_ps(ptr_v128++)); + min0 = Sse.min_ps(min0, Sse.loadu_ps(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Sse.min_ps(acc0, Sse.loadu_ps(ptr_v128++)); + min0 = Sse.min_ps(min0, Sse.loadu_ps(ptr_v128++)); length -= 3 * 4; } else @@ -2196,24 +2300,24 @@ public static float SIMD_Minimum(float* ptr, long length) } else { } - acc0 = Sse.min_ps(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse.min_ps(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely((int)length >= 2)) { - acc0 = Sse.min_ps(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + min0 = Sse.min_ps(min0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); ptr_v128 = (v128*)((long*)ptr_v128 + 1); length -= 2; } - acc0 = Sse.min_ps(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 0, 1))); + min0 = Sse.min_ps(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - acc0 = Sse.min_ss(acc0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); + min0 = Sse.min_ss(min0, Sse2.cvtsi32_si128(*(int*)ptr_v128)); } - return acc0.Float0; + return min0.Float0; } else { @@ -2303,36 +2407,41 @@ public static double SIMD_Minimum(double* ptr, long length) if (Avx.IsAvxSupported) { v256* ptr_v256 = (v256*)ptr; - v256 acc0 = new v256(double.PositiveInfinity); - v256 acc1 = new v256(double.PositiveInfinity); - v256 acc2 = new v256(double.PositiveInfinity); - v256 acc3 = new v256(double.PositiveInfinity); - - while (Hint.Likely(length >= 16)) + v256 min0 = new v256(double.PositiveInfinity); + + if (Hint.Likely(length >= 16)) { - acc0 = Avx.mm256_min_pd(acc0, Avx.mm256_loadu_pd(ptr_v256++)); - acc1 = Avx.mm256_min_pd(acc1, Avx.mm256_loadu_pd(ptr_v256++)); - acc2 = Avx.mm256_min_pd(acc2, Avx.mm256_loadu_pd(ptr_v256++)); - acc3 = Avx.mm256_min_pd(acc3, Avx.mm256_loadu_pd(ptr_v256++)); + v256 min1 = new v256(double.PositiveInfinity); + v256 min2 = new v256(double.PositiveInfinity); + v256 min3 = new v256(double.PositiveInfinity); - length -= 16; - } + do + { + min0 = Avx.mm256_min_pd(min0, Avx.mm256_loadu_pd(ptr_v256++)); + min1 = Avx.mm256_min_pd(min1, Avx.mm256_loadu_pd(ptr_v256++)); + min2 = Avx.mm256_min_pd(min2, Avx.mm256_loadu_pd(ptr_v256++)); + min3 = Avx.mm256_min_pd(min3, Avx.mm256_loadu_pd(ptr_v256++)); + + length -= 16; + } + while (Hint.Likely(length >= 16)); - acc0 = Avx.mm256_min_pd(acc0, acc1); - acc2 = Avx.mm256_min_pd(acc2, acc3); - acc0 = Avx.mm256_min_pd(acc0, acc2); + min0 = Avx.mm256_min_pd(min0, min1); + min2 = Avx.mm256_min_pd(min2, min3); + min0 = Avx.mm256_min_pd(min0, min2); + } if (Hint.Likely((int)length >= 4)) { - acc0 = Avx.mm256_min_pd(acc0, Avx.mm256_loadu_pd(ptr_v256++)); + min0 = Avx.mm256_min_pd(min0, Avx.mm256_loadu_pd(ptr_v256++)); if (Hint.Likely((int)length >= 2 * 4)) { - acc0 = Avx.mm256_min_pd(acc0, Avx.mm256_loadu_pd(ptr_v256++)); + min0 = Avx.mm256_min_pd(min0, Avx.mm256_loadu_pd(ptr_v256++)); if (Hint.Likely((int)length >= 3 * 4)) { - acc0 = Avx.mm256_min_pd(acc0, Avx.mm256_loadu_pd(ptr_v256++)); + min0 = Avx.mm256_min_pd(min0, Avx.mm256_loadu_pd(ptr_v256++)); length -= 3 * 4; } else @@ -2347,58 +2456,63 @@ public static double SIMD_Minimum(double* ptr, long length) } else { } - v128 acc128 = Sse2.min_pd(Avx.mm256_castpd256_pd128(acc0), Avx.mm256_extractf128_pd(acc0, 1)); + v128 min128 = Sse2.min_pd(Avx.mm256_castpd256_pd128(min0), Avx.mm256_extractf128_pd(min0, 1)); if (Hint.Likely((int)length >= 2)) { - acc128 = Sse2.min_pd(acc128, Sse.loadu_ps(ptr_v256)); + min128 = Sse2.min_pd(min128, Sse.loadu_ps(ptr_v256)); ptr_v256 = (v256*)((v128*)ptr_v256 + 1); length -= 2; } - acc128 = Sse2.min_pd(acc128, Avx.permute_pd(acc128, Sse.SHUFFLE(0, 0, 0, 1))); + min128 = Sse2.min_pd(min128, Avx.permute_pd(min128, Sse.SHUFFLE(0, 0, 0, 1))); if (Hint.Likely(length != 0)) { - acc128 = Sse2.min_sd(acc128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); + min128 = Sse2.min_sd(min128, Sse2.cvtsi64x_si128(*(long*)ptr_v256)); } - return acc128.Double0; + return min128.Double0; } else if (Sse2.IsSse2Supported) { v128* ptr_v128 = (v128*)ptr; - v128 acc0 = new v128(double.PositiveInfinity); - v128 acc1 = new v128(double.PositiveInfinity); - v128 acc2 = new v128(double.PositiveInfinity); - v128 acc3 = new v128(double.PositiveInfinity); - - while (Hint.Likely(length >= 8)) + v128 min0 = new v128(double.PositiveInfinity); + + if (Hint.Likely(length >= 8)) { - acc0 = Sse2.min_pd(acc0, Sse.loadu_ps(ptr_v128++)); - acc1 = Sse2.min_pd(acc1, Sse.loadu_ps(ptr_v128++)); - acc2 = Sse2.min_pd(acc2, Sse.loadu_ps(ptr_v128++)); - acc3 = Sse2.min_pd(acc3, Sse.loadu_ps(ptr_v128++)); + v128 min1 = new v128(double.PositiveInfinity); + v128 min2 = new v128(double.PositiveInfinity); + v128 min3 = new v128(double.PositiveInfinity); - length -= 8; - } + do + { + min0 = Sse2.min_pd(min0, Sse.loadu_ps(ptr_v128++)); + min1 = Sse2.min_pd(min1, Sse.loadu_ps(ptr_v128++)); + min2 = Sse2.min_pd(min2, Sse.loadu_ps(ptr_v128++)); + min3 = Sse2.min_pd(min3, Sse.loadu_ps(ptr_v128++)); + + length -= 8; + } + while (Hint.Likely(length >= 8)); - acc0 = Sse2.min_pd(acc0, acc1); - acc2 = Sse2.min_pd(acc2, acc3); - acc0 = Sse2.min_pd(acc0, acc2); + min0 = Sse2.min_pd(min0, min1); + min2 = Sse2.min_pd(min2, min3); + min0 = Sse2.min_pd(min0, min2); + } if (Hint.Likely((int)length >= 2)) { - acc0 = Sse2.min_pd(acc0, Sse.loadu_ps(ptr_v128++)); + min0 = Sse2.min_pd(min0, Sse.loadu_ps(ptr_v128++)); if (Hint.Likely((int)length >= 2 * 2)) { - acc0 = Sse2.min_pd(acc0, Sse.loadu_ps(ptr_v128++)); + min0 = Sse2.min_pd(min0, Sse.loadu_ps(ptr_v128++)); if (Hint.Likely((int)length >= 3 * 2)) { - acc0 = Sse2.min_pd(acc0, Sse.loadu_ps(ptr_v128++)); + min0 = Sse2.min_pd(min0, Sse.loadu_ps(ptr_v128++)); length -= 3 * 2; } else @@ -2413,14 +2527,14 @@ public static double SIMD_Minimum(double* ptr, long length) } else { } - acc0 = Sse2.min_pd(acc0, Sse2.shuffle_epi32(acc0, Sse.SHUFFLE(0, 0, 3, 2))); + min0 = Sse2.min_pd(min0, Sse2.shuffle_epi32(min0, Sse.SHUFFLE(0, 0, 3, 2))); if (Hint.Likely(length != 0)) { - acc0 = Sse2.min_sd(acc0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); + min0 = Sse2.min_sd(min0, Sse2.cvtsi64x_si128(*(long*)ptr_v128)); } - return acc0.Double0; + return min0.Double0; } else { @@ -2501,4 +2615,4 @@ public static double SIMD_Minimum(this NativeSlice array, int index, int return SIMD_Minimum((double*)array.GetUnsafeReadOnlyPtr() + index, numEntries); } } -} +} \ No newline at end of file diff --git a/Runtime/Enums/BitwiseOperation.cs b/Runtime/Enums/BitwiseOperation.cs index 1c9bcfa..3622178 100644 --- a/Runtime/Enums/BitwiseOperation.cs +++ b/Runtime/Enums/BitwiseOperation.cs @@ -15,16 +15,18 @@ public enum BitwiseOperation : byte /// countbits(arrayElement ^ mask) XOR, - /// countbits(~arrayElement & mask) - ANDNOT, - /// countbits(~arrayElement | mask) - ORNOT, - /// countbits(~(arrayElement & mask)) NAND, /// countbits(~(arrayElement | mask)) NOR, /// countbits(~(arrayElement ^ mask)) XNOR, + + /// countbits(~arrayElement & mask) + ANDNOT, + /// countbits(~arrayElement | mask) + ORNOT, + /// countbits(~arrayElement ^ mask) + XORNOT = XNOR } } \ No newline at end of file diff --git a/Runtime/Enums/Comparison.cs b/Runtime/Enums/Comparison.cs new file mode 100644 index 0000000..654abff --- /dev/null +++ b/Runtime/Enums/Comparison.cs @@ -0,0 +1,20 @@ +namespace SIMDAlgorithms +{ + public enum Comparison : byte + { + /// arrayElement == value + EqualTo, + /// arrayElement != value + NotEqualTo, + + /// arrayElement > value + GreaterThan, + /// arrayElement < value + LessThan, + + /// arrayElement >= value + GreaterThanOrEqualTo, + /// arrayElement <= value + LessThanOrEqualTo + } +} \ No newline at end of file diff --git a/Runtime/Helpers/Compare.cs b/Runtime/Helpers/Compare.cs new file mode 100644 index 0000000..4c306cd --- /dev/null +++ b/Runtime/Helpers/Compare.cs @@ -0,0 +1,1059 @@ +using Unity.Burst.Intrinsics; + +using static Unity.Burst.Intrinsics.X86; + +namespace SIMDAlgorithms +{ + internal static class Compare + { + #region byte + /// Inverted for: Comparison.NotEqualTo + public static v256 Bytes256(v256 left, v256 right, Comparison where) + { + if (Avx2.IsAvx2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Avx2.mm256_cmpeq_epi8(left, right); + } + case Comparison.NotEqualTo: + { + return Avx2.mm256_cmpeq_epi8(left, right); + } + case Comparison.GreaterThan: + { + v256 MASK = Avx.mm256_set1_epi8(1 << 7); + + return Avx2.mm256_cmpgt_epi8(Avx2.mm256_xor_si256(left, MASK), Avx2.mm256_xor_si256(right, MASK)); + } + case Comparison.LessThan: + { + v256 MASK = Avx.mm256_set1_epi8(1 << 7); + + return Avx2.mm256_cmpgt_epi8(Avx2.mm256_xor_si256(right, MASK), Avx2.mm256_xor_si256(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + return Avx2.mm256_cmpeq_epi8(left, Avx2.mm256_max_epu8(left, right)); + } + case Comparison.LessThanOrEqualTo: + { + return Avx2.mm256_cmpeq_epi8(left, Avx2.mm256_min_epu8(left, right)); + } + + default: return default(v256); + } + } + else + { + return default(v256); + } + } + + /// Inverted for: Comparison.NotEqualTo + public static v128 Bytes128(v128 left, v128 right, Comparison where) + { + if (Sse2.IsSse2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse2.cmpeq_epi8(left, right); + } + case Comparison.NotEqualTo: + { + return Sse2.cmpeq_epi8(left, right); + } + case Comparison.GreaterThan: + { + v128 MASK = Sse2.set1_epi8(unchecked((sbyte)(1 << 7))); + + return Sse2.cmpgt_epi8(Sse2.xor_si128(left, MASK), Sse2.xor_si128(right, MASK)); + } + case Comparison.LessThan: + { + v128 MASK = Sse2.set1_epi8(unchecked((sbyte)(1 << 7))); + + return Sse2.cmpgt_epi8(Sse2.xor_si128(right, MASK), Sse2.xor_si128(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + return Sse2.cmpeq_epi8(left, Sse2.max_epu8(left, right)); + } + case Comparison.LessThanOrEqualTo: + { + return Sse2.cmpeq_epi8(left, Sse2.min_epu8(left, right)); + } + + default: return default(v128); + } + } + else + { + return default(v128); + } + } + + public static bool Bytes(byte left, byte right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region ushort + /// Inverted for: Comparison.NotEqualTo + public static v256 UShorts256(v256 left, v256 right, Comparison where) + { + if (Avx2.IsAvx2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Avx2.mm256_cmpeq_epi16(left, right); + } + case Comparison.NotEqualTo: + { + return Avx2.mm256_cmpeq_epi16(left, right); + } + case Comparison.GreaterThan: + { + v256 MASK = Avx.mm256_set1_epi16(unchecked((short)(1 << 15))); + + return Avx2.mm256_cmpgt_epi16(Avx2.mm256_xor_si256(left, MASK), Avx2.mm256_xor_si256(right, MASK)); + } + case Comparison.LessThan: + { + v256 MASK = Avx.mm256_set1_epi16(unchecked((short)(1 << 15))); + + return Avx2.mm256_cmpgt_epi16(Avx2.mm256_xor_si256(right, MASK), Avx2.mm256_xor_si256(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + return Avx2.mm256_cmpeq_epi16(left, Avx2.mm256_max_epu16(left, right)); + } + case Comparison.LessThanOrEqualTo: + { + return Avx2.mm256_cmpeq_epi16(left, Avx2.mm256_min_epu16(left, right)); + } + + default: return default(v256); + } + } + else + { + return default(v256); + } + } + + /// Inverted for: Comparison.NotEqualTo + public static v128 UShorts128(v128 left, v128 right, Comparison where) + { + if (Sse4_1.IsSse41Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse2.cmpeq_epi16(left, right); + } + case Comparison.NotEqualTo: + { + return Sse2.cmpeq_epi16(left, right); + } + case Comparison.GreaterThan: + { + v128 MASK = Sse2.set1_epi16(unchecked((short)(1 << 15))); + + return Sse2.cmpgt_epi16(Sse2.xor_si128(left, MASK), Sse2.xor_si128(right, MASK)); + } + case Comparison.LessThan: + { + v128 MASK = Sse2.set1_epi16(unchecked((short)(1 << 15))); + + return Sse2.cmpgt_epi16(Sse2.xor_si128(right, MASK), Sse2.xor_si128(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + return Sse2.cmpeq_epi16(left, Sse4_1.max_epu16(left, right)); + } + case Comparison.LessThanOrEqualTo: + { + return Sse2.cmpeq_epi16(left, Sse4_1.min_epu16(left, right)); + } + + default: return default(v128); + } + } + else if (Sse2.IsSse2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse2.cmpeq_epi16(left, right); + } + case Comparison.NotEqualTo: + { + return Sse2.cmpeq_epi16(left, right); + } + case Comparison.GreaterThan: + { + v128 MASK = Sse2.set1_epi16(unchecked((short)(1 << 15))); + + return Sse2.cmpgt_epi16(Sse2.xor_si128(left, MASK), Sse2.xor_si128(right, MASK)); + } + case Comparison.LessThan: + { + v128 MASK = Sse2.set1_epi16(unchecked((short)(1 << 15))); + + return Sse2.cmpgt_epi16(Sse2.xor_si128(right, MASK), Sse2.xor_si128(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + return Sse2.cmpeq_epi16(Sse2.setzero_si128(), Sse2.subs_epu16(right, left)); + } + case Comparison.LessThanOrEqualTo: + { + return Sse2.cmpeq_epi16(Sse2.setzero_si128(), Sse2.subs_epu16(left, right)); + } + + default: return default(v128); + } + } + else + { + return default(v128); + } + } + + public static bool UShorts(ushort left, ushort right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region uint + /// Inverted for: Comparison.NotEqualTo + public static v256 UInts256(v256 left, v256 right, Comparison where) + { + if (Avx2.IsAvx2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Avx2.mm256_cmpeq_epi32(left, right); + } + case Comparison.NotEqualTo: + { + return Avx2.mm256_cmpeq_epi32(left, right); + } + case Comparison.GreaterThan: + { + v256 MASK = Avx.mm256_set1_epi32(unchecked((int)(1 << 31))); + + return Avx2.mm256_cmpgt_epi32(Avx2.mm256_xor_si256(left, MASK), Avx2.mm256_xor_si256(right, MASK)); + } + case Comparison.LessThan: + { + v256 MASK = Avx.mm256_set1_epi32(unchecked((int)(1 << 31))); + + return Avx2.mm256_cmpgt_epi32(Avx2.mm256_xor_si256(right, MASK), Avx2.mm256_xor_si256(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + return Avx2.mm256_cmpeq_epi32(left, Avx2.mm256_max_epu32(left, right)); + } + case Comparison.LessThanOrEqualTo: + { + return Avx2.mm256_cmpeq_epi32(left, Avx2.mm256_min_epu32(left, right)); + } + + default: return default(v256); + } + } + else + { + return default(v256); + } + } + + /// Inverted for: Sse4_1: Comparison.NotEqualTo; Sse2: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v128 UInts128(v128 left, v128 right, Comparison where) + { + if (Sse4_1.IsSse41Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse2.cmpeq_epi32(left, right); + } + case Comparison.NotEqualTo: + { + return Sse2.cmpeq_epi32(left, right); + } + case Comparison.GreaterThan: + { + v128 MASK = Sse2.set1_epi32(unchecked((int)(1 << 31))); + + return Sse2.cmpgt_epi32(Sse2.xor_si128(left, MASK), Sse2.xor_si128(right, MASK)); + } + case Comparison.LessThan: + { + v128 MASK = Sse2.set1_epi32(unchecked((int)(1 << 31))); + + return Sse2.cmpgt_epi32(Sse2.xor_si128(right, MASK), Sse2.xor_si128(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + return Sse2.cmpeq_epi32(left, Sse4_1.max_epu32(left, right)); + } + case Comparison.LessThanOrEqualTo: + { + return Sse2.cmpeq_epi32(left, Sse4_1.min_epu32(left, right)); + } + + default: return default(v128); + } + } + else if (Sse2.IsSse2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse2.cmpeq_epi32(left, right); + } + case Comparison.NotEqualTo: + { + return Sse2.cmpeq_epi32(left, right); + } + case Comparison.GreaterThan: + { + v128 MASK = Sse2.set1_epi32(unchecked((int)(1 << 31))); + + return Sse2.cmpgt_epi32(Sse2.xor_si128(left, MASK), Sse2.xor_si128(right, MASK)); + } + case Comparison.LessThan: + { + v128 MASK = Sse2.set1_epi32(unchecked((int)(1 << 31))); + + return Sse2.cmpgt_epi32(Sse2.xor_si128(right, MASK), Sse2.xor_si128(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v128); + } + } + else + { + return default(v128); + } + } + + public static bool UInts(uint left, uint right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region ulong + /// Inverted for: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v256 ULongs256(v256 left, v256 right, Comparison where) + { + if (Avx2.IsAvx2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Avx2.mm256_cmpeq_epi64(left, right); + } + case Comparison.NotEqualTo: + { + return Avx2.mm256_cmpeq_epi64(left, right); + } + case Comparison.GreaterThan: + { + v256 MASK = Avx.mm256_set1_epi64x(unchecked((long)(1ul << 63))); + + return Avx2.mm256_cmpgt_epi64(Avx2.mm256_xor_si256(left, MASK), Avx2.mm256_xor_si256(right, MASK)); + } + case Comparison.LessThan: + { + v256 MASK = Avx.mm256_set1_epi64x(unchecked((long)(1ul << 63))); + + return Avx2.mm256_cmpgt_epi64(Avx2.mm256_xor_si256(right, MASK), Avx2.mm256_xor_si256(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v256); + } + } + else + { + return default(v256); + } + } + + /// Inverted for: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v128 ULongs128(v128 left, v128 right, Comparison where) + { + if (Sse4_2.IsSse42Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse4_1.cmpeq_epi64(left, right); + } + case Comparison.NotEqualTo: + { + return Sse4_1.cmpeq_epi64(left, right); + } + case Comparison.GreaterThan: + { + v128 MASK = Sse2.set1_epi64x(unchecked((long)(1ul << 63))); + + return Sse4_2.cmpgt_epi64(Sse2.xor_si128(left, MASK), Sse2.xor_si128(right, MASK)); + } + case Comparison.LessThan: + { + v128 MASK = Sse2.set1_epi64x(unchecked((long)(1ul << 63))); + + return Sse4_2.cmpgt_epi64(Sse2.xor_si128(right, MASK), Sse2.xor_si128(left, MASK)); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v128); + } + } + else if (Sse4_1.IsSse41Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse4_1.cmpeq_epi64(left, right); + } + case Comparison.NotEqualTo: + { + return Sse4_1.cmpeq_epi64(left, right); + } + + default: return default(v128); + } + } + else + { + return default(v128); + } + } + + public static bool ULongs(ulong left, ulong right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region sbyte + /// Inverted for: Comparison.NotEqualTo + public static v256 SBytes256(v256 left, v256 right, Comparison where) + { + if (Avx2.IsAvx2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Avx2.mm256_cmpeq_epi8(left, right); + } + case Comparison.NotEqualTo: + { + return Avx2.mm256_cmpeq_epi8(left, right); + } + case Comparison.GreaterThan: + { + return Avx2.mm256_cmpgt_epi8(left, right); + } + case Comparison.LessThan: + { + return Avx2.mm256_cmpgt_epi8(right, left); + } + case Comparison.GreaterThanOrEqualTo: + { + return Avx2.mm256_cmpgt_epi8(right, left); + } + case Comparison.LessThanOrEqualTo: + { + return Avx2.mm256_cmpgt_epi8(left, right); + } + + default: return default(v256); + } + } + else + { + return default(v256); + } + } + + /// Inverted for: Comparison.NotEqualTo + public static v128 SBytes128(v128 left, v128 right, Comparison where) + { + if (Sse2.IsSse2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse2.cmpeq_epi8(left, right); + } + case Comparison.NotEqualTo: + { + return Sse2.cmpeq_epi8(left, right); + } + case Comparison.GreaterThan: + { + return Sse2.cmpgt_epi8(left, right); + } + case Comparison.LessThan: + { + return Sse2.cmpgt_epi8(right, left); + } + case Comparison.GreaterThanOrEqualTo: + { + return Sse2.cmpgt_epi8(right, left); + } + case Comparison.LessThanOrEqualTo: + { + return Sse2.cmpgt_epi8(left, right); + } + + default: return default(v128); + } + } + else + { + return default(v128); + } + } + + public static bool SBytes(sbyte left, sbyte right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region short + /// Inverted for: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v256 Shorts256(v256 left, v256 right, Comparison where) + { + if (Avx2.IsAvx2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Avx2.mm256_cmpeq_epi16(left, right); + } + case Comparison.NotEqualTo: + { + return Avx2.mm256_cmpeq_epi16(left, right); + } + case Comparison.GreaterThan: + { + return Avx2.mm256_cmpgt_epi16(left, right); + } + case Comparison.LessThan: + { + return Avx2.mm256_cmpgt_epi16(right, left); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v256); + } + } + else + { + return default(v256); + } + } + + /// Inverted for: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v128 Shorts128(v128 left, v128 right, Comparison where) + { + if (Sse2.IsSse2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse2.cmpeq_epi16(left, right); + } + case Comparison.NotEqualTo: + { + return Sse2.cmpeq_epi16(left, right); + } + case Comparison.GreaterThan: + { + return Sse2.cmpgt_epi16(left, right); + } + case Comparison.LessThan: + { + return Sse2.cmpgt_epi16(right, left); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v128); + } + } + else + { + return default(v128); + } + } + + public static bool Shorts(short left, short right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region int + /// Inverted for: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v256 Ints256(v256 left, v256 right, Comparison where) + { + if (Avx2.IsAvx2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Avx2.mm256_cmpeq_epi32(left, right); + } + case Comparison.NotEqualTo: + { + return Avx2.mm256_cmpeq_epi32(left, right); + } + case Comparison.GreaterThan: + { + return Avx2.mm256_cmpgt_epi32(left, right); + } + case Comparison.LessThan: + { + return Avx2.mm256_cmpgt_epi32(right, left); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v256); + } + } + else + { + return default(v256); + } + } + + /// Inverted for: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v128 Ints128(v128 left, v128 right, Comparison where) + { + if (Sse2.IsSse2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse2.cmpeq_epi32(left, right); + } + case Comparison.NotEqualTo: + { + return Sse2.cmpeq_epi32(left, right); + } + case Comparison.GreaterThan: + { + return Sse2.cmpgt_epi32(left, right); + } + case Comparison.LessThan: + { + return Sse2.cmpgt_epi32(right, left); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v128); + } + } + else + { + return default(v128); + } + } + + public static bool Ints(int left, int right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region long + /// Inverted for: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v256 Longs256(v256 left, v256 right, Comparison where) + { + if (Avx2.IsAvx2Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Avx2.mm256_cmpeq_epi64(left, right); + } + case Comparison.NotEqualTo: + { + return Avx2.mm256_cmpeq_epi64(left, right); + } + case Comparison.GreaterThan: + { + return Avx2.mm256_cmpgt_epi64(left, right); + } + case Comparison.LessThan: + { + return Avx2.mm256_cmpgt_epi64(right, left); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v256); + } + } + else + { + return default(v256); + } + } + + /// Inverted for: Comparison.NotEqualTo, Comparison.GreaterThanOrEqualTo, Comparison.LessThanOrEqualTo + public static v128 Longs128(v128 left, v128 right, Comparison where) + { + if (Sse4_2.IsSse42Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse4_1.cmpeq_epi64(left, right); + } + case Comparison.NotEqualTo: + { + return Sse4_1.cmpeq_epi64(left, right); + } + case Comparison.GreaterThan: + { + return Sse4_2.cmpgt_epi64(left, right); + } + case Comparison.LessThan: + { + return Sse4_2.cmpgt_epi64(right, left); + } + case Comparison.GreaterThanOrEqualTo: + { + goto case Comparison.LessThan; + } + case Comparison.LessThanOrEqualTo: + { + goto case Comparison.GreaterThan; + } + + default: return default(v128); + } + } + else if (Sse4_1.IsSse41Supported) + { + switch (where) + { + case Comparison.EqualTo: + { + return Sse4_1.cmpeq_epi64(left, right); + } + case Comparison.NotEqualTo: + { + return Sse4_1.cmpeq_epi64(left, right); + } + + default: return default(v128); + } + } + else + { + return default(v128); + } + } + + public static bool Longs(long left, long right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region float + public static v256 Floats256(v256 left, v256 right, Comparison where) + { + if (Avx.IsAvxSupported) + { + return where switch + { + Comparison.EqualTo => Avx.mm256_cmp_ps(left, right, (int)Avx.CMP.EQ_OQ), + Comparison.NotEqualTo => Avx.mm256_cmp_ps(left, right, (int)Avx.CMP.NEQ_OQ), + Comparison.GreaterThan => Avx.mm256_cmp_ps(left, right, (int)Avx.CMP.GT_OQ), + Comparison.LessThan => Avx.mm256_cmp_ps(left, right, (int)Avx.CMP.LT_OQ), + Comparison.GreaterThanOrEqualTo => Avx.mm256_cmp_ps(left, right, (int)Avx.CMP.GE_OQ), + Comparison.LessThanOrEqualTo => Avx.mm256_cmp_ps(left, right, (int)Avx.CMP.LE_OQ), + + _ => default(v256), + }; + } + else + { + return default(v256); + } + } + + public static v128 Floats128(v128 left, v128 right, Comparison where) + { + if (Sse.IsSseSupported) + { + return where switch + { + Comparison.EqualTo => Sse.cmpeq_ps(left, right), + Comparison.NotEqualTo => Sse.cmpneq_ps(left, right), + Comparison.GreaterThan => Sse.cmpgt_ps(left, right), + Comparison.LessThan => Sse.cmplt_ps(left, right), + Comparison.GreaterThanOrEqualTo => Sse.cmpge_ps(left, right), + Comparison.LessThanOrEqualTo => Sse.cmple_ps(left, right), + + _ => default(v128), + }; + } + else + { + return default(v128); + } + } + + public static bool Floats(float left, float right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + + #region double + public static v256 Doubles256(v256 left, v256 right, Comparison where) + { + if (Avx.IsAvxSupported) + { + return where switch + { + Comparison.EqualTo => Avx.mm256_cmp_pd(left, right, (int)Avx.CMP.EQ_OQ), + Comparison.NotEqualTo => Avx.mm256_cmp_pd(left, right, (int)Avx.CMP.NEQ_OQ), + Comparison.GreaterThan => Avx.mm256_cmp_pd(left, right, (int)Avx.CMP.GT_OQ), + Comparison.LessThan => Avx.mm256_cmp_pd(left, right, (int)Avx.CMP.LT_OQ), + Comparison.GreaterThanOrEqualTo => Avx.mm256_cmp_pd(left, right, (int)Avx.CMP.GE_OQ), + Comparison.LessThanOrEqualTo => Avx.mm256_cmp_pd(left, right, (int)Avx.CMP.LE_OQ), + + _ => default(v256), + }; + } + else + { + return default(v256); + } + } + + public static v128 Doubles128(v128 left, v128 right, Comparison where) + { + if (Sse2.IsSse2Supported) + { + return where switch + { + Comparison.EqualTo => Sse2.cmpeq_pd(left, right), + Comparison.NotEqualTo => Sse2.cmpneq_pd(left, right), + Comparison.GreaterThan => Sse2.cmpgt_pd(left, right), + Comparison.LessThan => Sse2.cmplt_pd(left, right), + Comparison.GreaterThanOrEqualTo => Sse2.cmpge_pd(left, right), + Comparison.LessThanOrEqualTo => Sse2.cmple_pd(left, right), + + _ => default(v128), + }; + } + else + { + return default(v128); + } + } + + public static bool Doubles(double left, double right, Comparison where) + { + return where switch + { + Comparison.EqualTo => left == right, + Comparison.NotEqualTo => left != right, + Comparison.GreaterThan => left > right, + Comparison.LessThan => left < right, + Comparison.GreaterThanOrEqualTo => left >= right, + Comparison.LessThanOrEqualTo => left <= right, + + _ => default(bool), + }; + } + #endregion + } +} \ No newline at end of file diff --git a/Runtime/Helpers/Fallback.cs b/Runtime/Helpers/Fallback.cs new file mode 100644 index 0000000..806fda0 --- /dev/null +++ b/Runtime/Helpers/Fallback.cs @@ -0,0 +1,24 @@ +using System.Runtime.CompilerServices; +using Unity.Burst.Intrinsics; + +using static Unity.Burst.Intrinsics.X86; + +namespace SIMDAlgorithms +{ + internal static class Fallback + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static v128 blendv_epi8_SSE2(v128 a, v128 b, v128 mask) + { + if (Sse2.IsSse2Supported) + { + return Sse2.or_si128(Sse2.and_si128(mask, b), + Sse2.andnot_si128(mask, a)); + } + else + { + return default(v128); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Helpers/PartialVectors.cs b/Runtime/Helpers/PartialVectors.cs new file mode 100644 index 0000000..12407dd --- /dev/null +++ b/Runtime/Helpers/PartialVectors.cs @@ -0,0 +1,117 @@ +using Unity.Burst.CompilerServices; + +using static Unity.Burst.Intrinsics.X86; + +namespace SIMDAlgorithms +{ + internal static class PartialVectors + { + public static bool ShouldMask(Comparison where, byte value) + { + switch (where) + { + case Comparison.LessThan: return !Constant.IsConstantExpression(value) && value != 0; + case Comparison.LessThanOrEqualTo: return true; + case Comparison.GreaterThan: return false; + + case Comparison.NotEqualTo: return true; + case Comparison.EqualTo: return !Constant.IsConstantExpression(value) && value == 0; + case Comparison.GreaterThanOrEqualTo: return !Constant.IsConstantExpression(value) && value == 0; + + default: return true; + } + } + + public static bool ShouldMask(Comparison where, ushort value) + { + switch (where) + { + case Comparison.LessThan: return !Constant.IsConstantExpression(value) && value != 0; + case Comparison.LessThanOrEqualTo: return true; + case Comparison.GreaterThan: return false; + + case Comparison.NotEqualTo: return true; + case Comparison.EqualTo: return !Constant.IsConstantExpression(value) && value == 0; + case Comparison.GreaterThanOrEqualTo: return !Constant.IsConstantExpression(value) && value == 0; + + default: return true; + } + } + + public static bool ShouldMask(Comparison where, uint value) + { + switch (where) + { + case Comparison.LessThan: return !Constant.IsConstantExpression(value) && value != 0; + case Comparison.LessThanOrEqualTo: return true; + case Comparison.GreaterThan: return false; + + case Comparison.NotEqualTo: return true; + case Comparison.EqualTo: return !Constant.IsConstantExpression(value) && value == 0; + case Comparison.GreaterThanOrEqualTo: { if (Sse4_1.IsSse41Supported) return !Constant.IsConstantExpression(value) && value == 0; else return true; }; + + default: return true; + } + } + + public static bool ShouldMask(Comparison where, sbyte value) + { + switch (where) + { + case Comparison.NotEqualTo: return true; + case Comparison.EqualTo: return !Constant.IsConstantExpression(value) && value == 0; + case Comparison.GreaterThan: return !Constant.IsConstantExpression(value) && value < 0; + case Comparison.GreaterThanOrEqualTo: return true; + case Comparison.LessThan: return !Constant.IsConstantExpression(value) && value > 0; + case Comparison.LessThanOrEqualTo: return true; + + default: return true; + } + } + + public static bool ShouldMask(Comparison where, short value) + { + switch (where) + { + case Comparison.NotEqualTo: return true; + case Comparison.EqualTo: return !Constant.IsConstantExpression(value) && value == 0; + case Comparison.GreaterThan: return !Constant.IsConstantExpression(value) && value < 0; + case Comparison.GreaterThanOrEqualTo: return true; + case Comparison.LessThan: return !Constant.IsConstantExpression(value) && value > 0; + case Comparison.LessThanOrEqualTo: return true; + + default: return true; + } + } + + public static bool ShouldMask(Comparison where, int value) + { + switch (where) + { + case Comparison.NotEqualTo: return true; + case Comparison.EqualTo: return !Constant.IsConstantExpression(value) && value == 0; + case Comparison.GreaterThan: return !Constant.IsConstantExpression(value) && value < 0; + case Comparison.GreaterThanOrEqualTo: return true; + case Comparison.LessThan: return !Constant.IsConstantExpression(value) && value > 0; + case Comparison.LessThanOrEqualTo: return true; + + default: return true; + } + } + + public static bool ShouldMask(Comparison where, float value) + { + switch (where) + { + case Comparison.NotEqualTo: return !Constant.IsConstantExpression(value) && value != 0f; + case Comparison.EqualTo: return !Constant.IsConstantExpression(value) && value == 0f; + case Comparison.GreaterThan: return !Constant.IsConstantExpression(value) && value < 0f; + case Comparison.GreaterThanOrEqualTo: return !Constant.IsConstantExpression(value) && value <= 0f; + case Comparison.LessThan: return !Constant.IsConstantExpression(value) && value > 0f; + case Comparison.LessThanOrEqualTo: return !Constant.IsConstantExpression(value) && value >= 0f; + + default: return true; + } + } + } +} \ No newline at end of file diff --git a/Runtime/Helpers/SummationRange.cs b/Runtime/Helpers/SummationRange.cs index ccc2727..ad91fed 100644 --- a/Runtime/Helpers/SummationRange.cs +++ b/Runtime/Helpers/SummationRange.cs @@ -74,5 +74,15 @@ public static TypeCode Summation(TypeCode summandType, long summandCount) } } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TypeCode Count(long arrayLength) + { + bool possible8BitOverflow = arrayLength > byte.MaxValue; + bool possible16BitOverflow = arrayLength > ushort.MaxValue; + bool possible32BitOverflow = arrayLength > uint.MaxValue; + + return (TypeCode)((int)TypeCode.Byte + ((*(byte*)&possible8BitOverflow + *(byte*)&possible16BitOverflow + *(byte*)&possible32BitOverflow) << 1)); + } } -} +} \ No newline at end of file diff --git a/Tests/AssemblyInfo.cs b/Tests/AssemblyInfo.cs index 5513c71..690fade 100644 --- a/Tests/AssemblyInfo.cs +++ b/Tests/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Tests/Editor/CONSTANTS.cs b/Tests/Editor/CONSTANTS.cs deleted file mode 100644 index af02321..0000000 --- a/Tests/Editor/CONSTANTS.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace SIMDAlgorithms.Tests -{ - public static class CONSTANTS - { - public const byte RNG_SEED = 123; - public const byte NUM_TESTS = 3; - } -} diff --git a/Tests/Editor/Contains.cs b/Tests/Editor/Contains.cs index 2ef8291..ab54520 100644 --- a/Tests/Editor/Contains.cs +++ b/Tests/Editor/Contains.cs @@ -5,19 +5,15 @@ namespace SIMDAlgorithms.Tests { public static class Contains { + #region EQUAL [Test] - public static void Byte() + public static void Byte_Equal() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 20000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); - } - ; for (int j = 0; j < 10; j++) { byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); @@ -34,30 +30,79 @@ public static void Byte() Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); } } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 500); + } + + [Test] + public static void UShort_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + bool std = array.Contains(test); + bool mine = array.SIMD_Contains(test); + + Assert.AreEqual(std, mine); - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 20000), Allocator.Persistent); - } + if (std == false) + { + test = array[rng.NextInt(0, array.Length)]; - array.Dispose(); + Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); } [Test] - public static void UShort() + public static void UInt_Equal() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + uint test = rng.NextUInt(); + + bool std = array.Contains(test); + bool mine = array.SIMD_Contains(test); + + Assert.AreEqual(std, mine); + + if (std == false) + { + test = array[rng.NextInt(0, array.Length)]; + + Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); + } } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + Helpers.Test( + (array) => + { for (int j = 0; j < 10; j++) { - ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); bool std = array.Contains(test); bool mine = array.SIMD_Contains(test); @@ -71,30 +116,79 @@ public static void UShort() Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); } } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + bool std = array.Contains(test); + bool mine = array.SIMD_Contains(test); + + Assert.AreEqual(std, mine); - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + if (std == false) + { + test = array[rng.NextInt(0, array.Length)]; - array.Dispose(); + Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1), + 500); } [Test] - public static void UInt() + public static void Short_Equal() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = rng.NextUInt(); + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + bool std = array.Contains(test); + bool mine = array.SIMD_Contains(test); + + Assert.AreEqual(std, mine); + + if (std == false) + { + test = array[rng.NextInt(0, array.Length)]; + + Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); + } } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1), + 100000); + } - for (int j = 0; j < 50; j++) + [Test] + public static void Int_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { - uint test = rng.NextUInt(); + int test = rng.NextInt(); bool std = array.Contains(test); bool mine = array.SIMD_Contains(test); @@ -108,30 +202,77 @@ public static void UInt() Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); } } + }, + rng.NextInt); + } + + [Test] + public static void Long_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + bool std = array.Contains(test); + bool mine = array.SIMD_Contains(test); + + Assert.AreEqual(std, mine); - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + if (std == false) + { + test = array[rng.NextInt(0, array.Length)]; - array.Dispose(); + Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); } [Test] - public static void ULong() + public static void Float_Equal() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 2000000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 25; j++) { - array[j] = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + float test = rng.NextFloat(); + + bool std = array.Contains(test); + bool mine = array.SIMD_Contains(test); + + Assert.AreEqual(std, mine); + + if (std == false) + { + test = array[rng.NextInt(0, array.Length)]; + + Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); + } } + }, + () => rng.NextFloat(float.MinValue, float.MaxValue)); + } + + [Test] + public static void Double_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int j = 0; j < 100; j++) + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) { - ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + double test = rng.NextDouble(); bool std = array.Contains(test); bool mine = array.SIMD_Contains(test); @@ -145,86 +286,1589 @@ public static void ULong() Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); } } + }, + () => rng.NextDouble(double.MinValue, double.MaxValue)); + } + #endregion + + #region NOT_EQUAL + [Test] + public static void Byte_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] != test) + { + std = true; + break; + } + } - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 2000000), Allocator.Persistent); - } + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); - array.Dispose(); + Assert.AreEqual(std, mine); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 500); } [Test] - public static void Float() + public static void UShort_NotEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = rng.NextFloat(); + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] != test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); + + Assert.AreEqual(std, mine); } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int j = 0; j < 50; j++) + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { - float test = rng.NextFloat(); + uint test = rng.NextUInt(); + + bool std = false; - bool std = array.Contains(test); - bool mine = array.SIMD_Contains(test); + for (int i = 0; i < array.Length; i++) + { + if (array[i] != test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); Assert.AreEqual(std, mine); + } + }, + rng.NextUInt); + } - if (std == false) + [Test] + public static void ULong_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) { - test = array[rng.NextInt(0, array.Length)]; + if (array[i] != test) + { + std = true; + break; + } + } - Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] != test) + { + std = true; + break; + } } + + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); + + Assert.AreEqual(std, mine); } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1), + 500); + } + + [Test] + public static void Short_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] != test) + { + std = true; + break; + } + } - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); - array.Dispose(); + Assert.AreEqual(std, mine); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1), + 100000); } [Test] - public static void Double() + public static void Int_NotEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 2000000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = rng.NextDouble(); + int test = rng.NextInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] != test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); + + Assert.AreEqual(std, mine); } + }, + rng.NextInt); + } - for (int j = 0; j < 100; j++) + [Test] + public static void Long_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { - double test = rng.NextDouble(); + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + bool std = false; - bool std = array.Contains(test); - bool mine = array.SIMD_Contains(test); + for (int i = 0; i < array.Length; i++) + { + if (array[i] != test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } - if (std == false) + [Test] + public static void Float_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + float test = rng.NextFloat(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) { - test = array[rng.NextInt(0, array.Length)]; + if (array[i] != test) + { + std = true; + break; + } + } - Assert.AreEqual(array.Contains(test), array.SIMD_Contains(test)); + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextFloat(float.MinValue, float.MaxValue)); + } + + [Test] + public static void Double_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + double test = rng.NextDouble(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] != test) + { + std = true; + break; + } } + + bool mine = array.SIMD_Contains(test, Comparison.NotEqualTo); + + Assert.AreEqual(std, mine); } + }, + () => rng.NextDouble(double.MinValue, double.MaxValue)); + } + #endregion + + #region LESS + [Test] + public static void Byte_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 2000000), Allocator.Persistent); - } + bool std = false; - array.Dispose(); + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 500); + } + + [Test] + public static void UShort_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + uint test = rng.NextUInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1), + 500); + } + + [Test] + public static void Short_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1), + 100000); + } + + [Test] + public static void Int_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + int test = rng.NextInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + float test = rng.NextFloat(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextFloat(float.MinValue, float.MaxValue)); + } + + [Test] + public static void Double_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + double test = rng.NextDouble(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] < test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThan); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextDouble(double.MinValue, double.MaxValue)); + } + #endregion + + #region GREATER + [Test] + public static void Byte_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 500); + } + + [Test] + public static void UShort_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + uint test = rng.NextUInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1), + 500); + } + + [Test] + public static void Short_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1), + 100000); + } + + [Test] + public static void Int_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + int test = rng.NextInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + float test = rng.NextFloat(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextFloat(float.MinValue, float.MaxValue)); + } + + [Test] + public static void Double_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + double test = rng.NextDouble(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] > test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThan); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextDouble(double.MinValue, double.MaxValue)); + } + #endregion + + #region LESS_EQUAL + [Test] + public static void Byte_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 500); + } + + [Test] + public static void UShort_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + uint test = rng.NextUInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1), + 500); + } + + [Test] + public static void Short_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1), + 100000); + } + + [Test] + public static void Int_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + int test = rng.NextInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + float test = rng.NextFloat(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextFloat(float.MinValue, float.MaxValue)); + } + + [Test] + public static void Double_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + double test = rng.NextDouble(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] <= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.LessThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextDouble(double.MinValue, double.MaxValue)); + } + #endregion + + #region GREATER_EQUAL + [Test] + public static void Byte_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 500); + } + + [Test] + public static void UShort_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + uint test = rng.NextUInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1), + 500); + } + + [Test] + public static void Short_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1), + 100000); + } + + [Test] + public static void Int_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + int test = rng.NextInt(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + float test = rng.NextFloat(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextFloat(float.MinValue, float.MaxValue)); + } + + [Test] + public static void Double_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 25; j++) + { + double test = rng.NextDouble(); + + bool std = false; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] >= test) + { + std = true; + break; + } + } + + bool mine = array.SIMD_Contains(test, Comparison.GreaterThanOrEqualTo); + + Assert.AreEqual(std, mine); + } + }, + () => rng.NextDouble(double.MinValue, double.MaxValue)); } + #endregion } } \ No newline at end of file diff --git a/Tests/Editor/Count.cs b/Tests/Editor/Count.cs index 78266f1..96b33e7 100644 --- a/Tests/Editor/Count.cs +++ b/Tests/Editor/Count.cs @@ -1,23 +1,18 @@ using NUnit.Framework; -using Unity.Collections; +using System; namespace SIMDAlgorithms.Tests { public static class Count { [Test] - public static void Bool() + public static void Bool_RangeInt() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextBool(); - } - long std_true = 0; long std_false = 0; @@ -35,28 +30,49 @@ public static void Bool() Assert.AreEqual(std_true, array.SIMD_Count()); Assert.AreEqual(std_false, array.SIMD_Count(false)); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextBool); } [Test] - public static void Byte() + public static void Bool_RangeByte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { + byte std_true = 0; + byte std_false = 0; + for (int j = 0; j < array.Length; j++) { - array[j] = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + if (array[j] == true) + { + std_true++; + } + else + { + std_false++; + } } - for (int j = 0; j < 100; j++) + Assert.AreEqual(std_true, array.SIMD_Count(true, TypeCode.Byte)); + Assert.AreEqual(std_false, array.SIMD_Count(false, TypeCode.Byte)); + }, + rng.NextBool); + } + + #region EQUAL + [Test] + public static void Byte_Equal_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { long std = 0; byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); @@ -71,28 +87,46 @@ public static void Byte() Assert.AreEqual(std, array.SIMD_Count(test)); } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); } [Test] - public static void UShort() + public static void Byte_Equal_RangeByte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + byte std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, returnType: TypeCode.Byte)); } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void UShort_Equal_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int j = 0; j < 100; j++) + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { long std = 0; ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); @@ -107,28 +141,46 @@ public static void UShort() Assert.AreEqual(std, array.SIMD_Count(test)); } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); } [Test] - public static void UInt() + public static void UShort_Equal_RangeShort() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = rng.NextUInt(); + ushort std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, returnType: TypeCode.UInt16)); } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UInt_Equal_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int j = 0; j < 100; j++) + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { long std = 0; uint test = rng.NextUInt(); @@ -156,31 +208,167 @@ public static void UInt() Assert.AreEqual(std, array.SIMD_Count(test)); } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + long std = 0; + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + if (std == 0) + { + test = array[rng.NextInt(0, array.Length)]; + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } + } - array.Dispose(); + Assert.AreEqual(std, array.SIMD_Count(test)); + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); } [Test] - public static void ULong() + public static void SByte_Equal_RangeInt() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) + { + long std = 0; + sbyte test = (sbyte)rng.NextInt(byte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void SByte_Equal_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { - array[j] = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + byte std = 0; + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, returnType: TypeCode.Byte)); } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } - for (int j = 0; j < 100; j++) + [Test] + public static void Short_Equal_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { long std = 0; - ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Short_Equal_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, returnType: TypeCode.UInt16)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Equal_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + int test = rng.NextInt(); for (int k = 0; k < array.Length; k++) { @@ -205,28 +393,56 @@ public static void ULong() Assert.AreEqual(std, array.SIMD_Count(test)); } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextInt); } [Test] - public static void Float() + public static void Long_Equal() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + long std = 0; + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } + + if (std == 0) { - array[j] = rng.NextFloat(); + test = array[rng.NextInt(0, array.Length)]; + + for (int k = 0; k < array.Length; k++) + { + if (array[k] == test) + { + std++; + } + } } - for (int j = 0; j < 100; j++) + Assert.AreEqual(std, array.SIMD_Count(test)); + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) { long std = 0; float test = rng.NextFloat(); @@ -254,28 +470,19 @@ public static void Float() Assert.AreEqual(std, array.SIMD_Count(test)); } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextFloat); } [Test] - public static void Double() + public static void Double_Equal() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextDouble(); - } - - for (int j = 0; j < 100; j++) + for (int j = 0; j < 10; j++) { long std = 0; double test = rng.NextDouble(); @@ -303,12 +510,1987 @@ public static void Double() Assert.AreEqual(std, array.SIMD_Count(test)); } + }, + rng.NextDouble); + } + #endregion + + #region NOT_EQUAL + [Test] + public static void Byte_NotEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void Byte_NotEqual_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo, TypeCode.Byte)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void UShort_NotEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UShort_NotEqual_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo, TypeCode.UInt16)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UInt_NotEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + uint test = rng.NextUInt(); - array.Dispose(); + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + if (std == array.Length) + { + test = array[rng.NextInt(0, array.Length)]; + std = 0; + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + if (std == array.Length) + { + test = array[rng.NextInt(0, array.Length)]; + std = 0; + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_NotEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + sbyte test = (sbyte)rng.NextInt(byte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void SByte_NotEqual_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo, TypeCode.Byte)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_NotEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Short_NotEqual_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo, TypeCode.UInt16)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_NotEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + int test = rng.NextInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + if (std == array.Length) + { + test = array[rng.NextInt(0, array.Length)]; + std = 0; + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + if (std == array.Length) + { + test = array[rng.NextInt(0, array.Length)]; + std = 0; + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + float test = rng.NextFloat(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + if (std == array.Length) + { + test = array[rng.NextInt(0, array.Length)]; + std = 0; + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + double test = rng.NextDouble(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + + if (std == array.Length) + { + test = array[rng.NextInt(0, array.Length)]; + std = 0; + + for (int k = 0; k < array.Length; k++) + { + if (array[k] != test) + { + std++; + } + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.NotEqualTo)); + } + }, + rng.NextDouble); + } + #endregion + + #region LESS + [Test] + public static void Byte_Less_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void Byte_Less_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan, TypeCode.Byte)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void UShort_Less_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UShort_Less_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan, TypeCode.UInt16)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UInt_Less_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + uint test = rng.NextUInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + long std = 0; + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Less_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + sbyte test = (sbyte)rng.NextInt(byte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void SByte_Less_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan, TypeCode.Byte)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_Less_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Short_Less_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan, TypeCode.UInt16)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Less_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + int test = rng.NextInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + long std = 0; + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + float test = rng.NextFloat(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + double test = rng.NextDouble(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] < test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThan)); + } + }, + rng.NextDouble); + } + #endregion + + #region GREATER + [Test] + public static void Byte_Greater_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void Byte_Greater_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan, TypeCode.Byte)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void UShort_Greater_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UShort_Greater_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan, TypeCode.UInt16)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UInt_Greater_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + uint test = rng.NextUInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Greater_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + sbyte test = (sbyte)rng.NextInt(byte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void SByte_Greater_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan, TypeCode.Byte)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_Greater_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Short_Greater_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan, TypeCode.UInt16)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Greater_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + int test = rng.NextInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + float test = rng.NextFloat(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + double test = rng.NextDouble(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] > test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThan)); + } + }, + rng.NextDouble); + } + #endregion + + #region LESS_EQUAL + [Test] + public static void Byte_LessOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void Byte_LessOrEqual_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo, TypeCode.Byte)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void UShort_LessOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UShort_LessOrEqual_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo, TypeCode.UInt16)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UInt_LessOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + uint test = rng.NextUInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_LessOrEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_LessOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + sbyte test = (sbyte)rng.NextInt(byte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void SByte_LessOrEqual_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo, TypeCode.Byte)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_LessOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Short_LessOrEqual_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo, TypeCode.UInt16)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_LessOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + int test = rng.NextInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_LessOrEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_LessOrEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + float test = rng.NextFloat(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_LessOrEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + double test = rng.NextDouble(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] <= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.LessThanOrEqualTo)); + } + }, + rng.NextDouble); + } + #endregion + + #region GREATER_EQUAL + [Test] + public static void Byte_GreaterOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void Byte_GreaterOrEqual_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo, TypeCode.Byte)); + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void UShort_GreaterOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UShort_GreaterOrEqual_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo, TypeCode.UInt16)); + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UInt_GreaterOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + uint test = rng.NextUInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_GreaterOrEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_GreaterOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + sbyte test = (sbyte)rng.NextInt(byte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void SByte_GreaterOrEqual_RangeByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte std = 0; + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo, TypeCode.Byte)); + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_GreaterOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Short_GreaterOrEqual_RangeShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort std = 0; + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo, TypeCode.UInt16)); + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_GreaterOrEqual_RangeInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + int test = rng.NextInt(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + rng.NextInt); + } + + [Test] + public static void Long_GreaterOrEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_GreaterOrEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + float test = rng.NextFloat(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_GreaterOrEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + long std = 0; + double test = rng.NextDouble(); + + for (int k = 0; k < array.Length; k++) + { + if (array[k] >= test) + { + std++; + } + } + + Assert.AreEqual(std, array.SIMD_Count(test, Comparison.GreaterThanOrEqualTo)); + } + }, + rng.NextDouble); } + #endregion } } \ No newline at end of file diff --git a/Tests/Editor/CountBits.cs b/Tests/Editor/CountBits.cs index a512955..344a315 100644 --- a/Tests/Editor/CountBits.cs +++ b/Tests/Editor/CountBits.cs @@ -30,7 +30,7 @@ private static ulong Scalar(void* ptr, long bytes) [Test] public static void Generic() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -50,7 +50,7 @@ public static void Generic() [Test] public static void Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -70,7 +70,7 @@ public static void Byte() [Test] public static void UShort() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -90,7 +90,7 @@ public static void UShort() [Test] public static void UInt() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -110,7 +110,7 @@ public static void UInt() [Test] public static void ULong() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -130,7 +130,7 @@ public static void ULong() [Test] public static void NOT_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -159,7 +159,7 @@ public static void NOT_1Byte() [Test] public static void AND_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -188,7 +188,7 @@ public static void AND_1Byte() [Test] public static void OR_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -217,7 +217,7 @@ public static void OR_1Byte() [Test] public static void XOR_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -246,7 +246,7 @@ public static void XOR_1Byte() [Test] public static void NAND_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -275,7 +275,7 @@ public static void NAND_1Byte() [Test] public static void NOR_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -304,7 +304,7 @@ public static void NOR_1Byte() [Test] public static void XNOR_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -333,7 +333,7 @@ public static void XNOR_1Byte() [Test] public static void ANDNOT_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -362,7 +362,7 @@ public static void ANDNOT_1Byte() [Test] public static void ORNOT_1Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -392,7 +392,7 @@ public static void ORNOT_1Byte() [Test] public static void NOT_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -421,7 +421,7 @@ public static void NOT_2Bytes() [Test] public static void AND_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -450,7 +450,7 @@ public static void AND_2Bytes() [Test] public static void OR_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -479,7 +479,7 @@ public static void OR_2Bytes() [Test] public static void XOR_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -508,7 +508,7 @@ public static void XOR_2Bytes() [Test] public static void NAND_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -537,7 +537,7 @@ public static void NAND_2Bytes() [Test] public static void NOR_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -566,7 +566,7 @@ public static void NOR_2Bytes() [Test] public static void XNOR_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -595,7 +595,7 @@ public static void XNOR_2Bytes() [Test] public static void ANDNOT_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -624,7 +624,7 @@ public static void ANDNOT_2Bytes() [Test] public static void ORNOT_2Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -654,7 +654,7 @@ public static void ORNOT_2Bytes() [Test] public static void NOT_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -683,7 +683,7 @@ public static void NOT_4Bytes() [Test] public static void AND_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -712,7 +712,7 @@ public static void AND_4Bytes() [Test] public static void OR_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -741,7 +741,7 @@ public static void OR_4Bytes() [Test] public static void XOR_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -770,7 +770,7 @@ public static void XOR_4Bytes() [Test] public static void NAND_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -799,7 +799,7 @@ public static void NAND_4Bytes() [Test] public static void NOR_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -828,7 +828,7 @@ public static void NOR_4Bytes() [Test] public static void XNOR_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -857,7 +857,7 @@ public static void XNOR_4Bytes() [Test] public static void ANDNOT_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -886,7 +886,7 @@ public static void ANDNOT_4Bytes() [Test] public static void ORNOT_4Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -916,7 +916,7 @@ public static void ORNOT_4Bytes() [Test] public static void NOT_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -945,7 +945,7 @@ public static void NOT_8Bytes() [Test] public static void AND_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -974,7 +974,7 @@ public static void AND_8Bytes() [Test] public static void OR_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -1003,7 +1003,7 @@ public static void OR_8Bytes() [Test] public static void XOR_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -1032,7 +1032,7 @@ public static void XOR_8Bytes() [Test] public static void NAND_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -1061,7 +1061,7 @@ public static void NAND_8Bytes() [Test] public static void NOR_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -1090,7 +1090,7 @@ public static void NOR_8Bytes() [Test] public static void XNOR_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -1119,7 +1119,7 @@ public static void XNOR_8Bytes() [Test] public static void ANDNOT_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { @@ -1148,7 +1148,7 @@ public static void ANDNOT_8Bytes() [Test] public static void ORNOT_8Bytes() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); for (int i = 0; i < 3; i++) { diff --git a/Tests/Editor/Helpers.cs b/Tests/Editor/Helpers.cs new file mode 100644 index 0000000..43aa0f9 --- /dev/null +++ b/Tests/Editor/Helpers.cs @@ -0,0 +1,36 @@ +using System; +using Unity.Collections; + +namespace SIMDAlgorithms.Tests +{ + public static class Helpers + { + public const int NUM_TESTS = 4; + + + public static uint GetRngSeed { get { long t = Environment.TickCount; return (uint)t != 0 ? (uint)t : 1; } } + + + public static void Test(Action> test, Func generateElement, int maxLength = 5000000) + where T : unmanaged + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(GetRngSeed); + NativeArray array = new NativeArray(rng.NextInt(0, maxLength), Allocator.Persistent); + + for (int i = 0; i < Helpers.NUM_TESTS; i++) + { + for (int j = 0; j < array.Length; j++) + { + array[j] = generateElement(); + } + + test(array); + + array.Dispose(); + array = new NativeArray(rng.NextInt(0, maxLength), Allocator.Persistent); + } + + array.Dispose(); + } + } +} \ No newline at end of file diff --git a/Tests/Editor/IndexOfFIrst.cs b/Tests/Editor/IndexOfFIrst.cs index 5fb4ecf..180b0e2 100644 --- a/Tests/Editor/IndexOfFIrst.cs +++ b/Tests/Editor/IndexOfFIrst.cs @@ -5,24 +5,4339 @@ namespace SIMDAlgorithms.Tests { public static class IndexOfFirst { + + #region EQUAL + [Test] + public static void Byte_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + byte test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void UShort_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + ushort test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void UInt_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + uint test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void ULong_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + ulong test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void SByte_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + sbyte test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void Short_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + short test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void Int_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + int test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void Long_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + long test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void Float_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + float test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void Double_Direct_EachIndex() + { + for (int i = 0;i < 64;i++) + { + double test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + } + + [Test] + public static void Byte_Direct_FirstBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_SecondBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[23] = test; + + Assert.AreEqual(23, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_ThirdBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(48, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[40] = test; + + Assert.AreEqual(40, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_FourthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(56, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[52] = test; + + Assert.AreEqual(52, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_SixthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(60, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[58] = test; + + Assert.AreEqual(58, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_SeventhBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(62, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[60] = test; + + Assert.AreEqual(60, array.SIMD_IndexOf(test)); + + array[60] = 200; + + array[61] = test; + + Assert.AreEqual(61, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_EighthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(63, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[62] = test; + + Assert.AreEqual(62, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_FirstBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_SecondBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[14] = test; + + Assert.AreEqual(14, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_ThirdBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(24, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[22] = test; + + Assert.AreEqual(22, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_FourthBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(28, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[26] = test; + + Assert.AreEqual(26, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_SixthBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(30, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[28] = test; + + Assert.AreEqual(28, array.SIMD_IndexOf(test)); + + array[28] = 200; + + array[29] = test; + + Assert.AreEqual(29, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_SeventhBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(31, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[30] = test; + + Assert.AreEqual(30, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_FirstBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_SecondBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_ThirdBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[10] = test; + + Assert.AreEqual(10, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_SixthBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[12] = test; + + Assert.AreEqual(12, array.SIMD_IndexOf(test)); + + array[12] = 200; + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_SeventhBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[14] = test; + + Assert.AreEqual(14, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void ULong_Direct_FirstBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void ULong_Direct_SecondBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void ULong_Direct_SixthBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[4] = test; + + Assert.AreEqual(4, array.SIMD_IndexOf(test)); + + array[4] = 200; + + array[5] = test; + + Assert.AreEqual(5, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void ULong_Direct_SeventhBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_FirstBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 123; + } + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_SecondBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 123; + } + + array[23] = test; + + Assert.AreEqual(23, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_ThirdBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(48, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 123; + } + + array[40] = test; + + Assert.AreEqual(40, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_FourthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(56, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 123; + } + + array[52] = test; + + Assert.AreEqual(52, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_SixthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(60, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 123; + } + + array[58] = test; + + Assert.AreEqual(58, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_SeventhBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(62, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 123; + } + + array[60] = test; + + Assert.AreEqual(60, array.SIMD_IndexOf(test)); + + array[60] = 123; + + array[61] = test; + + Assert.AreEqual(61, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_EighthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(63, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 123; + } + + array[62] = test; + + Assert.AreEqual(62, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_FirstBranch() + { + short test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_SecondBranch() + { + short test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[14] = test; + + Assert.AreEqual(14, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_ThirdBranch() + { + short test = 122; + + NativeArray array = new NativeArray(24, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[22] = test; + + Assert.AreEqual(22, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_FourthBranch() + { + short test = 122; + + NativeArray array = new NativeArray(28, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[26] = test; + + Assert.AreEqual(26, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_SixthBranch() + { + short test = 122; + + NativeArray array = new NativeArray(30, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[28] = test; + + Assert.AreEqual(28, array.SIMD_IndexOf(test)); + + array[28] = 200; + + array[29] = test; + + Assert.AreEqual(29, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_SeventhBranch() + { + short test = 122; + + NativeArray array = new NativeArray(31, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[30] = test; + + Assert.AreEqual(30, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_FirstBranch() + { + int test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_SecondBranch() + { + int test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_ThirdBranch() + { + int test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[10] = test; + + Assert.AreEqual(10, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_SixthBranch() + { + int test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[12] = test; + + Assert.AreEqual(12, array.SIMD_IndexOf(test)); + + array[12] = 200; + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_SeventhBranch() + { + int test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[14] = test; + + Assert.AreEqual(14, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Long_Direct_FirstBranch() + { + long test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Long_Direct_SecondBranch() + { + long test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Long_Direct_SixthBranch() + { + long test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[4] = test; + + Assert.AreEqual(4, array.SIMD_IndexOf(test)); + + array[4] = 200; + + array[5] = test; + + Assert.AreEqual(5, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Long_Direct_SeventhBranch() + { + long test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_FirstBranch() + { + float test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_SecondBranch() + { + float test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_ThirdBranch() + { + float test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[10] = test; + + Assert.AreEqual(10, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_SixthBranch() + { + float test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[12] = test; + + Assert.AreEqual(12, array.SIMD_IndexOf(test)); + + array[12] = 200; + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_SeventhBranch() + { + float test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[14] = test; + + Assert.AreEqual(14, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Double_Direct_FirstBranch() + { + double test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Double_Direct_SecondBranch() + { + double test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Double_Direct_SixthBranch() + { + double test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[4] = test; + + Assert.AreEqual(4, array.SIMD_IndexOf(test)); + + array[4] = 200; + + array[5] = test; + + Assert.AreEqual(5, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + [Test] + public static void Double_Direct_SeventhBranch() + { + double test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test)); + + array.Dispose(); + } + + + [Test] + public static void Byte_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + + [Test] + public static void UShort_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + + [Test] + public static void Short_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextDouble); + } + #endregion + + #region NOT_EQUAL + [Test] + public static void Byte_Indirect_EachIndex() + { + for (int i = 0;i < 64;i++) + { + byte test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + } + + [Test] + public static void UShort_Indirect_EachIndex() + { + for (int i = 0;i < 64;i++) + { + ushort test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + } + + [Test] + public static void UInt_Indirect_EachIndex() + { + for (int i = 0;i < 64;i++) + { + uint test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + } + + [Test] + public static void ULong_Indirect_EachIndex() + { + for (int i = 0;i < 64;i++) + { + ulong test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + } + + [Test] + public static void SByte_Indirect_EachIndex() + { + for (int i = 0;i < 64;i++) + { + sbyte test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + } + + [Test] + public static void Short_Indirect_EachIndex() + { + for (int i = 0;i < 64;i++) + { + short test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + } + + [Test] + public static void Int_Indirect_EachIndex() + { + for (int i = 0;i < 64;i++) + { + int test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + } + + [Test] + public static void Long_Indirect_EachIndex() + { + for (int i = 0;i < 64;i++) + { + long test = 47; + + NativeArray array = new NativeArray(64, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + } + + + [Test] + public static void Byte_Indirect_FirstBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[13] = 200; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_SecondBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[23] = 200; + + Assert.AreEqual(23, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_ThirdBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(48, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[40] = 200; + + Assert.AreEqual(40, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_FourthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(56, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[52] = 200; + + Assert.AreEqual(52, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_SixthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(60, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[58] = 200; + + Assert.AreEqual(58, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_SeventhBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(62, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[60] = 200; + + Assert.AreEqual(60, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array[60] = test; + + array[61] = 200; + + Assert.AreEqual(61, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_EighthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(63, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[62] = 200; + + Assert.AreEqual(62, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_FirstBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[6] = 200; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_SecondBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[14] = 200; + + Assert.AreEqual(14, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_ThirdBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(24, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[22] = 200; + + Assert.AreEqual(22, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_FourthBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(28, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[26] = 200; + + Assert.AreEqual(26, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_SixthBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(30, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[28] = 200; + + Assert.AreEqual(28, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array[28] = test; + + array[29] = 200; + + Assert.AreEqual(29, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_SeventhBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(31, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[30] = 200; + + Assert.AreEqual(30, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_FirstBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 200; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_SecondBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[6] = 200; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_ThirdBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[10] = 200; + + Assert.AreEqual(10, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_SixthBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[12] = 200; + + Assert.AreEqual(12, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array[12] = test; + + array[13] = 200; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_SeventhBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[14] = 200; + + Assert.AreEqual(14, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void ULong_Indirect_FirstBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[1] = 200; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void ULong_Indirect_SecondBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 200; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void ULong_Indirect_SixthBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[4] = 200; + + Assert.AreEqual(4, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array[4] = test; + + array[5] = 200; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void ULong_Indirect_SeventhBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[6] = 200; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_FirstBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[13] = 47; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_SecondBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[23] = 47; + + Assert.AreEqual(23, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_ThirdBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(48, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[40] = 47; + + Assert.AreEqual(40, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_FourthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(56, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[52] = 47; + + Assert.AreEqual(52, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_SixthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(60, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[58] = 47; + + Assert.AreEqual(58, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_SeventhBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(62, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[60] = 47; + + Assert.AreEqual(60, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array[60] = test; + + array[61] = 47; + + Assert.AreEqual(61, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_EighthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(63, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[62] = 47; + + Assert.AreEqual(62, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_FirstBranch() + { + short test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[6] = 200; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_SecondBranch() + { + short test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[14] = 200; + + Assert.AreEqual(14, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_ThirdBranch() + { + short test = 122; + + NativeArray array = new NativeArray(24, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[22] = 200; + + Assert.AreEqual(22, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_FourthBranch() + { + short test = 122; + + NativeArray array = new NativeArray(28, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[26] = 200; + + Assert.AreEqual(26, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_SixthBranch() + { + short test = 122; + + NativeArray array = new NativeArray(30, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[28] = 200; + + Assert.AreEqual(28, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array[28] = test; + + array[29] = 200; + + Assert.AreEqual(29, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_SeventhBranch() + { + short test = 122; + + NativeArray array = new NativeArray(31, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[30] = 200; + + Assert.AreEqual(30, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_FirstBranch() + { + int test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 200; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_SecondBranch() + { + int test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[6] = 200; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_ThirdBranch() + { + int test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[10] = 200; + + Assert.AreEqual(10, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_SixthBranch() + { + int test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[12] = 200; + + Assert.AreEqual(12, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array[12] = test; + + array[13] = 200; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_SeventhBranch() + { + int test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[14] = 200; + + Assert.AreEqual(14, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Long_Indirect_FirstBranch() + { + long test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[1] = 200; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Long_Indirect_SecondBranch() + { + long test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 200; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Long_Indirect_SixthBranch() + { + long test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[4] = 200; + + Assert.AreEqual(4, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array[4] = test; + + array[5] = 200; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Long_Indirect_SeventhBranch() + { + long test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[6] = 200; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.NotEqualTo)); + + array.Dispose(); + } + + [Test] + public static void Byte_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextDouble); + } + #endregion + + #region GREATER + [Test] + public static void Byte_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextDouble); + } + #endregion + + #region LESS + [Test] + public static void Byte_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextDouble); + } + #endregion + + #region GREATER_EQUAL + [Test] + public static void Byte_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + [Test] - public static void Byte() + public static void Float_GreaterEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); - } - - for (int j = 0; j < 10; j++) + for (int j = 0; j < 50; j++) { - byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + float test = rng.NextFloat(); - long index = array.SIMD_IndexOf(test); + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); if (index == -1) { @@ -30,51 +4345,87 @@ public static void Byte() for (int k = 0; k < array.Length; k++) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] >= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] >= test; bool noPreviousOccurrence = true; for (long k = 0; k < index; k++) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] >= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextFloat); } [Test] - public static void UShort() + public static void Double_GreaterEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 100; j++) { - array[j] = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + rng.NextDouble); + } + #endregion + + #region LESS_EQUAL + [Test] + public static void Byte_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + Helpers.Test( + (array) => + { for (int j = 0; j < 10; j++) { - ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); - long index = array.SIMD_IndexOf(test); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); if (index == -1) { @@ -82,51 +4433,87 @@ public static void UShort() for (int k = 0; k < array.Length; k++) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = 0; k < index; k++) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); } [Test] - public static void UInt() + public static void UShort_LessEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = rng.NextUInt(); + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + [Test] + public static void UInt_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { for (int j = 0; j < 50; j++) { uint test = rng.NextUInt(); - long index = array.SIMD_IndexOf(test); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); if (index == -1) { @@ -134,51 +4521,42 @@ public static void UInt() for (int k = 0; k < array.Length; k++) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = 0; k < index; k++) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextUInt); } [Test] - public static void ULong() + public static void ULong_LessEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); - } - for (int j = 0; j < 100; j++) { ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); - long index = array.SIMD_IndexOf(test); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); if (index == -1) { @@ -186,51 +4564,128 @@ public static void ULong() for (int k = 0; k < array.Length; k++) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = 0; k < index; k++) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + [Test] + public static void SByte_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - array.Dispose(); + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); } [Test] - public static void Float() + public static void Short_LessEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = rng.NextFloat(); + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + Helpers.Test( + (array) => + { for (int j = 0; j < 50; j++) { - float test = rng.NextFloat(); + int test = rng.NextInt(); - long index = array.SIMD_IndexOf(test); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); if (index == -1) { @@ -238,51 +4693,128 @@ public static void Float() for (int k = 0; k < array.Length; k++) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = 0; k < index; k++) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } + }, + rng.NextInt); + } - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + [Test] + public static void Long_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - array.Dispose(); + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); } [Test] - public static void Double() + public static void Float_LessEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 50; j++) { - array[j] = rng.NextDouble(); + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = 0; k < array.Length; k++) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = 0; k < index; k++) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + rng.NextFloat); + } + + [Test] + public static void Double_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + Helpers.Test( + (array) => + { for (int j = 0; j < 100; j++) { double test = rng.NextDouble(); - long index = array.SIMD_IndexOf(test); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo); if (index == -1) { @@ -290,31 +4822,28 @@ public static void Double() for (int k = 0; k < array.Length; k++) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = 0; k < index; k++) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextDouble); } + #endregion } } \ No newline at end of file diff --git a/Tests/Editor/IndexOfLast.cs b/Tests/Editor/IndexOfLast.cs index 79bca32..2455330 100644 --- a/Tests/Editor/IndexOfLast.cs +++ b/Tests/Editor/IndexOfLast.cs @@ -5,316 +5,4844 @@ namespace SIMDAlgorithms.Tests { public static class IndexOfLast { + #region EQUAL [Test] - public static void Byte() + public static void Byte_Direct_EachIndex() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + for (int i = 0; i < 65 ;i++) + { + byte test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void UShort_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + ushort test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void UInt_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + uint test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void ULong_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + ulong test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void SByte_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + sbyte test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void Short_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + short test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void Int_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + int test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void Long_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + long test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void Float_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + float test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void Double_Direct_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + double test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = 100; + } + + array[i] = test; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + + [Test] + public static void Byte_Direct_FirstBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[29] = test; + + Assert.AreEqual(29, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_SecondBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_ThirdBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(48, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[4] = test; + + Assert.AreEqual(4, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_FourthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(56, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[5] = test; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_SixthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(60, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_SeventhBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(62, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Direct_EighthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(63, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_FirstBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_SecondBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[3] = test; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_ThirdBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(24, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[5] = test; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_FourthBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(28, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_SixthBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(30, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Direct_SeventhBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(31, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_FirstBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_SecondBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_ThirdBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_SixthBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Direct_SeventhBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void ULong_Direct_FirstBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[3] = test; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void ULong_Direct_SecondBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void ULong_Direct_SixthBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void ULong_Direct_SeventhBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_FirstBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 47; + } + + array[29] = test; + + Assert.AreEqual(29, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_SecondBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 47; + } + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_ThirdBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(48, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 47; + } + + array[4] = test; + + Assert.AreEqual(4, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_FourthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(56, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 47; + } + + array[5] = test; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_SixthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(60, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 47; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_SeventhBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(62, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 47; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 47; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Direct_EighthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(63, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 47; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_FirstBranch() + { + short test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[13] = test; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_SecondBranch() + { + short test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[3] = test; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_ThirdBranch() + { + short test = 122; + + NativeArray array = new NativeArray(24, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[5] = test; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_FourthBranch() + { + short test = 122; + + NativeArray array = new NativeArray(28, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_SixthBranch() + { + short test = 122; + + NativeArray array = new NativeArray(30, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Direct_SeventhBranch() + { + short test = 122; + + NativeArray array = new NativeArray(31, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_FirstBranch() + { + int test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_SecondBranch() + { + int test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_ThirdBranch() + { + int test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_SixthBranch() + { + int test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Direct_SeventhBranch() + { + int test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Long_Direct_FirstBranch() + { + long test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[3] = test; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Long_Direct_SecondBranch() + { + long test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Long_Direct_SixthBranch() + { + long test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Long_Direct_SeventhBranch() + { + long test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_FirstBranch() + { + float test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[6] = test; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_SecondBranch() + { + float test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[2] = test; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_ThirdBranch() + { + float test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_SixthBranch() + { + float test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Float_Direct_SeventhBranch() + { + float test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Double_Direct_FirstBranch() + { + double test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[3] = test; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Double_Direct_SecondBranch() + { + double test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Double_Direct_SixthBranch() + { + double test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array[0] = 200; + + array[1] = test; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Double_Direct_SeventhBranch() + { + double test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = 200; + } + + array[0] = test; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + + [Test] + public static void Byte_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_Equal() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.EqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= array[k] != test; + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] == test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= array[(int)k] != test; + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextDouble); + } + #endregion + + #region NOT_EQUAL + [Test] + public static void Byte_Indirect_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + byte test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void UShort_Indirect_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + ushort test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void UInt_Indirect_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + uint test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void ULong_Indirect_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + ulong test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void SByte_Indirect_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + sbyte test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void Short_Indirect_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + short test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void Int_Indirect_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + int test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + [Test] + public static void Long_Indirect_EachIndex() + { + for (int i = 0; i < 65 ;i++) + { + long test = 47; + + NativeArray array = new NativeArray(65, Allocator.Temp); + for (int j = 0;j < array.Length;j++) + { + array[j] = test; + } + + array[i] = 100; + + Assert.AreEqual(i, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + } + + + [Test] + public static void Byte_Indirect_FirstBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[29] = 47; + + Assert.AreEqual(29, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_SecondBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[13] = 47; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_ThirdBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(48, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[4] = 47; + + Assert.AreEqual(4, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_FourthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(56, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[5] = 47; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_SixthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(60, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 47; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_SeventhBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(62, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array[0] = test; + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Byte_Indirect_EighthBranch() + { + byte test = 122; + + NativeArray array = new NativeArray(63, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_FirstBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[13] = 47; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_SecondBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[3] = 47; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_ThirdBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(24, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[5] = 47; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_FourthBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(28, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 47; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_SixthBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(30, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array[0] = test; + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UShort_Indirect_SeventhBranch() + { + ushort test = 122; + + NativeArray array = new NativeArray(31, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_FirstBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[6] = 47; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_SecondBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 47; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_ThirdBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_SixthBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array[0] = test; + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void UInt_Indirect_SeventhBranch() + { + uint test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void ULong_Indirect_FirstBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[3] = 47; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void ULong_Indirect_SecondBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void ULong_Indirect_SixthBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array[0] = test; + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void ULong_Indirect_SeventhBranch() + { + ulong test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_FirstBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[29] = 47; + + Assert.AreEqual(29, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_SecondBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(32, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[13] = 47; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_ThirdBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(48, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[4] = 47; + + Assert.AreEqual(4, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_FourthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(56, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[5] = 47; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_SixthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(60, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 47; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_SeventhBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(62, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array[0] = test; + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void SByte_Indirect_EighthBranch() + { + sbyte test = 122; + + NativeArray array = new NativeArray(63, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_FirstBranch() + { + short test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[13] = 47; + + Assert.AreEqual(13, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_SecondBranch() + { + short test = 122; + + NativeArray array = new NativeArray(16, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[3] = 47; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_ThirdBranch() + { + short test = 122; + + NativeArray array = new NativeArray(24, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[5] = 47; + + Assert.AreEqual(5, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_FourthBranch() + { + short test = 122; + + NativeArray array = new NativeArray(28, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 47; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_SixthBranch() + { + short test = 122; + + NativeArray array = new NativeArray(30, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array[0] = test; + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Short_Indirect_SeventhBranch() + { + short test = 122; + + NativeArray array = new NativeArray(31, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_FirstBranch() + { + int test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[6] = 47; + + Assert.AreEqual(6, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_SecondBranch() + { + int test = 122; + + NativeArray array = new NativeArray(8, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[2] = 47; + + Assert.AreEqual(2, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_ThirdBranch() + { + int test = 122; + + NativeArray array = new NativeArray(12, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_SixthBranch() + { + int test = 122; + + NativeArray array = new NativeArray(14, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array[0] = test; + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Int_Indirect_SeventhBranch() + { + int test = 122; + + NativeArray array = new NativeArray(15, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Long_Indirect_FirstBranch() + { + long test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[3] = 47; + + Assert.AreEqual(3, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Long_Indirect_SecondBranch() + { + long test = 122; + + NativeArray array = new NativeArray(4, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Long_Indirect_SixthBranch() + { + long test = 122; + + NativeArray array = new NativeArray(6, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array[0] = test; + + array[1] = 47; + + Assert.AreEqual(1, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + [Test] + public static void Long_Indirect_SeventhBranch() + { + long test = 122; + + NativeArray array = new NativeArray(7, Allocator.Temp); + for (int i = 0;i < array.Length;i++) + { + array[i] = test; + } + + array[0] = 47; + + Assert.AreEqual(0, array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending)); + + array.Dispose(); + } + + + [Test] + public static void Byte_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_NotEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.NotEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] != test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] != test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] != test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextDouble); + } + #endregion + + #region GREATER + [Test] + public static void Byte_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_Greater() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] > test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] > test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] > test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextDouble); + } + #endregion + + #region LESS + [Test] + public static void Byte_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } + + [Test] + public static void Float_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextFloat); + } + + [Test] + public static void Double_Less() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThan, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] < test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] < test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] < test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextDouble); + } + #endregion + + #region GREATER_EQUAL + [Test] + public static void Byte_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); + } + + [Test] + public static void UShort_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + + [Test] + public static void UInt_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + uint test = rng.NextUInt(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextUInt); + } + + [Test] + public static void ULong_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } + + [Test] + public static void SByte_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) + { + int test = rng.NextInt(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + rng.NextInt); + } + + [Test] + public static void Long_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 100; j++) { - array[j] = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); + } - for (int j = 0; j < 10; j++) + [Test] + public static void Float_GreaterEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + for (int j = 0; j < 50; j++) { - byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); + float test = rng.NextFloat(); - long index = array.SIMD_IndexOf(test, TraversalOrder.Descending); + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); if (index == -1) { bool noOccurrence = true; - for (int k = 0; k < array.Length; k++) + for (int k = array.Length - 1; k >= 0; k--) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] >= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] >= test; bool noPreviousOccurrence = true; for (long k = array.Length - 1; k > index; k--) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] >= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextFloat); } [Test] - public static void UShort() + public static void Double_GreaterEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 100; j++) { - array[j] = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + double test = rng.NextDouble(); + + long index = array.SIMD_IndexOf(test, Comparison.GreaterThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] >= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] >= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] >= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + rng.NextDouble); + } + #endregion + + #region LESS_EQUAL + [Test] + public static void Byte_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + Helpers.Test( + (array) => + { for (int j = 0; j < 10; j++) { - ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + byte test = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); - long index = array.SIMD_IndexOf(test, TraversalOrder.Descending); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); if (index == -1) { bool noOccurrence = true; - for (int k = 0; k < array.Length; k++) + for (int k = array.Length - 1; k >= 0; k--) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = array.Length - 1; k > index; k--) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 1000); } [Test] - public static void UInt() + public static void UShort_LessEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = rng.NextUInt(); + ushort test = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + () => (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1), + 100000); + } + [Test] + public static void UInt_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { for (int j = 0; j < 50; j++) { uint test = rng.NextUInt(); - long index = array.SIMD_IndexOf(test, TraversalOrder.Descending); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); if (index == -1) { bool noOccurrence = true; - for (int k = 0; k < array.Length; k++) + for (int k = array.Length - 1; k >= 0; k--) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = array.Length - 1; k > index; k--) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextUInt); } [Test] - public static void ULong() + public static void ULong_LessEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); - } - for (int j = 0; j < 100; j++) { ulong test = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); - long index = array.SIMD_IndexOf(test, TraversalOrder.Descending); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); if (index == -1) { bool noOccurrence = true; - for (int k = 0; k < array.Length; k++) + for (int k = array.Length - 1; k >= 0; k--) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = array.Length - 1; k > index; k--) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); + } - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + [Test] + public static void SByte_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - array.Dispose(); + Helpers.Test( + (array) => + { + for (int j = 0; j < 10; j++) + { + sbyte test = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); } [Test] - public static void Float() + public static void Short_LessEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 10; j++) { - array[j] = rng.NextFloat(); + short test = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + Helpers.Test( + (array) => + { for (int j = 0; j < 50; j++) { - float test = rng.NextFloat(); + int test = rng.NextInt(); - long index = array.SIMD_IndexOf(test, TraversalOrder.Descending); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); if (index == -1) { bool noOccurrence = true; - for (int k = 0; k < array.Length; k++) + for (int k = array.Length - 1; k >= 0; k--) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = array.Length - 1; k > index; k--) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } + }, + rng.NextInt); + } - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } + [Test] + public static void Long_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - array.Dispose(); + Helpers.Test( + (array) => + { + for (int j = 0; j < 100; j++) + { + long test = rng.NextUInt() | ((long)rng.NextUInt() << 32); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } + } + }, + () => rng.NextUInt() | ((long)rng.NextUInt() << 32)); } [Test] - public static void Double() + public static void Float_LessEqual() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) + for (int j = 0; j < 50; j++) { - array[j] = rng.NextDouble(); + float test = rng.NextFloat(); + + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); + + if (index == -1) + { + bool noOccurrence = true; + + for (int k = array.Length - 1; k >= 0; k--) + { + noOccurrence &= !(array[k] <= test); + } + + Assert.IsTrue(noOccurrence); + } + else + { + bool isCorrectIndex = array[(int)index] <= test; + bool noPreviousOccurrence = true; + + for (long k = array.Length - 1; k > index; k--) + { + noPreviousOccurrence &= !(array[(int)k] <= test); + } + + Assert.IsTrue(isCorrectIndex); + Assert.IsTrue(noPreviousOccurrence); + } } + }, + rng.NextFloat); + } + + [Test] + public static void Double_LessEqual() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + Helpers.Test( + (array) => + { for (int j = 0; j < 100; j++) { double test = rng.NextDouble(); - long index = array.SIMD_IndexOf(test, TraversalOrder.Descending); + long index = array.SIMD_IndexOf(test, Comparison.LessThanOrEqualTo, TraversalOrder.Descending); if (index == -1) { bool noOccurrence = true; - for (int k = 0; k < array.Length; k++) + for (int k = array.Length - 1; k >= 0; k--) { - noOccurrence &= array[k] != test; + noOccurrence &= !(array[k] <= test); } Assert.IsTrue(noOccurrence); } else { - bool isCorrectIndex = array[(int)index] == test; + bool isCorrectIndex = array[(int)index] <= test; bool noPreviousOccurrence = true; - + for (long k = array.Length - 1; k > index; k--) { - noPreviousOccurrence &= array[(int)k] != test; + noPreviousOccurrence &= !(array[(int)k] <= test); } Assert.IsTrue(isCorrectIndex); Assert.IsTrue(noPreviousOccurrence); } } - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextDouble); } + #endregion } } \ No newline at end of file diff --git a/Tests/Editor/Maximum.cs b/Tests/Editor/Maximum.cs index d1ed016..4ce3655 100644 --- a/Tests/Editor/Maximum.cs +++ b/Tests/Editor/Maximum.cs @@ -1,5 +1,4 @@ using NUnit.Framework; -using Unity.Collections; using Unity.Mathematics; namespace SIMDAlgorithms.Tests @@ -9,16 +8,11 @@ public static class Maximum [Test] public static void Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (byte)rng.NextUInt(byte.MinValue, byte.MaxValue + 1); - } - byte x = byte.MinValue; for (int j = 0; j < array.Length; j++) @@ -27,27 +21,18 @@ public static void Byte() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (byte)rng.NextUInt(byte.MaxValue, byte.MaxValue + 1)); } [Test] public static void UShort() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (ushort)rng.NextUInt(ushort.MinValue, ushort.MaxValue + 1); - } - ushort x = ushort.MinValue; for (int j = 0; j < array.Length; j++) @@ -56,27 +41,18 @@ public static void UShort() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (ushort)rng.NextUInt(ushort.MaxValue, ushort.MaxValue + 1)); } [Test] public static void UInt() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextUInt(); - } - uint x = uint.MinValue; for (int j = 0; j < array.Length; j++) @@ -85,27 +61,18 @@ public static void UInt() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextUInt); } [Test] public static void ULong() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); - } - ulong x = ulong.MinValue; for (int j = 0; j < array.Length; j++) @@ -114,27 +81,18 @@ public static void ULong() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); } [Test] public static void SByte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); - } - sbyte x = sbyte.MinValue; for (int j = 0; j < array.Length; j++) @@ -143,27 +101,18 @@ public static void SByte() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (sbyte)rng.NextInt(sbyte.MaxValue, sbyte.MaxValue + 1)); } [Test] public static void Short() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); - } - short x = short.MinValue; for (int j = 0; j < array.Length; j++) @@ -172,27 +121,18 @@ public static void Short() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (short)rng.NextInt(short.MaxValue, short.MaxValue + 1)); } [Test] public static void Int() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextInt(); - } - int x = int.MinValue; for (int j = 0; j < array.Length; j++) @@ -201,27 +141,18 @@ public static void Int() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextInt); } [Test] public static void Long() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextInt() | ((long)rng.NextInt() << 32); - } - long x = long.MinValue; for (int j = 0; j < array.Length; j++) @@ -230,27 +161,18 @@ public static void Long() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (long)rng.NextInt() | ((long)rng.NextInt() << 32)); } [Test] public static void Float() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextFloat(); - } - float x = float.NegativeInfinity; for (int j = 0; j < array.Length; j++) @@ -259,27 +181,18 @@ public static void Float() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextFloat); } [Test] public static void Double() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextDouble(); - } - double x = double.NegativeInfinity; for (int j = 0; j < array.Length; j++) @@ -288,12 +201,8 @@ public static void Double() } Assert.AreEqual(x, array.SIMD_Maximum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextDouble); } } } \ No newline at end of file diff --git a/Tests/Editor/MinMax.cs b/Tests/Editor/MinMax.cs new file mode 100644 index 0000000..192d10c --- /dev/null +++ b/Tests/Editor/MinMax.cs @@ -0,0 +1,167 @@ +using NUnit.Framework; + +namespace SIMDAlgorithms.Tests +{ + public static class MinMax + { + [Test] + public static void Byte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out byte min, out byte max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + () => (byte)rng.NextUInt(byte.MinValue, byte.MaxValue + 1)); + } + + [Test] + public static void UShort() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out ushort min, out ushort max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + () => (ushort)rng.NextUInt(ushort.MinValue, ushort.MaxValue + 1)); + } + + [Test] + public static void UInt() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out uint min, out uint max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + rng.NextUInt); + } + + [Test] + public static void ULong() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out ulong min, out ulong max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + () => ((ulong)rng.NextUInt() << 32) | rng.NextUInt()); + } + + [Test] + public static void SByte() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out sbyte min, out sbyte max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); + } + + [Test] + public static void Short() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out short min, out short max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); + } + + [Test] + public static void Int() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out int min, out int max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + rng.NextInt); + } + + [Test] + public static void Long() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out long min, out long max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + () => (long)(((ulong)rng.NextUInt() << 32) | rng.NextUInt())); + } + + [Test] + public static void Float() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out float min, out float max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + () => rng.NextFloat(float.MinValue, float.MaxValue)); + } + + [Test] + public static void Double() + { + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); + + Helpers.Test( + (array) => + { + array.SIMD_MinMax(out double min, out double max); + + Assert.AreEqual(min, array.SIMD_Minimum()); + Assert.AreEqual(max, array.SIMD_Maximum()); + }, + () => rng.NextDouble(double.MinValue, double.MaxValue)); + } + } +} \ No newline at end of file diff --git a/Tests/Editor/Minimum.cs b/Tests/Editor/Minimum.cs index fe04ec2..dd7521d 100644 --- a/Tests/Editor/Minimum.cs +++ b/Tests/Editor/Minimum.cs @@ -1,5 +1,4 @@ using NUnit.Framework; -using Unity.Collections; using Unity.Mathematics; namespace SIMDAlgorithms.Tests @@ -9,16 +8,11 @@ public static class Minimum [Test] public static void Byte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (byte)rng.NextUInt(byte.MinValue, byte.MaxValue + 1); - } - byte x = byte.MaxValue; for (int j = 0; j < array.Length; j++) @@ -27,27 +21,18 @@ public static void Byte() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (byte)rng.NextUInt(byte.MinValue, byte.MaxValue + 1)); } [Test] public static void UShort() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (ushort)rng.NextUInt(ushort.MinValue, ushort.MaxValue + 1); - } - ushort x = ushort.MaxValue; for (int j = 0; j < array.Length; j++) @@ -56,27 +41,18 @@ public static void UShort() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (ushort)rng.NextUInt(ushort.MinValue, ushort.MaxValue + 1)); } [Test] public static void UInt() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextUInt(); - } - uint x = uint.MaxValue; for (int j = 0; j < array.Length; j++) @@ -85,27 +61,18 @@ public static void UInt() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextUInt); } [Test] public static void ULong() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextUInt() | ((ulong)rng.NextUInt() << 32); - } - ulong x = ulong.MaxValue; for (int j = 0; j < array.Length; j++) @@ -114,27 +81,18 @@ public static void ULong() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => rng.NextUInt() | ((ulong)rng.NextUInt() << 32)); } [Test] public static void SByte() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); - } - sbyte x = sbyte.MaxValue; for (int j = 0; j < array.Length; j++) @@ -143,27 +101,18 @@ public static void SByte() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1)); } [Test] public static void Short() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); - } - short x = short.MaxValue; for (int j = 0; j < array.Length; j++) @@ -172,27 +121,18 @@ public static void Short() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1)); } [Test] public static void Int() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextInt(); - } - int x = int.MaxValue; for (int j = 0; j < array.Length; j++) @@ -201,27 +141,18 @@ public static void Int() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextInt); } [Test] public static void Long() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextInt() | ((long)rng.NextInt() << 32); - } - long x = long.MaxValue; for (int j = 0; j < array.Length; j++) @@ -230,27 +161,18 @@ public static void Long() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (long)rng.NextInt() | ((long)rng.NextInt() << 32)); } [Test] public static void Float() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextFloat(); - } - float x = float.PositiveInfinity; for (int j = 0; j < array.Length; j++) @@ -259,27 +181,18 @@ public static void Float() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextFloat); } [Test] public static void Double() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < 10 * CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = rng.NextDouble(); - } - double x = double.PositiveInfinity; for (int j = 0; j < array.Length; j++) @@ -288,12 +201,8 @@ public static void Double() } Assert.AreEqual(x, array.SIMD_Minimum()); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + rng.NextDouble); } } } \ No newline at end of file diff --git a/Tests/Editor/ShouldMask.cs b/Tests/Editor/ShouldMask.cs new file mode 100644 index 0000000..ed067ee --- /dev/null +++ b/Tests/Editor/ShouldMask.cs @@ -0,0 +1,470 @@ +using NUnit.Framework; +using Unity.Collections; + +namespace SIMDAlgorithms.Tests +{ + public static class ShouldMask + { + [Test] + public static void Unsigned() + { + NativeArray array = new NativeArray(8, Allocator.Temp); + + for (int i = 0;i < array.Length;i++) + { + array[i] = 100; + } + + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array.Length;i++) + { + array[i] = 0; + } + + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + array.Dispose(); + + NativeArray array2 = new NativeArray(4, Allocator.Temp); + + for (int i = 0;i < array2.Length;i++) + { + array2[i] = 100; + } + + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array2.Length;i++) + { + array2[i] = 0; + } + + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + array2.Dispose(); + + NativeArray array3 = new NativeArray(2, Allocator.Temp); + + for (int i = 0;i < array3.Length;i++) + { + array3[i] = 100; + } + + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array3.Length;i++) + { + array3[i] = 0; + } + + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + array3.Dispose(); + } + + [Test] + public static void Signed() + { + NativeArray array = new NativeArray(8, Allocator.Temp); + + for (int i = 0;i < array.Length;i++) + { + array[i] = 100; + } + + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array.Length;i++) + { + array[i] = 0; + } + + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array.Length;i++) + { + array[i] = -100; + } + + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(false, array.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + array.Dispose(); + + NativeArray array2 = new NativeArray(4, Allocator.Temp); + + for (int i = 0;i < array2.Length;i++) + { + array2[i] = 100; + } + + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array2.Length;i++) + { + array2[i] = 0; + } + + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array2.Length;i++) + { + array2[i] = -100; + } + + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(false, array2.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array2.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + array2.Dispose(); + + NativeArray array3 = new NativeArray(2, Allocator.Temp); + + for (int i = 0;i < array3.Length;i++) + { + array3[i] = 100; + } + + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array3.Length;i++) + { + array3[i] = 0; + } + + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array3.Length;i++) + { + array3[i] = -100; + } + + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(false, array3.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array3.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + array3.Dispose(); + + NativeArray array4 = new NativeArray(4, Allocator.Temp); + + for (int i = 0;i < array4.Length;i++) + { + array4[i] = 100; + } + + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array4.Length;i++) + { + array4[i] = 0; + } + + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + for (int i = 0;i < array4.Length;i++) + { + array4[i] = -100; + } + + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.EqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.NotEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.LessThan)); + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.GreaterThan)); + Assert.AreEqual(true, array4.SIMD_Contains(0, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(0, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.EqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.NotEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.LessThan)); + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.GreaterThan)); + Assert.AreEqual(true, array4.SIMD_Contains(100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(100, Comparison.GreaterThanOrEqualTo)); + + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.EqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.NotEqualTo)); + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.LessThan)); + Assert.AreEqual(false, array4.SIMD_Contains(-100, Comparison.GreaterThan)); + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.LessThanOrEqualTo)); + Assert.AreEqual(true, array4.SIMD_Contains(-100, Comparison.GreaterThanOrEqualTo)); + + array4.Dispose(); + } + } +} \ No newline at end of file diff --git a/Tests/Editor/Sum.cs b/Tests/Editor/Sum.cs index 131469d..3b73ce0 100644 --- a/Tests/Editor/Sum.cs +++ b/Tests/Editor/Sum.cs @@ -9,16 +9,11 @@ public static class Sum [Test] public static void TypeByte_RangeULong() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 2000000000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1); - } - ulong std = 0; for (int j = 0; j < array.Length; j++) @@ -27,27 +22,19 @@ public static void TypeByte_RangeULong() } Assert.AreEqual(std, array.SIMD_Sum(TypeCode.UInt64)); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 2000000000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 2000000000); } [Test] public static void TypeUShort_RangeULong() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 2000000000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (ushort)rng.NextInt(ushort.MinValue, ushort.MaxValue + 1); - } - ulong std = 0; for (int j = 0; j < array.Length; j++) @@ -56,27 +43,19 @@ public static void TypeUShort_RangeULong() } Assert.AreEqual(std, array.SIMD_Sum(TypeCode.UInt64)); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (byte)rng.NextInt(byte.MinValue, byte.MaxValue + 1), + 2000000000); } [Test] public static void TypeSByte_RangInt() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); - } - int std = 0; for (int j = 0; j < array.Length; j++) @@ -85,27 +64,19 @@ public static void TypeSByte_RangInt() } Assert.AreEqual(std, array.SIMD_Sum(TypeCode.Int32)); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 200000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1), + 2000000000); } [Test] public static void TypeSByte_RangeLong() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 2000000000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1); - } - long std = 0; for (int j = 0; j < array.Length; j++) @@ -114,27 +85,19 @@ public static void TypeSByte_RangeLong() } Assert.AreEqual(std, array.SIMD_Sum(TypeCode.Int64)); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 2000000000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (sbyte)rng.NextInt(sbyte.MinValue, sbyte.MaxValue + 1), + 2000000000); } [Test] public static void TypeShort_RangeLong() { - Unity.Mathematics.Random rng = new Unity.Mathematics.Random(CONSTANTS.RNG_SEED); - NativeArray array = new NativeArray(rng.NextInt(0, 200000000), Allocator.Persistent); + Unity.Mathematics.Random rng = new Unity.Mathematics.Random(Helpers.GetRngSeed); - for (int i = 0; i < CONSTANTS.NUM_TESTS; i++) + Helpers.Test( + (array) => { - for (int j = 0; j < array.Length; j++) - { - array[j] = (short)rng.NextInt(short.MinValue, short.MaxValue + 1); - } - long std = 0; for (int j = 0; j < array.Length; j++) @@ -143,12 +106,9 @@ public static void TypeShort_RangeLong() } Assert.AreEqual(std, array.SIMD_Sum(TypeCode.Int64)); - - array.Dispose(); - array = new NativeArray(rng.NextInt(0, 2000000000), Allocator.Persistent); - } - - array.Dispose(); + }, + () => (short)rng.NextInt(short.MinValue, short.MaxValue + 1), + 2000000000); } } } \ No newline at end of file diff --git a/manifest.json b/manifest.json index 45f2f63..d0d4ddd 100644 --- a/manifest.json +++ b/manifest.json @@ -1,13 +1,13 @@ { "name": "simd_algorithms", "displayName": "SIMD Algorithms", - "version": "1.0.1", + "version": "1.1.0", "unity": "2018.4", "description": "A collection of hand optimized SIMD versions of common array algorithms.", - "keywords": [ + "keywords": [ "Unity" ], - "dependencies": { + "dependencies": { "csharpdevtools" : "1.0.5": "https://github.com/MrUnbelievable92/C-Sharp-Dev-Tools.git", "com.unity.burst": "1.5.0", "com.unity.mathematics": "1.2.1", diff --git a/package.json b/package.json index 50914eb..83f9ead 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "simd_algorithms", "displayName": "SIMD Algorithms", - "version": "1.0.1", + "version": "1.1.0", "unity": "2018.4", "description": "A collection of hand optimized SIMD versions of common array algorithms.", "keywords": [