From f88dad098282ece65f5d6e224ca38305a8431829 Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Fri, 7 Apr 2017 19:38:18 +0200 Subject: [PATCH] Other: Revamped benchmark, now also covers Google's JS implementation --- README.md | 73 ++- bench/alloc.js | 47 -- bench/{ => data}/bench.json | 0 bench/{ => data}/bench.proto | 0 bench/data/static_jspb.js | 881 +++++++++++++++++++++++++++++++ bench/data/static_pbjs.js | 974 +++++++++++++++++++++++++++++++++++ bench/fromJSON.js | 15 - bench/index.html | 90 ---- bench/index.js | 166 +++--- bench/prof.js | 4 +- bench/read.js | 132 ----- bench/suite.js | 15 +- bench/write.js | 196 ------- config/eslint.json | 3 +- package.json | 1 + scripts/gentests.js | 6 +- tests/other_bench.js | 8 +- 17 files changed, 1981 insertions(+), 630 deletions(-) delete mode 100644 bench/alloc.js rename bench/{ => data}/bench.json (100%) rename bench/{ => data}/bench.proto (100%) create mode 100644 bench/data/static_jspb.js create mode 100644 bench/data/static_pbjs.js delete mode 100644 bench/fromJSON.js delete mode 100644 bench/index.html delete mode 100644 bench/read.js delete mode 100644 bench/write.js diff --git a/README.md b/README.md index 9979f9f0d..a86fb565d 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ In a nutshell, the wire format writer understands the following types: | Field type | Expected JS type (create, encode) | Conversion (fromObject) |------------|-----------------------------------|------------------------ -| s-/u-/int32
s-/fixed32 | `number` (32 bit integer) | `value | 0` if signed
`value >>> 0` if unsigned +| s-/u-/int32
s-/fixed32 | `number` (32 bit integer) | `value | 0` if signed
`value >>> 0` if unsigned | s-/u-/int64
s-/fixed64 | `Long`-like (optimal)
`number` (53 bit integer) | `Long.fromValue(value)` with long.js
`parseInt(value, 10)` otherwise | float
double | `number` | `Number(value)` | bool | `boolean` | `Boolean(value)` @@ -695,61 +695,52 @@ Additional documentation Performance ----------- -The package includes a benchmark that tries to compare performance to native JSON as far as this is possible. On an i7-2600K running node 6.9.1 it yields: +The package includes a benchmark that compares protobuf.js performance to native JSON (as far as this is possible) and [Google's JS implementation](https://github.com/google/protobuf/tree/master/js). On an i7-2600K running node 6.9.1 it yields: ``` benchmarking encoding performance ... -Type.encode to buffer x 547,361 ops/sec ±0.27% (94 runs sampled) -JSON.stringify to string x 310,848 ops/sec ±0.73% (92 runs sampled) -JSON.stringify to buffer x 173,608 ops/sec ±1.51% (86 runs sampled) +protobuf.js (reflect) x 547,366 ops/sec ±1.29% (90 runs sampled) +protobuf.js (static) x 525,722 ops/sec ±1.17% (91 runs sampled) +JSON (string) x 311,180 ops/sec ±0.67% (93 runs sampled) +JSON (buffer) x 183,724 ops/sec ±0.69% (92 runs sampled) +google-protobuf x 76,337 ops/sec ±0.73% (91 runs sampled) - Type.encode to buffer was fastest - JSON.stringify to string was 43.5% slower - JSON.stringify to buffer was 68.7% slower + protobuf.js (reflect) was fastest + protobuf.js (static) was 3.8% slower + JSON (string) was 42.8% slower + JSON (buffer) was 66.2% slower + google-protobuf was 86.0% slower benchmarking decoding performance ... -Type.decode from buffer x 1,294,378 ops/sec ±0.86% (90 runs sampled) -JSON.parse from string x 291,944 ops/sec ±0.72% (92 runs sampled) -JSON.parse from buffer x 256,325 ops/sec ±1.50% (90 runs sampled) +protobuf.js (reflect) x 1,401,958 ops/sec ±0.78% (93 runs sampled) +protobuf.js (static) x 1,391,017 ops/sec ±0.78% (90 runs sampled) +JSON (string) x 301,749 ops/sec ±0.88% (93 runs sampled) +JSON (buffer) x 268,792 ops/sec ±0.84% (90 runs sampled) +google-protobuf x 186,727 ops/sec ±0.81% (90 runs sampled) - Type.decode from buffer was fastest - JSON.parse from string was 77.4% slower - JSON.parse from buffer was 80.3% slower + protobuf.js (reflect) was fastest + protobuf.js (static) was 0.8% slower + JSON (string) was 78.5% slower + JSON (buffer) was 80.8% slower + google-protobuf was 86.7% slower benchmarking combined performance ... -Type to/from buffer x 254,126 ops/sec ±1.13% (91 runs sampled) -JSON to/from string x 122,896 ops/sec ±1.29% (90 runs sampled) -JSON to/from buffer x 88,005 ops/sec ±0.87% (89 runs sampled) +protobuf.js (reflect) x 274,685 ops/sec ±0.99% (89 runs sampled) +protobuf.js (static) x 278,352 ops/sec ±1.00% (90 runs sampled) +JSON (string) x 129,638 ops/sec ±0.83% (91 runs sampled) +JSON (buffer) x 90,904 ops/sec ±0.93% (87 runs sampled) +google-protobuf x 43,327 ops/sec ±0.89% (90 runs sampled) - Type to/from buffer was fastest - JSON to/from string was 51.7% slower - JSON to/from buffer was 65.3% slower - -benchmarking verifying performance ... - -Type.verify x 6,246,765 ops/sec ±2.00% (87 runs sampled) - -benchmarking message from object performance ... - -Type.fromObject x 2,892,973 ops/sec ±0.70% (92 runs sampled) - -benchmarking message to object performance ... - -Type.toObject x 3,601,738 ops/sec ±0.72% (93 runs sampled) + protobuf.js (static) was fastest + protobuf.js (reflect) was 1.3% slower + JSON (string) was 53.3% slower + JSON (buffer) was 67.3% slower + google-protobuf was 84.4% slower ``` -Note that JSON is a native binding nowadays and as such is about as fast as it possibly can get. So, how can protobuf.js be faster? - -* The benchmark is [somewhat flawed](https://github.com/dcodeIO/protobuf.js/blob/master/bench/index.js). -* Reader and writer interfaces configure themselves according to the environment to eliminate redundant conditionals. -* Node-specific reader and writer subclasses benefit from node's buffer binding. -* Reflection has built-in code generation that builds type-specific encoders, decoders and verifiers at runtime. -* Encoders and decoders do not implicitly call `verify` on messages to avoid unnecessary overhead where messages are already known to be valid. It's up to the user to call `verify` where necessary. -* Quite a bit of V8-specific profiling is accountable for everything else. - You can also run [the benchmark](https://github.com/dcodeIO/protobuf.js/blob/master/bench/index.js) ... ``` diff --git a/bench/alloc.js b/bench/alloc.js deleted file mode 100644 index 7dab2e9e8..000000000 --- a/bench/alloc.js +++ /dev/null @@ -1,47 +0,0 @@ -/*eslint-disable no-new*//*global ArrayBuffer*/ -"use strict"; - -var newSuite = require("./suite"), - protobuf = require(".."); - -var poolAlloc = protobuf.util.pool(function(size) { - return new Uint8Array(size); -}, Uint8Array.prototype.subarray); - -[ - 64, - 256, - 1024 -] -.forEach(function(size) { - - newSuite("buffer[" + size + "]") - .add("new Uint8Array", function() { - new Uint8Array(size); - }) - .add("Buffer.alloc", function() { - Buffer.alloc(size); - }) - .add("poolAlloc", function() { - poolAlloc(size); - }) - .add("Buffer.allocUnsafe", function() { - Buffer.allocUnsafe(size); - }) - .add("new Buffer", function() { - new Buffer(size); - }) - .run(); - - var ab = new ArrayBuffer(size); - - newSuite("wrap[" + size + "]") - .add("new Uint8Array(ArrayBuffer)", function() { - new Uint8Array(ab); - }) - .add("Buffer.from(ArrayBuffer)", function() { - Buffer.from(ab); - }) - .run(); - -}); diff --git a/bench/bench.json b/bench/data/bench.json similarity index 100% rename from bench/bench.json rename to bench/data/bench.json diff --git a/bench/bench.proto b/bench/data/bench.proto similarity index 100% rename from bench/bench.proto rename to bench/data/bench.proto diff --git a/bench/data/static_jspb.js b/bench/data/static_jspb.js new file mode 100644 index 000000000..46cb72668 --- /dev/null +++ b/bench/data/static_jspb.js @@ -0,0 +1,881 @@ +/*eslint-disable*/ +/** + * @fileoverview + * @enhanceable + * @public + */ +// GENERATED CODE -- DO NOT EDIT! + +var jspb = require('google-protobuf'); +var goog = jspb; +var global = Function('return this')(); + +goog.exportSymbol('proto.Outer', null, global); +goog.exportSymbol('proto.Test', null, global); +goog.exportSymbol('proto.Test.Enum', null, global); +goog.exportSymbol('proto.Test.Inner', null, global); +goog.exportSymbol('proto.Test.Inner.InnerInner', null, global); + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.Test = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.Test, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.Test.displayName = 'proto.Test'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.Test.prototype.toObject = function(opt_includeInstance) { + return proto.Test.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.Test} msg The msg instance to transform. + * @return {!Object} + */ +proto.Test.toObject = function(includeInstance, msg) { + var f, obj = { + string: jspb.Message.getFieldWithDefault(msg, 1, ""), + uint32: jspb.Message.getFieldWithDefault(msg, 2, 0), + inner: (f = msg.getInner()) && proto.Test.Inner.toObject(includeInstance, f), + pb_float: +jspb.Message.getFieldWithDefault(msg, 4, 0.0) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.Test} + */ +proto.Test.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.Test; + return proto.Test.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.Test} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.Test} + */ +proto.Test.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setString(value); + break; + case 2: + var value = /** @type {number} */ (reader.readUint32()); + msg.setUint32(value); + break; + case 3: + var value = new proto.Test.Inner; + reader.readMessage(value,proto.Test.Inner.deserializeBinaryFromReader); + msg.setInner(value); + break; + case 4: + var value = /** @type {number} */ (reader.readFloat()); + msg.setFloat(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.Test.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.Test.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.Test} message + * @param {!jspb.BinaryWriter} writer + */ +proto.Test.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getString(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getUint32(); + if (f !== 0) { + writer.writeUint32( + 2, + f + ); + } + f = message.getInner(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.Test.Inner.serializeBinaryToWriter + ); + } + f = message.getFloat(); + if (f !== 0.0) { + writer.writeFloat( + 4, + f + ); + } +}; + + +/** + * @enum {number} + */ +proto.Test.Enum = { + ONE: 0, + TWO: 1, + THREE: 2, + FOUR: 3, + FIVE: 4 +}; + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.Test.Inner = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.Test.Inner, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.Test.Inner.displayName = 'proto.Test.Inner'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.Test.Inner.prototype.toObject = function(opt_includeInstance) { + return proto.Test.Inner.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.Test.Inner} msg The msg instance to transform. + * @return {!Object} + */ +proto.Test.Inner.toObject = function(includeInstance, msg) { + var f, obj = { + int32: jspb.Message.getFieldWithDefault(msg, 1, 0), + innerinner: (f = msg.getInnerinner()) && proto.Test.Inner.InnerInner.toObject(includeInstance, f), + outer: (f = msg.getOuter()) && proto.Outer.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.Test.Inner} + */ +proto.Test.Inner.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.Test.Inner; + return proto.Test.Inner.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.Test.Inner} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.Test.Inner} + */ +proto.Test.Inner.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt32()); + msg.setInt32(value); + break; + case 2: + var value = new proto.Test.Inner.InnerInner; + reader.readMessage(value,proto.Test.Inner.InnerInner.deserializeBinaryFromReader); + msg.setInnerinner(value); + break; + case 3: + var value = new proto.Outer; + reader.readMessage(value,proto.Outer.deserializeBinaryFromReader); + msg.setOuter(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.Test.Inner.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.Test.Inner.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.Test.Inner} message + * @param {!jspb.BinaryWriter} writer + */ +proto.Test.Inner.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getInt32(); + if (f !== 0) { + writer.writeInt32( + 1, + f + ); + } + f = message.getInnerinner(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.Test.Inner.InnerInner.serializeBinaryToWriter + ); + } + f = message.getOuter(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.Outer.serializeBinaryToWriter + ); + } +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.Test.Inner.InnerInner = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.Test.Inner.InnerInner, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.Test.Inner.InnerInner.displayName = 'proto.Test.Inner.InnerInner'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.Test.Inner.InnerInner.prototype.toObject = function(opt_includeInstance) { + return proto.Test.Inner.InnerInner.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.Test.Inner.InnerInner} msg The msg instance to transform. + * @return {!Object} + */ +proto.Test.Inner.InnerInner.toObject = function(includeInstance, msg) { + var f, obj = { + pb_long: jspb.Message.getFieldWithDefault(msg, 1, 0), + pb_enum: jspb.Message.getFieldWithDefault(msg, 2, 0), + sint32: jspb.Message.getFieldWithDefault(msg, 3, 0) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.Test.Inner.InnerInner} + */ +proto.Test.Inner.InnerInner.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.Test.Inner.InnerInner; + return proto.Test.Inner.InnerInner.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.Test.Inner.InnerInner} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.Test.Inner.InnerInner} + */ +proto.Test.Inner.InnerInner.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt64()); + msg.setLong(value); + break; + case 2: + var value = /** @type {!proto.Test.Enum} */ (reader.readEnum()); + msg.setEnum(value); + break; + case 3: + var value = /** @type {number} */ (reader.readSint32()); + msg.setSint32(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.Test.Inner.InnerInner.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.Test.Inner.InnerInner.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.Test.Inner.InnerInner} message + * @param {!jspb.BinaryWriter} writer + */ +proto.Test.Inner.InnerInner.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getLong(); + if (f !== 0) { + writer.writeInt64( + 1, + f + ); + } + f = message.getEnum(); + if (f !== 0.0) { + writer.writeEnum( + 2, + f + ); + } + f = message.getSint32(); + if (f !== 0) { + writer.writeSint32( + 3, + f + ); + } +}; + + +/** + * optional int64 long = 1; + * @return {number} + */ +proto.Test.Inner.InnerInner.prototype.getLong = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.Test.Inner.InnerInner.prototype.setLong = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +/** + * optional Enum enum = 2; + * @return {!proto.Test.Enum} + */ +proto.Test.Inner.InnerInner.prototype.getEnum = function() { + return /** @type {!proto.Test.Enum} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** @param {!proto.Test.Enum} value */ +proto.Test.Inner.InnerInner.prototype.setEnum = function(value) { + jspb.Message.setField(this, 2, value); +}; + + +/** + * optional sint32 sint32 = 3; + * @return {number} + */ +proto.Test.Inner.InnerInner.prototype.getSint32 = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0)); +}; + + +/** @param {number} value */ +proto.Test.Inner.InnerInner.prototype.setSint32 = function(value) { + jspb.Message.setField(this, 3, value); +}; + + +/** + * optional int32 int32 = 1; + * @return {number} + */ +proto.Test.Inner.prototype.getInt32 = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.Test.Inner.prototype.setInt32 = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +/** + * optional InnerInner innerInner = 2; + * @return {?proto.Test.Inner.InnerInner} + */ +proto.Test.Inner.prototype.getInnerinner = function() { + return /** @type{?proto.Test.Inner.InnerInner} */ ( + jspb.Message.getWrapperField(this, proto.Test.Inner.InnerInner, 2)); +}; + + +/** @param {?proto.Test.Inner.InnerInner|undefined} value */ +proto.Test.Inner.prototype.setInnerinner = function(value) { + jspb.Message.setWrapperField(this, 2, value); +}; + + +proto.Test.Inner.prototype.clearInnerinner = function() { + this.setInnerinner(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.Test.Inner.prototype.hasInnerinner = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional Outer outer = 3; + * @return {?proto.Outer} + */ +proto.Test.Inner.prototype.getOuter = function() { + return /** @type{?proto.Outer} */ ( + jspb.Message.getWrapperField(this, proto.Outer, 3)); +}; + + +/** @param {?proto.Outer|undefined} value */ +proto.Test.Inner.prototype.setOuter = function(value) { + jspb.Message.setWrapperField(this, 3, value); +}; + + +proto.Test.Inner.prototype.clearOuter = function() { + this.setOuter(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.Test.Inner.prototype.hasOuter = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional string string = 1; + * @return {string} + */ +proto.Test.prototype.getString = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** @param {string} value */ +proto.Test.prototype.setString = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +/** + * optional uint32 uint32 = 2; + * @return {number} + */ +proto.Test.prototype.getUint32 = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** @param {number} value */ +proto.Test.prototype.setUint32 = function(value) { + jspb.Message.setField(this, 2, value); +}; + + +/** + * optional Inner inner = 3; + * @return {?proto.Test.Inner} + */ +proto.Test.prototype.getInner = function() { + return /** @type{?proto.Test.Inner} */ ( + jspb.Message.getWrapperField(this, proto.Test.Inner, 3)); +}; + + +/** @param {?proto.Test.Inner|undefined} value */ +proto.Test.prototype.setInner = function(value) { + jspb.Message.setWrapperField(this, 3, value); +}; + + +proto.Test.prototype.clearInner = function() { + this.setInner(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.Test.prototype.hasInner = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional float float = 4; + * @return {number} + */ +proto.Test.prototype.getFloat = function() { + return /** @type {number} */ (+jspb.Message.getFieldWithDefault(this, 4, 0.0)); +}; + + +/** @param {number} value */ +proto.Test.prototype.setFloat = function(value) { + jspb.Message.setField(this, 4, value); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.Outer = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.Outer.repeatedFields_, null); +}; +goog.inherits(proto.Outer, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.Outer.displayName = 'proto.Outer'; +} +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.Outer.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.Outer.prototype.toObject = function(opt_includeInstance) { + return proto.Outer.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.Outer} msg The msg instance to transform. + * @return {!Object} + */ +proto.Outer.toObject = function(includeInstance, msg) { + var f, obj = { + boolList: jspb.Message.getField(msg, 1), + pb_double: +jspb.Message.getFieldWithDefault(msg, 2, 0.0) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.Outer} + */ +proto.Outer.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.Outer; + return proto.Outer.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.Outer} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.Outer} + */ +proto.Outer.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Array.} */ (reader.readPackedBool()); + msg.setBoolList(value); + break; + case 2: + var value = /** @type {number} */ (reader.readDouble()); + msg.setDouble(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.Outer.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.Outer.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.Outer} message + * @param {!jspb.BinaryWriter} writer + */ +proto.Outer.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getBoolList(); + if (f.length > 0) { + writer.writePackedBool( + 1, + f + ); + } + f = message.getDouble(); + if (f !== 0.0) { + writer.writeDouble( + 2, + f + ); + } +}; + + +/** + * repeated bool bool = 1; + * Note that Boolean fields may be set to 0/1 when serialized from a Java server. + * You should avoid comparisons like {@code val === true/false} in those cases. + * If you change this array by adding, removing or replacing elements, or if you + * replace the array itself, then you must call the setter to update it. + * @return {!Array.} + */ +proto.Outer.prototype.getBoolList = function() { + return /** @type {!Array.} */ (jspb.Message.getField(this, 1)); +}; + + +/** @param {!Array.} value */ +proto.Outer.prototype.setBoolList = function(value) { + jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {!boolean} value + * @param {number=} opt_index + */ +proto.Outer.prototype.addBool = function(value, opt_index) { + jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +proto.Outer.prototype.clearBoolList = function() { + this.setBoolList([]); +}; + + +/** + * optional double double = 2; + * @return {number} + */ +proto.Outer.prototype.getDouble = function() { + return /** @type {number} */ (+jspb.Message.getFieldWithDefault(this, 2, 0.0)); +}; + + +/** @param {number} value */ +proto.Outer.prototype.setDouble = function(value) { + jspb.Message.setField(this, 2, value); +}; + + +goog.object.extend(exports, proto); diff --git a/bench/data/static_pbjs.js b/bench/data/static_pbjs.js new file mode 100644 index 000000000..8eb587c94 --- /dev/null +++ b/bench/data/static_pbjs.js @@ -0,0 +1,974 @@ +/*eslint-disable block-scoped-var, no-redeclare, no-control-regex, no-prototype-builtins*/ +"use strict"; + +var $protobuf = require("../../minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots.test_bench || ($protobuf.roots.test_bench = {}); + +$root.Test = (function() { + + /** + * Properties of a Test. + * @typedef Test$Properties + * @type {Object} + * @property {string} [string] Test string. + * @property {number} [uint32] Test uint32. + * @property {Test.Inner$Properties} [inner] Test inner. + * @property {number} [float] Test float. + */ + + /** + * Constructs a new Test. + * @exports Test + * @constructor + * @param {Test$Properties=} [properties] Properties to set + */ + function Test(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Test string. + * @type {string} + */ + Test.prototype.string = ""; + + /** + * Test uint32. + * @type {number} + */ + Test.prototype.uint32 = 0; + + /** + * Test inner. + * @type {(Test.Inner$Properties|null)} + */ + Test.prototype.inner = null; + + /** + * Test float. + * @type {number} + */ + Test.prototype.float = 0; + + /** + * Creates a new Test instance using the specified properties. + * @param {Test$Properties=} [properties] Properties to set + * @returns {Test} Test instance + */ + Test.create = function create(properties) { + return new Test(properties); + }; + + /** + * Encodes the specified Test message. Does not implicitly {@link Test.verify|verify} messages. + * @param {Test$Properties} message Test message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Test.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.string != null && message.hasOwnProperty("string")) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.string); + if (message.uint32 != null && message.hasOwnProperty("uint32")) + writer.uint32(/* id 2, wireType 0 =*/16).uint32(message.uint32); + if (message.inner != null && message.hasOwnProperty("inner")) + $root.Test.Inner.encode(message.inner, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + if (message.float != null && message.hasOwnProperty("float")) + writer.uint32(/* id 4, wireType 5 =*/37).float(message.float); + return writer; + }; + + /** + * Encodes the specified Test message, length delimited. Does not implicitly {@link Test.verify|verify} messages. + * @param {Test$Properties} message Test message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Test.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Test message from the specified reader or buffer. + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {Test} Test + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Test.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.string = reader.string(); + break; + case 2: + message.uint32 = reader.uint32(); + break; + case 3: + message.inner = $root.Test.Inner.decode(reader, reader.uint32()); + break; + case 4: + message.float = reader.float(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Test message from the specified reader or buffer, length delimited. + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {Test} Test + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Test.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Test message. + * @param {Object.} message Plain object to verify + * @returns {?string} `null` if valid, otherwise the reason why it is not + */ + Test.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.string != null && message.hasOwnProperty("string")) + if (!$util.isString(message.string)) + return "string: string expected"; + if (message.uint32 != null && message.hasOwnProperty("uint32")) + if (!$util.isInteger(message.uint32)) + return "uint32: integer expected"; + if (message.inner != null && message.hasOwnProperty("inner")) { + var error = $root.Test.Inner.verify(message.inner); + if (error) + return "inner." + error; + } + if (message.float != null && message.hasOwnProperty("float")) + if (typeof message.float !== "number") + return "float: number expected"; + return null; + }; + + /** + * Creates a Test message from a plain object. Also converts values to their respective internal types. + * @param {Object.} object Plain object + * @returns {Test} Test + */ + Test.fromObject = function fromObject(object) { + if (object instanceof $root.Test) + return object; + var message = new $root.Test(); + if (object.string != null) + message.string = String(object.string); + if (object.uint32 != null) + message.uint32 = object.uint32 >>> 0; + if (object.inner != null) { + if (typeof object.inner !== "object") + throw TypeError(".Test.inner: object expected"); + message.inner = $root.Test.Inner.fromObject(object.inner); + } + if (object.float != null) + message.float = Number(object.float); + return message; + }; + + /** + * Creates a Test message from a plain object. Also converts values to their respective internal types. + * This is an alias of {@link Test.fromObject}. + * @function + * @param {Object.} object Plain object + * @returns {Test} Test + */ + Test.from = Test.fromObject; + + /** + * Creates a plain object from a Test message. Also converts values to other types if specified. + * @param {Test} message Test + * @param {$protobuf.ConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Test.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.string = ""; + object.uint32 = 0; + object.inner = null; + object.float = 0; + } + if (message.string != null && message.hasOwnProperty("string")) + object.string = message.string; + if (message.uint32 != null && message.hasOwnProperty("uint32")) + object.uint32 = message.uint32; + if (message.inner != null && message.hasOwnProperty("inner")) + object.inner = $root.Test.Inner.toObject(message.inner, options); + if (message.float != null && message.hasOwnProperty("float")) + object.float = message.float; + return object; + }; + + /** + * Creates a plain object from this Test message. Also converts values to other types if specified. + * @param {$protobuf.ConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Test.prototype.toObject = function toObject(options) { + return this.constructor.toObject(this, options); + }; + + /** + * Converts this Test to JSON. + * @returns {Object.} JSON object + */ + Test.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + Test.Inner = (function() { + + /** + * Properties of an Inner. + * @typedef Test.Inner$Properties + * @type {Object} + * @property {number} [int32] Inner int32. + * @property {Test.Inner.InnerInner$Properties} [innerInner] Inner innerInner. + * @property {Outer$Properties} [outer] Inner outer. + */ + + /** + * Constructs a new Inner. + * @exports Test.Inner + * @constructor + * @param {Test.Inner$Properties=} [properties] Properties to set + */ + function Inner(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Inner int32. + * @type {number} + */ + Inner.prototype.int32 = 0; + + /** + * Inner innerInner. + * @type {(Test.Inner.InnerInner$Properties|null)} + */ + Inner.prototype.innerInner = null; + + /** + * Inner outer. + * @type {(Outer$Properties|null)} + */ + Inner.prototype.outer = null; + + /** + * Creates a new Inner instance using the specified properties. + * @param {Test.Inner$Properties=} [properties] Properties to set + * @returns {Test.Inner} Inner instance + */ + Inner.create = function create(properties) { + return new Inner(properties); + }; + + /** + * Encodes the specified Inner message. Does not implicitly {@link Test.Inner.verify|verify} messages. + * @param {Test.Inner$Properties} message Inner message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Inner.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.int32 != null && message.hasOwnProperty("int32")) + writer.uint32(/* id 1, wireType 0 =*/8).int32(message.int32); + if (message.innerInner != null && message.hasOwnProperty("innerInner")) + $root.Test.Inner.InnerInner.encode(message.innerInner, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.outer != null && message.hasOwnProperty("outer")) + $root.Outer.encode(message.outer, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified Inner message, length delimited. Does not implicitly {@link Test.Inner.verify|verify} messages. + * @param {Test.Inner$Properties} message Inner message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Inner.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an Inner message from the specified reader or buffer. + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {Test.Inner} Inner + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Inner.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test.Inner(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.int32 = reader.int32(); + break; + case 2: + message.innerInner = $root.Test.Inner.InnerInner.decode(reader, reader.uint32()); + break; + case 3: + message.outer = $root.Outer.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an Inner message from the specified reader or buffer, length delimited. + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {Test.Inner} Inner + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Inner.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an Inner message. + * @param {Object.} message Plain object to verify + * @returns {?string} `null` if valid, otherwise the reason why it is not + */ + Inner.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.int32 != null && message.hasOwnProperty("int32")) + if (!$util.isInteger(message.int32)) + return "int32: integer expected"; + if (message.innerInner != null && message.hasOwnProperty("innerInner")) { + var error = $root.Test.Inner.InnerInner.verify(message.innerInner); + if (error) + return "innerInner." + error; + } + if (message.outer != null && message.hasOwnProperty("outer")) { + var error = $root.Outer.verify(message.outer); + if (error) + return "outer." + error; + } + return null; + }; + + /** + * Creates an Inner message from a plain object. Also converts values to their respective internal types. + * @param {Object.} object Plain object + * @returns {Test.Inner} Inner + */ + Inner.fromObject = function fromObject(object) { + if (object instanceof $root.Test.Inner) + return object; + var message = new $root.Test.Inner(); + if (object.int32 != null) + message.int32 = object.int32 | 0; + if (object.innerInner != null) { + if (typeof object.innerInner !== "object") + throw TypeError(".Test.Inner.innerInner: object expected"); + message.innerInner = $root.Test.Inner.InnerInner.fromObject(object.innerInner); + } + if (object.outer != null) { + if (typeof object.outer !== "object") + throw TypeError(".Test.Inner.outer: object expected"); + message.outer = $root.Outer.fromObject(object.outer); + } + return message; + }; + + /** + * Creates an Inner message from a plain object. Also converts values to their respective internal types. + * This is an alias of {@link Test.Inner.fromObject}. + * @function + * @param {Object.} object Plain object + * @returns {Test.Inner} Inner + */ + Inner.from = Inner.fromObject; + + /** + * Creates a plain object from an Inner message. Also converts values to other types if specified. + * @param {Test.Inner} message Inner + * @param {$protobuf.ConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Inner.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.int32 = 0; + object.innerInner = null; + object.outer = null; + } + if (message.int32 != null && message.hasOwnProperty("int32")) + object.int32 = message.int32; + if (message.innerInner != null && message.hasOwnProperty("innerInner")) + object.innerInner = $root.Test.Inner.InnerInner.toObject(message.innerInner, options); + if (message.outer != null && message.hasOwnProperty("outer")) + object.outer = $root.Outer.toObject(message.outer, options); + return object; + }; + + /** + * Creates a plain object from this Inner message. Also converts values to other types if specified. + * @param {$protobuf.ConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Inner.prototype.toObject = function toObject(options) { + return this.constructor.toObject(this, options); + }; + + /** + * Converts this Inner to JSON. + * @returns {Object.} JSON object + */ + Inner.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + Inner.InnerInner = (function() { + + /** + * Properties of an InnerInner. + * @typedef Test.Inner.InnerInner$Properties + * @type {Object} + * @property {number|Long} [long] InnerInner long. + * @property {Test.Enum} ["enum"] InnerInner enum. + * @property {number} [sint32] InnerInner sint32. + */ + + /** + * Constructs a new InnerInner. + * @exports Test.Inner.InnerInner + * @constructor + * @param {Test.Inner.InnerInner$Properties=} [properties] Properties to set + */ + function InnerInner(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * InnerInner long. + * @type {number|Long} + */ + InnerInner.prototype.long = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * InnerInner enum. + * @type {Test.Enum} + */ + InnerInner.prototype["enum"] = 0; + + /** + * InnerInner sint32. + * @type {number} + */ + InnerInner.prototype.sint32 = 0; + + /** + * Creates a new InnerInner instance using the specified properties. + * @param {Test.Inner.InnerInner$Properties=} [properties] Properties to set + * @returns {Test.Inner.InnerInner} InnerInner instance + */ + InnerInner.create = function create(properties) { + return new InnerInner(properties); + }; + + /** + * Encodes the specified InnerInner message. Does not implicitly {@link Test.Inner.InnerInner.verify|verify} messages. + * @param {Test.Inner.InnerInner$Properties} message InnerInner message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + InnerInner.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.long != null && message.hasOwnProperty("long")) + writer.uint32(/* id 1, wireType 0 =*/8).int64(message.long); + if (message["enum"] != null && message.hasOwnProperty("enum")) + writer.uint32(/* id 2, wireType 0 =*/16).uint32(message["enum"]); + if (message.sint32 != null && message.hasOwnProperty("sint32")) + writer.uint32(/* id 3, wireType 0 =*/24).sint32(message.sint32); + return writer; + }; + + /** + * Encodes the specified InnerInner message, length delimited. Does not implicitly {@link Test.Inner.InnerInner.verify|verify} messages. + * @param {Test.Inner.InnerInner$Properties} message InnerInner message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + InnerInner.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an InnerInner message from the specified reader or buffer. + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {Test.Inner.InnerInner} InnerInner + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + InnerInner.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test.Inner.InnerInner(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.long = reader.int64(); + break; + case 2: + message["enum"] = reader.uint32(); + break; + case 3: + message.sint32 = reader.sint32(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an InnerInner message from the specified reader or buffer, length delimited. + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {Test.Inner.InnerInner} InnerInner + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + InnerInner.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an InnerInner message. + * @param {Object.} message Plain object to verify + * @returns {?string} `null` if valid, otherwise the reason why it is not + */ + InnerInner.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.long != null && message.hasOwnProperty("long")) + if (!$util.isInteger(message.long) && !(message.long && $util.isInteger(message.long.low) && $util.isInteger(message.long.high))) + return "long: integer|Long expected"; + if (message["enum"] != null && message.hasOwnProperty("enum")) + switch (message["enum"]) { + default: + return "enum: enum value expected"; + case 0: + case 1: + case 2: + case 3: + case 4: + break; + } + if (message.sint32 != null && message.hasOwnProperty("sint32")) + if (!$util.isInteger(message.sint32)) + return "sint32: integer expected"; + return null; + }; + + /** + * Creates an InnerInner message from a plain object. Also converts values to their respective internal types. + * @param {Object.} object Plain object + * @returns {Test.Inner.InnerInner} InnerInner + */ + InnerInner.fromObject = function fromObject(object) { + if (object instanceof $root.Test.Inner.InnerInner) + return object; + var message = new $root.Test.Inner.InnerInner(); + if (object.long != null) + if ($util.Long) + (message.long = $util.Long.fromValue(object.long)).unsigned = false; + else if (typeof object.long === "string") + message.long = parseInt(object.long, 10); + else if (typeof object.long === "number") + message.long = object.long; + else if (typeof object.long === "object") + message.long = new $util.LongBits(object.long.low >>> 0, object.long.high >>> 0).toNumber(); + switch (object["enum"]) { + case "ONE": + case 0: + message["enum"] = 0; + break; + case "TWO": + case 1: + message["enum"] = 1; + break; + case "THREE": + case 2: + message["enum"] = 2; + break; + case "FOUR": + case 3: + message["enum"] = 3; + break; + case "FIVE": + case 4: + message["enum"] = 4; + break; + } + if (object.sint32 != null) + message.sint32 = object.sint32 | 0; + return message; + }; + + /** + * Creates an InnerInner message from a plain object. Also converts values to their respective internal types. + * This is an alias of {@link Test.Inner.InnerInner.fromObject}. + * @function + * @param {Object.} object Plain object + * @returns {Test.Inner.InnerInner} InnerInner + */ + InnerInner.from = InnerInner.fromObject; + + /** + * Creates a plain object from an InnerInner message. Also converts values to other types if specified. + * @param {Test.Inner.InnerInner} message InnerInner + * @param {$protobuf.ConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + InnerInner.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, false); + object.long = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.long = options.longs === String ? "0" : 0; + object["enum"] = options.enums === String ? "ONE" : 0; + object.sint32 = 0; + } + if (message.long != null && message.hasOwnProperty("long")) + if (typeof message.long === "number") + object.long = options.longs === String ? String(message.long) : message.long; + else + object.long = options.longs === String ? $util.Long.prototype.toString.call(message.long) : options.longs === Number ? new $util.LongBits(message.long.low >>> 0, message.long.high >>> 0).toNumber() : message.long; + if (message["enum"] != null && message.hasOwnProperty("enum")) + object["enum"] = options.enums === String ? $root.Test.Enum[message["enum"]] : message["enum"]; + if (message.sint32 != null && message.hasOwnProperty("sint32")) + object.sint32 = message.sint32; + return object; + }; + + /** + * Creates a plain object from this InnerInner message. Also converts values to other types if specified. + * @param {$protobuf.ConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + InnerInner.prototype.toObject = function toObject(options) { + return this.constructor.toObject(this, options); + }; + + /** + * Converts this InnerInner to JSON. + * @returns {Object.} JSON object + */ + InnerInner.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return InnerInner; + })(); + + return Inner; + })(); + + /** + * Enum enum. + * @name Enum + * @memberof Test + * @enum {number} + * @property {number} ONE=0 ONE value + * @property {number} TWO=1 TWO value + * @property {number} THREE=2 THREE value + * @property {number} FOUR=3 FOUR value + * @property {number} FIVE=4 FIVE value + */ + Test.Enum = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "ONE"] = 0; + values[valuesById[1] = "TWO"] = 1; + values[valuesById[2] = "THREE"] = 2; + values[valuesById[3] = "FOUR"] = 3; + values[valuesById[4] = "FIVE"] = 4; + return values; + })(); + + return Test; +})(); + +$root.Outer = (function() { + + /** + * Properties of an Outer. + * @typedef Outer$Properties + * @type {Object} + * @property {Array.} [bool] Outer bool. + * @property {number} [double] Outer double. + */ + + /** + * Constructs a new Outer. + * @exports Outer + * @constructor + * @param {Outer$Properties=} [properties] Properties to set + */ + function Outer(properties) { + this.bool = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Outer bool. + * @type {Array.} + */ + Outer.prototype.bool = $util.emptyArray; + + /** + * Outer double. + * @type {number} + */ + Outer.prototype.double = 0; + + /** + * Creates a new Outer instance using the specified properties. + * @param {Outer$Properties=} [properties] Properties to set + * @returns {Outer} Outer instance + */ + Outer.create = function create(properties) { + return new Outer(properties); + }; + + /** + * Encodes the specified Outer message. Does not implicitly {@link Outer.verify|verify} messages. + * @param {Outer$Properties} message Outer message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Outer.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.bool != null && message.bool.length) { + writer.uint32(/* id 1, wireType 2 =*/10).fork(); + for (var i = 0; i < message.bool.length; ++i) + writer.bool(message.bool[i]); + writer.ldelim(); + } + if (message.double != null && message.hasOwnProperty("double")) + writer.uint32(/* id 2, wireType 1 =*/17).double(message.double); + return writer; + }; + + /** + * Encodes the specified Outer message, length delimited. Does not implicitly {@link Outer.verify|verify} messages. + * @param {Outer$Properties} message Outer message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Outer.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an Outer message from the specified reader or buffer. + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {Outer} Outer + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Outer.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Outer(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.bool && message.bool.length)) + message.bool = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.bool.push(reader.bool()); + } else + message.bool.push(reader.bool()); + break; + case 2: + message.double = reader.double(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an Outer message from the specified reader or buffer, length delimited. + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {Outer} Outer + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Outer.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an Outer message. + * @param {Object.} message Plain object to verify + * @returns {?string} `null` if valid, otherwise the reason why it is not + */ + Outer.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.bool != null && message.hasOwnProperty("bool")) { + if (!Array.isArray(message.bool)) + return "bool: array expected"; + for (var i = 0; i < message.bool.length; ++i) + if (typeof message.bool[i] !== "boolean") + return "bool: boolean[] expected"; + } + if (message.double != null && message.hasOwnProperty("double")) + if (typeof message.double !== "number") + return "double: number expected"; + return null; + }; + + /** + * Creates an Outer message from a plain object. Also converts values to their respective internal types. + * @param {Object.} object Plain object + * @returns {Outer} Outer + */ + Outer.fromObject = function fromObject(object) { + if (object instanceof $root.Outer) + return object; + var message = new $root.Outer(); + if (object.bool) { + if (!Array.isArray(object.bool)) + throw TypeError(".Outer.bool: array expected"); + message.bool = []; + for (var i = 0; i < object.bool.length; ++i) + message.bool[i] = Boolean(object.bool[i]); + } + if (object.double != null) + message.double = Number(object.double); + return message; + }; + + /** + * Creates an Outer message from a plain object. Also converts values to their respective internal types. + * This is an alias of {@link Outer.fromObject}. + * @function + * @param {Object.} object Plain object + * @returns {Outer} Outer + */ + Outer.from = Outer.fromObject; + + /** + * Creates a plain object from an Outer message. Also converts values to other types if specified. + * @param {Outer} message Outer + * @param {$protobuf.ConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Outer.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.bool = []; + if (options.defaults) + object.double = 0; + if (message.bool && message.bool.length) { + object.bool = []; + for (var j = 0; j < message.bool.length; ++j) + object.bool[j] = message.bool[j]; + } + if (message.double != null && message.hasOwnProperty("double")) + object.double = message.double; + return object; + }; + + /** + * Creates a plain object from this Outer message. Also converts values to other types if specified. + * @param {$protobuf.ConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Outer.prototype.toObject = function toObject(options) { + return this.constructor.toObject(this, options); + }; + + /** + * Converts this Outer to JSON. + * @returns {Object.} JSON object + */ + Outer.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Outer; +})(); + +module.exports = $root; diff --git a/bench/fromJSON.js b/bench/fromJSON.js deleted file mode 100644 index 68fd24a74..000000000 --- a/bench/fromJSON.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; - -var newSuite = require("./suite"); - -var protobuf = require(".."); - -var Root = protobuf.Root; -var root = protobuf.loadSync("tests/data/test.proto"); -var json = JSON.stringify(root); - -newSuite("fromJSON") -.add("Root.fromJSON", function() { - Root.fromJSON(json); -}) -.run(); diff --git a/bench/index.html b/bench/index.html deleted file mode 100644 index 0904ef7f4..000000000 --- a/bench/index.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - -

protobuf.js browser benchmark

- - - \ No newline at end of file diff --git a/bench/index.js b/bench/index.js index 5138ad764..7a8a55fbe 100644 --- a/bench/index.js +++ b/bench/index.js @@ -1,106 +1,90 @@ "use strict"; -var protobuf = require(".."), - newSuite = require("./suite"), - data = require("./bench.json"); - -// NOTE: This benchmark is flawed in that it compares protocol buffers, which is purely a binary -// format, to JSON, which is purely a string format. -// -// This matters because the encoder must convert JavaScript strings from UTF16 LE characters to -// UTF8 bytes with every string operation while JSON does not require a mechanism for this by its -// own. Ultimately, also strings produced by JSON must be converted to UTF8 somewhere down the -// road, but this implementation detail is hidden from JS code and cannot be reliably measured -// here without using some sort of networking layer, i.e. a tcp socket, in between, which would -// most likely introduce other statistical difficulties. +// NOTE: This benchmark partly compares apples and oranges in that it measures protocol buffers, +// which is purely a binary format, and JSON, which is purely a string format. // -// Hence, this benchmark compares to both pure string performance of JSON and additional binary -// conversion of the same data using node buffers, which is probably slower than what a modern -// VM uses under the hood when sending string data over the network. Comparable JSON performance -// should be somewhere in between what is displayed as "to string" and "to buffer", though. -// -// To experience the impact by yourself, increase string lengths within bench.json. - -var root = protobuf.loadSync(require.resolve("./bench.proto")), - Test = root.resolveAll().lookup("Test"); +// This matters because strings aren't actually transfered over the network but must still be +// converted to binary somewhere down the road. Because this can't be measured reliably, this +// benchmark compares both pure string performance of JSON and additional binary conversion of the +// same data using node buffers. Actual JSON performance on the network level should be somewhere +// in between. -// protobuf.util.codegen.verbose = true; +var newSuite = require("./suite"), + payload = require("./data/bench.json"); -var buf = Test.encode(data).finish(); +var Buffer_from = Buffer.from !== Uint8Array.from && Buffer.from || function(value, encoding) { return new Buffer(value, encoding); }; -// warm up -process.stdout.write("warming up ...\n"); -var i; -for (i = 0; i < 500000; ++i) - Test.encode(data).finish(); -for (i = 0; i < 1000000; ++i) - Test.decode(buf); -for (i = 0; i < 500000; ++i) - Test.verify(data); -process.stdout.write("\n"); +// protobuf.js dynamic: load the proto and set up a buffer +var pbjsCls = require("..").loadSync(require.resolve("./data/bench.proto")).resolveAll().lookup("Test"); +var pbjsMsg = payload; // alt: pbjsCls.fromObject(payload); +var pbjsBuf = pbjsCls.encode(pbjsMsg).finish(); -// give the optimizer some time to do its job -setTimeout(function() { - var str = JSON.stringify(data), - strbuf = protobuf.util._Buffer_from(str, "utf8"); +// protobuf.js static: load the proto +var pbjsStaticCls = require("./data/static_pbjs.js").Test; - newSuite("encoding") - .add("Type.encode to buffer", function() { - Test.encode(data).finish(); - }) - .add("JSON.stringify to string", function() { - JSON.stringify(data); - }) - .add("JSON.stringify to buffer", function() { - protobuf.util._Buffer_from(JSON.stringify(data), "utf8"); - }) - .run(); +// JSON: set up a string and a buffer +var jsonMsg = payload; +var jsonStr = JSON.stringify(jsonMsg); +var jsonBuf = Buffer_from(jsonStr, "utf8"); - newSuite("decoding") - .add("Type.decode from buffer", function() { - Test.decode(buf); // no allocation overhead, if you wondered - }) - .add("JSON.parse from string", function() { - JSON.parse(str); - }) - .add("JSON.parse from buffer", function() { - JSON.parse(strbuf.toString("utf8")); - }) - .run(); +// google-protobuf: load the proto, set up an Uint8Array and a message +var jspbCls = require("./data/static_jspb.js").Test; +var jspbBuf = new Uint8Array(Array.prototype.slice.call(pbjsBuf)); +var jspbMsg = jspbCls.deserializeBinary(jspbBuf); - newSuite("combined") - .add("Type to/from buffer", function() { - Test.decode(Test.encode(data).finish()); - }) - .add("JSON to/from string", function() { - JSON.parse(JSON.stringify(data)); - }) - .add("JSON to/from buffer", function() { - JSON.parse(protobuf.util._Buffer_from(JSON.stringify(data), "utf8").toString("utf8")); - }) - .run(); +newSuite("encoding") - newSuite("verifying") - .add("Type.verify", function() { - var r = Test.verify(data); - if (r) - throw Error(r); - }) - .run(); +.add("protobuf.js (reflect)", function() { + pbjsCls.encode(pbjsMsg).finish(); +}) +.add("protobuf.js (static)", function() { + pbjsStaticCls.encode(pbjsMsg).finish(); +}) +.add("JSON (string)", function() { + JSON.stringify(jsonMsg); +}) +.add("JSON (buffer)", function() { + Buffer_from(JSON.stringify(jsonMsg), "utf8"); +}) +.add("google-protobuf", function() { + jspbMsg.serializeBinary(); +}) +.run(); - var dataMessage = Test.from(data); - var dataObject = dataMessage.toObject(); +newSuite("decoding") - newSuite("message from object") - .add("Type.fromObject", function() { - Test.fromObject(dataObject); - }) - .run(); +.add("protobuf.js (reflect)", function() { + pbjsCls.decode(pbjsBuf); // no allocation overhead, if you wondered +}) +.add("protobuf.js (static)", function() { + pbjsStaticCls.decode(pbjsBuf); +}) +.add("JSON (string)", function() { + JSON.parse(jsonStr); +}) +.add("JSON (buffer)", function() { + JSON.parse(jsonBuf.toString("utf8")); +}) +.add("google-protobuf", function() { + jspbCls.deserializeBinary(jspbBuf); +}) +.run(); - newSuite("message to object") - .add("Type.toObject", function() { - Test.toObject(dataMessage); - }) - .run(); +newSuite("combined") -}, 3000); +.add("protobuf.js (reflect)", function() { + pbjsCls.decode(pbjsCls.encode(pbjsMsg).finish()); +}) +.add("protobuf.js (static)", function() { + pbjsStaticCls.decode(pbjsStaticCls.encode(pbjsMsg).finish()); +}) +.add("JSON (string)", function() { + JSON.parse(JSON.stringify(jsonMsg)); +}) +.add("JSON (buffer)", function() { + JSON.parse(Buffer_from(JSON.stringify(jsonMsg), "utf8").toString("utf8")); +}) +.add("google-protobuf", function() { + jspbCls.deserializeBinary(jspbMsg.serializeBinary()); +}) +.run(); diff --git a/bench/prof.js b/bench/prof.js index e62a4dba4..4c3497a6d 100644 --- a/bench/prof.js +++ b/bench/prof.js @@ -60,10 +60,10 @@ if (process.argv[2] === "fromjson") { var Test, data, count; if (process.argv.indexOf("--alt") < 0) { - root = protobuf.parse(fs.readFileSync(require.resolve("../bench/bench.proto")).toString("utf8")).root; + root = protobuf.parse(fs.readFileSync(require.resolve("../bench/data/bench.proto")).toString("utf8")).root; Test = root.lookup("Test"); json = JSON.stringify(root); - data = require("../bench/bench.json"); + data = require("../bench/data/bench.json"); count = 10000000; process.stdout.write("bench.proto"); } else { diff --git a/bench/read.js b/bench/read.js deleted file mode 100644 index fd37c3873..000000000 --- a/bench/read.js +++ /dev/null @@ -1,132 +0,0 @@ -"use strict"; -var newSuite = require("./suite"), - ieee754 = require("../lib/ieee754"); - -// This benchmark compares raw data type performance of Uint8Array and Buffer. - -var data = [ 0xCD, 0xCC, 0xCC, 0x3D ]; // ~0.10000000149011612 LE -var array = new Uint8Array(data); -var buffer = Buffer.from(data); - -var f64 = new Float64Array(1); -var f32 = new Float32Array(f64.buffer); -var f8b = new Uint8Array(f64.buffer); - -// raw float read speed -newSuite("float") -.add("ieee754 array", function() { - ieee754.read(array, 0, false, 23, 4); -}) -.add("ieee754 buffer", function() { - ieee754.read(buffer, 0, false, 23, 4); -}) -.add("f32 array", function() { - var pos = 0; - f8b[pos++] = array[0]; - f8b[pos++] = array[1]; - f8b[pos++] = array[2]; - f8b[pos ] = array[3]; - return f32[0]; -}) -.add("f32 buffer", function() { - var pos = 0; - f8b[pos++] = buffer[0]; - f8b[pos++] = buffer[1]; - f8b[pos++] = buffer[2]; - f8b[pos ] = buffer[3]; - return f32[0]; -}) -.add("readFloatLE buffer", function() { - buffer.readFloatLE(0, true); -}) -.run(); - -data = [ 0x9A, 0x99, 0x99, 0x99, 0x99, 0x99, 0xB9, 0x3F ]; // 0.1 LE -array = new Uint8Array(data); -buffer = Buffer.from(data); - -// raw double read speed -newSuite("double") -.add("ieee754 array", function() { - ieee754.read(array, 0, false, 52, 8); -}) -.add("ieee754 buffer", function() { - ieee754.read(buffer, 0, false, 52, 8); -}) -.add("f64 array", function() { - var pos = 0; - f8b[pos++] = array[0]; - f8b[pos++] = array[1]; - f8b[pos++] = array[2]; - f8b[pos++] = array[3]; - f8b[pos++] = array[4]; - f8b[pos++] = array[5]; - f8b[pos++] = array[6]; - f8b[pos ] = array[7]; - return f64[0]; -}) -.add("f64 buffer", function() { - var pos = 0; - f8b[pos++] = buffer[0]; - f8b[pos++] = buffer[1]; - f8b[pos++] = buffer[2]; - f8b[pos++] = buffer[3]; - f8b[pos++] = buffer[4]; - f8b[pos++] = buffer[5]; - f8b[pos++] = buffer[6]; - f8b[pos ] = buffer[7]; - return f64[0]; -}) -.add("readDoubleLE buffer", function() { - buffer.readDoubleLE(0, true); -}) -.run(); - -function readString(bytes) { - var len = bytes.length; - if (len) { - var out = new Array(len), p = 0, c = 0; - while (p < len) { - var c1 = bytes[p++]; - if (c1 < 128) - out[c++] = c1; - else if (c1 > 191 && c1 < 224) - out[c++] = (c1 & 31) << 6 | bytes[p++] & 63; - else if (c1 > 239 && c1 < 365) { - var u = ((c1 & 7) << 18 | (bytes[p++] & 63) << 12 | (bytes[p++] & 63) << 6 | bytes[p++] & 63) - 0x10000; - out[c++] = 0xD800 + (u >> 10); - out[c++] = 0xDC00 + (u & 1023); - } else - out[c++] = (c1 & 15) << 12 | (bytes[p++] & 63) << 6 | bytes[p++] & 63; - } - return String.fromCharCode.apply(String, out.slice(0, c)); - } - return ""; -} - -// raw string read speed -[ - "Lorem ipsu", - "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore ipsum." -].forEach(function(str) { - - var buffer = Buffer.from(str, "utf8"), - array = new Uint8Array(buffer.length); - for (var i = 0; i < buffer.length; ++i) - array[i] = buffer[i]; - - newSuite("string[" + str.length + "]") - .add("readString array", function() { - readString(array); - }) - .add("readString buffer", function() { - readString(buffer); - }) - .add("toString buffer", function() { - buffer.toString("utf8", 0, buffer.length); - }) - .add("utf8Slice buffer", function() { - buffer.utf8Slice(0, buffer.length); - }) - .run(); -}); diff --git a/bench/suite.js b/bench/suite.js index e8016d23e..2ba1c3267 100644 --- a/bench/suite.js +++ b/bench/suite.js @@ -4,7 +4,7 @@ module.exports = newSuite; var benchmark = require("benchmark"), chalk = require("chalk"); -var padSize = 27; +var padSize = 23; function newSuite(name) { var benches = []; @@ -20,13 +20,12 @@ function newSuite(name) { }) .on("complete", function() { if (benches.length > 1) { - var fastest = this.filter("fastest"), // eslint-disable-line no-invalid-this - fastestHz = getHz(fastest[0]); - process.stdout.write("\n" + chalk.white(pad(fastest[0].name, padSize)) + " was " + chalk.green("fastest") + "\n"); - benches.forEach(function(bench) { - if (fastest.indexOf(bench) === 0) - return; - var hz = hz = getHz(bench); + benches.sort(function(a, b) { return getHz(b) - getHz(a); }); + var fastest = benches[0], + fastestHz = getHz(fastest); + process.stdout.write("\n" + chalk.white(pad(fastest.name, padSize)) + " was " + chalk.green("fastest") + "\n"); + benches.slice(1).forEach(function(bench) { + var hz = getHz(bench); var percent = (1 - hz / fastestHz) * 100; process.stdout.write(chalk.white(pad(bench.name, padSize)) + " was " + chalk.red(percent.toFixed(1) + "% slower") + "\n"); }); diff --git a/bench/write.js b/bench/write.js deleted file mode 100644 index fb210a3d4..000000000 --- a/bench/write.js +++ /dev/null @@ -1,196 +0,0 @@ -"use strict"; -var newSuite = require("./suite"), - ieee754 = require("../lib/ieee754"); - -// This benchmark compares raw data type performance of Uint8Array and Buffer. - -var array = new Uint8Array(8); -var buffer = new Buffer(8); - -// raw fixed32 write speed -newSuite("fixed32") -.add("shift array", function() { - var val = 0x7fffffff; - array[0] = val & 255; - array[1] = val >>> 8 & 255; - array[2] = val >>> 16 & 255; - array[3] = val >>> 24; -}) -.add("shift buffer", function() { - var val = 0x7fffffff; - buffer[0] = val & 255; - buffer[1] = val >>> 8 & 255; - buffer[2] = val >>> 16 & 255; - buffer[3] = val >>> 24; -}) -.add("writeUInt32LE buffer", function() { - var val = 0x7fffffff; - buffer.writeUInt32LE(val, 0, true); -}) -.run(); - -var f64 = new Float64Array(1); -var f32 = new Float32Array(f64.buffer); -var f8b = new Uint8Array(f64.buffer); - -// raw float write speed -newSuite("float") -.add("ieee754 array", function() { - ieee754.write(array, 0.1, 0, false, 23, 4); -}) -.add("ieee754 buffer", function() { - ieee754.write(buffer, 0.1, 0, false, 23, 4); -}) -.add("f32 array", function() { - f32[0] = 0.1; - array[0] = f8b[0]; - array[0+1] = f8b[1]; - array[0+2] = f8b[2]; - array[0+3] = f8b[3]; -}) -.add("f32 buffer", function() { - f32[0] = 0.1; - buffer[0] = f8b[0]; - buffer[0+1] = f8b[1]; - buffer[0+2] = f8b[2]; - buffer[0+3] = f8b[3]; -}) -.add("writeFloatLE buffer", function() { - buffer.writeFloatLE(0.1, 0, true); -}) -.run(); - -// raw double write speed -newSuite("double") -.add("ieee754 array", function() { - ieee754.write(array, 0.1, 0, false, 52, 8); -}) -.add("ieee754 buffer", function() { - ieee754.write(buffer, 0.1, 0, false, 52, 8); -}) -.add("f64 array", function() { - f64[0] = 0.1; - array[0] = f8b[0]; - array[0+1] = f8b[1]; - array[0+2] = f8b[2]; - array[0+3] = f8b[3]; - array[0+4] = f8b[4]; - array[0+5] = f8b[5]; - array[0+6] = f8b[6]; - array[0+7] = f8b[7]; -}) -.add("f64 buffer", function() { - f64[0] = 0.1; - buffer[0] = f8b[0]; - buffer[0+1] = f8b[1]; - buffer[0+2] = f8b[2]; - buffer[0+3] = f8b[3]; - buffer[0+4] = f8b[4]; - buffer[0+5] = f8b[5]; - buffer[0+6] = f8b[6]; - buffer[0+7] = f8b[7]; -}) -.add("writeDoubleLE buffer", function() { - buffer.writeDoubleLE(0.1, 0, true); -}) -.run(); - -var source = Buffer.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); -array = new Uint8Array(16); -buffer = new Buffer(16); - -// raw bytes write speed -newSuite("bytes") -.add("set array", function() { - array.set(source, 0); -}) -.add("for array", function() { - for (var i = 0; i < source.length; ++i) - array[i] = source[i]; -}) -.add("set buffer", function() { - buffer.set(source, 0); -}) -.add("for buffer", function() { - for (var i = 0; i < source.length; ++i) - buffer[i] = source[i]; -}) -.add("copy buffer", function() { - source.copy(buffer, 0); -}) -.run(); - -function writeString(buf, pos, val) { - for (var i = 0; i < val.length; ++i) { - var c1 = val.charCodeAt(i), c2; - if (c1 < 128) { - buf[pos++] = c1; - } else if (c1 < 2048) { - buf[pos++] = c1 >> 6 | 192; - buf[pos++] = c1 & 63 | 128; - } else if ((c1 & 0xFC00) === 0xD800 && ((c2 = val.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) { - c1 = 0x10000 + ((c1 & 0x03FF) << 10) + (c2 & 0x03FF); - ++i; - buf[pos++] = c1 >> 18 | 240; - buf[pos++] = c1 >> 12 & 63 | 128; - buf[pos++] = c1 >> 6 & 63 | 128; - buf[pos++] = c1 & 63 | 128; - } else { - buf[pos++] = c1 >> 12 | 224; - buf[pos++] = c1 >> 6 & 63 | 128; - buf[pos++] = c1 & 63 | 128; - } - } -} - -/* function byteLength(val) { - var strlen = val.length >>> 0; - var len = 0; - for (var i = 0; i < strlen; ++i) { - var c1 = val.charCodeAt(i); - if (c1 < 128) - len += 1; - else if (c1 < 2048) - len += 2; - else if ((c1 & 0xFC00) === 0xD800 && (val.charCodeAt(i + 1) & 0xFC00) === 0xDC00) { - ++i; - len += 4; - } else - len += 3; - } - return len; -} */ - -array = new Uint8Array(1000); -buffer = new Buffer(1000); - -[ - "Lorem ipsu", - "Lorem ipsum dolo", - "Lorem ipsum dolor ", - "Lorem ipsum dolor s", - "Lorem ipsum dolor si", - "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore ipsum." -].forEach(function(str) { - // raw string write speed - newSuite("string[" + str.length + "]") - .add("writeString array", function() { - writeString(array, 0, str); - }) - .add("writeString buffer", function() { - writeString(buffer, 0, str); - }) - .add("write buffer", function() { - buffer.write(str, 0); - }) - .add("utf8Write buffer", function() { - buffer.utf8Write(str, 0); - }) - /* .add("byteLength array", function() { - byteLength(str) - }) - .add("byteLength buffer", function() { - Buffer.byteLength(str) - }) */ - .run(); -}); diff --git a/config/eslint.json b/config/eslint.json index 2d02d5096..da9e09d83 100644 --- a/config/eslint.json +++ b/config/eslint.json @@ -37,7 +37,7 @@ "default-case": 0, // just forces unnecessary code "dot-location": 0, // looks nicer for chainables "dot-notation": 0, // not compatible with some reserved properties - "eqeqeq": 1, + "eqeqeq": [1, "allow-null"], "guard-for-in": 1, "no-alert": 1, "no-caller": 1, @@ -45,7 +45,6 @@ "no-div-regex": 1, "no-else-return": 1, "no-empty-function": 1, - "no-eq-null": 0, // used to test if not null and not undefined "no-eval": 1, "no-extend-native": 1, "no-extra-bind": 1, diff --git a/package.json b/package.json index ead607077..b71ad76c4 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "git-raw-commits": "^1.2.0", "git-semver-tags": "^1.2.0", "glob": "^7.1.1", + "google-protobuf": "^3.2.0", "gulp": "^3.9.1", "gulp-header": "^1.8.8", "gulp-if": "^2.0.1", diff --git a/scripts/gentests.js b/scripts/gentests.js index 407bd1f85..5725a5edd 100644 --- a/scripts/gentests.js +++ b/scripts/gentests.js @@ -12,10 +12,12 @@ var fs = require("fs"), { file: "tests/data/rpc.proto", flags: [ "es6" ] }, { file: "tests/data/rpc.proto", flags: [] }, { file: "tests/data/test.proto", flags: [] }, + { file: "bench/data/bench.proto", flags: [], out: "bench/data/static_pbjs.js" } ] -.forEach(function({ file, flags }) { +.forEach(function({ file, flags, out }) { var basename = file.replace(/\.proto$/, ""); - var out = [ basename ].concat(flags).join("-") + ".js"; + if (!out) + out = [ basename ].concat(flags).join("-") + ".js"; pbjs.main([ "--target", "static-module", "--wrap", "commonjs", diff --git a/tests/other_bench.js b/tests/other_bench.js index 108ed1c97..182bb561d 100644 --- a/tests/other_bench.js +++ b/tests/other_bench.js @@ -5,13 +5,13 @@ var protobuf = require(".."), tape.test("bench.proto and bench.json", function(test) { test.plan(4); - protobuf.load("bench/bench.proto", undefined, function(err, root) { + protobuf.load(require.resolve("../bench/data/bench.proto"), undefined, function(err, root) { if (err) return test.fail(err.message); - + var Test = root.lookup("Test"); - - var data = require("../bench/bench.json"); + + var data = require("../bench/data/bench.json"); test.equal(Test.verify(data), null, "should verify our test data"); test.equal(Test.ctor.verify(data), null, "should verify our test data (static)");