@@ -81,17 +81,63 @@ Packet.prototype.readSInt32 = function ()
8181 return this . buffer . readInt32LE ( this . offset - 4 , true ) ;
8282} ;
8383
84- Packet . prototype . readInt64 = function ( ) {
85- return this . readInt32 ( ) + 0x100000000 * this . readInt32 ( ) ;
84+ Packet . prototype . readInt64JSNumber = function ( ) {
85+ var word0 = this . readInt32 ( ) ;
86+ var word1 = this . readInt32 ( ) ;
87+ var l = new Long ( word0 , word1 , true ) ;
88+ return l . toNumber ( ) ;
8689} ;
8790
88- Packet . prototype . readSInt64 = function ( ) {
91+ Packet . prototype . readSInt64JSNumber = function ( ) {
8992 var word0 = this . readInt32 ( ) ;
9093 var word1 = this . readInt32 ( ) ;
9194 if ( ! ( word1 & 0x80000000 ) ) {
9295 return word0 + 0x100000000 * word1 ;
9396 }
94- return - ( ( ( ( ~ word1 ) >>> 0 ) * 0x100000000 ) + ( ( ~ word0 ) >>> 0 ) + 1 ) ;
97+ var l = new Long ( word0 , word1 , false ) ;
98+ return l . toNumber ( ) ;
99+ } ;
100+
101+ Packet . prototype . readInt64String = function ( ) {
102+ var word0 = this . readInt32 ( ) ;
103+ var word1 = this . readInt32 ( ) ;
104+ var res = new Long ( word0 , word1 , true ) ;
105+ return res . toString ( ) ;
106+ } ;
107+
108+ Packet . prototype . readSInt64String = function ( ) {
109+ var word0 = this . readInt32 ( ) ;
110+ var word1 = this . readInt32 ( ) ;
111+ var res = new Long ( word0 , word1 , false ) ;
112+ return res . toString ( ) ;
113+ } ;
114+
115+ Packet . prototype . readInt64 = function ( ) {
116+ var word0 = this . readInt32 ( ) ;
117+ var word1 = this . readInt32 ( ) ;
118+ var res = new Long ( word0 , word1 , true ) ;
119+ var resNumber = res . toNumber ( )
120+ , resString = res . toString ( ) ;
121+
122+ res = resNumber . toString ( ) === resString
123+ ? resNumber
124+ : resString ;
125+
126+ return res ;
127+ } ;
128+
129+ Packet . prototype . readSInt64 = function ( ) {
130+ var word0 = this . readInt32 ( ) ;
131+ var word1 = this . readInt32 ( ) ;
132+ var res = new Long ( word0 , word1 , false ) ;
133+ var resNumber = res . toNumber ( )
134+ , resString = res . toString ( ) ;
135+
136+ res = resNumber . toString ( ) === resString
137+ ? resNumber
138+ : resString ;
139+
140+ return res ;
95141} ;
96142
97143Packet . prototype . isEOF = function ( ) {
@@ -328,17 +374,35 @@ Packet.prototype.readString = function (len) {
328374 return this . buffer . utf8Slice ( this . offset - len , this . offset ) ;
329375} ;
330376
377+ // The whole reason parse* function below exist
378+ // is because String creation is relatively expensive (at least with V8), and if we have
379+ // a buffer with "12345" content ideally we would like to bypass intermediate
380+ // "12345" string creation and directly build 12345 number out of
381+ // <Buffer 31 32 33 34 35> data.
382+ // In my benchmarks the difference is ~25M 8-digit numbers per second vs
383+ // 4.5 M using Number(packet.readLengthCodedString())
384+ // not used when size is close to max precision as series of *10 accumulate error
385+ // and approximate result mihgt be diffreent from (approximate as well) Number(bigNumStringValue))
386+ // In the futire node version if speed difference is smaller parse* functions might be removed
387+ // don't consider them as Packet public API
388+
331389var minus = '-' . charCodeAt ( 0 ) ;
332390var plus = '+' . charCodeAt ( 0 ) ;
333- // TODO: faster versions of parseInt for smaller types?
334- // discard overflow checks if we know from type definition it's safe so
335- Packet . prototype . parseInt = function ( len ) {
391+
392+ Packet . prototype . parseInt = function ( len , supportBigNumbers ) {
336393
337394 if ( len === null ) {
338395 return null ;
339396 }
340397
398+ if ( len >= 14 && ! supportBigNumbers ) {
399+ var s = this . buffer . toString ( 'ascii' , this . offset , this . offset + len ) ;
400+ this . offset += len ;
401+ return Number ( s ) ;
402+ }
403+
341404 var result = 0 ;
405+ var start = this . offset ;
342406 var end = this . offset + len ;
343407 var sign = 1 ;
344408 if ( len === 0 ) {
@@ -351,23 +415,62 @@ Packet.prototype.parseInt = function (len) {
351415 }
352416
353417 // max precise int is 9007199254740992
354- // note that we are here after handling optional +/-
355- // treat everything above 9000000000000000 as potential overflow
356418 var str ;
357419 var numDigits = end - this . offset ;
358- if ( numDigits == 16 && ( this . buffer [ this . offset ] - 48 ) > 8 ) {
359- str = this . readString ( end - this . offset ) ;
360- result = parseInt ( str , 10 ) ;
361- if ( result . toString ( ) == str ) {
362- return sign * result ;
363- } else {
420+ if ( supportBigNumbers ) {
421+ if ( numDigits >= 15 ) {
422+ str = this . readString ( end - this . offset ) ;
423+ result = parseInt ( str , 10 ) ;
424+ if ( result . toString ( ) == str ) {
425+ return sign * result ;
426+ } else {
427+ return sign == - 1 ? '-' + str : str ;
428+ }
429+ } else if ( numDigits > 16 ) {
430+ str = this . readString ( end - this . offset ) ;
364431 return sign == - 1 ? '-' + str : str ;
365432 }
366- } else if ( numDigits > 16 ) {
367- str = this . readString ( end - this . offset ) ;
368- return sign == - 1 ? '-' + str : str ;
369433 }
370434
435+ if ( this . buffer [ this . offset ] == plus ) {
436+ this . offset ++ ; // just ignore
437+ }
438+ while ( this . offset < end ) {
439+ result *= 10 ;
440+ result += this . buffer [ this . offset ] - 48 ;
441+ this . offset ++ ;
442+ }
443+ var num = result * sign ;
444+ if ( ! supportBigNumbers ) {
445+ return num ;
446+ }
447+ str = this . buffer . toString ( 'ascii' , start , end ) ;
448+ if ( num . toString ( ) == str ) {
449+ return num ;
450+ } else {
451+ return str ;
452+ }
453+ } ;
454+
455+ // note that if value of inputNumberAsString is bigger than MAX_SAFE_INTEGER
456+ // ( or smaller than MIN_SAFE_INTEGER ) the parseIntNoBigCheck result might be
457+ // different from what you would get from Number(inputNumberAsString)
458+ // String(parseIntNoBigCheck) <> String(Number(inputNumberAsString)) <> inputNumberAsString
459+ Packet . prototype . parseIntNoBigCheck = function ( len ) {
460+ if ( len === null ) {
461+ return null ;
462+ }
463+ var result = 0 ;
464+ var end = this . offset + len ;
465+ var sign = 1 ;
466+ if ( len === 0 ) {
467+ return 0 ; // TODO: assert? exception?
468+ }
469+
470+ if ( this . buffer [ this . offset ] == minus ) {
471+ this . offset ++ ;
472+ sign = - 1 ;
473+ }
371474 if ( this . buffer [ this . offset ] == plus ) {
372475 this . offset ++ ; // just ignore
373476 }
@@ -515,8 +618,12 @@ Packet.prototype.parseFloat = function (len) {
515618 return result / factor ;
516619} ;
517620
518- Packet . prototype . parseLengthCodedInt = function ( ) {
519- return this . parseInt ( this . readLengthCodedNumber ( ) ) ;
621+ Packet . prototype . parseLengthCodedIntNoBigCheck = function ( ) {
622+ return this . parseIntNoBigCheck ( this . readLengthCodedNumber ( ) ) ;
623+ } ;
624+
625+ Packet . prototype . parseLengthCodedInt = function ( supportBigNumbers ) {
626+ return this . parseInt ( this . readLengthCodedNumber ( ) , supportBigNumbers ) ;
520627} ;
521628
522629Packet . prototype . parseLengthCodedIntString = function ( ) {
0 commit comments