private static unsafe int CalculateDistance(string sourceString, int sourceLength, string targetString, int targetLength, int startIndex) { var arrayPool = ArrayPool <ushort> .Shared; var pooledArray = arrayPool.Rent(targetLength); Span <ushort> previousRow = pooledArray; ReadOnlySpan <char> source = sourceString.AsSpan().Slice(startIndex, sourceLength); ReadOnlySpan <char> target = targetString.AsSpan().Slice(startIndex, targetLength); //ArrayPool values are sometimes bigger than allocated, let's trim our span to exactly what we use previousRow = previousRow.Slice(0, targetLength); fixed(char *targetPtr = target) fixed(char *srcPtr = source) fixed(ushort *previousRowPtr = previousRow) { FillRow(previousRowPtr, targetLength); var rowIndex = 0; for (; rowIndex < sourceLength - 7; rowIndex += 8) { // todo max var temp = Vector128.Create(rowIndex); var diag = Sse42.PackUnsignedSaturate(temp, temp); var one = Vector128.Create((ushort)1); var left = Sse42.AddSaturate(diag, one); var sourceV = Sse42.LoadVector128((ushort *)(srcPtr + rowIndex)); var targetV = Vector128 <ushort> .Zero; var shift = Vector128.CreateScalar(ushort.MaxValue); // First 3 iterations fills the vector for (int columnIndex = 0; columnIndex < 7; columnIndex++) { // Shift in the next character targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 2); targetV = Sse42.Insert(targetV, (ushort)targetPtr[columnIndex], 0); // Insert "(rowIndex + columnIndex + 1)" from the left var leftValue = Vector128.Create(rowIndex + columnIndex + 1); left = Sse42.Or(Sse42.And(shift, Sse42.PackUnsignedSaturate(leftValue, leftValue)), left); shift = Sse42.ShiftLeftLogical128BitLane(shift, 2); // compare source to target // alternativ, compare equal and OR with One var match = Sse42.CompareEqual(sourceV, targetV); var add = Sse42.AndNot(match, one); var next = Sse42.AddSaturate(diag, add); // Create next diag which is current up var up = Sse42.ShiftLeftLogical128BitLane(left, 2); up = Sse42.Insert(up, (ushort)previousRowPtr[columnIndex], 0); var tmp = Sse42.AddSaturate(Sse42.Min(left, up), one); next = Sse42.Min(next, tmp); left = next; diag = up; } previousRowPtr[0] = Sse42.Extract(left, 7); var writePtr = previousRowPtr + 1; for (int columnIndex = 8; columnIndex < targetLength; columnIndex++) { // Shift in the next character targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 2); targetV = Sse42.Insert(targetV, (ushort)targetPtr[columnIndex], 0); // compare source to target // alternativ, compare equal and OR with One var match = Sse42.CompareEqual(sourceV, targetV); var add = Sse42.AndNot(match, one); var next = Sse42.AddSaturate(diag, add); // Create next diag which is current up var up = Sse42.ShiftLeftLogical128BitLane(left, 2); up = Sse42.Insert(up, (ushort)previousRowPtr[columnIndex], 0); var tmp = Sse42.AddSaturate(Sse42.Min(left, up), one); next = Sse42.Min(next, tmp); left = next; diag = up; // Store one value *writePtr = Sse42.Extract(next, 7); writePtr = writePtr + 1; // Store one value //previousRowPtr[columnIndex - 7] = Sse42.Extract(next, 7); } // Finish with last 3 items, dont read any more chars just extract them for (int i = targetLength - 7; i < previousRow.Length; i++) { // Shift in the next character targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 2); // compare source to target // alternativ, compare equal and OR with One var match = Sse42.CompareEqual(sourceV, targetV); var add = Sse42.AndNot(match, one); var next = Sse42.AddSaturate(diag, add); // Create next diag which is current up var up = Sse42.ShiftLeftLogical128BitLane(left, 2); var tmp = Sse42.AddSaturate(Sse42.Min(left, up), one); next = Sse42.Min(next, tmp); left = next; diag = up; // Store one value previousRowPtr[i] = Sse42.Extract(next, 7); } #if DEBUG if (true) { Console.Write("prev values for row {0}:", rowIndex); for (int i = 0; i < targetLength; ++i) { Console.Write("{0} ", previousRow[i]); } Console.WriteLine(); } #endif } //Calculate Single Rows for (; rowIndex < sourceLength; rowIndex++) { var lastSubstitutionCost = rowIndex; var lastInsertionCost = rowIndex + 1; var sourcePrevChar = source[rowIndex]; #if DEBUG Console.Write("prev values for row {0}:", rowIndex); for (int i = 0; i < targetLength; ++i) { Console.Write("{0} ", previousRow[i]); } Console.WriteLine(); #endif CalculateRow(previousRowPtr, targetPtr, targetLength, sourcePrevChar, lastInsertionCost, lastSubstitutionCost); } } var result = previousRow[targetLength - 1]; arrayPool.Return(pooledArray); return(result); }