diff --git a/llvm/include/llvm/ADT/edit_distance.h b/llvm/include/llvm/ADT/edit_distance.h index 6989cecab9b1..6df3db6125d4 100644 --- a/llvm/include/llvm/ADT/edit_distance.h +++ b/llvm/include/llvm/ADT/edit_distance.h @@ -61,6 +61,15 @@ unsigned ComputeMappedEditDistance(ArrayRef FromArray, ArrayRef ToArray, typename ArrayRef::size_type m = FromArray.size(); typename ArrayRef::size_type n = ToArray.size(); + if (MaxEditDistance) { + // If the difference in size between the 2 arrays is larger than the max + // distance allowed, we can bail out as we will always need at least + // MaxEditDistance insertions or removals. + typename ArrayRef::size_type AbsDiff = m > n ? m - n : n - m; + if (AbsDiff > MaxEditDistance) + return MaxEditDistance + 1; + } + const unsigned SmallBufferSize = 64; unsigned SmallBuffer[SmallBufferSize]; std::unique_ptr Allocated; diff --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt index 3b3d7c5483c2..c6bd570d69ae 100644 --- a/llvm/unittests/ADT/CMakeLists.txt +++ b/llvm/unittests/ADT/CMakeLists.txt @@ -22,6 +22,7 @@ add_llvm_unittest(ADTTests DenseSetTest.cpp DepthFirstIteratorTest.cpp DirectedGraphTest.cpp + EditDistanceTest.cpp EnumeratedArrayTest.cpp EquivalenceClassesTest.cpp FallibleIteratorTest.cpp diff --git a/llvm/unittests/ADT/EditDistanceTest.cpp b/llvm/unittests/ADT/EditDistanceTest.cpp new file mode 100644 index 000000000000..6e35f1b56ceb --- /dev/null +++ b/llvm/unittests/ADT/EditDistanceTest.cpp @@ -0,0 +1,63 @@ +//===- llvm/unittest/Support/EditDistanceTest.cpp - Edit distance tests ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/edit_distance.h" +#include "gtest/gtest.h" +#include + +using namespace llvm; + +namespace { + +struct Result { + unsigned NumMaps; + unsigned EditDist; +}; +} // namespace + +static Result editDistanceAndMaps(StringRef A, StringRef B, + unsigned MaxEditDistance = 0) { + unsigned NumMaps = 0; + auto TrackMaps = [&](const char X) { + ++NumMaps; + return X; + }; + unsigned EditDist = llvm::ComputeMappedEditDistance( + makeArrayRef(A.data(), A.size()), makeArrayRef(B.data(), B.size()), + TrackMaps, true, MaxEditDistance); + return {NumMaps, EditDist}; +} + +TEST(EditDistance, VerifyShortCircuit) { + StringRef Hello = "Hello"; + StringRef HelloWorld = "HelloWorld"; + Result R = editDistanceAndMaps(Hello, HelloWorld, 5); + EXPECT_EQ(R.EditDist, 5U); + EXPECT_GT(R.NumMaps, 0U); + + R = editDistanceAndMaps(Hello, HelloWorld); + EXPECT_EQ(R.EditDist, 5U); + EXPECT_GT(R.NumMaps, 0U); + + R = editDistanceAndMaps(Hello, HelloWorld, 4); + EXPECT_EQ(R.EditDist, 5U); + EXPECT_EQ(R.NumMaps, 0U); + + R = editDistanceAndMaps(HelloWorld, Hello, 4); + EXPECT_EQ(R.EditDist, 5U); + EXPECT_EQ(R.NumMaps, 0U); + + R = editDistanceAndMaps(Hello, HelloWorld, 1); + EXPECT_EQ(R.EditDist, 2U); + EXPECT_EQ(R.NumMaps, 0U); + + R = editDistanceAndMaps(HelloWorld, Hello, 1); + EXPECT_EQ(R.EditDist, 2U); + EXPECT_EQ(R.NumMaps, 0U); +}