1
0
Fork 0
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:
jules 2015-08-05 10:22:50 +01:00
parent 37cb1bb18b
commit e43d008f16

View file

@ -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)