mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-20 01:14:20 +00:00
Fix for the TextDiff algorithm when given large input buffers
This commit is contained in:
parent
37cb1bb18b
commit
e43d008f16
1 changed files with 45 additions and 21 deletions
|
|
@ -28,7 +28,8 @@
|
|||
|
||||
struct TextDiffHelpers
|
||||
{
|
||||
enum { minLengthToMatch = 3 };
|
||||
enum { minLengthToMatch = 3,
|
||||
maxLengthToScan = 128 * 1024 };
|
||||
|
||||
struct StringRegion
|
||||
{
|
||||
|
|
@ -38,6 +39,8 @@ struct TextDiffHelpers
|
|||
StringRegion (const String::CharPointerType t, int s, int len) noexcept
|
||||
: text (t), start (s), length (len) {}
|
||||
|
||||
void incrementStart() noexcept { ++text; ++start; --length; }
|
||||
|
||||
String::CharPointerType text;
|
||||
int start, length;
|
||||
};
|
||||
|
|
@ -61,27 +64,26 @@ struct TextDiffHelpers
|
|||
|
||||
static void diffSkippingCommonStart (TextDiff& td, StringRegion a, StringRegion b)
|
||||
{
|
||||
String::CharPointerType sa (a.text);
|
||||
String::CharPointerType sb (b.text);
|
||||
const int maxLen = jmax (a.length, b.length);
|
||||
|
||||
for (int i = 0; i < maxLen; ++i, ++sa, ++sb)
|
||||
for (;;)
|
||||
{
|
||||
if (*sa != *sb)
|
||||
{
|
||||
diffRecursively (td, StringRegion (sa, a.start + i, a.length - i),
|
||||
StringRegion (sb, b.start + i, b.length - i));
|
||||
const juce_wchar ca = *a.text;
|
||||
const juce_wchar cb = *b.text;
|
||||
|
||||
if (ca != cb || ca == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
a.incrementStart();
|
||||
b.incrementStart();
|
||||
}
|
||||
|
||||
diffRecursively (td, a, b);
|
||||
}
|
||||
|
||||
static void diffRecursively (TextDiff& td, StringRegion a, StringRegion b)
|
||||
{
|
||||
int indexA, indexB;
|
||||
const int len = findLongestCommonSubstring (a.text, a.length,
|
||||
b.text, b.length,
|
||||
indexA, indexB);
|
||||
int indexA = 0, indexB = 0;
|
||||
const int len = findLongestCommonSubstring (a.text, a.length, indexA,
|
||||
b.text, b.length, indexB);
|
||||
|
||||
if (len >= minLengthToMatch)
|
||||
{
|
||||
|
|
@ -103,22 +105,25 @@ struct TextDiffHelpers
|
|||
}
|
||||
}
|
||||
|
||||
static int findLongestCommonSubstring (String::CharPointerType a, const int lenA,
|
||||
const String::CharPointerType b, const int lenB,
|
||||
int& indexInA, int& indexInB)
|
||||
static int findLongestCommonSubstring (String::CharPointerType a, const int lenA, int& indexInA,
|
||||
String::CharPointerType b, const int lenB, int& indexInB) noexcept
|
||||
{
|
||||
if (lenA == 0 || lenB == 0)
|
||||
return 0;
|
||||
|
||||
HeapBlock<int> lines;
|
||||
lines.calloc (2 + 2 * (size_t) lenB);
|
||||
if (lenA > maxLengthToScan || lenB > maxLengthToScan)
|
||||
return findCommonSuffix (a, lenA, indexInA,
|
||||
b, lenB, indexInB);
|
||||
|
||||
const size_t scratchSpace = sizeof (int) * (2 + 2 * (size_t) lenB);
|
||||
int* const lines = (int*) alloca (scratchSpace);
|
||||
zeromem (lines, scratchSpace);
|
||||
|
||||
int* l0 = lines;
|
||||
int* l1 = l0 + lenB + 1;
|
||||
|
||||
int loopsWithoutImprovement = 0;
|
||||
int bestLength = 0;
|
||||
indexInA = indexInB = 0;
|
||||
|
||||
for (int i = 0; i < lenA; ++i)
|
||||
{
|
||||
|
|
@ -156,6 +161,25 @@ struct TextDiffHelpers
|
|||
indexInB -= bestLength - 1;
|
||||
return bestLength;
|
||||
}
|
||||
|
||||
static int findCommonSuffix (String::CharPointerType a, const int lenA, int& indexInA,
|
||||
String::CharPointerType b, const int lenB, int& indexInB) noexcept
|
||||
{
|
||||
int length = 0;
|
||||
a += lenA - 1;
|
||||
b += lenB - 1;
|
||||
|
||||
while (length < lenA && length < lenB && *a == *b)
|
||||
{
|
||||
--a;
|
||||
--b;
|
||||
++length;
|
||||
}
|
||||
|
||||
indexInA = lenA - length;
|
||||
indexInB = lenB - length;
|
||||
return length;
|
||||
}
|
||||
};
|
||||
|
||||
TextDiff::TextDiff (const String& original, const String& target)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue