Skip to content

Commit 2358fd0

Browse files
committed
Optimize d3_dsv.
Replace regular expression search with a simple if-else. Replace a for-loop with a new Function to convert rows to objects, such that each row is defined in a single step as an object literal rather than lazily defining properties on a blank object. Note that parseRows can still be substantially faster for large files provided you convert strings to smaller types (e.g., numbers or booleans); greedy type-conversion reduces peak memory usage and accelerates garbage collection.
1 parent 2356206 commit 2358fd0

3 files changed

Lines changed: 50 additions & 58 deletions

File tree

d3.js

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,56 +1844,50 @@
18441844
function formatValue(text) {
18451845
return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
18461846
}
1847-
var reParse = new RegExp("\r\n|[" + delimiter + "\r\n]", "g"), reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
1847+
var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
18481848
dsv.parse = function(text) {
1849-
var header;
1850-
return dsv.parseRows(text, function(row, i) {
1851-
if (i) {
1852-
var o = {}, j = -1, m = header.length;
1853-
while (++j < m) o[header[j]] = row[j];
1854-
return o;
1855-
} else {
1856-
header = row;
1857-
return null;
1858-
}
1849+
var o;
1850+
return dsv.parseRows(text, function(row) {
1851+
if (o) return o(row);
1852+
o = new Function("d", "return {" + row.map(function(name, i) {
1853+
return JSON.stringify(name) + ": d[" + i + "]";
1854+
}).join(",") + "}");
18591855
});
18601856
};
18611857
dsv.parseRows = function(text, f) {
18621858
function token() {
1863-
if (reParse.lastIndex >= text.length) return EOF;
1864-
if (eol) {
1865-
eol = false;
1866-
return EOL;
1867-
}
1868-
var j = reParse.lastIndex;
1859+
if (I >= N) return EOF;
1860+
if (eol) return eol = false, EOL;
1861+
var j = I;
18691862
if (text.charCodeAt(j) === 34) {
18701863
var i = j;
1871-
while (i++ < text.length) {
1864+
while (i++ < N) {
18721865
if (text.charCodeAt(i) === 34) {
18731866
if (text.charCodeAt(i + 1) !== 34) break;
1874-
i++;
1867+
++i;
18751868
}
18761869
}
1877-
reParse.lastIndex = i + 2;
1870+
I = i + 2;
18781871
var c = text.charCodeAt(i + 1);
18791872
if (c === 13) {
18801873
eol = true;
1881-
if (text.charCodeAt(i + 2) === 10) reParse.lastIndex++;
1874+
if (text.charCodeAt(i + 2) === 10) ++I;
18821875
} else if (c === 10) {
18831876
eol = true;
18841877
}
18851878
return text.substring(j + 1, i).replace(/""/g, '"');
18861879
}
1887-
var m = reParse.exec(text);
1888-
if (m) {
1889-
eol = m[0].charCodeAt(0) !== delimiterCode;
1890-
return text.substring(j, m.index);
1880+
while (I < N) {
1881+
var c = text.charCodeAt(I++), k = 1;
1882+
if (c === 10) eol = true; else if (c === 13) {
1883+
eol = true;
1884+
if (text.charCodeAt(I) === 10) ++I, ++k;
1885+
} else if (c !== delimiterCode) continue;
1886+
return text.substring(j, I - k);
18911887
}
1892-
reParse.lastIndex = text.length;
18931888
return text.substring(j);
18941889
}
1895-
var EOL = {}, EOF = {}, rows = [], n = 0, t, eol;
1896-
reParse.lastIndex = 0;
1890+
var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
18971891
while ((t = token()) !== EOF) {
18981892
var a = [];
18991893
while (t !== EOL && t !== EOF) {

0 commit comments

Comments
 (0)