Commit 4adb0c24 authored by Mike Bostock's avatar Mike Bostock
Browse files

Optimize interpolateString.

parent fa55eead
......@@ -5617,71 +5617,38 @@
}
d3.interpolateString = d3_interpolateString;
function d3_interpolateString(a, b) {
var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = [];
a = a + "", b = b + "";
d3_interpolate_number.lastIndex = 0;
for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
if (m.index) s.push(b.substring(s0, s1 = m.index));
q.push({
i: s.length,
x: m[0]
});
s.push(null);
s0 = d3_interpolate_number.lastIndex;
}
if (s0 < b.length) s.push(b.substring(s0));
for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
o = q[i];
if (o.x == m[0]) {
if (o.i) {
if (s[o.i + 1] == null) {
s[o.i - 1] += o.x;
s.splice(o.i, 1);
for (j = i + 1; j < n; ++j) q[j].i--;
} else {
s[o.i - 1] += o.x + s[o.i + 1];
s.splice(o.i, 2);
for (j = i + 1; j < n; ++j) q[j].i -= 2;
}
} else {
if (s[o.i + 1] == null) {
s[o.i] = o.x;
} else {
s[o.i] = o.x + s[o.i + 1];
s.splice(o.i + 1, 1);
for (j = i + 1; j < n; ++j) q[j].i--;
}
}
q.splice(i, 1);
n--;
i--;
} else {
o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) {
if ((bs = bm.index) > bi) {
bs = b.substring(bi, bs);
if (s[i]) s[i] += bs; else s[++i] = bs;
}
}
while (i < n) {
o = q.pop();
if (s[o.i + 1] == null) {
s[o.i] = o.x;
if ((am = +am[0]) === (bm = +(bs = bm[0]))) {
if (s[i]) s[i] += bs; else s[++i] = bs;
} else {
s[o.i] = o.x + s[o.i + 1];
s.splice(o.i + 1, 1);
s[++i] = null;
q.push({
i: i,
x: d3_interpolateNumber(am, bm)
});
}
n--;
bi = d3_interpolate_numberB.lastIndex;
}
if (s.length === 1) {
return s[0] == null ? (o = q[0].x, function(t) {
return o(t) + "";
}) : function() {
return b;
};
if (bi < b.length) {
bs = b.substring(bi);
if (s[i]) s[i] += bs; else s[++i] = bs;
}
return function(t) {
for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
return s.length < 2 ? q[0] ? (b = q[0].x, function(t) {
return b(t) + "";
}) : function() {
return b;
} : (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
};
});
}
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
d3.interpolate = d3_interpolate;
function d3_interpolate(a, b) {
var i = d3.interpolators.length, f;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,86 +3,52 @@ import "number";
d3.interpolateString = d3_interpolateString;
function d3_interpolateString(a, b) {
var m, // current match
i, // current index
j, // current index (for coalescing)
s0 = 0, // start index of current string prefix
s1 = 0, // end index of current string prefix
var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, // scan index for next number in b
am, // current match in a
bm, // current match in b
bs, // string preceding current number in b, if any
i = -1, // index in s
s = [], // string constants and placeholders
q = [], // number interpolators
n, // q.length
o;
q = []; // number interpolators
// Coerce inputs to strings.
a = a + "", b = b + "";
// Reset our regular expression!
d3_interpolate_number.lastIndex = 0;
// Find all numbers in b.
for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
if (m.index) s.push(b.substring(s0, s1 = m.index));
q.push({i: s.length, x: m[0]});
s.push(null);
s0 = d3_interpolate_number.lastIndex;
}
if (s0 < b.length) s.push(b.substring(s0));
// Find all numbers in a.
for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
o = q[i];
if (o.x == m[0]) { // The numbers match, so coalesce.
if (o.i) {
if (s[o.i + 1] == null) { // This match is followed by another number.
s[o.i - 1] += o.x;
s.splice(o.i, 1);
for (j = i + 1; j < n; ++j) q[j].i--;
} else { // This match is followed by a string, so coalesce twice.
s[o.i - 1] += o.x + s[o.i + 1];
s.splice(o.i, 2);
for (j = i + 1; j < n; ++j) q[j].i -= 2;
}
} else {
if (s[o.i + 1] == null) { // This match is followed by another number.
s[o.i] = o.x;
} else { // This match is followed by a string, so coalesce twice.
s[o.i] = o.x + s[o.i + 1];
s.splice(o.i + 1, 1);
for (j = i + 1; j < n; ++j) q[j].i--;
}
}
q.splice(i, 1);
n--;
i--;
} else {
o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
// Interpolate pairs of numbers in a & b.
while ((am = d3_interpolate_numberA.exec(a))
&& (bm = d3_interpolate_numberB.exec(b))) {
if ((bs = bm.index) > bi) { // a string precedes the next number in b
bs = b.substring(bi, bs);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
}
// Remove any numbers in b not found in a.
while (i < n) {
o = q.pop();
if (s[o.i + 1] == null) { // This match is followed by another number.
s[o.i] = o.x;
} else { // This match is followed by a string, so coalesce twice.
s[o.i] = o.x + s[o.i + 1];
s.splice(o.i + 1, 1);
if ((am = +am[0]) === (bm = +(bs = bm[0]))) { // coalesce matching numbers
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
} else { // interpolate non-matching numbers
s[++i] = null;
q.push({i: i, x: d3_interpolateNumber(am, bm)});
}
n--;
bi = d3_interpolate_numberB.lastIndex;
}
// Special optimization for only a single match.
if (s.length === 1) {
return s[0] == null
? (o = q[0].x, function(t) { return o(t) + ""; })
: function() { return b; };
// Add remains of b.
if (bi < b.length) {
bs = b.substring(bi);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
// Special optimization for only a single match.
// Otherwise, interpolate each of the numbers and rejoin the string.
return function(t) {
for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
};
return s.length < 2
? (q[0] ? (b = q[0].x, function(t) { return b(t) + ""; })
: function() { return b; })
: (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
});
}
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
......@@ -36,6 +36,15 @@ suite.addBatch({
assert.strictEqual(interpolate("-1.e-3", "-1.e-4")(.5), "-0.00055");
assert.strictEqual(interpolate("+1.e-3", "+1.e-4")(.5), "0.00055");
assert.strictEqual(interpolate(".1e-2", ".1e-3")(.5), "0.00055");
},
"with no numbers, returns the target string": function(interpolate) {
assert.strictEqual(interpolate("foo", "bar")(.5), "bar");
assert.strictEqual(interpolate("foo", "")(.5), "");
assert.strictEqual(interpolate("", "bar")(.5), "bar");
assert.strictEqual(interpolate("", "")(.5), "");
},
"with two numerically-equivalent numbers, returns the target format": function(interpolate) {
assert.strictEqual(interpolate("top: 1000px;", "top: 1e3px;")(.5), "top: 1e3px;");
}
}
});
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment