/*
 * Copyright 2008-present MongoDB, Inc.
 * Copyright 2010 The Guava Authors
 * Copyright 2011 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.bson.internal;

import java.math.BigInteger;

Utilities for treating long values as unsigned.

Similar methods are now available in Java 8, but are required here for Java 6/7 compatibility.

This class is not part of the public API and may be removed or changed at any time.

/** * Utilities for treating long values as unsigned. * * <p> * Similar methods are now available in Java 8, but are required here for Java 6/7 compatibility. * </p> * <p> * This class is not part of the public API and may be removed or changed at any time. * </p> */
public final class UnsignedLongs {
Equivalent of Long.compareUnsigned in Java 8.
Params:
  • first – the first value
  • second – the second value
Returns:0 if the values are equal, a value greater than zero if first is greater than second, a value less than zero if first is less than second
/** * Equivalent of Long.compareUnsigned in Java 8. * * @param first the first value * @param second the second value * @return 0 if the values are equal, a value greater than zero if first is greater than second, * a value less than zero if first is less than second */
public static int compare(final long first, final long second) { return compareLongs(first + Long.MIN_VALUE, second + Long.MIN_VALUE); }
Equivalent to Long.toUnsignedString in Java 8.
Params:
  • value – the long value to treat as unsigned
Returns:the string representation of unsignedLong treated as an unsigned value
/** * Equivalent to Long.toUnsignedString in Java 8. * * @param value the long value to treat as unsigned * @return the string representation of unsignedLong treated as an unsigned value */
public static String toString(final long value) { if (value >= 0) { return Long.toString(value); } else { // emulate unsigned division and then append the remainder long quotient = (value >>> 1) / 5; // Unsigned divide by 10 and floor long remainder = value - quotient * 10; return Long.toString(quotient) + remainder; } } //
Equivalent to Long.parseUnsignedLong in Java 8.
Params:
  • string – the string representation of an unsigned long
Returns:the unsigned long
/** * Equivalent to Long.parseUnsignedLong in Java 8. * * @param string the string representation of an unsigned long * @return the unsigned long */
public static long parse(final String string) { if (string.length() == 0) { throw new NumberFormatException("empty string"); } int radix = 10; int maxSafePos = MAX_SAFE_DIGITS[radix] - 1; long value = 0; for (int pos = 0; pos < string.length(); pos++) { int digit = Character.digit(string.charAt(pos), radix); if (digit == -1) { throw new NumberFormatException(string); } if (pos > maxSafePos && overflowInParse(value, digit, radix)) { throw new NumberFormatException("Too large for unsigned long: " + string); } value = (value * radix) + digit; } return value; } // Returns true if (current * radix) + digit is a number too large to be represented by an // unsigned long. This is useful for detecting overflow while parsing a string representation of a // number. private static boolean overflowInParse(final long current, final int digit, final int radix) { if (current >= 0) { if (current < MAX_VALUE_DIVS[radix]) { return false; } if (current > MAX_VALUE_DIVS[radix]) { return true; } // current == maxValueDivs[radix] return (digit > MAX_VALUE_MODS[radix]); } // current < 0: high bit is set return true; } // this is the equivalent of Long.compare in Java 7 private static int compareLongs(final long x, final long y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); } // Returns dividend / divisor, where the dividend and divisor are treated as unsigned 64-bit quantities. private static long divide(final long dividend, final long divisor) { if (divisor < 0) { // i.e., divisor >= 2^63: if (compare(dividend, divisor) < 0) { return 0; // dividend < divisor } else { return 1; // dividend >= divisor } } // Optimization - use signed division if dividend < 2^63 if (dividend >= 0) { return dividend / divisor; } // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is // guaranteed to be either exact or one less than the correct value. This follows from fact that // floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not quite // trivial. long quotient = ((dividend >>> 1) / divisor) << 1; long rem = dividend - quotient * divisor; return quotient + (compare(rem, divisor) >= 0 ? 1 : 0); } // Returns dividend % divisor, where the dividend and divisor are treated as unsigned 64-bit* quantities. private static long remainder(final long dividend, final long divisor) { if (divisor < 0) { // i.e., divisor >= 2^63: if (compare(dividend, divisor) < 0) { return dividend; // dividend < divisor } else { return dividend - divisor; // dividend >= divisor } } // Optimization - use signed modulus if dividend < 2^63 if (dividend >= 0) { return dividend % divisor; } // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is // guaranteed to be either exact or one less than the correct value. This follows from the fact // that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not // quite trivial. long quotient = ((dividend >>> 1) / divisor) << 1; long rem = dividend - quotient * divisor; return rem - (compare(rem, divisor) >= 0 ? divisor : 0); } private static final long MAX_VALUE = -1L; // Equivalent to 2^64 - 1 private static final long[] MAX_VALUE_DIVS = new long[Character.MAX_RADIX + 1]; private static final int[] MAX_VALUE_MODS = new int[Character.MAX_RADIX + 1]; private static final int[] MAX_SAFE_DIGITS = new int[Character.MAX_RADIX + 1]; static { BigInteger overflow = new BigInteger("10000000000000000", 16); for (int i = Character.MIN_RADIX; i <= Character.MAX_RADIX; i++) { MAX_VALUE_DIVS[i] = divide(MAX_VALUE, i); MAX_VALUE_MODS[i] = (int) remainder(MAX_VALUE, i); MAX_SAFE_DIGITS[i] = overflow.toString(i).length() - 1; } } private UnsignedLongs() { } }