/*
|
* %CopyrightBegin%
|
*
|
* Copyright Ericsson AB 2000-2009. All Rights Reserved.
|
*
|
* 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.
|
*
|
* %CopyrightEnd%
|
*/
|
package com.ericsson.otp.erlang;
|
|
import java.math.BigInteger;
|
|
/**
|
* Provides a Java representation of Erlang integral types. Erlang does not
|
* distinguish between different integral types, however this class and its
|
* subclasses {@link OtpErlangByte}, {@link OtpErlangChar}, {@link OtpErlangInt}
|
* , and {@link OtpErlangShort} attempt to map the Erlang types onto the various
|
* Java integral types. Two additional classes, {@link OtpErlangUInt} and
|
* {@link OtpErlangUShort} are provided for Corba compatibility. See the
|
* documentation for IC for more information.
|
*/
|
public class OtpErlangLong extends OtpErlangObject {
|
// don't change this!
|
private static final long serialVersionUID = 1610466859236755096L;
|
private long val;
|
private BigInteger bigVal = null;
|
|
/**
|
* Create an Erlang integer from the given value.
|
*
|
* @param l the long value to use.
|
*/
|
public OtpErlangLong(final long l) {
|
val = l;
|
}
|
|
/**
|
* Create an Erlang integer from the given value.
|
*
|
* @param v the big integer value to use.
|
*/
|
public OtpErlangLong(final BigInteger v) {
|
if (v == null) {
|
throw new java.lang.NullPointerException();
|
}
|
if (v.bitLength() < 64) {
|
val = v.longValue();
|
} else {
|
bigVal = v;
|
}
|
}
|
|
/**
|
* Create an Erlang integer from a stream containing an integer encoded in
|
* Erlang external format.
|
*
|
* @param buf the stream containing the encoded value.
|
* @throws OtpErlangDecodeException if the buffer does not contain a valid external
|
* representation of an Erlang integer.
|
*/
|
public OtpErlangLong(final OtpInputStream buf)
|
throws OtpErlangDecodeException {
|
final byte[] b = buf.read_integer_byte_array();
|
try {
|
val = OtpInputStream.byte_array_to_long(b, false);
|
} catch (final OtpErlangDecodeException e) {
|
bigVal = new BigInteger(b);
|
}
|
}
|
|
/**
|
* Get this number as a BigInteger.
|
*
|
* @return the value of this number, as a BigInteger.
|
*/
|
public BigInteger bigIntegerValue() {
|
if (bigVal != null) {
|
return bigVal;
|
}
|
return BigInteger.valueOf(val);
|
}
|
|
/**
|
* Get this number as a long, or rather truncate all but the least
|
* significant 64 bits from the 2's complement representation of this number
|
* and return them as a long.
|
*
|
* @return the value of this number, as a long.
|
*/
|
public long longValue() {
|
if (bigVal != null) {
|
return bigVal.longValue();
|
}
|
return val;
|
}
|
|
/**
|
* Determine if this value can be represented as a long without truncation.
|
*
|
* @return true if this value fits in a long, false otherwise.
|
*/
|
public boolean isLong() {
|
// To just chech this.bigVal is a wee bit to simple, since
|
// there just might have be a mean bignum that arrived on
|
// a stream, and was a long disguised as more than 8 byte integer.
|
if (bigVal != null) {
|
return bigVal.bitLength() < 64;
|
}
|
return true;
|
}
|
|
/**
|
* Determine if this value can be represented as an unsigned long without
|
* truncation, that is if the value is non-negative and its bit pattern
|
* completely fits in a long.
|
*
|
* @return true if this value is non-negative and fits in a long false
|
* otherwise.
|
*/
|
public boolean isULong() {
|
// Here we have the same problem as for isLong(), plus
|
// the whole range 1<<63 .. (1<<64-1) is allowed.
|
if (bigVal != null) {
|
return bigVal.signum() >= 0 && bigVal.bitLength() <= 64;
|
}
|
return val >= 0;
|
}
|
|
/**
|
* Returns the number of bits in the minimal two's-complement representation
|
* of this BigInteger, excluding a sign bit.
|
*
|
* @return number of bits in the minimal two's-complement representation of
|
* this BigInteger, excluding a sign bit.
|
*/
|
public int bitLength() {
|
if (bigVal != null) {
|
return bigVal.bitLength();
|
}
|
if (val == 0 || val == -1) {
|
return 0;
|
}
|
// Binary search for bit length
|
int i = 32; // mask length
|
long m = (1L << i) - 1; // AND mask with ones in little end
|
if (val < 0) {
|
m = ~m; // OR mask with ones in big end
|
for (int j = i >> 1; j > 0; j >>= 1) { // mask delta
|
if ((val | m) == val) { // mask >= enough
|
i -= j;
|
m >>= j; // try less bits
|
} else {
|
i += j;
|
m <<= j; // try more bits
|
}
|
}
|
if ((val | m) != val) {
|
i++; // mask < enough
|
}
|
} else {
|
for (int j = i >> 1; j > 0; j >>= 1) { // mask delta
|
if ((val & m) == val) { // mask >= enough
|
i -= j;
|
m >>= j; // try less bits
|
} else {
|
i += j;
|
m = m << j | m; // try more bits
|
}
|
}
|
if ((val & m) != val) {
|
i++; // mask < enough
|
}
|
}
|
return i;
|
}
|
|
/**
|
* Return the signum function of this object.
|
*
|
* @return -1, 0 or 1 as the value is negative, zero or positive.
|
*/
|
public int signum() {
|
if (bigVal != null) {
|
return bigVal.signum();
|
}
|
return val > 0 ? 1 : val < 0 ? -1 : 0;
|
}
|
|
/**
|
* Get this number as an int.
|
*
|
* @return the value of this number, as an int.
|
* @throws OtpErlangRangeException if the value is too large to be represented as an int.
|
*/
|
public int intValue() throws OtpErlangRangeException {
|
final long l = longValue();
|
final int i = (int) l;
|
if (i != l) {
|
throw new OtpErlangRangeException("Value too large for int: " + val);
|
}
|
return i;
|
}
|
|
/**
|
* Get this number as a non-negative int.
|
*
|
* @return the value of this number, as an int.
|
* @throws OtpErlangRangeException if the value is too large to be represented as an int, or
|
* if the value is negative.
|
*/
|
public int uIntValue() throws OtpErlangRangeException {
|
final long l = longValue();
|
final int i = (int) l;
|
if (i != l) {
|
throw new OtpErlangRangeException("Value too large for int: " + val);
|
} else if (i < 0) {
|
throw new OtpErlangRangeException("Value not positive: " + val);
|
}
|
return i;
|
}
|
|
/**
|
* Get this number as a short.
|
*
|
* @return the value of this number, as a short.
|
* @throws OtpErlangRangeException if the value is too large to be represented as a short.
|
*/
|
public short shortValue() throws OtpErlangRangeException {
|
final long l = longValue();
|
final short i = (short) l;
|
if (i != l) {
|
throw new OtpErlangRangeException("Value too large for short: "
|
+ val);
|
}
|
return i;
|
}
|
|
/**
|
* Get this number as a non-negative short.
|
*
|
* @return the value of this number, as a short.
|
* @throws OtpErlangRangeException if the value is too large to be represented as a short, or
|
* if the value is negative.
|
*/
|
public short uShortValue() throws OtpErlangRangeException {
|
final long l = longValue();
|
final short i = (short) l;
|
if (i != l) {
|
throw new OtpErlangRangeException("Value too large for short: "
|
+ val);
|
} else if (i < 0) {
|
throw new OtpErlangRangeException("Value not positive: " + val);
|
}
|
return i;
|
}
|
|
/**
|
* Get this number as a char.
|
*
|
* @return the char value of this number.
|
* @throws OtpErlangRangeException if the value is too large to be represented as a char.
|
*/
|
public char charValue() throws OtpErlangRangeException {
|
final long l = longValue();
|
final char i = (char) l;
|
if (i != l) {
|
throw new OtpErlangRangeException("Value too large for char: "
|
+ val);
|
}
|
return i;
|
}
|
|
/**
|
* Get this number as a byte.
|
*
|
* @return the byte value of this number.
|
* @throws OtpErlangRangeException if the value is too large to be represented as a byte.
|
*/
|
public byte byteValue() throws OtpErlangRangeException {
|
final long l = longValue();
|
final byte i = (byte) l;
|
if (i != l) {
|
throw new OtpErlangRangeException("Value too large for byte: "
|
+ val);
|
}
|
return i;
|
}
|
|
/**
|
* Get the string representation of this number.
|
*
|
* @return the string representation of this number.
|
*/
|
public String toString() {
|
if (bigVal != null) {
|
return "" + bigVal;
|
}
|
return "" + val;
|
}
|
|
/**
|
* Convert this number to the equivalent Erlang external representation.
|
*
|
* @param buf an output stream to which the encoded number should be
|
* written.
|
*/
|
public void encode(final OtpOutputStream buf) {
|
if (bigVal != null) {
|
buf.write_big_integer(bigVal);
|
} else {
|
buf.write_long(val);
|
}
|
}
|
|
/**
|
* Determine if two numbers are equal. Numbers are equal if they contain the
|
* same value.
|
*
|
* @param o the number to compare to.
|
* @return true if the numbers have the same value.
|
*/
|
public boolean equals(final Object o) {
|
if (!(o instanceof OtpErlangLong)) {
|
return false;
|
}
|
final OtpErlangLong that = (OtpErlangLong) o;
|
if (bigVal != null && that.bigVal != null) {
|
return bigVal.equals(that.bigVal);
|
} else if (bigVal == null && that.bigVal == null) {
|
return val == that.val;
|
}
|
return false;
|
}
|
|
protected int doHashCode() {
|
if (bigVal != null) {
|
return bigVal.hashCode();
|
}
|
return BigInteger.valueOf(val).hashCode();
|
}
|
}
|