From d36c0c538a545fac5d9db6ba65c525246d4efa95 Mon Sep 17 00:00:00 2001 From: Feng Xiao Date: Wed, 29 Mar 2017 14:32:48 -0700 Subject: Down-integrate from google3. --- js/binary/decoder.js | 17 +++++++++++------ js/binary/decoder_test.js | 19 +++++++++++++++++++ js/binary/encoder.js | 4 ++-- js/binary/reader.js | 2 +- js/binary/utils.js | 2 +- js/binary/writer.js | 4 ++-- js/binary/writer_test.js | 2 +- js/map.js | 10 +++++----- js/message.js | 31 +++++++++++++++++++++++++------ js/message_test.js | 1 + 10 files changed, 68 insertions(+), 24 deletions(-) (limited to 'js') diff --git a/js/binary/decoder.js b/js/binary/decoder.js index 26bf3594..ad9cb01b 100644 --- a/js/binary/decoder.js +++ b/js/binary/decoder.js @@ -71,7 +71,7 @@ jspb.BinaryIterator = function(opt_decoder, opt_next, opt_elements) { */ this.nextMethod_ = null; - /** @private {Array.} */ + /** @private {?Array} */ this.elements_ = null; /** @private {number} */ @@ -100,7 +100,7 @@ jspb.BinaryIterator.prototype.init_ = this.decoder_ = opt_decoder; this.nextMethod_ = opt_next; } - this.elements_ = opt_elements ? opt_elements : null; + this.elements_ = opt_elements || null; this.cursor_ = 0; this.nextValue_ = null; this.atEnd_ = !this.decoder_ && !this.elements_; @@ -953,6 +953,7 @@ jspb.BinaryDecoder.prototype.readString = function(length) { var end = cursor + length; var codeUnits = []; + var result = ''; while (cursor < end) { var c = bytes[cursor++]; if (c < 128) { // Regular 7-bit ASCII. @@ -973,7 +974,7 @@ jspb.BinaryDecoder.prototype.readString = function(length) { var c2 = bytes[cursor++]; var c3 = bytes[cursor++]; var c4 = bytes[cursor++]; - // Characters written on 4 bytes have 21 bits for a codepoint. + // Characters written on 4 bytes have 21 bits for a codepoint. // We can't fit that on 16bit characters, so we use surrogates. var codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63); // Surrogates formula from wikipedia. @@ -986,10 +987,14 @@ jspb.BinaryDecoder.prototype.readString = function(length) { var high = ((codepoint >> 10) & 1023) + 0xD800; codeUnits.push(high, low); } + + // Avoid exceeding the maximum stack size when calling {@code apply}. + if (codeUnits.length >= 8192) { + result += String.fromCharCode.apply(null, codeUnits); + codeUnits.length = 0; + } } - // String.fromCharCode.apply is faster than manually appending characters on - // Chrome 25+, and generates no additional cons string garbage. - var result = String.fromCharCode.apply(null, codeUnits); + result += String.fromCharCode.apply(null, codeUnits); this.cursor_ = cursor; return result; }; diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js index cb8aff96..d0139e29 100644 --- a/js/binary/decoder_test.js +++ b/js/binary/decoder_test.js @@ -210,6 +210,25 @@ describe('binaryDecoderTest', function() { assertEquals(hashD, decoder.readFixedHash64()); }); + /** + * Tests reading and writing large strings + */ + it('testLargeStrings', function() { + var encoder = new jspb.BinaryEncoder(); + + var len = 150000; + var long_string = ''; + for (var i = 0; i < len; i++) { + long_string += 'a'; + } + + encoder.writeString(long_string); + + var decoder = jspb.BinaryDecoder.alloc(encoder.end()); + + assertEquals(long_string, decoder.readString(len)); + }); + /** * Test encoding and decoding utf-8. */ diff --git a/js/binary/encoder.js b/js/binary/encoder.js index aee33e7e..f25935f1 100644 --- a/js/binary/encoder.js +++ b/js/binary/encoder.js @@ -355,8 +355,8 @@ jspb.BinaryEncoder.prototype.writeInt64 = function(value) { */ jspb.BinaryEncoder.prototype.writeInt64String = function(value) { goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && - (value < jspb.BinaryConstants.TWO_TO_63)); + goog.asserts.assert((+value >= -jspb.BinaryConstants.TWO_TO_63) && + (+value < jspb.BinaryConstants.TWO_TO_63)); jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(value)); this.writeSplitFixed64(jspb.utils.split64Low, jspb.utils.split64High); }; diff --git a/js/binary/reader.js b/js/binary/reader.js index 8c5a4e88..d5d698f7 100644 --- a/js/binary/reader.js +++ b/js/binary/reader.js @@ -971,7 +971,7 @@ jspb.BinaryReader.prototype.readFixedHash64 = function() { /** * Reads a packed scalar field using the supplied raw reader function. - * @param {function()} decodeMethod + * @param {function(this:jspb.BinaryDecoder)} decodeMethod * @return {!Array} * @private */ diff --git a/js/binary/utils.js b/js/binary/utils.js index 3ecd08e9..7702020b 100644 --- a/js/binary/utils.js +++ b/js/binary/utils.js @@ -430,7 +430,7 @@ jspb.utils.joinHash64 = function(bitsLow, bitsHigh) { /** * Individual digits for number->string conversion. - * @const {!Array.} + * @const {!Array.} */ jspb.utils.DIGITS = [ '0', '1', '2', '3', '4', '5', '6', '7', diff --git a/js/binary/writer.js b/js/binary/writer.js index c3009dbb..672e94bd 100644 --- a/js/binary/writer.js +++ b/js/binary/writer.js @@ -596,8 +596,8 @@ jspb.BinaryWriter.prototype.writeSint64 = function(field, value) { */ jspb.BinaryWriter.prototype.writeSint64String = function(field, value) { if (value == null) return; - goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && - (value < jspb.BinaryConstants.TWO_TO_63)); + goog.asserts.assert((+value >= -jspb.BinaryConstants.TWO_TO_63) && + (+value < jspb.BinaryConstants.TWO_TO_63)); this.writeZigzagVarint64String_(field, value); }; diff --git a/js/binary/writer_test.js b/js/binary/writer_test.js index 83fcdf91..118eecfc 100644 --- a/js/binary/writer_test.js +++ b/js/binary/writer_test.js @@ -47,7 +47,7 @@ goog.require('jspb.BinaryWriter'); * @param {function()} func This function should throw an error when run. */ function assertFails(func) { - var e = assertThrows(func); + assertThrows(func); } diff --git a/js/map.js b/js/map.js index 4f562dbc..d423499f 100644 --- a/js/map.js +++ b/js/map.js @@ -136,7 +136,7 @@ jspb.Map.prototype.toArray = function() { * * @param {boolean=} includeInstance Whether to include the JSPB instance for * transitional soy proto support: http://goto/soy-param-migration - * @param {!function((boolean|undefined),!V):!Object=} valueToObject + * @param {!function((boolean|undefined),V):!Object=} valueToObject * The static toObject() method, if V is a message type. * @return {!Array>} */ @@ -146,7 +146,7 @@ jspb.Map.prototype.toObject = function(includeInstance, valueToObject) { for (var i = 0; i < rawArray.length; i++) { var entry = this.map_[rawArray[i][0].toString()]; this.wrapEntry_(entry); - var valueWrapper = /** @type {!V|undefined} */ (entry.valueWrapper); + var valueWrapper = /** @type {V|undefined} */ (entry.valueWrapper); if (valueWrapper) { goog.asserts.assert(valueToObject); entries.push([entry.key, valueToObject(includeInstance, valueWrapper)]); @@ -412,8 +412,8 @@ jspb.Map.prototype.has = function(key) { * @param {!jspb.BinaryWriter} writer * @param {!function(this:jspb.BinaryWriter,number,K)} keyWriterFn * The method on BinaryWriter that writes type K to the stream. - * @param {!function(this:jspb.BinaryWriter,number,V)| - * function(this:jspb.BinaryReader,V,?)} valueWriterFn + * @param {!function(this:jspb.BinaryWriter,number,V,?=)| + * function(this:jspb.BinaryWriter,number,V,?)} valueWriterFn * The method on BinaryWriter that writes type V to the stream. May be * writeMessage, in which case the second callback arg form is used. * @param {function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback @@ -509,7 +509,7 @@ jspb.Map.prototype.stringKeys_ = function() { /** - * @param {!K} key The entry's key. + * @param {K} key The entry's key. * @param {V=} opt_value The entry's value wrapper. * @constructor * @struct diff --git a/js/message.js b/js/message.js index 220a5bdb..1f6bf16b 100644 --- a/js/message.js +++ b/js/message.js @@ -106,8 +106,9 @@ jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn, /** * Stores binary-related information for a single extension field. * @param {!jspb.ExtensionFieldInfo} fieldInfo - * @param {!function(number,?)} binaryReaderFn - * @param {!function(number,?)|function(number,?,?,?,?,?)} binaryWriterFn + * @param {function(this:jspb.BinaryReader,number,?)} binaryReaderFn + * @param {function(this:jspb.BinaryWriter,number,?) + * |function(this:jspb.BinaryWriter,number,?,?,?,?,?)} binaryWriterFn * @param {function(?,?)=} opt_binaryMessageSerializeFn * @param {function(?,?)=} opt_binaryMessageDeserializeFn * @param {boolean=} opt_isPacked @@ -141,6 +142,21 @@ jspb.ExtensionFieldInfo.prototype.isMessageType = function() { /** * Base class for all JsPb messages. + * + * Several common methods (toObject, serializeBinary, in particular) are not + * defined on the prototype to encourage code patterns that minimize code bloat + * due to otherwise unused code on all protos contained in the project. + * + * If you want to call these methods on a generic message, either + * pass in your instance of method as a parameter: + * someFunction(instanceOfKnownProto, + * KnownProtoClass.prototype.serializeBinary); + * or use a lambda that knows the type: + * someFunction(()=>instanceOfKnownProto.serializeBinary()); + * or, if you don't care about code size, just suppress the + * WARNING - Property serializeBinary never defined on jspb.Message + * and call it the intuitive way. + * * @constructor * @struct */ @@ -524,7 +540,7 @@ jspb.Message.toObjectExtension = function(proto, obj, extensions, * @param {!jspb.Message} proto The proto whose extensions to convert. * @param {*} writer The binary-format writer to write to. * @param {!Object} extensions The proto class' registered extensions. - * @param {function(jspb.ExtensionFieldInfo) : *} getExtensionFn The proto + * @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo) : *} getExtensionFn The proto * class' getExtension function. Passed for effective dead code removal. */ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions, @@ -570,10 +586,13 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions, * Reads an extension field from the given reader and, if a valid extension, * sets the extension value. * @param {!jspb.Message} msg A jspb proto. - * @param {{skipField:function(),getFieldNumber:function():number}} reader + * @param {{ + * skipField:function(this:jspb.BinaryReader), + * getFieldNumber:function(this:jspb.BinaryReader):number + * }} reader * @param {!Object} extensions The extensions object. - * @param {function(jspb.ExtensionFieldInfo)} getExtensionFn - * @param {function(jspb.ExtensionFieldInfo, ?)} setExtensionFn + * @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo)} getExtensionFn + * @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo, ?)} setExtensionFn */ jspb.Message.readBinaryExtension = function(msg, reader, extensions, getExtensionFn, setExtensionFn) { diff --git a/js/message_test.js b/js/message_test.js index 2298742d..dc0ae211 100644 --- a/js/message_test.js +++ b/js/message_test.js @@ -40,6 +40,7 @@ goog.require('goog.userAgent'); goog.require('jspb.Message'); // CommonJS-LoadFromFile: test8_pb proto.jspb.exttest.nested +goog.require('proto.jspb.exttest.nested.TestNestedExtensionsMessage'); goog.require('proto.jspb.exttest.nested.TestOuterMessage'); // CommonJS-LoadFromFile: test5_pb proto.jspb.exttest.beta -- cgit v1.2.3