aboutsummaryrefslogblamecommitdiffstats
path: root/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java
blob: 47a691224be03033f066251f01393e8fe38592d7 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                   
  
                                                        
  




                                                                      
  



                                                                         
  



                                




                                                                           




                                                                                
   
                                                    
                         
                                                                      





                                                     
      
               
                                        

                                        
                



                                                     
      
               
                                               

                                              







                                                       




                                                                              
      
                 

                                                          
                                          

                                                                     

                                                  






                                                              



                                       
      


                                                         



                                       





                                                                                
      


                                                   



                                      



                                                                               
      


                                                                  






                                                                          





                                                                             
      



                                                                          





                                                                    




                                                                                
      



                                                                               





































                                                                   
     


                                                 
      


                                                                     



                                              



                                 
      
                                                   
      
                                         
                                                                            

                                                          

                                   
 


                                                                                 
 
                 



                                             
      
                                                   
      
                                         

                                                                               

                                                           

                                   
 




                                                                                 
 
                 



                                  
      
                                                    
      
                                         
                                                                             

                                                              

                                   
 



                                                                           
 
                 



                                               
      
                                                    
      
                                         

                                                                                

                                                               

                                   
 





                                                                            
 
                 



                                 
      
                                             
      
                                         
                                                                            

                                                            

                                   
 



                                                                          
 
                 



                                 
      
                                             
      
                                         
                                                                            

                                                            

                                   
 



                                                                          
 
                 



                                                    
      



                                                        



                               



                                                                            
      
                 

                                                                        


                                                   




                                          




                                                                                
      
               

                                           



                                                       











                                                           
     
 

                                



                                                  

     
/*
 * %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.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.
     *
     * @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;
        }
        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.
     *
     * @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;
        }
        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();
        }
        return BigInteger.valueOf(val).hashCode();
    }
}