Skip to content

Commit 1a974c6

Browse files
author
Ruben Bridgewater
committed
Further optimizations
Don't use `continue` Make sure the returned strings are always proper utf8 values Make sure the jit knows has as much information as possible Don't return a bulk string before `\n` is present Improve hiredis warnings
1 parent b245cd6 commit 1a974c6

File tree

2 files changed

+30
-26
lines changed

2 files changed

+30
-26
lines changed

lib/parser.js

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
var ReplyError = require('./replyError')
44

55
/**
6-
* Used for lengths only, faster perf on arrays / bulks
6+
* Used for lengths and numbers only, faster perf on arrays / bulks
7+
* Don't use this for strings, as fromCharCode returns utf-16 and breaks utf-8 compatibility
78
* @param parser
89
* @returns {*}
910
*/
@@ -14,14 +15,9 @@ function parseSimpleString (parser) {
1415

1516
while (offset < length) {
1617
var c1 = parser.buffer[offset++]
17-
if (c1 === 13) {
18-
var c2 = parser.buffer[offset++]
19-
if (c2 === 10) {
20-
parser.offset = offset
21-
return string
22-
}
23-
string += String.fromCharCode(c1) + String.fromCharCode(c2)
24-
continue
18+
if (c1 === 13 && parser.buffer[offset] === 10) { // \r\n
19+
parser.offset = offset + 1
20+
return string
2521
}
2622
string += String.fromCharCode(c1)
2723
}
@@ -57,7 +53,7 @@ function parseSimpleStringViaOffset (parser) {
5753

5854
while (offset < length) {
5955
var c1 = parser.buffer[offset++]
60-
if (c1 === 13) { // \r // Finding a \r is sufficient here, since in a simple string \r is always followed by \n
56+
if (c1 === 13 && parser.buffer[offset] === 10) { // \r\n
6157
parser.offset = offset + 1
6258
return convertBufferRange(parser, start, offset - 1)
6359
}
@@ -72,11 +68,7 @@ function parseSimpleStringViaOffset (parser) {
7268
function parseLength (parser) {
7369
var string = parseSimpleString(parser)
7470
if (string !== undefined) {
75-
var length = +string
76-
if (length === -1) {
77-
return null
78-
}
79-
return length
71+
return +string
8072
}
8173
}
8274

@@ -105,8 +97,11 @@ function parseInteger (parser) {
10597
*/
10698
function parseBulkString (parser) {
10799
var length = parseLength(parser)
108-
if (length === null || length === undefined) {
109-
return length
100+
if (length === undefined) {
101+
return
102+
}
103+
if (length === -1) {
104+
return null
110105
}
111106
var offsetEnd = parser.offset + length
112107
if (offsetEnd + 2 > parser.buffer.length) {
@@ -128,9 +123,9 @@ function parseBulkString (parser) {
128123
* @returns {Error}
129124
*/
130125
function parseError (parser) {
131-
var str = parseSimpleString(parser)
132-
if (str !== undefined) {
133-
return new ReplyError(str)
126+
var string = parseSimpleStringViaOffset(parser)
127+
if (string !== undefined) {
128+
return new ReplyError(string)
134129
}
135130
}
136131

@@ -151,8 +146,11 @@ function handleError (parser, error) {
151146
*/
152147
function parseArray (parser) {
153148
var length = parseLength(parser)
154-
if (length === null || length === undefined) {
155-
return length
149+
if (length === undefined) {
150+
return
151+
}
152+
if (length === -1) {
153+
return null
156154
}
157155

158156
var responses = new Array(length)
@@ -185,7 +183,7 @@ function parseType (parser, type) {
185183
case 58: // :
186184
return parseInteger(parser)
187185
case 43: // +
188-
return parser.optionReturnBuffers ? parseSimpleStringViaOffset(parser) : parseSimpleString(parser)
186+
return parseSimpleStringViaOffset(parser)
189187
case 42: // *
190188
return parseArray(parser)
191189
case 45: // -
@@ -214,9 +212,11 @@ function JavascriptRedisParser (options) {
214212
if (options.name === 'hiredis') {
215213
try {
216214
var Hiredis = require('../test/hiredis')
217-
console.error(new TypeError('Using the hiredis parser is discouraged. Please remove the name option.').stack)
215+
console.error(new TypeError('Using the hiredis parser is discouraged. Please remove the name option.').stack.replace('Error', 'Warning'))
218216
return new Hiredis(options)
219-
} catch (e) {}
217+
} catch (e) {
218+
console.error(new TypeError('Hiredis is not installed. Please remove the `name` option. The (faster) JS parser is used instead.').stack.replace('Error', 'Warning'))
219+
}
220220
}
221221
this.optionReturnBuffers = !!options.returnBuffers
222222
this.optionStringNumbers = !!options.stringNumbers

test/parsers.spec.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ describe('parsers', function () {
149149
it('should handle \\r and \\n characters properly', function () {
150150
// If a string contains \r or \n characters it will always be send as a bulk string
151151
var replyCount = 0
152-
var entries = ['foo\r', 'foo\r\nbar', '\r\nfoo', 'foo\r\n']
152+
var entries = ['foo\r', 'foo\r\nbar', '\r\nfoo', 'foo\r\n', 'foo']
153153
function checkReply (reply) {
154154
assert.strictEqual(reply, entries[replyCount])
155155
replyCount++
@@ -164,6 +164,10 @@ describe('parsers', function () {
164164
assert.strictEqual(replyCount, 2)
165165
parser.execute(new Buffer('foo\r\n$5\r\nfoo\r\n\r\n'))
166166
assert.strictEqual(replyCount, 4)
167+
parser.execute(new Buffer('+foo\r'))
168+
assert.strictEqual(replyCount, 4)
169+
parser.execute(new Buffer('\n'))
170+
assert.strictEqual(replyCount, 5)
167171
})
168172

169173
it('line breaks in the beginning of the last chunk', function () {

0 commit comments

Comments
 (0)