Skip to content

Commit

Permalink
Single-function fallback decoder, eslint happyness
Browse files Browse the repository at this point in the history
  • Loading branch information
dcodeIO committed Nov 9, 2016
1 parent fdd8dce commit 45d3e73
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 96 deletions.
5 changes: 2 additions & 3 deletions scripts/bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ protobuf.load(__dirname + "/bench.proto", function(err, root) {
console.log();
}

var reader = protobuf.Reader(new Buffer(0)),
writer = protobuf.Writer();

function bench_protobuf_rw() {
var reader = protobuf.Reader(new Buffer(0)),
writer = protobuf.Writer();
var start = Date.now(),
len = 0;
for (var i = 0; i < times; ++i) {
Expand Down
2 changes: 1 addition & 1 deletion src/codegen.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function codegen(/* varargs */) {
* @type {boolean}
*/
codegen.supported = false;
try { codegen.supported = codegen("a","b")("return a-b").eof()(2,1) === 1; } catch (e) {} // eslint-disable-line no-empty
// try { codegen.supported = codegen("a","b")("return a-b").eof()(2,1) === 1; } catch (e) {} // eslint-disable-line no-empty

/**
* When set to true, codegen will log generated code to console. Useful for debugging.
Expand Down
25 changes: 0 additions & 25 deletions src/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,31 +305,6 @@ function encode_generate(field) {

Field.generateEncoder = encode_generate;

/**
* Decodes a field value.
* @param {Reader} reader Reader to decode from
* @param {number} receivedWireType Wire type received
* @returns {*} Field value
* @throws {Error} If the wire format is invalid
*/
FieldPrototype.decode = function decode_internal(reader, receivedWireType) {
var type = this.resolve().resolvedType instanceof Enum ? "uint32" : this.type;
if (this.repeated && this.packed && types.packableWireTypes[type] === receivedWireType) {
var limit = reader.uint32() + reader.pos,
values = [], i = 0;
while (reader.pos < limit)
values[i++] = reader[type]();
return values;
}
var value = receivedWireType === types.wireTypes[type]
? reader[type]()
: this.resolvedType.decodeDelimited_(reader, this.resolvedType._constructor // assumes wire type 2, throws if invalid
? new this.resolvedType._constructor()
: Object.create(this.resolvedType.prototype)
);
return this.repeated ? [ value ] : value;
};

/**
* Converts a field value to JSON using the specified options.
* @param {*} value Field value
Expand Down
32 changes: 0 additions & 32 deletions src/mapfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,35 +145,3 @@ function encode_generate(field) {
}

MapField.generateEncoder = encode_generate;

/**
* @override
*/
MapFieldPrototype.decode = function decode_setup(reader) {
var length = reader.uint32(), map = {};
if (length) {
length += reader.pos;

var keyType = this.resolve().resolvedKeyType /* only valid is enum */ ? "uint32" : this.keyType,
valueType = this.resolvedType instanceof Enum ? "uint32" : this.type,
valueWireType = types.wireTypes[valueType];

var keys = [], ki = 0, values = [], vi = 0;
while (reader.pos < length) {
var tag = reader.tag();
if (tag.id === 1)
keys[ki++] = reader[keyType]();
else if (tag.id === 2) {
if (valueWireType !== undefined)
values[vi++] = reader[valueType]();
else
values[vi++] = this.resolvedType.decodeDelimited_(reader); // throws if invalid
} else
throw Error("illegal wire format for " + this.fullName);
}
var key;
for (ki = 0; i < ki; ++ki)
map[typeof (key = keys[ki]) === 'object' ? util.toHash(key) : key] = values[ki];
}
return map;
}
16 changes: 8 additions & 8 deletions src/reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,26 +199,26 @@ ReaderPrototype.sfixed64 = function read_sfixed64() {
* @function
* @returns {number} Value read
*/
ReaderPrototype.float = (function read_float(ieee754_read) {
ReaderPrototype.float = function read_float() {
if (this.pos + 4 > this.len)
throw RangeError(indexOutOfRange(this, 4));
var value = ieee754_read(this.buf, this.pos, true, 23, 4);
var value = ieee754.read(this.buf, this.pos, true, 23, 4);
this.pos += 4;
return this;
}).bind(null, ieee754.read);
return value;
};

/**
* Reads a double (64 bit float) as a number.
* @function
* @returns {number} Value read
*/
ReaderPrototype.double = (function read_double(ieee754_read) {
ReaderPrototype.double = function read_double() {
if (this.pos + 8 > this.len)
throw RangeError(indexOutOfRange(this, 4));
var value = ieee754_read(this.buf, this.pos, true, 52, 8);
var value = ieee754.read(this.buf, this.pos, true, 52, 8);
this.pos += 8;
return this;
}).bind(null, ieee754.read);
return value;
};

/**
* Reads a sequence of bytes preceeded by its length as a varint.
Expand Down
2 changes: 2 additions & 0 deletions src/support/ieee754.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/
// ref: https://github.com/feross/ieee754

/* eslint-disable semi, no-extra-parens, no-empty */

exports.read = function (buffer, offset, isLE, mLen, nBytes) {
var e, m
var eLen = nBytes * 8 - mLen - 1
Expand Down
103 changes: 82 additions & 21 deletions src/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,40 +448,101 @@ TypePrototype.decode = function decode(readerOrBuffer, constructor, length) {
TypePrototype.decode_ = function decode_setup(reader, message, limit) {
this.decode_ = codegen.supported
? generateDecoder(this)
: decode_internal;
: decode_fallback;
return this.decode_(reader, message, limit);
};

// Codegen reference and fallback if code generation is not supported.
function decode_internal(reader, message, limit) {
/* eslint-disable no-invalid-this */
var values = message.$values,
fieldsById = this.fieldsById;
function decode_fallback(reader, message, limit) {
// NOTE: This intentionally performs as few checks as possible which SHOULD however still result
// in errors being thrown for invalid wire formats. If it doesn't throw, feel free to fill an
// issue.

/* eslint-disable no-invalid-this, block-scoped-var, no-redeclare */
var fieldsById = this.fieldsById;
while (reader.pos < limit) {
var tag = reader.tag(),
field = fieldsById[tag.id];
if (field /* known */) {
var name = field.name,
value = field.decode(reader, tag.wireType);
if (field.repeated)
Array.prototype.push.apply(values[name], value);
else
values[name] = value;
var tag = reader.tag(),
field = fieldsById[tag.id],
type = field.resolvedType instanceof Enum ? "uint32" : field.type,
wireType = types.wireTypes[type];

// Known fields
if (field) {

// Map fields
if (field.map) {

var keyType = field.resolve().resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType,
length = reader.uint32(),
map = {};
if (length) {
length += reader.pos;
var keys = [], values = [], ki = 0, vi = 0;
while (reader.pos < length) {
tag = reader.tag();
if (tag.id === 1)
keys[ki++] = reader[keyType]();
else if (tag.id === 2) {
if (wireType !== undefined)
values[vi++] = reader[type]();
else {
var resolvedType = field.resolvedType;
values[vi++] = resolvedType.decodeDelimited_(reader, resolvedType._constructor ? new resolvedType._constructor() : Object.create(resolvedType.prototype));
}
} else
throw Error('illegal wire format for ' + this);
}
var key;
for (ki = 0; ki < vi; ++ki)
map[typeof (key = keys[ki]) === 'object' ? util.toHash(key) : key] = values[ki];
}
message.$values[field.name] = map;

// Repeated fields
} else if (field.repeated) {

var values = message.$values[field.name],
length = values.length,
packType = types.packableWireTypes[type];

// Packed
if (field.packed && tag.wireType === packType) {
var plimit = reader.uint32() + reader.pos;
while (reader.pos < plimit)
values[length++] = reader[type]();

// Non-packed
} else if (wireType !== undefined) {
values[length++] = reader[type]();
} else {
var resolvedType = field.resolvedType;
values[length++] = resolvedType.decodeDelimited_(reader, resolvedType._constructor ? new resolvedType._constructor() : Object.create(resolvedType.prototype));
}

// Non-repeated
} else if (wireType !== undefined) {
message.$values[field.name] = reader[type]();
} else{
var resolvedType = field.resolvedType;
message.$values[field.name] = resolvedType.decodeDelimited_(reader, resolvedType._constructor ? new resolvedType._constructor() : Object.create(resolvedType.prototype));
}

// Unknown fields
} else
reader.skipType(tag.wireType);
}
return message;
/* eslint-enable no-invalid-this */
/* eslint-enable no-invalid-this, block-scoped-var, no-redeclare */
}

/**
* Generates a decoder specific to the specified message type.
* @memberof Type
* @param {Type} type Message type
* @param {Type} messageType Message type
* @returns {function} Decoder
*/
function generateDecoder(Type) {
var fieldsArray = Type.fieldsArray,
function generateDecoder(messageType) {
var fieldsArray = messageType.fieldsArray,
fieldsCount = fieldsArray.length;

var gen = codegen("$resolvedTypes", "$toHash", "reader", "message", "limit")
Expand All @@ -491,7 +552,7 @@ function generateDecoder(Type) {
("var tag = reader.tag();")
("switch (tag.id) {");

for (var i = 0, field; i < fieldsCount; ++i) {
for (var i = 0; i < fieldsCount; ++i) {
var field = fieldsArray[i].resolve(),
type = field.resolvedType instanceof Enum ? "uint32" : field.type,
wireType = types.wireTypes[type],
Expand Down Expand Up @@ -528,7 +589,7 @@ function generateDecoder(Type) {

} else if (field.repeated) { gen

("var values = message.$values[%j], length = values.length;", field.name)
("var values = message.$values[%j], length = values.length;", field.name);

if (field.packed && packType !== undefined) { gen

Expand Down Expand Up @@ -571,7 +632,7 @@ function generateDecoder(Type) {
("}")
("}")
("return message;");
return gen.eof(Type.fullName + "$decode").bind(Type, fieldsArray.map(function(field) { return field.resolvedType; }), util.toHash);
return gen.eof(messageType.fullName + "$decode").bind(messageType, fieldsArray.map(function(fld) { return fld.resolvedType; }), util.toHash);
}

Type.generateDecoder = generateDecoder;
Expand Down
12 changes: 6 additions & 6 deletions src/writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,27 +275,27 @@ WriterPrototype.sfixed64 = function write_sfixed64(value) {
* @param {number} value Value to write
* @returns {Writer} `this`
*/
WriterPrototype.float = (function write_float(ieee754_write, value) {
WriterPrototype.float = function write_float(value) {
if (this.pos + 4 > this.len)
expand(this, 4);
ieee754_write(this.buf, value, this.pos, true, 23, 4);
ieee754.write(this.buf, value, this.pos, true, 23, 4);
this.pos += 4;
return this;
}).bind(null, ieee754.write);
};

/**
* Writes a double (64 bit float).
* @function
* @param {number} value Value to write
* @returns {Writer} `this`
*/
WriterPrototype.double = (function write_double(ieee754_write, value) {
WriterPrototype.double = function write_double(value) {
if (this.pos + 8 > this.len)
expand(this, 8);
ieee754_write(this.buf, value, this.pos, true, 52, 8);
ieee754.write(this.buf, value, this.pos, true, 52, 8);
this.pos += 8;
return this;
}).bind(null, ieee754.write);
};

/**
* Writes a sequence of bytes.
Expand Down

0 comments on commit 45d3e73

Please sign in to comment.