Skip to content

Instantly share code, notes, and snippets.

@papandreou
Created February 17, 2012 22:49
Show Gist options
  • Save papandreou/1855943 to your computer and use it in GitHub Desktop.
Save papandreou/1855943 to your computer and use it in GitHub Desktop.
Benchmark of different ways of matching /@(-(?:[a-z]+-)+)?keyframes/ against a specific position in a string
var testCases = [
{
input: new Array(4001).join('0123456789') + '@-webkit-keyframes {}' + new Array(4096).join('0123456789'),
idx: 40000
},
{
input: new Array(4001).join('0123456789') + '@keyframes {}' + new Array(4096).join('0123456789'),
idx: 40000
},
{
input: new Array(4001).join('0123456789') + '@invalid' + new Array(4001).join('0123456789') + '@keyframes{}',
idx: 40000
}
];
var atKeyframesRegExp = /@(-(?:[a-z]+-)+)?keyframes/g,
atKeyframesAtStartRegExp = /^@(-(?:[a-z]+-)+)?keyframes/;
exports.compare = {
'lastIndex + regExp.exec()': function () {
testCases.forEach(function (testCase) {
atKeyframesRegExp.lastIndex = testCase.idx;
var matchKeyframes = atKeyframesRegExp.exec(testCase.input);
if (matchKeyframes && matchKeyframes.index === testCase.idx) {
// Match! vendorPrefix === matchKeyframes[1]
}
});
},
'substring().match()': function () {
testCases.forEach(function (testCase) {
var matchKeyframes = atKeyframesAtStartRegExp.exec(testCase.input.substring(testCase.idx));
if (matchKeyframes) {
// Match! vendorPrefix = matchKeyframes[1]
}
});
},
'low-level string gymnastics': function () {
testCases.forEach(function (testCase) {
var input = testCase.input;
if (input.substring(testCase.idx, testCase.idx + '@keyframes'.length) === '@keyframes') {
// Match! vendorPrefix = undefined
} else {
var j = testCase.idx + 1,
state = 0,
accept = false;
OUTER: while (j < testCase.input.length) {
var ch = input[j];
switch (state) {
case 0:
if (ch === '-') {
state = 1;
break;
} else {
break OUTER;
}
case 1:
if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 2:
if (ch >= 'a' && ch <= 'z') {
// Stay in state 2
break;
} else if (ch === '-') {
state = 3;
break;
} else {
break OUTER;
}
case 3:
if (ch === 'k') {
state = 4;
break;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 4:
if (ch === 'e') {
state = 5;
break;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 5:
if (ch === 'y') {
state = 6;
break;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 6:
if (ch === 'f') {
state = 7;
break;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 7:
if (ch === 'r') {
state = 8;
break;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 8:
if (ch === 'a') {
state = 9;
break;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 9:
if (ch === 'm') {
state = 10;
break;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 10:
if (ch === 'e') {
state = 11;
break;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
case 11:
if (ch === 's') {
accept = true;
break OUTER;
} else if (ch >= 'a' && ch <= 'z') {
state = 2;
break;
} else {
break OUTER;
}
}
j += 1;
}
var vendorPrefix;
if (accept) {
// Match! vendorPrefix = testCase.input.substring(testCase.idx + 1, 1 + j - 'keyframes'.length);
}
}
});
}
};
require('bench').runMain();
benchmarking /home/andreas/work/gist-1855943/bench.js
Please be patient.
{ node: '0.4.13-pre',
v8: '3.1.8.27',
ares: '1.7.4',
ev: '4.4',
openssl: '0.9.8o' }
Scores: (bigger is better)
low-level string gymnastics
Raw:
> 998.001998001998
> 989.010989010989
> 1013.986013986014
> 999.000999000999
> 1025.974025974026
Average (mean) 1005.1948051948053
substring().match()
Raw:
> 41.62537165510406
> 40.553907022749755
> 40.75546719681908
> 42.03323558162268
> 40.0390625
Average (mean) 41.00140879125912
lastIndex + regExp.exec()
Raw:
> 22.30843840931135
> 22.660098522167488
> 22.660098522167488
> 22.22222222222222
> 22.373540856031127
Average (mean) 22.444879706379936
Winner: low-level string gymnastics
Compared with next highest (substring().match()), it's:
95.92% faster
24.52 times as fast
1.39 order(s) of magnitude faster
Compared with the slowest (lastIndex + regExp.exec()), it's:
97.77% faster
44.79 times as fast
1.65 order(s) of magnitude faster
benchmarking /home/andreas/work/gist-1855943/bench.js
Please be patient.
{ node: '0.4.13-pre',
v8: '3.1.8.27',
ares: '1.7.4',
ev: '4.4',
openssl: '0.9.8o' }
Scores: (bigger is better)
lastIndex + regExp.exec()
Raw:
> 2060.939060939061
> 1980.01998001998
> 1966.033966033966
> 1926.073926073926
> 2102.8971028971027
Average (mean) 2007.1928071928073
low-level string gymnastics
Raw:
> 1171.828171828172
> 1167.832167832168
> 1195.8041958041958
> 1219.7802197802198
> 1170.8291708291708
Average (mean) 1185.2147852147853
substring().match()
Raw:
> 55.50049554013875
> 55.61072492552135
> 54.509415262636274
> 54.78087649402391
> 54.40158259149357
Average (mean) 54.96061896276277
Winner: lastIndex + regExp.exec()
Compared with next highest (low-level string gymnastics), it's:
40.95% faster
1.69 times as fast
0.23 order(s) of magnitude faster
Compared with the slowest (substring().match()), it's:
97.26% faster
36.52 times as fast
1.56 order(s) of magnitude faster
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment