private static unsafe int CalculateDistance(string sourceString, int sourceLength, string targetString, int targetLength, int startIndex) { var arrayPool = ArrayPool <int> .Shared; var pooledArray = arrayPool.Rent(targetLength); Span <int> 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(int *previousRowPtr = previousRow) { FillRow(previousRowPtr, targetLength); var rowIndex = 0; for (; rowIndex < sourceLength - 3; rowIndex += 4) { var diag = Vector128.Create(rowIndex); var left = Vector128.Create(rowIndex + 1); var sourceV = Sse42.ConvertToVector128Int32((short *)(srcPtr + rowIndex)); var targetV = Vector128 <int> .Zero; var one = Vector128.Create(1); // First 3 iterations fills the vector var shift = Vector128.CreateScalar(-1); for (int columnIndex = 0; columnIndex < 4; columnIndex++) { // Shift in the next character targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 4); targetV = Sse42.Insert(targetV, (short)targetPtr[columnIndex], 0); //left = Sse42.Insert(left, rowIndex + columnIndex + 1, (byte)columnIndex); var leftValue = Vector128.Create(rowIndex + columnIndex + 1); left = Sse42.Or(Sse42.And(shift, leftValue), left); shift = Sse42.ShiftLeftLogical128BitLane(shift, 4); // compare source to target // alternativ, compare equal and OR with One var match = Sse.CompareNotEqual(sourceV.AsSingle(), targetV.AsSingle()); var next = Sse42.Subtract(diag, match.AsInt32()); // Create next diag which is current up var up = Sse42.ShiftLeftLogical128BitLane(left, 4); up = Sse42.Insert(up, previousRowPtr[columnIndex], 0); var tmp = Sse42.Add(Sse42.Min(left, up), one); next = Sse42.Min(next, tmp); left = next; diag = up; } previousRowPtr[0] = Sse42.Extract(left, 3); for (int columnIndex = 4; columnIndex < targetLength; columnIndex++) { // Shift in the next character targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 4); targetV = Sse42.Insert(targetV, (short)targetPtr[columnIndex], 0); // compare source to target // alternativ, compare equal and OR with One var match = Sse42.CompareNotEqual(sourceV.AsSingle(), targetV.AsSingle()); var next = Sse42.Subtract(diag, match.AsInt32()); // Create next diag which is current up var up = Sse42.ShiftLeftLogical128BitLane(left, 4); up = Sse42.Insert(up, previousRowPtr[columnIndex], 0); var tmp = Sse42.Add(Sse42.Min(left, up), one); next = Sse42.Min(next, tmp); left = next; diag = up; // Store one value previousRowPtr[columnIndex - 3] = Sse42.Extract(next, 3); } // Finish with last 3 items, dont read any more chars just extract them for (int i = targetLength - 3; i < targetLength; i++) { // Shift in the next character targetV = Sse42.ShiftLeftLogical128BitLane(targetV, 4); // compare source to target // alternativ, compare equal and OR with One var match = Sse.CompareNotEqual(sourceV.AsSingle(), targetV.AsSingle()); var next = Sse42.Subtract(diag, match.AsInt32()); // Create next diag which is current up var up = Sse42.ShiftLeftLogical128BitLane(left, 4); var tmp = Sse42.Add(Sse42.Min(left, up), one); next = Sse42.Min(next, tmp); left = next; diag = up; // Store one value previousRowPtr[i] = Sse42.Extract(next, 3); } #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); }