From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- .../com/ericsson/otp/erlang/OtpErlangLong.java | 399 +++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java (limited to 'lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java') diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java new file mode 100644 index 0000000000..7e3e2a7296 --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java @@ -0,0 +1,399 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2000-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +package com.ericsson.otp.erlang; + +import java.io.Serializable; +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 implements Serializable, + Cloneable { + // don't change this! + 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 val + * the long 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. + * + * @exception 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; + } else { + 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(); + } else { + 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; + } else { + // 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(); + } else { + return val > 0 ? 1 : val < 0 ? -1 : 0; + } + } + + /** + * Get this number as an int. + * + * @return the value of this number, as an int. + * + * @exception 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. + * + * @exception 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. + * + * @exception 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. + * + * @exception 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. + * + * @exception 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. + * + * @exception 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. + */ + @Override + public String toString() { + if (bigVal != null) { + return "" + bigVal; + } else { + return "" + val; + } + } + + /** + * Convert this number to the equivalent Erlang external representation. + * + * @param buf + * an output stream to which the encoded number should be + * written. + */ + @Override + 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. + */ + @Override + 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; + } + + @Override + protected int doHashCode() { + if (bigVal != null) { + return bigVal.hashCode(); + } else { + return BigInteger.valueOf(val).hashCode(); + } + } +} -- cgit v1.2.3