Replace diff_match_patch with dtl library for performing text diffs
Replacement is done for license reasons: diff_match_patch is distributed under Apache-2.0 license which is not GPLv2-compatible.
This commit is contained in:
parent
3fdfab33f4
commit
e1986bd86b
21 changed files with 1618 additions and 4132 deletions
|
@ -716,7 +716,7 @@ endif (NOT MSVC)
|
|||
##
|
||||
subdirs(
|
||||
mscore awl bww2mxml share midi audiofile fluid libmscore synthesizer
|
||||
effects thirdparty/rtf2html thirdparty/diff thirdparty/beatroot
|
||||
effects thirdparty/rtf2html thirdparty/beatroot
|
||||
thirdparty/qzip thirdparty/kQOAuth
|
||||
)
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ else (NOT MSVC)
|
|||
endif (NOT MSVC)
|
||||
|
||||
include_directories(
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/diff
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/dtl
|
||||
)
|
||||
|
||||
add_library (
|
||||
|
@ -106,10 +106,6 @@ add_library (
|
|||
scorediff.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(libmscore
|
||||
diff_match_patch
|
||||
)
|
||||
|
||||
##
|
||||
## Code coverage. Only affects DEBUG builds.
|
||||
##
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "staff.h"
|
||||
#include "xml.h"
|
||||
|
||||
#include "diff_match_patch.h"
|
||||
#include "dtl/dtl.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
@ -29,7 +29,7 @@ namespace Ms {
|
|||
// MscxModeDiff
|
||||
//---------------------------------------------------------
|
||||
|
||||
class MscxModeDiff : private ::diff_match_patch {
|
||||
class MscxModeDiff {
|
||||
static constexpr const char* tagRegExpStr = "</?(?<name>[A-z_][A-z_0-9\\-.:]*)( [A-z_0-9\\-.:\\s=\"]*)?/?>";
|
||||
const QRegularExpression tagRegExp;
|
||||
|
||||
|
@ -42,6 +42,8 @@ class MscxModeDiff : private ::diff_match_patch {
|
|||
Tag(int l, TagType t, const QString& n) : line(l), type(t), name(n) {}
|
||||
};
|
||||
|
||||
static DiffType fromDtlDiffType(dtl::edit_t dtlType);
|
||||
|
||||
void adjustSemanticsMscx(std::vector<TextDiff>&);
|
||||
int adjustSemanticsMscxOneDiff(std::vector<TextDiff>& diffs, int index);
|
||||
int nextDiffOnShiftIndex(const std::vector<TextDiff>& diffs, int index, bool down);
|
||||
|
@ -91,84 +93,86 @@ MscxModeDiff::MscxModeDiff()
|
|||
: tagRegExp(tagRegExpStr)
|
||||
{}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// MscxModeDiff::fromDtlDiffType
|
||||
//---------------------------------------------------------
|
||||
|
||||
DiffType MscxModeDiff::fromDtlDiffType(dtl::edit_t dtlType)
|
||||
{
|
||||
switch(dtlType) {
|
||||
case dtl::SES_DELETE:
|
||||
return DiffType::DELETE;
|
||||
case dtl::SES_COMMON:
|
||||
return DiffType::EQUAL;
|
||||
case dtl::SES_ADD:
|
||||
return DiffType::INSERT;
|
||||
}
|
||||
Q_ASSERT(false); // dtlType must have one of the values handled above.
|
||||
return DiffType::EQUAL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// MscxModeDiff::lineModeDiff
|
||||
//---------------------------------------------------------
|
||||
|
||||
std::vector<TextDiff> MscxModeDiff::lineModeDiff(const QString& s1, const QString& s2)
|
||||
{
|
||||
QList<QVariant> l = diff_linesToChars(s1, s2);
|
||||
QList<::Diff> diffLines = diff_main(l[0].toString(), l[1].toString(), false);
|
||||
// type declarations for dtl library
|
||||
typedef QStringRef elem;
|
||||
typedef std::pair<elem, dtl::elemInfo> sesElem;
|
||||
typedef std::vector<sesElem> sesElemVec;
|
||||
|
||||
std::vector<TextDiff> diffs(diffLines.size());
|
||||
// QVector does not contain range constructor used inside dtl
|
||||
// so we have to convert to std::vector.
|
||||
std::vector<QStringRef> lines1 = s1.splitRef('\n').toStdVector();
|
||||
std::vector<QStringRef> lines2 = s2.splitRef('\n').toStdVector();
|
||||
dtl::Diff<QStringRef, std::vector<QStringRef>> diff(lines1, lines2);
|
||||
|
||||
diff.compose();
|
||||
|
||||
const sesElemVec changes = diff.getSes().getSequence();
|
||||
std::vector<TextDiff> diffs;
|
||||
int line[2][2] {{1, 1}, {1, 1}}; // for correct assigning line numbers to
|
||||
// DELETE and INSERT diffs we need to
|
||||
// count lines separately for these diff
|
||||
// types (EQUAL can use both counters).
|
||||
for (int i = 0; i < diffLines.size(); ++i) {
|
||||
TextDiff& d = diffs[i];
|
||||
::Diff& ld = diffLines[i];
|
||||
const int iThis = (ld.operation == DELETE) ? 0 : 1; // for EQUAL doesn't matter
|
||||
const int iOther = (iThis == 1) ? 0 : 1;
|
||||
|
||||
if (ld.operation == EQUAL)
|
||||
line[iThis][iOther] = line[iOther][iOther];
|
||||
for (const sesElem& ch : changes) {
|
||||
DiffType type = fromDtlDiffType(ch.second.type);
|
||||
const int iThis = (type == DiffType::DELETE) ? 0 : 1; // for EQUAL doesn't matter
|
||||
|
||||
d.start[0] = line[iThis][0];
|
||||
d.start[1] = line[iThis][1];
|
||||
// After diff_linesToChars call each line is represented by one
|
||||
// Unicode character, so counting them we can count differing lines
|
||||
const int lines = ld.text.size();
|
||||
switch (ld.operation) {
|
||||
case DELETE:
|
||||
line[iThis][iThis] += lines;
|
||||
d.type = DiffType::DELETE;
|
||||
break;
|
||||
case INSERT:
|
||||
line[iThis][iThis] += lines;
|
||||
d.type = DiffType::INSERT;
|
||||
break;
|
||||
case EQUAL:
|
||||
line[iThis][0] += lines;
|
||||
line[iThis][1] += lines;
|
||||
d.type = DiffType::EQUAL;
|
||||
break;
|
||||
if (diffs.empty() || diffs.back().type != type) {
|
||||
if (!diffs.empty()) {
|
||||
// sync line numbers
|
||||
DiffType prevType = diffs.back().type;
|
||||
const int prevThis = (prevType == DiffType::DELETE) ? 0 : 1;
|
||||
const int prevOther = (prevThis == 1) ? 0 : 1;
|
||||
if (prevType == DiffType::EQUAL)
|
||||
std::copy_n(line[prevThis], 2, line[prevOther]);
|
||||
else
|
||||
line[prevThis][prevOther] = line[prevOther][prevOther];
|
||||
|
||||
if (type == DiffType::EQUAL) {
|
||||
const int iOther = (iThis == 1) ? 0 : 1;
|
||||
line[iThis][iOther] = line[iOther][iOther];
|
||||
}
|
||||
}
|
||||
|
||||
diffs.emplace_back();
|
||||
TextDiff& d = diffs.back();
|
||||
d.type = type;
|
||||
std::copy_n(line[iThis], 2, d.start);
|
||||
d.end[0] = line[iThis][0] - 1; // equal line numbers would mean an actual change in that line.
|
||||
d.end[1] = line[iThis][1] - 1;
|
||||
}
|
||||
d.end[0] = line[iThis][0] - 1;
|
||||
d.end[1] = line[iThis][1] - 1;
|
||||
|
||||
// sync line numbers
|
||||
switch(ld.operation) {
|
||||
case DELETE:
|
||||
case INSERT:
|
||||
line[iThis][iOther] = line[iOther][iOther];
|
||||
// Do not update line[iOther], if the next diff has
|
||||
// other type (but not EQUAL), old values are correct.
|
||||
break;
|
||||
case EQUAL:
|
||||
std::copy(line[iThis], line[iThis] + 2, line[iOther]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update text in diffs to match actual content of MSCX code
|
||||
diff_charsToLines(diffLines, l[2].toStringList());
|
||||
for (int i = 0; i < diffLines.size(); ++i) {
|
||||
TextDiff& diff = diffs[i];
|
||||
QString& text = diffLines[i].text;
|
||||
switch(diff.type) {
|
||||
case DiffType::DELETE:
|
||||
diff.text[0] = text;
|
||||
break;
|
||||
case DiffType::INSERT:
|
||||
diff.text[1] = text;
|
||||
break;
|
||||
case DiffType::EQUAL:
|
||||
diff.text[0] = text;
|
||||
diff.text[1] = text;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
TextDiff& d = diffs.back();
|
||||
d.end[iThis] = (line[iThis][iThis]++);
|
||||
d.text[iThis].append(ch.first).append('\n');
|
||||
if (type == DiffType::EQUAL) {
|
||||
const int iOther = (iThis == 1) ? 0 : 1;
|
||||
d.end[iOther] = (line[iThis][iOther]++);
|
||||
d.text[iOther].append(ch.first).append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -446,7 +446,6 @@ endif (MSVC)
|
|||
|
||||
target_link_libraries(mscore
|
||||
awl
|
||||
diff_match_patch
|
||||
bww
|
||||
rtf2html
|
||||
${QTSINGLEAPPLICATION_LIBRARIES}
|
||||
|
|
|
@ -83,7 +83,6 @@
|
|||
#include "omr/importpdf.h"
|
||||
#endif
|
||||
|
||||
#include "diff/diff_match_patch.h"
|
||||
#include "libmscore/chordlist.h"
|
||||
#include "libmscore/mscore.h"
|
||||
#include "thirdparty/qzip/qzipreader_p.h"
|
||||
|
|
65
thirdparty/diff/CMakeLists.txt
vendored
65
thirdparty/diff/CMakeLists.txt
vendored
|
@ -1,65 +0,0 @@
|
|||
#=============================================================================
|
||||
# MusE
|
||||
# Linux Music Editor
|
||||
# $Id:$
|
||||
#
|
||||
# Copyright (C) 2010 by Werner Schweer and others
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#=============================================================================
|
||||
|
||||
include (${PROJECT_SOURCE_DIR}/build/gch.cmake)
|
||||
|
||||
if (APPLE)
|
||||
file(GLOB_RECURSE INCS "*.h")
|
||||
else (APPLE)
|
||||
set(INCS "")
|
||||
endif (APPLE)
|
||||
|
||||
if (NOT MSVC)
|
||||
set(_all_h_file "${PROJECT_BINARY_DIR}/all.h")
|
||||
else (NOT MSVC)
|
||||
set(_all_h_file "${PROJECT_SOURCE_DIR}/all.h")
|
||||
endif (NOT MSVC)
|
||||
|
||||
add_library(diff_match_patch STATIC
|
||||
diff_match_patch.cpp
|
||||
${_all_h_file}
|
||||
${PCH}
|
||||
${INCS}
|
||||
)
|
||||
|
||||
if (NOT MSVC)
|
||||
set_target_properties (
|
||||
diff_match_patch
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${PCH_INCLUDE} -g -Wall -Wextra -Winvalid-pch"
|
||||
)
|
||||
else (NOT MSVC)
|
||||
set_target_properties (
|
||||
diff_match_patch
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${PCH_INCLUDE}"
|
||||
)
|
||||
endif (NOT MSVC)
|
||||
|
||||
xcode_pch(diff_match_patch all)
|
||||
|
||||
# Use MSVC pre-compiled headers
|
||||
vstudio_pch( diff_match_patch )
|
||||
|
||||
# MSVC does not depend on mops1 & mops2 for PCH
|
||||
if (NOT MSVC)
|
||||
ADD_DEPENDENCIES(diff_match_patch mops1)
|
||||
ADD_DEPENDENCIES(diff_match_patch mops2)
|
||||
endif (NOT MSVC)
|
11
thirdparty/diff/README.txt
vendored
11
thirdparty/diff/README.txt
vendored
|
@ -1,11 +0,0 @@
|
|||
Diff, Match and Patch Library
|
||||
http://code.google.com/p/google-diff-match-patch/
|
||||
Neil Fraser
|
||||
|
||||
C++: (ported by Mike Slemmer)
|
||||
* diff_match_patch.pro
|
||||
* diff_match_patch.h
|
||||
* diff_match_patch.cpp
|
||||
* diff_match_patch_test.h
|
||||
* diff_match_patch_test.cpp
|
||||
|
2079
thirdparty/diff/diff_match_patch.cpp
vendored
2079
thirdparty/diff/diff_match_patch.cpp
vendored
File diff suppressed because it is too large
Load diff
628
thirdparty/diff/diff_match_patch.h
vendored
628
thirdparty/diff/diff_match_patch.h
vendored
|
@ -1,628 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 Google Inc. All Rights Reserved.
|
||||
* Author: fraser@google.com (Neil Fraser)
|
||||
* Author: mikeslemmer@gmail.com (Mike Slemmer)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Diff Match and Patch
|
||||
* http://code.google.com/p/google-diff-match-patch/
|
||||
*/
|
||||
|
||||
#ifndef DIFF_MATCH_PATCH_H
|
||||
#define DIFF_MATCH_PATCH_H
|
||||
|
||||
#include <ctime>
|
||||
|
||||
/*
|
||||
* Functions for diff, match and patch.
|
||||
* Computes the difference between two texts to create a patch.
|
||||
* Applies the patch onto another text, allowing for errors.
|
||||
*
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*
|
||||
* Qt/C++ port by mikeslemmer@gmail.com (Mike Slemmer):
|
||||
*
|
||||
* Code known to compile and run with Qt 4.3 through Qt 4.7.
|
||||
*
|
||||
* Here is a trivial sample program which works properly when linked with this
|
||||
* library:
|
||||
*
|
||||
|
||||
#include <QtCore>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include "diff_match_patch.h"
|
||||
int main(int argc, char **argv) {
|
||||
diff_match_patch dmp;
|
||||
QString str1 = QString("First string in diff");
|
||||
QString str2 = QString("Second string in diff");
|
||||
|
||||
QString strPatch = dmp.patch_toText(dmp.patch_make(str1, str2));
|
||||
QPair<QString, QVector<bool> > out
|
||||
= dmp.patch_apply(dmp.patch_fromText(strPatch), str1);
|
||||
QString strResult = out.first;
|
||||
|
||||
// here, strResult will equal str2 above.
|
||||
return 0;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/**-
|
||||
* The data structure representing a diff is a Linked list of Diff objects:
|
||||
* {Diff(Operation.DELETE, "Hello"), Diff(Operation.INSERT, "Goodbye"),
|
||||
* Diff(Operation.EQUAL, " world.")}
|
||||
* which means: delete "Hello", add "Goodbye" and keep " world."
|
||||
*/
|
||||
#undef DELETE
|
||||
#undef INSERT
|
||||
#undef EQUAL
|
||||
enum Operation {
|
||||
DELETE, INSERT, EQUAL
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class representing one diff operation.
|
||||
*/
|
||||
class Diff {
|
||||
public:
|
||||
Operation operation;
|
||||
// One of: INSERT, DELETE or EQUAL.
|
||||
QString text;
|
||||
// The text associated with this diff operation.
|
||||
|
||||
/**
|
||||
* Constructor. Initializes the diff with the provided values.
|
||||
* @param operation One of INSERT, DELETE or EQUAL.
|
||||
* @param text The text being applied.
|
||||
*/
|
||||
Diff(Operation _operation, const QString &_text);
|
||||
Diff();
|
||||
inline bool isNull() const;
|
||||
QString toString() const;
|
||||
bool operator==(const Diff &d) const;
|
||||
bool operator!=(const Diff &d) const;
|
||||
|
||||
static QString strOperation(Operation op);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class representing one patch operation.
|
||||
*/
|
||||
class Patch {
|
||||
public:
|
||||
QList<Diff> diffs;
|
||||
int start1;
|
||||
int start2;
|
||||
int length1;
|
||||
int length2;
|
||||
|
||||
/**
|
||||
* Constructor. Initializes with an empty list of diffs.
|
||||
*/
|
||||
Patch();
|
||||
bool isNull() const;
|
||||
QString toString();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class containing the diff, match and patch methods.
|
||||
* Also contains the behaviour settings.
|
||||
*/
|
||||
class diff_match_patch {
|
||||
|
||||
friend class diff_match_patch_test;
|
||||
|
||||
public:
|
||||
// Defaults.
|
||||
// Set these on your diff_match_patch instance to override the defaults.
|
||||
|
||||
// Number of seconds to map a diff before giving up (0 for infinity).
|
||||
float Diff_Timeout;
|
||||
// Cost of an empty edit operation in terms of edit characters.
|
||||
short Diff_EditCost;
|
||||
// At what point is no match declared (0.0 = perfection, 1.0 = very loose).
|
||||
float Match_Threshold;
|
||||
// How far to search for a match (0 = exact location, 1000+ = broad match).
|
||||
// A match this many characters away from the expected location will add
|
||||
// 1.0 to the score (0.0 is a perfect match).
|
||||
int Match_Distance;
|
||||
// When deleting a large block of text (over ~64 characters), how close does
|
||||
// the contents have to match the expected contents. (0.0 = perfection,
|
||||
// 1.0 = very loose). Note that Match_Threshold controls how closely the
|
||||
// end points of a delete need to match.
|
||||
float Patch_DeleteThreshold;
|
||||
// Chunk size for context length.
|
||||
short Patch_Margin;
|
||||
|
||||
// The number of bits in an int.
|
||||
short Match_MaxBits;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
diff_match_patch();
|
||||
|
||||
// DIFF FUNCTIONS
|
||||
|
||||
|
||||
/**
|
||||
* Find the differences between two texts.
|
||||
* Run a faster slightly less optimal diff.
|
||||
* This method allows the 'checklines' of diff_main() to be optional.
|
||||
* Most of the time checklines is wanted, so default to true.
|
||||
* @param text1 Old string to be diffed.
|
||||
* @param text2 New string to be diffed.
|
||||
* @return Linked List of Diff objects.
|
||||
*/
|
||||
QList<Diff> diff_main(const QString &text1, const QString &text2);
|
||||
|
||||
/**
|
||||
* Find the differences between two texts.
|
||||
* @param text1 Old string to be diffed.
|
||||
* @param text2 New string to be diffed.
|
||||
* @param checklines Speedup flag. If false, then don't run a
|
||||
* line-level diff first to identify the changed areas.
|
||||
* If true, then run a faster slightly less optimal diff.
|
||||
* @return Linked List of Diff objects.
|
||||
*/
|
||||
QList<Diff> diff_main(const QString &text1, const QString &text2, bool checklines);
|
||||
|
||||
/**
|
||||
* Find the differences between two texts. Simplifies the problem by
|
||||
* stripping any common prefix or suffix off the texts before diffing.
|
||||
* @param text1 Old string to be diffed.
|
||||
* @param text2 New string to be diffed.
|
||||
* @param checklines Speedup flag. If false, then don't run a
|
||||
* line-level diff first to identify the changed areas.
|
||||
* If true, then run a faster slightly less optimal diff.
|
||||
* @param deadline Time when the diff should be complete by. Used
|
||||
* internally for recursive calls. Users should set DiffTimeout instead.
|
||||
* @return Linked List of Diff objects.
|
||||
*/
|
||||
private:
|
||||
QList<Diff> diff_main(const QString &text1, const QString &text2, bool checklines, clock_t deadline);
|
||||
|
||||
/**
|
||||
* Find the differences between two texts. Assumes that the texts do not
|
||||
* have any common prefix or suffix.
|
||||
* @param text1 Old string to be diffed.
|
||||
* @param text2 New string to be diffed.
|
||||
* @param checklines Speedup flag. If false, then don't run a
|
||||
* line-level diff first to identify the changed areas.
|
||||
* If true, then run a faster slightly less optimal diff.
|
||||
* @param deadline Time when the diff should be complete by.
|
||||
* @return Linked List of Diff objects.
|
||||
*/
|
||||
private:
|
||||
QList<Diff> diff_compute(QString text1, QString text2, bool checklines, clock_t deadline);
|
||||
|
||||
/**
|
||||
* Do a quick line-level diff on both strings, then rediff the parts for
|
||||
* greater accuracy.
|
||||
* This speedup can produce non-minimal diffs.
|
||||
* @param text1 Old string to be diffed.
|
||||
* @param text2 New string to be diffed.
|
||||
* @param deadline Time when the diff should be complete by.
|
||||
* @return Linked List of Diff objects.
|
||||
*/
|
||||
private:
|
||||
QList<Diff> diff_lineMode(QString text1, QString text2, clock_t deadline);
|
||||
|
||||
/**
|
||||
* Find the 'middle snake' of a diff, split the problem in two
|
||||
* and return the recursively constructed diff.
|
||||
* See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
|
||||
* @param text1 Old string to be diffed.
|
||||
* @param text2 New string to be diffed.
|
||||
* @return Linked List of Diff objects.
|
||||
*/
|
||||
protected:
|
||||
QList<Diff> diff_bisect(const QString &text1, const QString &text2, clock_t deadline);
|
||||
|
||||
/**
|
||||
* Given the location of the 'middle snake', split the diff in two parts
|
||||
* and recurse.
|
||||
* @param text1 Old string to be diffed.
|
||||
* @param text2 New string to be diffed.
|
||||
* @param x Index of split point in text1.
|
||||
* @param y Index of split point in text2.
|
||||
* @param deadline Time at which to bail if not yet complete.
|
||||
* @return LinkedList of Diff objects.
|
||||
*/
|
||||
private:
|
||||
QList<Diff> diff_bisectSplit(const QString &text1, const QString &text2, int x, int y, clock_t deadline);
|
||||
|
||||
/**
|
||||
* Split two texts into a list of strings. Reduce the texts to a string of
|
||||
* hashes where each Unicode character represents one line.
|
||||
* @param text1 First string.
|
||||
* @param text2 Second string.
|
||||
* @return Three element Object array, containing the encoded text1, the
|
||||
* encoded text2 and the List of unique strings. The zeroth element
|
||||
* of the List of unique strings is intentionally blank.
|
||||
*/
|
||||
protected:
|
||||
QList<QVariant> diff_linesToChars(const QString &text1, const QString &text2); // return elems 0 and 1 are QString, elem 2 is QStringList
|
||||
|
||||
/**
|
||||
* Split a text into a list of strings. Reduce the texts to a string of
|
||||
* hashes where each Unicode character represents one line.
|
||||
* @param text String to encode.
|
||||
* @param lineArray List of unique strings.
|
||||
* @param lineHash Map of strings to indices.
|
||||
* @return Encoded string.
|
||||
*/
|
||||
private:
|
||||
QString diff_linesToCharsMunge(const QString &text, QStringList &lineArray,
|
||||
QMap<QString, int> &lineHash);
|
||||
|
||||
/**
|
||||
* Rehydrate the text in a diff from a string of line hashes to real lines of
|
||||
* text.
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
* @param lineArray List of unique strings.
|
||||
*/
|
||||
protected: // changed for usage in scorediff
|
||||
void diff_charsToLines(QList<Diff> &diffs, const QStringList &lineArray);
|
||||
|
||||
/**
|
||||
* Determine the common prefix of two strings.
|
||||
* @param text1 First string.
|
||||
* @param text2 Second string.
|
||||
* @return The number of characters common to the start of each string.
|
||||
*/
|
||||
public:
|
||||
int diff_commonPrefix(const QString &text1, const QString &text2);
|
||||
|
||||
/**
|
||||
* Determine the common suffix of two strings.
|
||||
* @param text1 First string.
|
||||
* @param text2 Second string.
|
||||
* @return The number of characters common to the end of each string.
|
||||
*/
|
||||
public:
|
||||
int diff_commonSuffix(const QString &text1, const QString &text2);
|
||||
|
||||
/**
|
||||
* Determine if the suffix of one string is the prefix of another.
|
||||
* @param text1 First string.
|
||||
* @param text2 Second string.
|
||||
* @return The number of characters common to the end of the first
|
||||
* string and the start of the second string.
|
||||
*/
|
||||
protected:
|
||||
int diff_commonOverlap(const QString &text1, const QString &text2);
|
||||
|
||||
/**
|
||||
* Do the two texts share a substring which is at least half the length of
|
||||
* the longer text?
|
||||
* This speedup can produce non-minimal diffs.
|
||||
* @param text1 First string.
|
||||
* @param text2 Second string.
|
||||
* @return Five element String array, containing the prefix of text1, the
|
||||
* suffix of text1, the prefix of text2, the suffix of text2 and the
|
||||
* common middle. Or null if there was no match.
|
||||
*/
|
||||
protected:
|
||||
QStringList diff_halfMatch(const QString &text1, const QString &text2);
|
||||
|
||||
/**
|
||||
* Does a substring of shorttext exist within longtext such that the
|
||||
* substring is at least half the length of longtext?
|
||||
* @param longtext Longer string.
|
||||
* @param shorttext Shorter string.
|
||||
* @param i Start index of quarter length substring within longtext.
|
||||
* @return Five element String array, containing the prefix of longtext, the
|
||||
* suffix of longtext, the prefix of shorttext, the suffix of shorttext
|
||||
* and the common middle. Or null if there was no match.
|
||||
*/
|
||||
private:
|
||||
QStringList diff_halfMatchI(const QString &longtext, const QString &shorttext, int i);
|
||||
|
||||
/**
|
||||
* Reduce the number of edits by eliminating semantically trivial equalities.
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
*/
|
||||
public:
|
||||
void diff_cleanupSemantic(QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Look for single edits surrounded on both sides by equalities
|
||||
* which can be shifted sideways to align the edit to a word boundary.
|
||||
* e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
*/
|
||||
public:
|
||||
void diff_cleanupSemanticLossless(QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Given two strings, compute a score representing whether the internal
|
||||
* boundary falls on logical boundaries.
|
||||
* Scores range from 5 (best) to 0 (worst).
|
||||
* @param one First string.
|
||||
* @param two Second string.
|
||||
* @return The score.
|
||||
*/
|
||||
private:
|
||||
int diff_cleanupSemanticScore(const QString &one, const QString &two);
|
||||
|
||||
/**
|
||||
* Reduce the number of edits by eliminating operationally trivial equalities.
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
*/
|
||||
public:
|
||||
void diff_cleanupEfficiency(QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Reorder and merge like edit sections. Merge equalities.
|
||||
* Any edit section can move as long as it doesn't cross an equality.
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
*/
|
||||
public:
|
||||
void diff_cleanupMerge(QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* loc is a location in text1, compute and return the equivalent location in
|
||||
* text2.
|
||||
* e.g. "The cat" vs "The big cat", 1->1, 5->8
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
* @param loc Location within text1.
|
||||
* @return Location within text2.
|
||||
*/
|
||||
public:
|
||||
int diff_xIndex(const QList<Diff> &diffs, int loc);
|
||||
|
||||
/**
|
||||
* Convert a Diff list into a pretty HTML report.
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
* @return HTML representation.
|
||||
*/
|
||||
public:
|
||||
QString diff_prettyHtml(const QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Compute and return the source text (all equalities and deletions).
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
* @return Source text.
|
||||
*/
|
||||
public:
|
||||
QString diff_text1(const QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Compute and return the destination text (all equalities and insertions).
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
* @return Destination text.
|
||||
*/
|
||||
public:
|
||||
QString diff_text2(const QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Compute the Levenshtein distance; the number of inserted, deleted or
|
||||
* substituted characters.
|
||||
* @param diffs LinkedList of Diff objects.
|
||||
* @return Number of changes.
|
||||
*/
|
||||
public:
|
||||
int diff_levenshtein(const QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Crush the diff into an encoded string which describes the operations
|
||||
* required to transform text1 into text2.
|
||||
* E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'.
|
||||
* Operations are tab-separated. Inserted text is escaped using %xx notation.
|
||||
* @param diffs Array of diff tuples.
|
||||
* @return Delta text.
|
||||
*/
|
||||
public:
|
||||
QString diff_toDelta(const QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Given the original text1, and an encoded string which describes the
|
||||
* operations required to transform text1 into text2, compute the full diff.
|
||||
* @param text1 Source string for the diff.
|
||||
* @param delta Delta text.
|
||||
* @return Array of diff tuples or null if invalid.
|
||||
* @throws QString If invalid input.
|
||||
*/
|
||||
public:
|
||||
QList<Diff> diff_fromDelta(const QString &text1, const QString &delta);
|
||||
|
||||
|
||||
// MATCH FUNCTIONS
|
||||
|
||||
|
||||
/**
|
||||
* Locate the best instance of 'pattern' in 'text' near 'loc'.
|
||||
* Returns -1 if no match found.
|
||||
* @param text The text to search.
|
||||
* @param pattern The pattern to search for.
|
||||
* @param loc The location to search around.
|
||||
* @return Best match index or -1.
|
||||
*/
|
||||
public:
|
||||
int match_main(const QString &text, const QString &pattern, int loc);
|
||||
|
||||
/**
|
||||
* Locate the best instance of 'pattern' in 'text' near 'loc' using the
|
||||
* Bitap algorithm. Returns -1 if no match found.
|
||||
* @param text The text to search.
|
||||
* @param pattern The pattern to search for.
|
||||
* @param loc The location to search around.
|
||||
* @return Best match index or -1.
|
||||
*/
|
||||
protected:
|
||||
int match_bitap(const QString &text, const QString &pattern, int loc);
|
||||
|
||||
/**
|
||||
* Compute and return the score for a match with e errors and x location.
|
||||
* @param e Number of errors in match.
|
||||
* @param x Location of match.
|
||||
* @param loc Expected location of match.
|
||||
* @param pattern Pattern being sought.
|
||||
* @return Overall score for match (0.0 = good, 1.0 = bad).
|
||||
*/
|
||||
private:
|
||||
double match_bitapScore(int e, int x, int loc, const QString &pattern);
|
||||
|
||||
/**
|
||||
* Initialise the alphabet for the Bitap algorithm.
|
||||
* @param pattern The text to encode.
|
||||
* @return Hash of character locations.
|
||||
*/
|
||||
protected:
|
||||
QMap<QChar, int> match_alphabet(const QString &pattern);
|
||||
|
||||
|
||||
// PATCH FUNCTIONS
|
||||
|
||||
|
||||
/**
|
||||
* Increase the context until it is unique,
|
||||
* but don't let the pattern expand beyond Match_MaxBits.
|
||||
* @param patch The patch to grow.
|
||||
* @param text Source text.
|
||||
*/
|
||||
protected:
|
||||
void patch_addContext(Patch &patch, const QString &text);
|
||||
|
||||
/**
|
||||
* Compute a list of patches to turn text1 into text2.
|
||||
* A set of diffs will be computed.
|
||||
* @param text1 Old text.
|
||||
* @param text2 New text.
|
||||
* @return LinkedList of Patch objects.
|
||||
*/
|
||||
public:
|
||||
QList<Patch> patch_make(const QString &text1, const QString &text2);
|
||||
|
||||
/**
|
||||
* Compute a list of patches to turn text1 into text2.
|
||||
* text1 will be derived from the provided diffs.
|
||||
* @param diffs Array of diff tuples for text1 to text2.
|
||||
* @return LinkedList of Patch objects.
|
||||
*/
|
||||
public:
|
||||
QList<Patch> patch_make(const QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Compute a list of patches to turn text1 into text2.
|
||||
* text2 is ignored, diffs are the delta between text1 and text2.
|
||||
* @param text1 Old text.
|
||||
* @param text2 Ignored.
|
||||
* @param diffs Array of diff tuples for text1 to text2.
|
||||
* @return LinkedList of Patch objects.
|
||||
* @deprecated Prefer patch_make(const QString &text1, const QList<Diff> &diffs).
|
||||
*/
|
||||
public:
|
||||
QList<Patch> patch_make(const QString &text1, const QString &text2, const QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Compute a list of patches to turn text1 into text2.
|
||||
* text2 is not provided, diffs are the delta between text1 and text2.
|
||||
* @param text1 Old text.
|
||||
* @param diffs Array of diff tuples for text1 to text2.
|
||||
* @return LinkedList of Patch objects.
|
||||
*/
|
||||
public:
|
||||
QList<Patch> patch_make(const QString &text1, const QList<Diff> &diffs);
|
||||
|
||||
/**
|
||||
* Given an array of patches, return another array that is identical.
|
||||
* @param patches Array of patch objects.
|
||||
* @return Array of patch objects.
|
||||
*/
|
||||
public:
|
||||
QList<Patch> patch_deepCopy(QList<Patch> &patches);
|
||||
|
||||
/**
|
||||
* Merge a set of patches onto the text. Return a patched text, as well
|
||||
* as an array of true/false values indicating which patches were applied.
|
||||
* @param patches Array of patch objects.
|
||||
* @param text Old text.
|
||||
* @return Two element Object array, containing the new text and an array of
|
||||
* boolean values.
|
||||
*/
|
||||
public:
|
||||
QPair<QString,QVector<bool> > patch_apply(QList<Patch> &patches, const QString &text);
|
||||
|
||||
/**
|
||||
* Add some padding on text start and end so that edges can match something.
|
||||
* Intended to be called only from within patch_apply.
|
||||
* @param patches Array of patch objects.
|
||||
* @return The padding string added to each side.
|
||||
*/
|
||||
public:
|
||||
QString patch_addPadding(QList<Patch> &patches);
|
||||
|
||||
/**
|
||||
* Look through the patches and break up any which are longer than the
|
||||
* maximum limit of the match algorithm.
|
||||
* Intended to be called only from within patch_apply.
|
||||
* @param patches LinkedList of Patch objects.
|
||||
*/
|
||||
public:
|
||||
void patch_splitMax(QList<Patch> &patches);
|
||||
|
||||
/**
|
||||
* Take a list of patches and return a textual representation.
|
||||
* @param patches List of Patch objects.
|
||||
* @return Text representation of patches.
|
||||
*/
|
||||
public:
|
||||
QString patch_toText(const QList<Patch> &patches);
|
||||
|
||||
/**
|
||||
* Parse a textual representation of patches and return a List of Patch
|
||||
* objects.
|
||||
* @param textline Text representation of patches.
|
||||
* @return List of Patch objects.
|
||||
* @throws QString If invalid input.
|
||||
*/
|
||||
public:
|
||||
QList<Patch> patch_fromText(const QString &textline);
|
||||
|
||||
/**
|
||||
* A safer version of QString.mid(pos). This one returns "" instead of
|
||||
* null when the postion equals the string length.
|
||||
* @param str String to take a substring from.
|
||||
* @param pos Position to start the substring from.
|
||||
* @return Substring.
|
||||
*/
|
||||
private:
|
||||
static inline QString safeMid(const QString &str, int pos) {
|
||||
return (pos == str.length()) ? QString("") : str.mid(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* A safer version of QString.mid(pos, len). This one returns "" instead of
|
||||
* null when the postion equals the string length.
|
||||
* @param str String to take a substring from.
|
||||
* @param pos Position to start the substring from.
|
||||
* @param len Length of substring.
|
||||
* @return Substring.
|
||||
*/
|
||||
private:
|
||||
static inline QString safeMid(const QString &str, int pos, int len) {
|
||||
return (pos == str.length()) ? QString("") : str.mid(pos, len);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // DIFF_MATCH_PATCH_H
|
1184
thirdparty/diff/diff_match_patch_test.cpp
vendored
1184
thirdparty/diff/diff_match_patch_test.cpp
vendored
File diff suppressed because it is too large
Load diff
92
thirdparty/diff/diff_match_patch_test.h
vendored
92
thirdparty/diff/diff_match_patch_test.h
vendored
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 Google Inc. All Rights Reserved.
|
||||
* Author: fraser@google.com (Neil Fraser)
|
||||
* Author: mikeslemmer@gmail.com (Mike Slemmer)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Diff Match and Patch -- Test Harness
|
||||
* http://code.google.com/p/google-diff-match-patch/
|
||||
*/
|
||||
|
||||
#ifndef DIFF_MATCH_PATCH_TEST_H
|
||||
#define DIFF_MATCH_PATCH_TEST_H
|
||||
|
||||
class diff_match_patch_test {
|
||||
public:
|
||||
diff_match_patch_test();
|
||||
void run_all_tests();
|
||||
|
||||
// DIFF TEST FUNCTIONS
|
||||
void testDiffCommonPrefix();
|
||||
void testDiffCommonSuffix();
|
||||
void testDiffCommonOverlap();
|
||||
void testDiffHalfmatch();
|
||||
void testDiffLinesToChars();
|
||||
void testDiffCharsToLines();
|
||||
void testDiffCleanupMerge();
|
||||
void testDiffCleanupSemanticLossless();
|
||||
void testDiffCleanupSemantic();
|
||||
void testDiffCleanupEfficiency();
|
||||
void testDiffPrettyHtml();
|
||||
void testDiffText();
|
||||
void testDiffDelta();
|
||||
void testDiffXIndex();
|
||||
void testDiffLevenshtein();
|
||||
void testDiffBisect();
|
||||
void testDiffMain();
|
||||
|
||||
// MATCH TEST FUNCTIONS
|
||||
void testMatchAlphabet();
|
||||
void testMatchBitap();
|
||||
void testMatchMain();
|
||||
|
||||
// PATCH TEST FUNCTIONS
|
||||
void testPatchObj();
|
||||
void testPatchFromText();
|
||||
void testPatchToText();
|
||||
void testPatchAddContext();
|
||||
void testPatchMake();
|
||||
void testPatchSplitMax();
|
||||
void testPatchAddPadding();
|
||||
void testPatchApply();
|
||||
|
||||
private:
|
||||
diff_match_patch dmp;
|
||||
|
||||
// Define equality.
|
||||
void assertEquals(const QString &strCase, int n1, int n2);
|
||||
void assertEquals(const QString &strCase, const QString &s1, const QString &s2);
|
||||
void assertEquals(const QString &strCase, const Diff &d1, const Diff &d2);
|
||||
void assertEquals(const QString &strCase, const QList<Diff> &list1, const QList<Diff> &list2);
|
||||
void assertEquals(const QString &strCase, const QList<QVariant> &list1, const QList<QVariant> &list2);
|
||||
void assertEquals(const QString &strCase, const QVariant &var1, const QVariant &var2);
|
||||
void assertEquals(const QString &strCase, const QMap<QChar, int> &m1, const QMap<QChar, int> &m2);
|
||||
void assertEquals(const QString &strCase, const QStringList &list1, const QStringList &list2);
|
||||
void assertTrue(const QString &strCase, bool value);
|
||||
void assertFalse(const QString &strCase, bool value);
|
||||
void assertEmpty(const QString &strCase, const QStringList &list);
|
||||
|
||||
// Construct the two texts which made up the diff originally.
|
||||
QStringList diff_rebuildtexts(QList<Diff> diffs);
|
||||
// Private function for quickly building lists of diffs.
|
||||
QList<Diff> diffList(
|
||||
// Diff(INSERT, NULL) is invalid and thus is used as the default argument.
|
||||
Diff d1 = Diff(INSERT, NULL), Diff d2 = Diff(INSERT, NULL),
|
||||
Diff d3 = Diff(INSERT, NULL), Diff d4 = Diff(INSERT, NULL),
|
||||
Diff d5 = Diff(INSERT, NULL), Diff d6 = Diff(INSERT, NULL),
|
||||
Diff d7 = Diff(INSERT, NULL), Diff d8 = Diff(INSERT, NULL),
|
||||
Diff d9 = Diff(INSERT, NULL), Diff d10 = Diff(INSERT, NULL));
|
||||
};
|
||||
|
||||
#endif // DIFF_MATCH_PATCH_TEST_H
|
2
thirdparty/dtl/CONTRIBUTORS
vendored
Normal file
2
thirdparty/dtl/CONTRIBUTORS
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
Jan Weiß <jan@geheimwerk.de>
|
30
thirdparty/dtl/COPYING
vendored
Normal file
30
thirdparty/dtl/COPYING
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
692
thirdparty/dtl/dtl/Diff.hpp
vendored
Normal file
692
thirdparty/dtl/dtl/Diff.hpp
vendored
Normal file
|
@ -0,0 +1,692 @@
|
|||
/**
|
||||
dtl -- Diff Template Library
|
||||
|
||||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* If you use this library, you must include dtl.hpp only. */
|
||||
|
||||
#ifndef DTL_DIFF_H
|
||||
#define DTL_DIFF_H
|
||||
|
||||
namespace dtl {
|
||||
|
||||
/**
|
||||
* diff class template
|
||||
* sequence must support random_access_iterator.
|
||||
*/
|
||||
template <typename elem, typename sequence = vector< elem >, typename comparator = Compare< elem > >
|
||||
class Diff
|
||||
{
|
||||
private :
|
||||
dtl_typedefs(elem, sequence)
|
||||
sequence A;
|
||||
sequence B;
|
||||
size_t M;
|
||||
size_t N;
|
||||
size_t delta;
|
||||
size_t offset;
|
||||
long long *fp;
|
||||
long long editDistance;
|
||||
Lcs< elem > lcs;
|
||||
Ses< elem > ses;
|
||||
editPath path;
|
||||
editPathCordinates pathCordinates;
|
||||
bool swapped;
|
||||
bool huge;
|
||||
bool trivial;
|
||||
bool editDistanceOnly;
|
||||
uniHunkVec uniHunks;
|
||||
comparator cmp;
|
||||
public :
|
||||
Diff () {}
|
||||
|
||||
Diff (const sequence& a,
|
||||
const sequence& b) : A(a), B(b), ses(false) {
|
||||
init();
|
||||
}
|
||||
|
||||
Diff (const sequence& a,
|
||||
const sequence& b,
|
||||
bool deletesFirst) : A(a), B(b), ses(deletesFirst) {
|
||||
init();
|
||||
}
|
||||
|
||||
Diff (const sequence& a,
|
||||
const sequence& b,
|
||||
const comparator& comp) : A(a), B(b), ses(false), cmp(comp) {
|
||||
init();
|
||||
}
|
||||
|
||||
Diff (const sequence& a,
|
||||
const sequence& b,
|
||||
bool deleteFirst,
|
||||
const comparator& comp) : A(a), B(b), ses(deleteFirst), cmp(comp) {
|
||||
init();
|
||||
}
|
||||
|
||||
~Diff() {}
|
||||
|
||||
long long getEditDistance () const {
|
||||
return editDistance;
|
||||
}
|
||||
|
||||
Lcs< elem > getLcs () const {
|
||||
return lcs;
|
||||
}
|
||||
|
||||
elemVec getLcsVec () const {
|
||||
return lcs.getSequence();
|
||||
}
|
||||
|
||||
Ses< elem > getSes () const {
|
||||
return ses;
|
||||
}
|
||||
|
||||
uniHunkVec getUniHunks () const {
|
||||
return uniHunks;
|
||||
}
|
||||
|
||||
/* These should be deprecated */
|
||||
bool isHuge () const {
|
||||
return huge;
|
||||
}
|
||||
|
||||
void onHuge () {
|
||||
this->huge = true;
|
||||
}
|
||||
|
||||
void offHuge () {
|
||||
this->huge = false;
|
||||
}
|
||||
|
||||
bool isUnserious () const {
|
||||
return trivial;
|
||||
}
|
||||
|
||||
void onUnserious () {
|
||||
this->trivial = true;
|
||||
}
|
||||
|
||||
void offUnserious () {
|
||||
this->trivial = false;
|
||||
}
|
||||
|
||||
void onOnlyEditDistance () {
|
||||
this->editDistanceOnly = true;
|
||||
}
|
||||
|
||||
/* These are the replacements for the above */
|
||||
bool hugeEnabled () const {
|
||||
return huge;
|
||||
}
|
||||
|
||||
void enableHuge () {
|
||||
this->huge = true;
|
||||
}
|
||||
|
||||
void disableHuge () {
|
||||
this->huge = false;
|
||||
}
|
||||
|
||||
bool trivialEnabled () const {
|
||||
return trivial;
|
||||
}
|
||||
|
||||
void enableTrivial () const {
|
||||
this->trivial = true;
|
||||
}
|
||||
|
||||
void disableTrivial () {
|
||||
this->trivial = false;
|
||||
}
|
||||
|
||||
void editDistanceOnlyEnabled () {
|
||||
this->editDistanceOnly = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* patching with Unified Format Hunks
|
||||
*/
|
||||
sequence uniPatch (const sequence& seq) {
|
||||
elemList seqLst(seq.begin(), seq.end());
|
||||
sesElemVec shunk;
|
||||
sesElemVec_iter vsesIt;
|
||||
elemList_iter lstIt = seqLst.begin();
|
||||
long long inc_dec_total = 0;
|
||||
long long gap = 1;
|
||||
for (uniHunkVec_iter it=uniHunks.begin();it!=uniHunks.end();++it) {
|
||||
joinSesVec(shunk, it->common[0]);
|
||||
joinSesVec(shunk, it->change);
|
||||
joinSesVec(shunk, it->common[1]);
|
||||
it->a += inc_dec_total;
|
||||
inc_dec_total += it->inc_dec_count;
|
||||
for (long long i=0;i<it->a - gap;++i) {
|
||||
++lstIt;
|
||||
}
|
||||
gap = it->a + it->b + it->inc_dec_count;
|
||||
vsesIt = shunk.begin();
|
||||
while (vsesIt!=shunk.end()) {
|
||||
switch (vsesIt->second.type) {
|
||||
case SES_ADD :
|
||||
seqLst.insert(lstIt, vsesIt->first);
|
||||
break;
|
||||
case SES_DELETE :
|
||||
if (lstIt != seqLst.end()) {
|
||||
lstIt = seqLst.erase(lstIt);
|
||||
}
|
||||
break;
|
||||
case SES_COMMON :
|
||||
if (lstIt != seqLst.end()) {
|
||||
++lstIt;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
// no fall-through
|
||||
break;
|
||||
}
|
||||
++vsesIt;
|
||||
}
|
||||
shunk.clear();
|
||||
}
|
||||
|
||||
sequence patchedSeq(seqLst.begin(), seqLst.end());
|
||||
return patchedSeq;
|
||||
}
|
||||
|
||||
/**
|
||||
* patching with Shortest Edit Script (SES)
|
||||
*/
|
||||
sequence patch (const sequence& seq) const {
|
||||
sesElemVec sesSeq = ses.getSequence();
|
||||
elemList seqLst(seq.begin(), seq.end());
|
||||
elemList_iter lstIt = seqLst.begin();
|
||||
for (sesElemVec_iter sesIt=sesSeq.begin();sesIt!=sesSeq.end();++sesIt) {
|
||||
switch (sesIt->second.type) {
|
||||
case SES_ADD :
|
||||
seqLst.insert(lstIt, sesIt->first);
|
||||
break;
|
||||
case SES_DELETE :
|
||||
lstIt = seqLst.erase(lstIt);
|
||||
break;
|
||||
case SES_COMMON :
|
||||
++lstIt;
|
||||
break;
|
||||
default :
|
||||
// no through
|
||||
break;
|
||||
}
|
||||
}
|
||||
sequence patchedSeq(seqLst.begin(), seqLst.end());
|
||||
return patchedSeq;
|
||||
}
|
||||
|
||||
/**
|
||||
* compose Longest Common Subsequence and Shortest Edit Script.
|
||||
* The algorithm implemented here is based on "An O(NP) Sequence Comparison Algorithm"
|
||||
* described by Sun Wu, Udi Manber and Gene Myers
|
||||
*/
|
||||
void compose() {
|
||||
|
||||
if (isHuge()) {
|
||||
pathCordinates.reserve(MAX_CORDINATES_SIZE);
|
||||
}
|
||||
|
||||
long long p = -1;
|
||||
fp = new long long[M + N + 3];
|
||||
fill(&fp[0], &fp[M + N + 3], -1);
|
||||
path = editPath(M + N + 3);
|
||||
fill(path.begin(), path.end(), -1);
|
||||
ONP:
|
||||
do {
|
||||
++p;
|
||||
for (long long k=-p;k<=static_cast<long long>(delta)-1;++k) {
|
||||
fp[k+offset] = snake(k, fp[k-1+offset]+1, fp[k+1+offset]);
|
||||
}
|
||||
for (long long k=static_cast<long long>(delta)+p;k>=static_cast<long long>(delta)+1;--k) {
|
||||
fp[k+offset] = snake(k, fp[k-1+offset]+1, fp[k+1+offset]);
|
||||
}
|
||||
fp[delta+offset] = snake(static_cast<long long>(delta), fp[delta-1+offset]+1, fp[delta+1+offset]);
|
||||
} while (fp[delta+offset] != static_cast<long long>(N) && pathCordinates.size() < MAX_CORDINATES_SIZE);
|
||||
|
||||
editDistance += static_cast<long long>(delta) + 2 * p;
|
||||
long long r = path[delta+offset];
|
||||
P cordinate;
|
||||
editPathCordinates epc(0);
|
||||
|
||||
// recording edit distance only
|
||||
if (editDistanceOnly) {
|
||||
delete[] this->fp;
|
||||
return;
|
||||
}
|
||||
|
||||
while(r != -1) {
|
||||
cordinate.x = pathCordinates[(size_t)r].x;
|
||||
cordinate.y = pathCordinates[(size_t)r].y;
|
||||
epc.push_back(cordinate);
|
||||
r = pathCordinates[(size_t)r].k;
|
||||
}
|
||||
|
||||
// record Longest Common Subsequence & Shortest Edit Script
|
||||
if (!recordSequence(epc)) {
|
||||
pathCordinates.resize(0);
|
||||
epc.resize(0);
|
||||
p = -1;
|
||||
goto ONP;
|
||||
}
|
||||
delete[] this->fp;
|
||||
}
|
||||
|
||||
/**
|
||||
* print difference between A and B as an SES
|
||||
*/
|
||||
template < typename stream >
|
||||
void printSES (stream& out) const {
|
||||
sesElemVec ses_v = ses.getSequence();
|
||||
for_each(ses_v.begin(), ses_v.end(), ChangePrinter< sesElem, stream >(out));
|
||||
}
|
||||
|
||||
void printSES (ostream& out = cout) const {
|
||||
printSES< ostream >(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* print differences given an SES
|
||||
*/
|
||||
template < typename stream >
|
||||
static void printSES (const Ses< elem >& s, stream& out) {
|
||||
sesElemVec ses_v = s.getSequence();
|
||||
for_each(ses_v.begin(), ses_v.end(), ChangePrinter< sesElem, stream >(out));
|
||||
}
|
||||
|
||||
static void printSES (const Ses< elem >& s, ostream& out = cout) {
|
||||
printSES< ostream >(s, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* print difference between A and B as an SES with custom printer
|
||||
*/
|
||||
template < typename stream, template < typename SEET, typename STRT > class PT >
|
||||
void printSES (stream& out) const {
|
||||
sesElemVec ses_v = ses.getSequence ();
|
||||
for_each (ses_v.begin (), ses_v.end(), PT < sesElem, stream > (out));
|
||||
}
|
||||
|
||||
/**
|
||||
* print difference between A and B in the Unified Format
|
||||
*/
|
||||
template < typename stream >
|
||||
void printUnifiedFormat (stream& out) const {
|
||||
for_each(uniHunks.begin(), uniHunks.end(), UniHunkPrinter< sesElem, stream >(out));
|
||||
}
|
||||
|
||||
void printUnifiedFormat (ostream& out = cout) const {
|
||||
printUnifiedFormat< ostream >(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* print unified format difference with given unified format hunks
|
||||
*/
|
||||
template < typename stream >
|
||||
static void printUnifiedFormat (const uniHunkVec& hunks, stream& out) {
|
||||
for_each(hunks.begin(), hunks.end(), UniHunkPrinter< sesElem >(out));
|
||||
}
|
||||
|
||||
static void printUnifiedFormat (const uniHunkVec& hunks, ostream& out = cout) {
|
||||
printUnifiedFormat< ostream >(hunks, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* compose Unified Format Hunks from Shortest Edit Script
|
||||
*/
|
||||
void composeUnifiedHunks () {
|
||||
sesElemVec common[2];
|
||||
sesElemVec change;
|
||||
sesElemVec ses_v = ses.getSequence();
|
||||
long long l_cnt = 1;
|
||||
long long length = distance(ses_v.begin(), ses_v.end());
|
||||
long long middle = 0;
|
||||
bool isMiddle, isAfter;
|
||||
elemInfo einfo;
|
||||
long long a, b, c, d; // @@ -a,b +c,d @@
|
||||
long long inc_dec_count = 0;
|
||||
uniHunk< sesElem > hunk;
|
||||
sesElemVec adds;
|
||||
sesElemVec deletes;
|
||||
|
||||
isMiddle = isAfter = false;
|
||||
a = b = c = d = 0;
|
||||
|
||||
for (sesElemVec_iter it=ses_v.begin();it!=ses_v.end();++it, ++l_cnt) {
|
||||
einfo = it->second;
|
||||
switch (einfo.type) {
|
||||
case SES_ADD :
|
||||
middle = 0;
|
||||
++inc_dec_count;
|
||||
adds.push_back(*it);
|
||||
if (!isMiddle) isMiddle = true;
|
||||
if (isMiddle) ++d;
|
||||
if (l_cnt >= length) {
|
||||
joinSesVec(change, deletes);
|
||||
joinSesVec(change, adds);
|
||||
isAfter = true;
|
||||
}
|
||||
break;
|
||||
case SES_DELETE :
|
||||
middle = 0;
|
||||
--inc_dec_count;
|
||||
deletes.push_back(*it);
|
||||
if (!isMiddle) isMiddle = true;
|
||||
if (isMiddle) ++b;
|
||||
if (l_cnt >= length) {
|
||||
joinSesVec(change, deletes);
|
||||
joinSesVec(change, adds);
|
||||
isAfter = true;
|
||||
}
|
||||
break;
|
||||
case SES_COMMON :
|
||||
++b;++d;
|
||||
if (common[1].empty() && adds.empty() && deletes.empty() && change.empty()) {
|
||||
if (static_cast<long long>(common[0].size()) < DTL_CONTEXT_SIZE) {
|
||||
if (a == 0 && c == 0) {
|
||||
if (!wasSwapped()) {
|
||||
a = einfo.beforeIdx;
|
||||
c = einfo.afterIdx;
|
||||
} else {
|
||||
a = einfo.afterIdx;
|
||||
c = einfo.beforeIdx;
|
||||
}
|
||||
}
|
||||
common[0].push_back(*it);
|
||||
} else {
|
||||
rotate(common[0].begin(), common[0].begin() + 1, common[0].end());
|
||||
common[0].pop_back();
|
||||
common[0].push_back(*it);
|
||||
++a;++c;
|
||||
--b;--d;
|
||||
}
|
||||
}
|
||||
if (isMiddle && !isAfter) {
|
||||
++middle;
|
||||
joinSesVec(change, deletes);
|
||||
joinSesVec(change, adds);
|
||||
change.push_back(*it);
|
||||
if (middle >= DTL_SEPARATE_SIZE || l_cnt >= length) {
|
||||
isAfter = true;
|
||||
}
|
||||
adds.clear();
|
||||
deletes.clear();
|
||||
}
|
||||
break;
|
||||
default :
|
||||
// no through
|
||||
break;
|
||||
}
|
||||
// compose unified format hunk
|
||||
if (isAfter && !change.empty()) {
|
||||
sesElemVec_iter cit = it;
|
||||
long long cnt = 0;
|
||||
for (long long i=0;i<DTL_SEPARATE_SIZE && (cit != ses_v.end());++i, ++cit) {
|
||||
if (cit->second.type == SES_COMMON) {
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
if (cnt < DTL_SEPARATE_SIZE && l_cnt < length) {
|
||||
middle = 0;
|
||||
isAfter = false;
|
||||
continue;
|
||||
}
|
||||
if (static_cast<long long>(common[0].size()) >= DTL_SEPARATE_SIZE) {
|
||||
long long c0size = static_cast<long long>(common[0].size());
|
||||
rotate(common[0].begin(),
|
||||
common[0].begin() + (size_t)c0size - DTL_SEPARATE_SIZE,
|
||||
common[0].end());
|
||||
for (long long i=0;i<c0size - DTL_SEPARATE_SIZE;++i) {
|
||||
common[0].pop_back();
|
||||
}
|
||||
a += c0size - DTL_SEPARATE_SIZE;
|
||||
c += c0size - DTL_SEPARATE_SIZE;
|
||||
}
|
||||
if (a == 0) ++a;
|
||||
if (c == 0) ++c;
|
||||
if (wasSwapped()) swap(a, c);
|
||||
hunk.a = a;
|
||||
hunk.b = b;
|
||||
hunk.c = c;
|
||||
hunk.d = d;
|
||||
hunk.common[0] = common[0];
|
||||
hunk.change = change;
|
||||
hunk.common[1] = common[1];
|
||||
hunk.inc_dec_count = inc_dec_count;
|
||||
uniHunks.push_back(hunk);
|
||||
isMiddle = false;
|
||||
isAfter = false;
|
||||
common[0].clear();
|
||||
common[1].clear();
|
||||
adds.clear();
|
||||
deletes.clear();
|
||||
change.clear();
|
||||
a = b = c = d = middle = inc_dec_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* compose ses from stream
|
||||
*/
|
||||
template <typename stream>
|
||||
static Ses< elem > composeSesFromStream (stream& st)
|
||||
{
|
||||
elem line;
|
||||
Ses< elem > ret;
|
||||
long long x_idx, y_idx;
|
||||
x_idx = y_idx = 1;
|
||||
while (getline(st, line)) {
|
||||
elem mark(line.begin(), line.begin() + 1);
|
||||
elem e(line.begin() + 1, line.end());
|
||||
if (mark == SES_MARK_DELETE) {
|
||||
ret.addSequence(e, x_idx, 0, SES_DELETE);
|
||||
++x_idx;
|
||||
} else if (mark == SES_MARK_ADD) {
|
||||
ret.addSequence(e, y_idx, 0, SES_ADD);
|
||||
++y_idx;
|
||||
} else if (mark == SES_MARK_COMMON) {
|
||||
ret.addSequence(e, x_idx, y_idx, SES_COMMON);
|
||||
++x_idx;
|
||||
++y_idx;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private :
|
||||
/**
|
||||
* initialize
|
||||
*/
|
||||
void init () {
|
||||
M = distance(A.begin(), A.end());
|
||||
N = distance(B.begin(), B.end());
|
||||
if (M < N) {
|
||||
swapped = false;
|
||||
} else {
|
||||
swap(A, B);
|
||||
swap(M, N);
|
||||
swapped = true;
|
||||
}
|
||||
editDistance = 0;
|
||||
delta = N - M;
|
||||
offset = M + 1;
|
||||
huge = false;
|
||||
trivial = false;
|
||||
editDistanceOnly = false;
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* search shortest path and record the path
|
||||
*/
|
||||
long long snake(const long long& k, const long long& above, const long long& below) {
|
||||
long long r = above > below ? path[(size_t)k-1+offset] : path[(size_t)k+1+offset];
|
||||
long long y = max(above, below);
|
||||
long long x = y - k;
|
||||
while ((size_t)x < M && (size_t)y < N && (swapped ? cmp.impl(B[(size_t)y], A[(size_t)x]) : cmp.impl(A[(size_t)x], B[(size_t)y]))) {
|
||||
++x;++y;
|
||||
}
|
||||
|
||||
path[(size_t)k+offset] = static_cast<long long>(pathCordinates.size());
|
||||
if (!editDistanceOnly) {
|
||||
P p;
|
||||
p.x = x;p.y = y;p.k = r;
|
||||
pathCordinates.push_back(p);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* record SES and LCS
|
||||
*/
|
||||
bool recordSequence (const editPathCordinates& v) {
|
||||
sequence_const_iter x(A.begin());
|
||||
sequence_const_iter y(B.begin());
|
||||
long long x_idx, y_idx; // line number for Unified Format
|
||||
long long px_idx, py_idx; // cordinates
|
||||
bool complete = false;
|
||||
x_idx = y_idx = 1;
|
||||
px_idx = py_idx = 0;
|
||||
for (size_t i=v.size()-1;!complete;--i) {
|
||||
while(px_idx < v[i].x || py_idx < v[i].y) {
|
||||
if (v[i].y - v[i].x > py_idx - px_idx) {
|
||||
if (!wasSwapped()) {
|
||||
ses.addSequence(*y, 0, y_idx, SES_ADD);
|
||||
} else {
|
||||
ses.addSequence(*y, y_idx, 0, SES_DELETE);
|
||||
}
|
||||
++y;
|
||||
++y_idx;
|
||||
++py_idx;
|
||||
} else if (v[i].y - v[i].x < py_idx - px_idx) {
|
||||
if (!wasSwapped()) {
|
||||
ses.addSequence(*x, x_idx, 0, SES_DELETE);
|
||||
} else {
|
||||
ses.addSequence(*x, 0, x_idx, SES_ADD);
|
||||
}
|
||||
++x;
|
||||
++x_idx;
|
||||
++px_idx;
|
||||
} else {
|
||||
if (!wasSwapped()) {
|
||||
lcs.addSequence(*x);
|
||||
ses.addSequence(*x, x_idx, y_idx, SES_COMMON);
|
||||
} else {
|
||||
lcs.addSequence(*y);
|
||||
ses.addSequence(*y, y_idx, x_idx, SES_COMMON);
|
||||
}
|
||||
++x;
|
||||
++y;
|
||||
++x_idx;
|
||||
++y_idx;
|
||||
++px_idx;
|
||||
++py_idx;
|
||||
}
|
||||
}
|
||||
if (i == 0) complete = true;
|
||||
}
|
||||
|
||||
if (x_idx > static_cast<long long>(M) && y_idx > static_cast<long long>(N)) {
|
||||
// all recording succeeded
|
||||
} else {
|
||||
// trivial difference
|
||||
if (trivialEnabled()) {
|
||||
if (!wasSwapped()) {
|
||||
recordOddSequence(x_idx, M, x, SES_DELETE);
|
||||
recordOddSequence(y_idx, N, y, SES_ADD);
|
||||
} else {
|
||||
recordOddSequence(x_idx, M, x, SES_ADD);
|
||||
recordOddSequence(y_idx, N, y, SES_DELETE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// nontrivial difference
|
||||
sequence A_(A.begin() + (size_t)x_idx - 1, A.end());
|
||||
sequence B_(B.begin() + (size_t)y_idx - 1, B.end());
|
||||
A = A_;
|
||||
B = B_;
|
||||
M = distance(A.begin(), A.end());
|
||||
N = distance(B.begin(), B.end());
|
||||
delta = N - M;
|
||||
offset = M + 1;
|
||||
delete[] fp;
|
||||
fp = new long long[M + N + 3];
|
||||
fill(&fp[0], &fp[M + N + 3], -1);
|
||||
fill(path.begin(), path.end(), -1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* record odd sequence in SES
|
||||
*/
|
||||
void inline recordOddSequence (long long idx, long long length, sequence_const_iter it, const edit_t et) {
|
||||
while(idx < length){
|
||||
ses.addSequence(*it, idx, 0, et);
|
||||
++it;
|
||||
++idx;
|
||||
++editDistance;
|
||||
}
|
||||
ses.addSequence(*it, idx, 0, et);
|
||||
++editDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* join SES vectors
|
||||
*/
|
||||
void inline joinSesVec (sesElemVec& s1, sesElemVec& s2) const {
|
||||
if (!s2.empty()) {
|
||||
for (sesElemVec_iter vit=s2.begin();vit!=s2.end();++vit) {
|
||||
s1.push_back(*vit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the sequences have been swapped
|
||||
*/
|
||||
bool inline wasSwapped () const {
|
||||
return swapped;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DTL_DIFF_H
|
245
thirdparty/dtl/dtl/Diff3.hpp
vendored
Normal file
245
thirdparty/dtl/dtl/Diff3.hpp
vendored
Normal file
|
@ -0,0 +1,245 @@
|
|||
/**
|
||||
dtl -- Diff Template Library
|
||||
|
||||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* If you use this library, you must include dtl.hpp only. */
|
||||
|
||||
#ifndef DTL_DIFF3_H
|
||||
#define DTL_DIFF3_H
|
||||
|
||||
namespace dtl {
|
||||
|
||||
/**
|
||||
* diff3 class template
|
||||
* sequence must support random_access_iterator.
|
||||
*/
|
||||
template <typename elem, typename sequence = vector< elem >, typename comparator = Compare< elem > >
|
||||
class Diff3
|
||||
{
|
||||
private:
|
||||
dtl_typedefs(elem, sequence)
|
||||
sequence A;
|
||||
sequence B;
|
||||
sequence C;
|
||||
sequence S;
|
||||
Diff< elem, sequence, comparator > diff_ba;
|
||||
Diff< elem, sequence, comparator > diff_bc;
|
||||
bool conflict;
|
||||
elem csepabegin;
|
||||
elem csepa;
|
||||
elem csepaend;
|
||||
public :
|
||||
Diff3 () {}
|
||||
Diff3 (const sequence& a,
|
||||
const sequence& b,
|
||||
const sequence& c) : A(a), B(b), C(c),
|
||||
diff_ba(b, a), diff_bc(b, c),
|
||||
conflict(false) {}
|
||||
|
||||
~Diff3 () {}
|
||||
|
||||
bool isConflict () const {
|
||||
return conflict;
|
||||
}
|
||||
|
||||
sequence getMergedSequence () const {
|
||||
return S;
|
||||
}
|
||||
|
||||
/**
|
||||
* merge changes B and C into A
|
||||
*/
|
||||
bool merge () {
|
||||
if (diff_ba.getEditDistance() == 0) { // A == B
|
||||
if (diff_bc.getEditDistance() == 0) { // A == B == C
|
||||
S = B;
|
||||
return true;
|
||||
}
|
||||
S = C;
|
||||
return true;
|
||||
} else { // A != B
|
||||
if (diff_bc.getEditDistance() == 0) { // A != B == C
|
||||
S = A;
|
||||
return true;
|
||||
} else { // A != B != C
|
||||
S = merge_();
|
||||
if (isConflict()) { // conflict occured
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* compose differences
|
||||
*/
|
||||
void compose () {
|
||||
diff_ba.compose();
|
||||
diff_bc.compose();
|
||||
}
|
||||
|
||||
private :
|
||||
/**
|
||||
* merge implementation
|
||||
*/
|
||||
sequence merge_ () {
|
||||
elemVec seq;
|
||||
Ses< elem > ses_ba = diff_ba.getSes();
|
||||
Ses< elem > ses_bc = diff_bc.getSes();
|
||||
sesElemVec ses_ba_v = ses_ba.getSequence();
|
||||
sesElemVec ses_bc_v = ses_bc.getSequence();
|
||||
sesElemVec_iter ba_it = ses_ba_v.begin();
|
||||
sesElemVec_iter bc_it = ses_bc_v.begin();
|
||||
sesElemVec_iter ba_end = ses_ba_v.end();
|
||||
sesElemVec_iter bc_end = ses_bc_v.end();
|
||||
|
||||
while (!isEnd(ba_end, ba_it) || !isEnd(bc_end, bc_it)) {
|
||||
while (true) {
|
||||
if (!isEnd(ba_end, ba_it) &&
|
||||
!isEnd(bc_end, bc_it) &&
|
||||
ba_it->first == bc_it->first &&
|
||||
ba_it->second.type == SES_COMMON &&
|
||||
bc_it->second.type == SES_COMMON) {
|
||||
// do nothing
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if (!isEnd(ba_end, ba_it)) seq.push_back(ba_it->first);
|
||||
else if (!isEnd(bc_end, bc_it)) seq.push_back(bc_it->first);
|
||||
forwardUntilEnd(ba_end, ba_it);
|
||||
forwardUntilEnd(bc_end, bc_it);
|
||||
}
|
||||
if (isEnd(ba_end, ba_it) || isEnd(bc_end, bc_it)) break;
|
||||
if ( ba_it->second.type == SES_COMMON
|
||||
&& bc_it->second.type == SES_DELETE) {
|
||||
forwardUntilEnd(ba_end, ba_it);
|
||||
forwardUntilEnd(bc_end, bc_it);
|
||||
} else if (ba_it->second.type == SES_COMMON &&
|
||||
bc_it->second.type == SES_ADD) {
|
||||
seq.push_back(bc_it->first);
|
||||
forwardUntilEnd(bc_end, bc_it);
|
||||
} else if (ba_it->second.type == SES_DELETE &&
|
||||
bc_it->second.type == SES_COMMON) {
|
||||
forwardUntilEnd(ba_end, ba_it);
|
||||
forwardUntilEnd(bc_end, bc_it);
|
||||
} else if (ba_it->second.type == SES_DELETE &&
|
||||
bc_it->second.type == SES_DELETE) {
|
||||
if (ba_it->first == bc_it->first) {
|
||||
forwardUntilEnd(ba_end, ba_it);
|
||||
forwardUntilEnd(bc_end, bc_it);
|
||||
} else {
|
||||
// conflict
|
||||
conflict = true;
|
||||
return B;
|
||||
}
|
||||
} else if (ba_it->second.type == SES_DELETE &&
|
||||
bc_it->second.type == SES_ADD) {
|
||||
// conflict
|
||||
conflict = true;
|
||||
return B;
|
||||
} else if (ba_it->second.type == SES_ADD &&
|
||||
bc_it->second.type == SES_COMMON) {
|
||||
seq.push_back(ba_it->first);
|
||||
forwardUntilEnd(ba_end, ba_it);
|
||||
} else if (ba_it->second.type == SES_ADD &&
|
||||
bc_it->second.type == SES_DELETE) {
|
||||
// conflict
|
||||
conflict = true;
|
||||
return B;
|
||||
} else if (ba_it->second.type == SES_ADD &&
|
||||
bc_it->second.type == SES_ADD) {
|
||||
if (ba_it->first == bc_it->first) {
|
||||
seq.push_back(ba_it->first);
|
||||
forwardUntilEnd(ba_end, ba_it);
|
||||
forwardUntilEnd(bc_end, bc_it);
|
||||
} else {
|
||||
// conflict
|
||||
conflict = true;
|
||||
return B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isEnd(ba_end, ba_it)) {
|
||||
addDecentSequence(bc_end, bc_it, seq);
|
||||
} else if (isEnd(bc_end, bc_it)) {
|
||||
addDecentSequence(ba_end, ba_it, seq);
|
||||
}
|
||||
|
||||
sequence mergedSeq(seq.begin(), seq.end());
|
||||
return mergedSeq;
|
||||
}
|
||||
|
||||
/**
|
||||
* join elem vectors
|
||||
*/
|
||||
void inline joinElemVec (elemVec& s1, elemVec& s2) const {
|
||||
if (!s2.empty()) {
|
||||
for (elemVec_iter vit=s2.begin();vit!=s2.end();++vit) {
|
||||
s1.push_back(*vit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if sequence is at end
|
||||
*/
|
||||
template <typename T_iter>
|
||||
bool inline isEnd (const T_iter& end, const T_iter& it) const {
|
||||
return it == end ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* increment iterator until iterator is at end
|
||||
*/
|
||||
template <typename T_iter>
|
||||
void inline forwardUntilEnd (const T_iter& end, T_iter& it) const {
|
||||
if (!isEnd(end, it)) ++it;
|
||||
}
|
||||
|
||||
/**
|
||||
* add elements whose SES's type is ADD
|
||||
*/
|
||||
void inline addDecentSequence (const sesElemVec_iter& end, sesElemVec_iter& it, elemVec& seq) const {
|
||||
while (!isEnd(end, it)) {
|
||||
if (it->second.type == SES_ADD) seq.push_back(it->first);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DTL_DIFF3_H
|
55
thirdparty/dtl/dtl/Lcs.hpp
vendored
Normal file
55
thirdparty/dtl/dtl/Lcs.hpp
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
dtl -- Diff Template Library
|
||||
|
||||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* If you use this library, you must include dtl.hpp only. */
|
||||
|
||||
#ifndef DTL_LCS_H
|
||||
#define DTL_LCS_H
|
||||
|
||||
namespace dtl {
|
||||
|
||||
/**
|
||||
* Longest Common Subsequence template class
|
||||
*/
|
||||
template <typename elem>
|
||||
class Lcs : public Sequence< elem >
|
||||
{
|
||||
public :
|
||||
Lcs () {}
|
||||
~Lcs () {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DTL_LCS_H
|
65
thirdparty/dtl/dtl/Sequence.hpp
vendored
Normal file
65
thirdparty/dtl/dtl/Sequence.hpp
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
dtl -- Diff Template Library
|
||||
|
||||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* If you use this library, you must include dtl.hpp only. */
|
||||
|
||||
#ifndef DTL_SEQUENCE_H
|
||||
#define DTL_SEQUENCE_H
|
||||
|
||||
namespace dtl {
|
||||
|
||||
/**
|
||||
* sequence class template
|
||||
*/
|
||||
template <typename elem>
|
||||
class Sequence
|
||||
{
|
||||
public :
|
||||
typedef vector< elem > elemVec;
|
||||
Sequence () {}
|
||||
virtual ~Sequence () {}
|
||||
|
||||
elemVec getSequence () const {
|
||||
return sequence;
|
||||
}
|
||||
void addSequence (elem e) {
|
||||
sequence.push_back(e);
|
||||
}
|
||||
protected :
|
||||
elemVec sequence;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DTL_SEQUENCE_H
|
132
thirdparty/dtl/dtl/Ses.hpp
vendored
Normal file
132
thirdparty/dtl/dtl/Ses.hpp
vendored
Normal file
|
@ -0,0 +1,132 @@
|
|||
/**
|
||||
dtl -- Diff Template Library
|
||||
|
||||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* If you use this library, you must include dtl.hpp only. */
|
||||
|
||||
#ifndef DTL_SES_H
|
||||
#define DTL_SES_H
|
||||
|
||||
namespace dtl {
|
||||
|
||||
/**
|
||||
* Shortest Edit Script template class
|
||||
*/
|
||||
template <typename elem>
|
||||
class Ses : public Sequence< elem >
|
||||
{
|
||||
private :
|
||||
typedef pair< elem, elemInfo > sesElem;
|
||||
typedef vector< sesElem > sesElemVec;
|
||||
public :
|
||||
|
||||
Ses () : onlyAdd(true), onlyDelete(true), onlyCopy(true), deletesFirst(false) {
|
||||
nextDeleteIdx = 0;
|
||||
}
|
||||
Ses (bool moveDel) : onlyAdd(true), onlyDelete(true), onlyCopy(true), deletesFirst(moveDel) {
|
||||
nextDeleteIdx = 0;
|
||||
}
|
||||
~Ses () {}
|
||||
|
||||
bool isOnlyAdd () const {
|
||||
return onlyAdd;
|
||||
}
|
||||
|
||||
bool isOnlyDelete () const {
|
||||
return onlyDelete;
|
||||
}
|
||||
|
||||
bool isOnlyCopy () const {
|
||||
return onlyCopy;
|
||||
}
|
||||
|
||||
bool isOnlyOneOperation () const {
|
||||
return isOnlyAdd() || isOnlyDelete() || isOnlyCopy();
|
||||
}
|
||||
|
||||
bool isChange () const {
|
||||
return !onlyCopy;
|
||||
}
|
||||
|
||||
using Sequence< elem >::addSequence;
|
||||
void addSequence (elem e, long long beforeIdx, long long afterIdx, const edit_t type) {
|
||||
elemInfo info;
|
||||
info.beforeIdx = beforeIdx;
|
||||
info.afterIdx = afterIdx;
|
||||
info.type = type;
|
||||
sesElem pe(e, info);
|
||||
if (!deletesFirst) {
|
||||
sequence.push_back(pe);
|
||||
}
|
||||
switch (type) {
|
||||
case SES_DELETE:
|
||||
onlyCopy = false;
|
||||
onlyAdd = false;
|
||||
if (deletesFirst) {
|
||||
sequence.insert(sequence.begin() + nextDeleteIdx, pe);
|
||||
nextDeleteIdx++;
|
||||
}
|
||||
break;
|
||||
case SES_COMMON:
|
||||
onlyAdd = false;
|
||||
onlyDelete = false;
|
||||
if (deletesFirst) {
|
||||
sequence.push_back(pe);
|
||||
nextDeleteIdx = sequence.size();
|
||||
}
|
||||
break;
|
||||
case SES_ADD:
|
||||
onlyDelete = false;
|
||||
onlyCopy = false;
|
||||
if (deletesFirst) {
|
||||
sequence.push_back(pe);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sesElemVec getSequence () const {
|
||||
return sequence;
|
||||
}
|
||||
private :
|
||||
sesElemVec sequence;
|
||||
bool onlyAdd;
|
||||
bool onlyDelete;
|
||||
bool onlyCopy;
|
||||
bool deletesFirst;
|
||||
size_t nextDeleteIdx;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DTL_SES_H
|
47
thirdparty/dtl/dtl/dtl.hpp
vendored
Normal file
47
thirdparty/dtl/dtl/dtl.hpp
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
dtl -- Diff Template Library
|
||||
|
||||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DTL_H
|
||||
#define DTL_H
|
||||
|
||||
#include "variables.hpp"
|
||||
#include "functors.hpp"
|
||||
#include "Sequence.hpp"
|
||||
#include "Lcs.hpp"
|
||||
#include "Ses.hpp"
|
||||
#include "Diff.hpp"
|
||||
#include "Diff3.hpp"
|
||||
|
||||
#endif // DTL_H
|
137
thirdparty/dtl/dtl/functors.hpp
vendored
Normal file
137
thirdparty/dtl/dtl/functors.hpp
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
dtl -- Diff Template Library
|
||||
|
||||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* If you use this library, you must include dtl.hpp only. */
|
||||
|
||||
#ifndef DTL_FUNCTORS_H
|
||||
#define DTL_FUNCTORS_H
|
||||
|
||||
namespace dtl {
|
||||
|
||||
/**
|
||||
* printer class template
|
||||
*/
|
||||
template <typename sesElem, typename stream = ostream >
|
||||
class Printer
|
||||
{
|
||||
public :
|
||||
Printer () : out_(cout) {}
|
||||
Printer (stream& out) : out_(out) {}
|
||||
virtual ~Printer () {}
|
||||
virtual void operator() (const sesElem& se) const = 0;
|
||||
protected :
|
||||
stream& out_;
|
||||
};
|
||||
|
||||
/**
|
||||
* common element printer class template
|
||||
*/
|
||||
template <typename sesElem, typename stream = ostream >
|
||||
class CommonPrinter : public Printer < sesElem, stream >
|
||||
{
|
||||
public :
|
||||
CommonPrinter () : Printer < sesElem, stream > () {}
|
||||
CommonPrinter (stream& out) : Printer < sesElem, stream > (out) {}
|
||||
~CommonPrinter () {}
|
||||
void operator() (const sesElem& se) const {
|
||||
this->out_ << SES_MARK_COMMON << se.first << endl;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ses element printer class template
|
||||
*/
|
||||
template <typename sesElem, typename stream = ostream >
|
||||
class ChangePrinter : public Printer < sesElem, stream >
|
||||
{
|
||||
public :
|
||||
ChangePrinter () : Printer < sesElem, stream > () {}
|
||||
ChangePrinter (stream& out) : Printer < sesElem, stream > (out) {}
|
||||
~ChangePrinter () {}
|
||||
void operator() (const sesElem& se) const {
|
||||
switch (se.second.type) {
|
||||
case SES_ADD:
|
||||
this->out_ << SES_MARK_ADD << se.first << endl;
|
||||
break;
|
||||
case SES_DELETE:
|
||||
this->out_ << SES_MARK_DELETE << se.first << endl;
|
||||
break;
|
||||
case SES_COMMON:
|
||||
this->out_ << SES_MARK_COMMON << se.first << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* unified format element printer class template
|
||||
*/
|
||||
template <typename sesElem, typename stream = ostream >
|
||||
class UniHunkPrinter
|
||||
{
|
||||
public :
|
||||
UniHunkPrinter () : out_(cout) {}
|
||||
UniHunkPrinter (stream& out) : out_(out) {}
|
||||
~UniHunkPrinter () {}
|
||||
void operator() (const uniHunk< sesElem >& hunk) const {
|
||||
out_ << "@@"
|
||||
<< " -" << hunk.a << "," << hunk.b
|
||||
<< " +" << hunk.c << "," << hunk.d
|
||||
<< " @@" << endl;
|
||||
|
||||
for_each(hunk.common[0].begin(), hunk.common[0].end(), CommonPrinter< sesElem, stream >(out_));
|
||||
for_each(hunk.change.begin(), hunk.change.end(), ChangePrinter< sesElem, stream >(out_));
|
||||
for_each(hunk.common[1].begin(), hunk.common[1].end(), CommonPrinter< sesElem, stream >(out_));
|
||||
}
|
||||
private :
|
||||
stream& out_;
|
||||
};
|
||||
|
||||
/**
|
||||
* compare class template
|
||||
*/
|
||||
template <typename elem>
|
||||
class Compare
|
||||
{
|
||||
public :
|
||||
Compare () {}
|
||||
virtual ~Compare () {}
|
||||
virtual inline bool impl (const elem& e1, const elem& e2) const {
|
||||
return e1 == e2;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DTL_FUNCTORS_H
|
142
thirdparty/dtl/dtl/variables.hpp
vendored
Normal file
142
thirdparty/dtl/dtl/variables.hpp
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
dtl -- Diff Template Library
|
||||
|
||||
In short, Diff Template Library is distributed under so called "BSD license",
|
||||
|
||||
Copyright (c) 2015 Tatsuhiko Kubo <cubicdaiya@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* If you use this library, you must include dtl.hpp only. */
|
||||
|
||||
#ifndef DTL_VARIABLES_H
|
||||
#define DTL_VARIABLES_H
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace dtl {
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::pair;
|
||||
using std::ostream;
|
||||
using std::list;
|
||||
using std::for_each;
|
||||
using std::distance;
|
||||
using std::fill;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::rotate;
|
||||
using std::swap;
|
||||
using std::max;
|
||||
|
||||
/**
|
||||
* version string
|
||||
*/
|
||||
const string version = "1.19";
|
||||
|
||||
/**
|
||||
* type of edit for SES
|
||||
*/
|
||||
typedef int edit_t;
|
||||
const edit_t SES_DELETE = -1;
|
||||
const edit_t SES_COMMON = 0;
|
||||
const edit_t SES_ADD = 1;
|
||||
|
||||
/**
|
||||
* mark of SES
|
||||
*/
|
||||
#define SES_MARK_DELETE "-"
|
||||
#define SES_MARK_COMMON " "
|
||||
#define SES_MARK_ADD "+"
|
||||
|
||||
/**
|
||||
* info for Unified Format
|
||||
*/
|
||||
typedef struct eleminfo {
|
||||
long long beforeIdx; // index of prev sequence
|
||||
long long afterIdx; // index of after sequence
|
||||
edit_t type; // type of edit(Add, Delete, Common)
|
||||
bool operator==(const eleminfo& other) const{
|
||||
return (this->beforeIdx == other.beforeIdx && this->afterIdx == other.afterIdx && this->type == other.type);
|
||||
}
|
||||
} elemInfo;
|
||||
|
||||
const long long DTL_SEPARATE_SIZE = 3;
|
||||
const long long DTL_CONTEXT_SIZE = 3;
|
||||
|
||||
/**
|
||||
* cordinate for registering route
|
||||
*/
|
||||
typedef struct Point {
|
||||
long long x; // x cordinate
|
||||
long long y; // y cordinate
|
||||
long long k; // vertex
|
||||
} P;
|
||||
|
||||
/**
|
||||
* limit of cordinate size
|
||||
*/
|
||||
const unsigned long long MAX_CORDINATES_SIZE = 2000000;
|
||||
|
||||
typedef vector< long long > editPath;
|
||||
typedef vector< P > editPathCordinates;
|
||||
|
||||
/**
|
||||
* Structure of Unified Format Hunk
|
||||
*/
|
||||
template <typename sesElem>
|
||||
struct uniHunk {
|
||||
long long a, b, c, d; // @@ -a,b +c,d @@
|
||||
vector< sesElem > common[2]; // anteroposterior commons on changes
|
||||
vector< sesElem > change; // changes
|
||||
long long inc_dec_count; // count of increace and decrease
|
||||
};
|
||||
|
||||
#define dtl_typedefs(elem, sequence) \
|
||||
typedef pair< elem, elemInfo > sesElem; \
|
||||
typedef vector< sesElem > sesElemVec; \
|
||||
typedef vector< uniHunk< sesElem > > uniHunkVec; \
|
||||
typedef list< elem > elemList; \
|
||||
typedef vector< elem > elemVec; \
|
||||
typedef typename uniHunkVec::iterator uniHunkVec_iter; \
|
||||
typedef typename sesElemVec::iterator sesElemVec_iter; \
|
||||
typedef typename elemList::iterator elemList_iter; \
|
||||
typedef typename sequence::iterator sequence_iter; \
|
||||
typedef typename sequence::const_iterator sequence_const_iter; \
|
||||
typedef typename elemVec::iterator elemVec_iter;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // DTL_VARIABLES_H
|
Loading…
Reference in a new issue