1b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Protocol Buffers - Google's data interchange format
2b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Copyright 2008 Google Inc.  All rights reserved.
3b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// https://developers.google.com/protocol-buffers/
4b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
5b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Redistribution and use in source and binary forms, with or without
6b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// modification, are permitted provided that the following conditions are
7b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// met:
8b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
9b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions of source code must retain the above copyright
10b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// notice, this list of conditions and the following disclaimer.
11b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions in binary form must reproduce the above
12b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// copyright notice, this list of conditions and the following disclaimer
13b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in the documentation and/or other materials provided with the
14b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// distribution.
15b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Neither the name of Google Inc. nor the names of its
16b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// contributors may be used to endorse or promote products derived from
17b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// this software without specific prior written permission.
18b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
19b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
31b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
32b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @fileoverview This file contains helper code used by jspb.utils to
33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * handle 64-bit integer conversion to/from strings.
34b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
35b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @author cfallin@google.com (Chris Fallin)
36b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * TODO(haberman): move this to javascript/closure/math?
38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
39b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammergoog.provide('jspb.arith.Int64');
41b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammergoog.provide('jspb.arith.UInt64');
42b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * UInt64 implements some 64-bit arithmetic routines necessary for properly
45b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * handling 64-bit integer fields. It implements lossless integer arithmetic on
46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * top of JavaScript's number type, which has only 53 bits of precision, by
47b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * representing 64-bit integers as two 32-bit halves.
48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {number} lo The low 32 bits.
50b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {number} hi The high 32 bits.
51b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @constructor
52b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
53b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64 = function(lo, hi) {
54b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
55b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * The low 32 bits.
56b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @public {number}
57b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  this.lo = lo;
59b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
60b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * The high 32 bits.
61b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @public {number}
62b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
63b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  this.hi = hi;
64b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
65b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
66b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
67b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Compare two 64-bit numbers. Returns -1 if the first is
69b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * less, +1 if the first is greater, or 0 if both are equal.
70b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {!jspb.arith.UInt64} other
71b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {number}
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.cmp = function(other) {
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (this.hi < other.hi || (this.hi == other.hi && this.lo < other.lo)) {
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return -1;
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else if (this.hi == other.hi && this.lo == other.lo) {
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return 0;
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else {
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return 1;
80b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
81b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
82b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
83b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
85b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Right-shift this number by one bit.
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.UInt64}
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
88b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.rightShift = function() {
89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var hi = this.hi >>> 1;
90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var lo = (this.lo >>> 1) | ((this.hi & 1) << 31);
91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Left-shift this number by one bit.
97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.UInt64}
98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.leftShift = function() {
100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var lo = this.lo << 1;
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var hi = (this.hi << 1) | (this.lo >>> 31);
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Test the MSB.
108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {boolean}
109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.msb = function() {
111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return !!(this.hi & 0x80000000);
112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Test the LSB.
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {boolean}
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.lsb = function() {
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return !!(this.lo & 1);
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Test whether this number is zero.
126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {boolean}
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.zero = function() {
129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return this.lo == 0 && this.hi == 0;
130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Add two 64-bit numbers to produce a 64-bit number.
135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {!jspb.arith.UInt64} other
136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.UInt64}
137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.add = function(other) {
139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var lo = ((this.lo + other.lo) & 0xffffffff) >>> 0;
140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var hi =
141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (((this.hi + other.hi) & 0xffffffff) >>> 0) +
142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (((this.lo + other.lo) >= 0x100000000) ? 1 : 0);
143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Subtract two 64-bit numbers to produce a 64-bit number.
149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {!jspb.arith.UInt64} other
150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.UInt64}
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.sub = function(other) {
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var lo = ((this.lo - other.lo) & 0xffffffff) >>> 0;
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var hi =
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (((this.hi - other.hi) & 0xffffffff) >>> 0) -
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (((this.lo - other.lo) < 0) ? 1 : 0);
157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Multiply two 32-bit numbers to produce a 64-bit number.
163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {number} a The first integer:  must be in [0, 2^32-1).
164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {number} b The second integer: must be in [0, 2^32-1).
165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.UInt64}
166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.mul32x32 = function(a, b) {
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Directly multiplying two 32-bit numbers may produce up to 64 bits of
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // precision, thus losing precision because of the 53-bit mantissa of
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // JavaScript numbers. So we multiply with 16-bit digits (radix 65536)
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // instead.
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var aLow = (a & 0xffff);
173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var aHigh = (a >>> 16);
174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var bLow = (b & 0xffff);
175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var bHigh = (b >>> 16);
176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var productLow =
177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // 32-bit result, result bits 0-31, take all 32 bits
178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (aLow * bLow) +
179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // 32-bit result, result bits 16-47, take bottom 16 as our top 16
180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ((aLow * bHigh) & 0xffff) * 0x10000 +
181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // 32-bit result, result bits 16-47, take bottom 16 as our top 16
182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ((aHigh * bLow) & 0xffff) * 0x10000;
183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var productHigh =
184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // 32-bit result, result bits 32-63, take all 32 bits
185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (aHigh * bHigh) +
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // 32-bit result, result bits 16-47, take top 16 as our bottom 16
187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ((aLow * bHigh) >>> 16) +
188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // 32-bit result, result bits 16-47, take top 16 as our bottom 16
189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ((aHigh * bLow) >>> 16);
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Carry. Note that we actually have up to *two* carries due to addition of
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // three terms.
193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (productLow >= 0x100000000) {
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    productLow -= 0x100000000;
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    productHigh += 1;
196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.UInt64(productLow >>> 0, productHigh >>> 0);
199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Multiply this number by a 32-bit number, producing a 96-bit number, then
204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * truncate the top 32 bits.
205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {number} a The multiplier.
206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.UInt64}
207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.mul = function(a) {
209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Produce two parts: at bits 0-63, and 32-95.
210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var lo = jspb.arith.UInt64.mul32x32(this.lo, a);
211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var hi = jspb.arith.UInt64.mul32x32(this.hi, a);
212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Left-shift hi by 32 bits, truncating its top bits. The parts will then be
213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // aligned for addition.
214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hi.hi = hi.lo;
215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hi.lo = 0;
216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return lo.add(hi);
217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Divide a 64-bit number by a 32-bit number to produce a
222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 64-bit quotient and a 32-bit remainder.
223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {number} _divisor
224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {Array.<jspb.arith.UInt64>} array of [quotient, remainder],
225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * unless divisor is 0, in which case an empty array is returned.
226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.div = function(_divisor) {
228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (_divisor == 0) {
229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return [];
230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // We perform long division using a radix-2 algorithm, for simplicity (i.e.,
233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // one bit at a time). TODO: optimize to a radix-2^32 algorithm, taking care
234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // to get the variable shifts right.
235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var quotient = new jspb.arith.UInt64(0, 0);
236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var remainder = new jspb.arith.UInt64(this.lo, this.hi);
237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var divisor = new jspb.arith.UInt64(_divisor, 0);
238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var unit = new jspb.arith.UInt64(1, 0);
239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Left-shift the divisor and unit until the high bit of divisor is set.
241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (!divisor.msb()) {
242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    divisor = divisor.leftShift();
243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    unit = unit.leftShift();
244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Perform long division one bit at a time.
247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (!unit.zero()) {
248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If divisor < remainder, add unit to quotient and subtract divisor from
249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // remainder.
250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (divisor.cmp(remainder) <= 0) {
251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      quotient = quotient.add(unit);
252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      remainder = remainder.sub(divisor);
253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Right-shift the divisor and unit.
255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    divisor = divisor.rightShift();
256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    unit = unit.rightShift();
257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return [quotient, remainder];
260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Convert a 64-bit number to a string.
265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {string}
266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @override
267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.toString = function() {
269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var result = '';
270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var num = this;
271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (!num.zero()) {
272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    var divResult = num.div(10);
273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    var quotient = divResult[0], remainder = divResult[1];
274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    result = remainder.lo + result;
275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    num = quotient;
276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (result == '') {
278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    result = '0';
279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return result;
281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Parse a string into a 64-bit number. Returns `null` on a parse error.
286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {string} s
287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {?jspb.arith.UInt64}
288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.fromString = function(s) {
290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var result = new jspb.arith.UInt64(0, 0);
291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // optimization: reuse this instance for each digit.
292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var digit64 = new jspb.arith.UInt64(0, 0);
293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  for (var i = 0; i < s.length; i++) {
294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (s[i] < '0' || s[i] > '9') {
295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return null;
296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    var digit = parseInt(s[i], 10);
298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    digit64.lo = digit;
299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    result = result.mul(10).add(digit64);
300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return result;
302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Make a copy of the uint64.
307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.UInt64}
308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.UInt64.prototype.clone = function() {
310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.UInt64(this.lo, this.hi);
311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Int64 is like UInt64, but modifies string conversions to interpret the stored
316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 64-bit value as a twos-complement-signed integer. It does *not* support the
317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * full range of operations that UInt64 does: only add, subtract, and string
318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * conversions.
319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * N.B. that multiply and divide routines are *NOT* supported. They will throw
321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * exceptions. (They are not necessary to implement string conversions, which
322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * are the only operations we really need in jspb.)
323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {number} lo The low 32 bits.
325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {number} hi The high 32 bits.
326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @constructor
327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.Int64 = function(lo, hi) {
329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * The low 32 bits.
331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @public {number}
332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  this.lo = lo;
334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  /**
335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * The high 32 bits.
336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   * @public {number}
337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer   */
338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  this.hi = hi;
339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Add two 64-bit numbers to produce a 64-bit number.
344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {!jspb.arith.Int64} other
345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.Int64}
346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.Int64.prototype.add = function(other) {
348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var lo = ((this.lo + other.lo) & 0xffffffff) >>> 0;
349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var hi =
350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (((this.hi + other.hi) & 0xffffffff) >>> 0) +
351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (((this.lo + other.lo) >= 0x100000000) ? 1 : 0);
352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.Int64(lo >>> 0, hi >>> 0);
353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Subtract two 64-bit numbers to produce a 64-bit number.
358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {!jspb.arith.Int64} other
359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.Int64}
360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.Int64.prototype.sub = function(other) {
362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var lo = ((this.lo - other.lo) & 0xffffffff) >>> 0;
363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var hi =
364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (((this.hi - other.hi) & 0xffffffff) >>> 0) -
365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      (((this.lo - other.lo) < 0) ? 1 : 0);
366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.Int64(lo >>> 0, hi >>> 0);
367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Make a copy of the int64.
372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {!jspb.arith.Int64}
373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.Int64.prototype.clone = function() {
375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.Int64(this.lo, this.hi);
376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Convert a 64-bit number to a string.
381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {string}
382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @override
383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.Int64.prototype.toString = function() {
385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // If the number is negative, find its twos-complement inverse.
386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var sign = (this.hi & 0x80000000) != 0;
387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var num = new jspb.arith.UInt64(this.lo, this.hi);
388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (sign) {
389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    num = new jspb.arith.UInt64(0, 0).sub(num);
390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return (sign ? '-' : '') + num.toString();
392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/**
396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Parse a string into a 64-bit number. Returns `null` on a parse error.
397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param {string} s
398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return {?jspb.arith.Int64}
399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerjspb.arith.Int64.fromString = function(s) {
401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var hasNegative = (s.length > 0 && s[0] == '-');
402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (hasNegative) {
403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    s = s.substring(1);
404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  var num = jspb.arith.UInt64.fromString(s);
406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (num === null) {
407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return null;
408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (hasNegative) {
410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    num = new jspb.arith.UInt64(0, 0).sub(num);
411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return new jspb.arith.Int64(num.lo, num.hi);
413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer};
414