mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-11 09:31:01 +01:00
import original version of https://github.com/Swatinem/diff
This commit is contained in:
parent
dd979ff5ff
commit
2aa704651d
2 changed files with 207 additions and 0 deletions
34
src/lib/diff/README.md
Normal file
34
src/lib/diff/README.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# diff
|
||||||
|
|
||||||
|
implementation of myers diff algorithm
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/Swatinem/diff.png?branch=master)](https://travis-ci.org/Swatinem/diff)
|
||||||
|
[![Coverage Status](https://coveralls.io/repos/Swatinem/diff/badge.png?branch=master)](https://coveralls.io/r/Swatinem/diff)
|
||||||
|
[![Dependency Status](https://gemnasium.com/Swatinem/diff.png)](https://gemnasium.com/Swatinem/diff)
|
||||||
|
|
||||||
|
|
||||||
|
This uses the [*An O(ND) Difference Algorithm and Its Variations*](http://www.xmailserver.org/diff2.pdf)
|
||||||
|
Also see http://simplygenius.net/Article/DiffTutorial2 and
|
||||||
|
http://www.mathertel.de/Diff/ViewSrc.aspx for more inspiration
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
$ npm install diff
|
||||||
|
$ component install Swatinem/diff
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### diff(a, b, [eql(a, b)])
|
||||||
|
|
||||||
|
Given two arrays (or array-likes, such as strings) `a` and `b` and an optional
|
||||||
|
equal function `eql`, this will return an array with the following operations:
|
||||||
|
* *nop* the element is in both arrays
|
||||||
|
* *ins* the element is only in array `b` and will be inserted
|
||||||
|
* *del* the element in only in array `a` and will be removed
|
||||||
|
* *rep* the element from `a` will be replaced by the element from `b`.
|
||||||
|
This is essentially the same as a del+ins
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
LGPLv3
|
||||||
|
|
173
src/lib/diff/swatinem_diff.js
Normal file
173
src/lib/diff/swatinem_diff.js
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/* vim: set shiftwidth=2 tabstop=2 noexpandtab textwidth=80 wrap : */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = diff;
|
||||||
|
|
||||||
|
function diff(a, b, eql) {
|
||||||
|
if (!eql)
|
||||||
|
eql = function (a, b) { return a === b; };
|
||||||
|
|
||||||
|
var d = new Diff(a, b, eql);
|
||||||
|
return d.editscript();
|
||||||
|
}
|
||||||
|
|
||||||
|
diff.Diff = Diff;
|
||||||
|
|
||||||
|
function Diff(a, b, eql) {
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
this.eql = eql;
|
||||||
|
|
||||||
|
this.moda = Array.apply(null, new Array(a.length)).map(true.valueOf, false);
|
||||||
|
this.modb = Array.apply(null, new Array(b.length)).map(true.valueOf, false);
|
||||||
|
|
||||||
|
// just to save some allocations:
|
||||||
|
this.down = {};
|
||||||
|
this.up = {};
|
||||||
|
|
||||||
|
this.lcs(0, a.length, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Diff.NOOP = 'nop';
|
||||||
|
Diff.DELETE = 'del';
|
||||||
|
Diff.INSERT = 'ins';
|
||||||
|
Diff.REPLACE = 'rep';
|
||||||
|
|
||||||
|
Diff.prototype.editscript = function Diff_editscript() {
|
||||||
|
var moda = this.moda, modb = this.modb;
|
||||||
|
var astart = 0, aend = moda.length;
|
||||||
|
var bstart = 0, bend = modb.length;
|
||||||
|
var result = [];
|
||||||
|
while (astart < aend || bstart < bend) {
|
||||||
|
if (astart < aend && bstart < bend) {
|
||||||
|
if (!moda[astart] && !modb[bstart]) {
|
||||||
|
result.push(Diff.NOOP);
|
||||||
|
astart++; bstart++;
|
||||||
|
continue;
|
||||||
|
} else if (moda[astart] && modb[bstart]) {
|
||||||
|
result.push(Diff.REPLACE);
|
||||||
|
astart++; bstart++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (astart < aend && (bstart >= bend || moda[astart])) {
|
||||||
|
result.push(Diff.DELETE);
|
||||||
|
astart++;
|
||||||
|
}
|
||||||
|
if (bstart < bend && (astart >= aend || modb[bstart])) {
|
||||||
|
result.push(Diff.INSERT);
|
||||||
|
bstart++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
Diff.prototype.lcs = function Diff_lcs(astart, aend, bstart, bend) {
|
||||||
|
var a = this.a, b = this.b, eql = this.eql;
|
||||||
|
// separate common head
|
||||||
|
while (astart < aend && bstart < bend && eql(a[astart], b[bstart])) {
|
||||||
|
astart++; bstart++;
|
||||||
|
}
|
||||||
|
// separate common tail
|
||||||
|
while (astart < aend && bstart < bend && eql(a[aend - 1], b[bend - 1])) {
|
||||||
|
aend--; bend--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (astart === aend) {
|
||||||
|
// only insertions
|
||||||
|
while (bstart < bend) {
|
||||||
|
this.modb[bstart] = true;
|
||||||
|
bstart++;
|
||||||
|
}
|
||||||
|
} else if (bend === bstart) {
|
||||||
|
// only deletions
|
||||||
|
while (astart < aend) {
|
||||||
|
this.moda[astart] = true;
|
||||||
|
astart++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var snake = this.snake(astart, aend, bstart, bend);
|
||||||
|
|
||||||
|
this.lcs(astart, snake.x, bstart, snake.y);
|
||||||
|
this.lcs(snake.u, aend, snake.v, bend);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Diff.prototype.snake = function Diff_snake(astart, aend, bstart, bend) {
|
||||||
|
var a = this.a, b = this.b, eql = this.eql;
|
||||||
|
|
||||||
|
var N = aend - astart,
|
||||||
|
M = bend - bstart;
|
||||||
|
|
||||||
|
var kdown = astart - bstart;
|
||||||
|
var kup = aend - bend;
|
||||||
|
|
||||||
|
var delta = N - M;
|
||||||
|
var deltaOdd = delta & 1;
|
||||||
|
|
||||||
|
var down = this.down;
|
||||||
|
down[kdown + 1] = astart;
|
||||||
|
var up = this.up;
|
||||||
|
up[kup - 1] = aend;
|
||||||
|
|
||||||
|
var Dmax = (N + M + 1) / 2;
|
||||||
|
for (var D = 0; D <= Dmax; D++) {
|
||||||
|
var k, x, y;
|
||||||
|
// forward path
|
||||||
|
for (k = kdown - D; k <= kdown + D; k += 2) {
|
||||||
|
if (k === kdown - D) {
|
||||||
|
x = down[k + 1]; // down
|
||||||
|
} else {
|
||||||
|
x = down[k - 1] + 1; // right
|
||||||
|
if ((k < kdown + D) && (down[k + 1] >= x)) {
|
||||||
|
x = down[k + 1]; // down
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y = x - k;
|
||||||
|
|
||||||
|
while (x < aend && y < bend && eql(a[x], b[y])) {
|
||||||
|
x++; y++; // diagonal
|
||||||
|
}
|
||||||
|
down[k] = x;
|
||||||
|
|
||||||
|
if (deltaOdd && (kup - D < k) && (k < kup + D) &&
|
||||||
|
up[k] <= down[k]) {
|
||||||
|
return {
|
||||||
|
x: down[k],
|
||||||
|
y: down[k] - k,
|
||||||
|
u: up[k],
|
||||||
|
v: up[k] - k,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse path
|
||||||
|
for (k = kup - D; k <= kup + D; k += 2) {
|
||||||
|
if (k === kup + D) {
|
||||||
|
x = up[k - 1]; // up
|
||||||
|
} else {
|
||||||
|
x = up[k + 1] - 1; // left
|
||||||
|
if ((k > kup - D) && (up[k - 1] < x)) {
|
||||||
|
x = up[k - 1]; // up
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y = x - k;
|
||||||
|
|
||||||
|
while (x > astart && y > bstart && eql(a[x - 1], b[y - 1])) {
|
||||||
|
x--; y--; // diagonal
|
||||||
|
}
|
||||||
|
up[k] = x;
|
||||||
|
|
||||||
|
if (!deltaOdd && (kdown - D <= k) && (k <= kdown + D) &&
|
||||||
|
up[k] <= down[k]) {
|
||||||
|
return {
|
||||||
|
x: down[k],
|
||||||
|
y: down[k] - k,
|
||||||
|
u: up[k],
|
||||||
|
v: up[k] - k,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue