1ffe3c632Sopenharmony_ci/**
2ffe3c632Sopenharmony_ci * @fileoverview Protobufs Int64 representation.
3ffe3c632Sopenharmony_ci */
4ffe3c632Sopenharmony_cigoog.module('protobuf.Int64');
5ffe3c632Sopenharmony_ci
6ffe3c632Sopenharmony_ciconst Long = goog.require('goog.math.Long');
7ffe3c632Sopenharmony_ciconst {assert} = goog.require('goog.asserts');
8ffe3c632Sopenharmony_ci
9ffe3c632Sopenharmony_ci/**
10ffe3c632Sopenharmony_ci * A container for protobufs Int64/Uint64 data type.
11ffe3c632Sopenharmony_ci * @final
12ffe3c632Sopenharmony_ci */
13ffe3c632Sopenharmony_ciclass Int64 {
14ffe3c632Sopenharmony_ci  /** @return {!Int64} */
15ffe3c632Sopenharmony_ci  static getZero() {
16ffe3c632Sopenharmony_ci    return ZERO;
17ffe3c632Sopenharmony_ci  }
18ffe3c632Sopenharmony_ci
19ffe3c632Sopenharmony_ci  /** @return {!Int64} */
20ffe3c632Sopenharmony_ci  static getMinValue() {
21ffe3c632Sopenharmony_ci    return MIN_VALUE;
22ffe3c632Sopenharmony_ci  }
23ffe3c632Sopenharmony_ci
24ffe3c632Sopenharmony_ci  /** @return {!Int64} */
25ffe3c632Sopenharmony_ci  static getMaxValue() {
26ffe3c632Sopenharmony_ci    return MAX_VALUE;
27ffe3c632Sopenharmony_ci  }
28ffe3c632Sopenharmony_ci
29ffe3c632Sopenharmony_ci  /**
30ffe3c632Sopenharmony_ci   * Constructs a Int64 given two 32 bit numbers
31ffe3c632Sopenharmony_ci   * @param {number} lowBits
32ffe3c632Sopenharmony_ci   * @param {number} highBits
33ffe3c632Sopenharmony_ci   * @return {!Int64}
34ffe3c632Sopenharmony_ci   */
35ffe3c632Sopenharmony_ci  static fromBits(lowBits, highBits) {
36ffe3c632Sopenharmony_ci    return new Int64(lowBits, highBits);
37ffe3c632Sopenharmony_ci  }
38ffe3c632Sopenharmony_ci
39ffe3c632Sopenharmony_ci  /**
40ffe3c632Sopenharmony_ci   * Constructs an Int64 from a signed 32 bit number.
41ffe3c632Sopenharmony_ci   * @param {number} value
42ffe3c632Sopenharmony_ci   * @return {!Int64}
43ffe3c632Sopenharmony_ci   */
44ffe3c632Sopenharmony_ci  static fromInt(value) {
45ffe3c632Sopenharmony_ci    // TODO: Use our own checking system here.
46ffe3c632Sopenharmony_ci    assert(value === (value | 0), 'value should be a 32-bit integer');
47ffe3c632Sopenharmony_ci    // Right shift 31 bits so all high bits are equal to the sign bit.
48ffe3c632Sopenharmony_ci    // Note: cannot use >> 32, because (1 >> 32) = 1 (!).
49ffe3c632Sopenharmony_ci    const signExtendedHighBits = value >> 31;
50ffe3c632Sopenharmony_ci    return new Int64(value, signExtendedHighBits);
51ffe3c632Sopenharmony_ci  }
52ffe3c632Sopenharmony_ci
53ffe3c632Sopenharmony_ci  /**
54ffe3c632Sopenharmony_ci   * Constructs an Int64 from a number (over 32 bits).
55ffe3c632Sopenharmony_ci   * @param {number} value
56ffe3c632Sopenharmony_ci   * @return {!Int64}
57ffe3c632Sopenharmony_ci   */
58ffe3c632Sopenharmony_ci  static fromNumber(value) {
59ffe3c632Sopenharmony_ci    if (value > 0) {
60ffe3c632Sopenharmony_ci      return new Int64(value, value / TWO_PWR_32_DBL);
61ffe3c632Sopenharmony_ci    } else if (value < 0) {
62ffe3c632Sopenharmony_ci      return negate(-value, -value / TWO_PWR_32_DBL);
63ffe3c632Sopenharmony_ci    }
64ffe3c632Sopenharmony_ci    return ZERO;
65ffe3c632Sopenharmony_ci  }
66ffe3c632Sopenharmony_ci
67ffe3c632Sopenharmony_ci  /**
68ffe3c632Sopenharmony_ci   * Construct an Int64 from a signed decimal string.
69ffe3c632Sopenharmony_ci   * @param {string} value
70ffe3c632Sopenharmony_ci   * @return {!Int64}
71ffe3c632Sopenharmony_ci   */
72ffe3c632Sopenharmony_ci  static fromDecimalString(value) {
73ffe3c632Sopenharmony_ci    // TODO: Use our own checking system here.
74ffe3c632Sopenharmony_ci    assert(value.length > 0);
75ffe3c632Sopenharmony_ci    // The basic Number conversion loses precision, but we can use it for
76ffe3c632Sopenharmony_ci    // a quick validation that the format is correct and it is an integer.
77ffe3c632Sopenharmony_ci    assert(Math.floor(Number(value)).toString().length == value.length);
78ffe3c632Sopenharmony_ci    return decimalStringToInt64(value);
79ffe3c632Sopenharmony_ci  }
80ffe3c632Sopenharmony_ci
81ffe3c632Sopenharmony_ci  /**
82ffe3c632Sopenharmony_ci   * Construct an Int64 from a signed hexadecimal string.
83ffe3c632Sopenharmony_ci   * @param {string} value
84ffe3c632Sopenharmony_ci   * @return {!Int64}
85ffe3c632Sopenharmony_ci   */
86ffe3c632Sopenharmony_ci  static fromHexString(value) {
87ffe3c632Sopenharmony_ci    // TODO: Use our own checking system here.
88ffe3c632Sopenharmony_ci    assert(value.length > 0);
89ffe3c632Sopenharmony_ci    assert(value.slice(0, 2) == '0x' || value.slice(0, 3) == '-0x');
90ffe3c632Sopenharmony_ci    const minus = value[0] === '-';
91ffe3c632Sopenharmony_ci    // Strip the 0x or -0x prefix.
92ffe3c632Sopenharmony_ci    value = value.slice(minus ? 3 : 2);
93ffe3c632Sopenharmony_ci    const lowBits = parseInt(value.slice(-8), 16);
94ffe3c632Sopenharmony_ci    const highBits = parseInt(value.slice(-16, -8) || '', 16);
95ffe3c632Sopenharmony_ci    return (minus ? negate : Int64.fromBits)(lowBits, highBits);
96ffe3c632Sopenharmony_ci  }
97ffe3c632Sopenharmony_ci
98ffe3c632Sopenharmony_ci  // Note to the reader:
99ffe3c632Sopenharmony_ci  // goog.math.Long suffers from a code size issue. JsCompiler almost always
100ffe3c632Sopenharmony_ci  // considers toString methods to be alive in a program. So if you are
101ffe3c632Sopenharmony_ci  // constructing a Long instance the toString method is assumed to be live.
102ffe3c632Sopenharmony_ci  // Unfortunately Long's toString method makes a large chunk of code alive
103ffe3c632Sopenharmony_ci  // of the entire class adding 1.3kB (gzip) of extra code size.
104ffe3c632Sopenharmony_ci  // Callers that are sensitive to code size and are not using Long already
105ffe3c632Sopenharmony_ci  // should avoid calling this method.
106ffe3c632Sopenharmony_ci  /**
107ffe3c632Sopenharmony_ci   * Creates an Int64 instance from a Long value.
108ffe3c632Sopenharmony_ci   * @param {!Long} value
109ffe3c632Sopenharmony_ci   * @return {!Int64}
110ffe3c632Sopenharmony_ci   */
111ffe3c632Sopenharmony_ci  static fromLong(value) {
112ffe3c632Sopenharmony_ci    return new Int64(value.getLowBits(), value.getHighBits());
113ffe3c632Sopenharmony_ci  }
114ffe3c632Sopenharmony_ci
115ffe3c632Sopenharmony_ci  /**
116ffe3c632Sopenharmony_ci   * @param {number} lowBits
117ffe3c632Sopenharmony_ci   * @param {number} highBits
118ffe3c632Sopenharmony_ci   * @private
119ffe3c632Sopenharmony_ci   */
120ffe3c632Sopenharmony_ci  constructor(lowBits, highBits) {
121ffe3c632Sopenharmony_ci    /** @const @private {number} */
122ffe3c632Sopenharmony_ci    this.lowBits_ = lowBits | 0;
123ffe3c632Sopenharmony_ci    /** @const @private {number} */
124ffe3c632Sopenharmony_ci    this.highBits_ = highBits | 0;
125ffe3c632Sopenharmony_ci  }
126ffe3c632Sopenharmony_ci
127ffe3c632Sopenharmony_ci  /**
128ffe3c632Sopenharmony_ci   * Returns the int64 value as a JavaScript number. This will lose precision
129ffe3c632Sopenharmony_ci   * if the number is outside of the safe range for JavaScript of 53 bits
130ffe3c632Sopenharmony_ci   * precision.
131ffe3c632Sopenharmony_ci   * @return {number}
132ffe3c632Sopenharmony_ci   */
133ffe3c632Sopenharmony_ci  asNumber() {
134ffe3c632Sopenharmony_ci    const result = this.highBits_ * TWO_PWR_32_DBL + this.getLowBitsUnsigned();
135ffe3c632Sopenharmony_ci    // TODO: Use our own checking system here.
136ffe3c632Sopenharmony_ci    assert(
137ffe3c632Sopenharmony_ci        Number.isSafeInteger(result), 'conversion to number loses precision.');
138ffe3c632Sopenharmony_ci    return result;
139ffe3c632Sopenharmony_ci  }
140ffe3c632Sopenharmony_ci
141ffe3c632Sopenharmony_ci  // Note to the reader:
142ffe3c632Sopenharmony_ci  // goog.math.Long suffers from a code size issue. JsCompiler almost always
143ffe3c632Sopenharmony_ci  // considers toString methods to be alive in a program. So if you are
144ffe3c632Sopenharmony_ci  // constructing a Long instance the toString method is assumed to be live.
145ffe3c632Sopenharmony_ci  // Unfortunately Long's toString method makes a large chunk of code alive
146ffe3c632Sopenharmony_ci  // of the entire class adding 1.3kB (gzip) of extra code size.
147ffe3c632Sopenharmony_ci  // Callers that are sensitive to code size and are not using Long already
148ffe3c632Sopenharmony_ci  // should avoid calling this method.
149ffe3c632Sopenharmony_ci  /** @return {!Long} */
150ffe3c632Sopenharmony_ci  asLong() {
151ffe3c632Sopenharmony_ci    return Long.fromBits(this.lowBits_, this.highBits_);
152ffe3c632Sopenharmony_ci  }
153ffe3c632Sopenharmony_ci
154ffe3c632Sopenharmony_ci  /** @return {number} Signed 32-bit integer value. */
155ffe3c632Sopenharmony_ci  getLowBits() {
156ffe3c632Sopenharmony_ci    return this.lowBits_;
157ffe3c632Sopenharmony_ci  }
158ffe3c632Sopenharmony_ci
159ffe3c632Sopenharmony_ci  /** @return {number} Signed 32-bit integer value. */
160ffe3c632Sopenharmony_ci  getHighBits() {
161ffe3c632Sopenharmony_ci    return this.highBits_;
162ffe3c632Sopenharmony_ci  }
163ffe3c632Sopenharmony_ci
164ffe3c632Sopenharmony_ci  /** @return {number} Unsigned 32-bit integer. */
165ffe3c632Sopenharmony_ci  getLowBitsUnsigned() {
166ffe3c632Sopenharmony_ci    return this.lowBits_ >>> 0;
167ffe3c632Sopenharmony_ci  }
168ffe3c632Sopenharmony_ci
169ffe3c632Sopenharmony_ci  /** @return {number} Unsigned 32-bit integer. */
170ffe3c632Sopenharmony_ci  getHighBitsUnsigned() {
171ffe3c632Sopenharmony_ci    return this.highBits_ >>> 0;
172ffe3c632Sopenharmony_ci  }
173ffe3c632Sopenharmony_ci
174ffe3c632Sopenharmony_ci  /** @return {string} */
175ffe3c632Sopenharmony_ci  toSignedDecimalString() {
176ffe3c632Sopenharmony_ci    return joinSignedDecimalString(this);
177ffe3c632Sopenharmony_ci  }
178ffe3c632Sopenharmony_ci
179ffe3c632Sopenharmony_ci  /** @return {string} */
180ffe3c632Sopenharmony_ci  toUnsignedDecimalString() {
181ffe3c632Sopenharmony_ci    return joinUnsignedDecimalString(this);
182ffe3c632Sopenharmony_ci  }
183ffe3c632Sopenharmony_ci
184ffe3c632Sopenharmony_ci  /**
185ffe3c632Sopenharmony_ci   * Returns an unsigned hexadecimal string representation of the Int64.
186ffe3c632Sopenharmony_ci   * @return {string}
187ffe3c632Sopenharmony_ci   */
188ffe3c632Sopenharmony_ci  toHexString() {
189ffe3c632Sopenharmony_ci    let nibbles = new Array(16);
190ffe3c632Sopenharmony_ci    let lowBits = this.lowBits_;
191ffe3c632Sopenharmony_ci    let highBits = this.highBits_;
192ffe3c632Sopenharmony_ci    for (let highIndex = 7, lowIndex = 15; lowIndex > 7;
193ffe3c632Sopenharmony_ci         highIndex--, lowIndex--) {
194ffe3c632Sopenharmony_ci      nibbles[highIndex] = HEX_DIGITS[highBits & 0xF];
195ffe3c632Sopenharmony_ci      nibbles[lowIndex] = HEX_DIGITS[lowBits & 0xF];
196ffe3c632Sopenharmony_ci      highBits = highBits >>> 4;
197ffe3c632Sopenharmony_ci      lowBits = lowBits >>> 4;
198ffe3c632Sopenharmony_ci    }
199ffe3c632Sopenharmony_ci    // Always leave the least significant hex digit.
200ffe3c632Sopenharmony_ci    while (nibbles.length > 1 && nibbles[0] == '0') {
201ffe3c632Sopenharmony_ci      nibbles.shift();
202ffe3c632Sopenharmony_ci    }
203ffe3c632Sopenharmony_ci    return `0x${nibbles.join('')}`;
204ffe3c632Sopenharmony_ci  }
205ffe3c632Sopenharmony_ci
206ffe3c632Sopenharmony_ci  /**
207ffe3c632Sopenharmony_ci   * @param {*} other object to compare against.
208ffe3c632Sopenharmony_ci   * @return {boolean} Whether this Int64 equals the other.
209ffe3c632Sopenharmony_ci   */
210ffe3c632Sopenharmony_ci  equals(other) {
211ffe3c632Sopenharmony_ci    if (this === other) {
212ffe3c632Sopenharmony_ci      return true;
213ffe3c632Sopenharmony_ci    }
214ffe3c632Sopenharmony_ci    if (!(other instanceof Int64)) {
215ffe3c632Sopenharmony_ci      return false;
216ffe3c632Sopenharmony_ci    }
217ffe3c632Sopenharmony_ci    // Compare low parts first as there is higher chance they are different.
218ffe3c632Sopenharmony_ci    const otherInt64 = /** @type{!Int64} */ (other);
219ffe3c632Sopenharmony_ci    return (this.lowBits_ === otherInt64.lowBits_) &&
220ffe3c632Sopenharmony_ci        (this.highBits_ === otherInt64.highBits_);
221ffe3c632Sopenharmony_ci  }
222ffe3c632Sopenharmony_ci
223ffe3c632Sopenharmony_ci  /**
224ffe3c632Sopenharmony_ci   * Returns a number (int32) that is suitable for using in hashed structures.
225ffe3c632Sopenharmony_ci   * @return {number}
226ffe3c632Sopenharmony_ci   */
227ffe3c632Sopenharmony_ci  hashCode() {
228ffe3c632Sopenharmony_ci    return (31 * this.lowBits_ + 17 * this.highBits_) | 0;
229ffe3c632Sopenharmony_ci  }
230ffe3c632Sopenharmony_ci}
231ffe3c632Sopenharmony_ci
232ffe3c632Sopenharmony_ci/**
233ffe3c632Sopenharmony_ci * Losslessly converts a 64-bit unsigned integer in 32:32 split representation
234ffe3c632Sopenharmony_ci * into a decimal string.
235ffe3c632Sopenharmony_ci * @param {!Int64} int64
236ffe3c632Sopenharmony_ci * @return {string} The binary number represented as a string.
237ffe3c632Sopenharmony_ci */
238ffe3c632Sopenharmony_ciconst joinUnsignedDecimalString = (int64) => {
239ffe3c632Sopenharmony_ci  const lowBits = int64.getLowBitsUnsigned();
240ffe3c632Sopenharmony_ci  const highBits = int64.getHighBitsUnsigned();
241ffe3c632Sopenharmony_ci  // Skip the expensive conversion if the number is small enough to use the
242ffe3c632Sopenharmony_ci  // built-in conversions.
243ffe3c632Sopenharmony_ci  // Number.MAX_SAFE_INTEGER = 0x001FFFFF FFFFFFFF, thus any number with
244ffe3c632Sopenharmony_ci  // highBits <= 0x1FFFFF can be safely expressed with a double and retain
245ffe3c632Sopenharmony_ci  // integer precision.
246ffe3c632Sopenharmony_ci  // Proven by: Number.isSafeInteger(0x1FFFFF * 2**32 + 0xFFFFFFFF) == true.
247ffe3c632Sopenharmony_ci  if (highBits <= 0x1FFFFF) {
248ffe3c632Sopenharmony_ci    return String(TWO_PWR_32_DBL * highBits + lowBits);
249ffe3c632Sopenharmony_ci  }
250ffe3c632Sopenharmony_ci
251ffe3c632Sopenharmony_ci  // What this code is doing is essentially converting the input number from
252ffe3c632Sopenharmony_ci  // base-2 to base-1e7, which allows us to represent the 64-bit range with
253ffe3c632Sopenharmony_ci  // only 3 (very large) digits. Those digits are then trivial to convert to
254ffe3c632Sopenharmony_ci  // a base-10 string.
255ffe3c632Sopenharmony_ci
256ffe3c632Sopenharmony_ci  // The magic numbers used here are -
257ffe3c632Sopenharmony_ci  // 2^24 = 16777216 = (1,6777216) in base-1e7.
258ffe3c632Sopenharmony_ci  // 2^48 = 281474976710656 = (2,8147497,6710656) in base-1e7.
259ffe3c632Sopenharmony_ci
260ffe3c632Sopenharmony_ci  // Split 32:32 representation into 16:24:24 representation so our
261ffe3c632Sopenharmony_ci  // intermediate digits don't overflow.
262ffe3c632Sopenharmony_ci  const low = lowBits & LOW_24_BITS;
263ffe3c632Sopenharmony_ci  const mid = ((lowBits >>> 24) | (highBits << 8)) & LOW_24_BITS;
264ffe3c632Sopenharmony_ci  const high = (highBits >> 16) & LOW_16_BITS;
265ffe3c632Sopenharmony_ci
266ffe3c632Sopenharmony_ci  // Assemble our three base-1e7 digits, ignoring carries. The maximum
267ffe3c632Sopenharmony_ci  // value in a digit at this step is representable as a 48-bit integer, which
268ffe3c632Sopenharmony_ci  // can be stored in a 64-bit floating point number.
269ffe3c632Sopenharmony_ci  let digitA = low + (mid * 6777216) + (high * 6710656);
270ffe3c632Sopenharmony_ci  let digitB = mid + (high * 8147497);
271ffe3c632Sopenharmony_ci  let digitC = (high * 2);
272ffe3c632Sopenharmony_ci
273ffe3c632Sopenharmony_ci  // Apply carries from A to B and from B to C.
274ffe3c632Sopenharmony_ci  const base = 10000000;
275ffe3c632Sopenharmony_ci  if (digitA >= base) {
276ffe3c632Sopenharmony_ci    digitB += Math.floor(digitA / base);
277ffe3c632Sopenharmony_ci    digitA %= base;
278ffe3c632Sopenharmony_ci  }
279ffe3c632Sopenharmony_ci
280ffe3c632Sopenharmony_ci  if (digitB >= base) {
281ffe3c632Sopenharmony_ci    digitC += Math.floor(digitB / base);
282ffe3c632Sopenharmony_ci    digitB %= base;
283ffe3c632Sopenharmony_ci  }
284ffe3c632Sopenharmony_ci
285ffe3c632Sopenharmony_ci  // If digitC is 0, then we should have returned in the trivial code path
286ffe3c632Sopenharmony_ci  // at the top for non-safe integers. Given this, we can assume both digitB
287ffe3c632Sopenharmony_ci  // and digitA need leading zeros.
288ffe3c632Sopenharmony_ci  // TODO: Use our own checking system here.
289ffe3c632Sopenharmony_ci  assert(digitC);
290ffe3c632Sopenharmony_ci  return digitC + decimalFrom1e7WithLeadingZeros(digitB) +
291ffe3c632Sopenharmony_ci      decimalFrom1e7WithLeadingZeros(digitA);
292ffe3c632Sopenharmony_ci};
293ffe3c632Sopenharmony_ci
294ffe3c632Sopenharmony_ci/**
295ffe3c632Sopenharmony_ci * @param {number} digit1e7 Number < 1e7
296ffe3c632Sopenharmony_ci * @return {string} Decimal representation of digit1e7 with leading zeros.
297ffe3c632Sopenharmony_ci */
298ffe3c632Sopenharmony_ciconst decimalFrom1e7WithLeadingZeros = (digit1e7) => {
299ffe3c632Sopenharmony_ci  const partial = String(digit1e7);
300ffe3c632Sopenharmony_ci  return '0000000'.slice(partial.length) + partial;
301ffe3c632Sopenharmony_ci};
302ffe3c632Sopenharmony_ci
303ffe3c632Sopenharmony_ci/**
304ffe3c632Sopenharmony_ci * Losslessly converts a 64-bit signed integer in 32:32 split representation
305ffe3c632Sopenharmony_ci * into a decimal string.
306ffe3c632Sopenharmony_ci * @param {!Int64} int64
307ffe3c632Sopenharmony_ci * @return {string} The binary number represented as a string.
308ffe3c632Sopenharmony_ci */
309ffe3c632Sopenharmony_ciconst joinSignedDecimalString = (int64) => {
310ffe3c632Sopenharmony_ci  // If we're treating the input as a signed value and the high bit is set, do
311ffe3c632Sopenharmony_ci  // a manual two's complement conversion before the decimal conversion.
312ffe3c632Sopenharmony_ci  const negative = (int64.getHighBits() & 0x80000000);
313ffe3c632Sopenharmony_ci  if (negative) {
314ffe3c632Sopenharmony_ci    int64 = negate(int64.getLowBits(), int64.getHighBits());
315ffe3c632Sopenharmony_ci  }
316ffe3c632Sopenharmony_ci
317ffe3c632Sopenharmony_ci  const result = joinUnsignedDecimalString(int64);
318ffe3c632Sopenharmony_ci  return negative ? '-' + result : result;
319ffe3c632Sopenharmony_ci};
320ffe3c632Sopenharmony_ci
321ffe3c632Sopenharmony_ci/**
322ffe3c632Sopenharmony_ci * @param {string} dec
323ffe3c632Sopenharmony_ci * @return {!Int64}
324ffe3c632Sopenharmony_ci */
325ffe3c632Sopenharmony_ciconst decimalStringToInt64 = (dec) => {
326ffe3c632Sopenharmony_ci  // Check for minus sign.
327ffe3c632Sopenharmony_ci  const minus = dec[0] === '-';
328ffe3c632Sopenharmony_ci  if (minus) {
329ffe3c632Sopenharmony_ci    dec = dec.slice(1);
330ffe3c632Sopenharmony_ci  }
331ffe3c632Sopenharmony_ci
332ffe3c632Sopenharmony_ci  // Work 6 decimal digits at a time, acting like we're converting base 1e6
333ffe3c632Sopenharmony_ci  // digits to binary. This is safe to do with floating point math because
334ffe3c632Sopenharmony_ci  // Number.isSafeInteger(ALL_32_BITS * 1e6) == true.
335ffe3c632Sopenharmony_ci  const base = 1e6;
336ffe3c632Sopenharmony_ci  let lowBits = 0;
337ffe3c632Sopenharmony_ci  let highBits = 0;
338ffe3c632Sopenharmony_ci  function add1e6digit(begin, end = undefined) {
339ffe3c632Sopenharmony_ci    // Note: Number('') is 0.
340ffe3c632Sopenharmony_ci    const digit1e6 = Number(dec.slice(begin, end));
341ffe3c632Sopenharmony_ci    highBits *= base;
342ffe3c632Sopenharmony_ci    lowBits = lowBits * base + digit1e6;
343ffe3c632Sopenharmony_ci    // Carry bits from lowBits to
344ffe3c632Sopenharmony_ci    if (lowBits >= TWO_PWR_32_DBL) {
345ffe3c632Sopenharmony_ci      highBits = highBits + ((lowBits / TWO_PWR_32_DBL) | 0);
346ffe3c632Sopenharmony_ci      lowBits = lowBits % TWO_PWR_32_DBL;
347ffe3c632Sopenharmony_ci    }
348ffe3c632Sopenharmony_ci  }
349ffe3c632Sopenharmony_ci  add1e6digit(-24, -18);
350ffe3c632Sopenharmony_ci  add1e6digit(-18, -12);
351ffe3c632Sopenharmony_ci  add1e6digit(-12, -6);
352ffe3c632Sopenharmony_ci  add1e6digit(-6);
353ffe3c632Sopenharmony_ci
354ffe3c632Sopenharmony_ci  return (minus ? negate : Int64.fromBits)(lowBits, highBits);
355ffe3c632Sopenharmony_ci};
356ffe3c632Sopenharmony_ci
357ffe3c632Sopenharmony_ci/**
358ffe3c632Sopenharmony_ci * @param {number} lowBits
359ffe3c632Sopenharmony_ci * @param {number} highBits
360ffe3c632Sopenharmony_ci * @return {!Int64} Two's compliment negation of input.
361ffe3c632Sopenharmony_ci * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Signed_32-bit_integers
362ffe3c632Sopenharmony_ci */
363ffe3c632Sopenharmony_ciconst negate = (lowBits, highBits) => {
364ffe3c632Sopenharmony_ci  highBits = ~highBits;
365ffe3c632Sopenharmony_ci  if (lowBits) {
366ffe3c632Sopenharmony_ci    lowBits = ~lowBits + 1;
367ffe3c632Sopenharmony_ci  } else {
368ffe3c632Sopenharmony_ci    // If lowBits is 0, then bitwise-not is 0xFFFFFFFF,
369ffe3c632Sopenharmony_ci    // adding 1 to that, results in 0x100000000, which leaves
370ffe3c632Sopenharmony_ci    // the low bits 0x0 and simply adds one to the high bits.
371ffe3c632Sopenharmony_ci    highBits += 1;
372ffe3c632Sopenharmony_ci  }
373ffe3c632Sopenharmony_ci  return Int64.fromBits(lowBits, highBits);
374ffe3c632Sopenharmony_ci};
375ffe3c632Sopenharmony_ci
376ffe3c632Sopenharmony_ci/** @const {!Int64} */
377ffe3c632Sopenharmony_ciconst ZERO = new Int64(0, 0);
378ffe3c632Sopenharmony_ci
379ffe3c632Sopenharmony_ci/** @const @private {number} */
380ffe3c632Sopenharmony_ciconst LOW_16_BITS = 0xFFFF;
381ffe3c632Sopenharmony_ci
382ffe3c632Sopenharmony_ci/** @const @private {number} */
383ffe3c632Sopenharmony_ciconst LOW_24_BITS = 0xFFFFFF;
384ffe3c632Sopenharmony_ci
385ffe3c632Sopenharmony_ci/** @const @private {number} */
386ffe3c632Sopenharmony_ciconst LOW_31_BITS = 0x7FFFFFFF;
387ffe3c632Sopenharmony_ci
388ffe3c632Sopenharmony_ci/** @const @private {number} */
389ffe3c632Sopenharmony_ciconst ALL_32_BITS = 0xFFFFFFFF;
390ffe3c632Sopenharmony_ci
391ffe3c632Sopenharmony_ci/** @const {!Int64} */
392ffe3c632Sopenharmony_ciconst MAX_VALUE = Int64.fromBits(ALL_32_BITS, LOW_31_BITS);
393ffe3c632Sopenharmony_ci
394ffe3c632Sopenharmony_ci/** @const {!Int64} */
395ffe3c632Sopenharmony_ciconst MIN_VALUE = Int64.fromBits(0, 0x80000000);
396ffe3c632Sopenharmony_ci
397ffe3c632Sopenharmony_ci/** @const {number} */
398ffe3c632Sopenharmony_ciconst TWO_PWR_32_DBL = 0x100000000;
399ffe3c632Sopenharmony_ci
400ffe3c632Sopenharmony_ci/** @const {string} */
401ffe3c632Sopenharmony_ciconst HEX_DIGITS = '0123456789abcdef';
402ffe3c632Sopenharmony_ci
403ffe3c632Sopenharmony_ciexports = Int64;
404