/**
* Copyright (C) 2010 dennis zhuang (killme2008@gmail.com)
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
**/
package com.googlecode.aviator.runtime.type;
import java.util.Map;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.exception.ExpressionRuntimeException;
import com.googlecode.aviator.utils.TypeUtils;
/**
* Aviator long type
*
* @author dennis
*
*/
public class AviatorLong extends AviatorNumber {
private static class LongCache {
private LongCache() {
}
static final AviatorLong cache[] = new AviatorLong[256];
static {
for (long i = 0; i < cache.length; i++) {
cache[(int) i] = new AviatorLong(i - 128);
}
}
}
public AviatorLong(Number number) {
super(number);
}
public static AviatorLong valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int) l + offset];
}
return new AviatorLong(l);
}
public static AviatorLong valueOf(Long l) {
return valueOf(l.longValue());
}
@Override
public AviatorObject neg(Map<String, Object> env) {
return AviatorLong.valueOf(-this.number.longValue());
}
@Override
public int innerCompare(AviatorNumber other) {
switch (other.getAviatorType()) {
case BigInt:
return this.toBigInt().compareTo(other.toBigInt());
case Decimal:
return this.toDecimal().compareTo(other.toDecimal());
case Long:
return TypeUtils.comapreLong(this.longValue(), other.longValue());
case Double:
return Double.compare(this.number.doubleValue(), other.doubleValue());
default:
throw new ExpressionRuntimeException("Could not compare " + this + " with " + other);
}
}
@Override
public AviatorObject innerDiv(AviatorNumber other) {
switch (other.getAviatorType()) {
case BigInt:
return AviatorBigInt.valueOf(this.toBigInt().divide(other.toBigInt()));
case Decimal:
return AviatorDecimal
.valueOf(this.toDecimal().divide(other.toDecimal(), AviatorEvaluator.getMathContext()));
case Long:
return AviatorLong.valueOf(this.number.longValue() / other.longValue());
default:
return new AviatorDouble(this.number.longValue() / other.doubleValue());
}
}
@Override
public AviatorObject innerAdd(AviatorNumber other) {
switch (other.getAviatorType()) {
case BigInt:
return AviatorBigInt.valueOf(this.toBigInt().add(other.toBigInt()));
case Decimal:
return AviatorDecimal.valueOf(this.toDecimal().add(other.toDecimal(), AviatorEvaluator.getMathContext()));
case Long:
return AviatorLong.valueOf(this.number.longValue() + other.longValue());
default:
return new AviatorDouble(this.number.longValue() + other.doubleValue());
}
}
@Override
public AviatorObject innerMod(AviatorNumber other) {
switch (other.getAviatorType()) {
case BigInt:
return AviatorBigInt.valueOf(this.toBigInt().mod(other.toBigInt()));
case Decimal:
return AviatorDecimal.valueOf(this.toDecimal().remainder(other.toDecimal(),
AviatorEvaluator.getMathContext()));
case Long:
return AviatorLong.valueOf(this.number.longValue() % other.longValue());
default:
return new AviatorDouble(this.number.longValue() % other.doubleValue());
}
}
@Override
public AviatorObject innerMult(AviatorNumber other) {
switch (other.getAviatorType()) {
case BigInt:
return AviatorBigInt.valueOf(this.toBigInt().multiply(other.toBigInt()));
case Decimal:
return AviatorDecimal.valueOf(this.toDecimal().multiply(other.toDecimal(),
AviatorEvaluator.getMathContext()));
case Long:
return AviatorLong.valueOf(this.number.longValue() * other.longValue());
default:
return new AviatorDouble(this.number.longValue() * other.doubleValue());
}
}
protected void ensureLong(AviatorObject other) {
if (other.getAviatorType() != AviatorType.Long) {
throw new ExpressionRuntimeException(other + " is not long type,could not be used as a bit operand.");
}
}
@Override
public AviatorObject bitAnd(AviatorObject other, Map<String, Object> env) {
switch (other.getAviatorType()) {
case BigInt:
case Decimal:
case Long:
case Double:
return this.innerBitAnd(other);
case JavaType:
AviatorJavaType otherJavaType = (AviatorJavaType) other;
final Object otherValue = otherJavaType.getValue(env);
if (otherValue instanceof Number) {
return this.innerBitAnd(AviatorNumber.valueOf(otherValue));
}
else {
return super.bitAnd(other, env);
}
default:
return super.bitAnd(other, env);
}
}
protected AviatorObject innerBitAnd(AviatorObject other) {
this.ensureLong(other);
AviatorLong otherLong = (AviatorLong) other;
return AviatorLong.valueOf(this.number.longValue() & otherLong.longValue());
}
protected AviatorObject innerBitOr(AviatorObject other) {
this.ensureLong(other);
AviatorLong otherLong = (AviatorLong) other;
return AviatorLong.valueOf(this.number.longValue() | otherLong.longValue());
}
protected AviatorObject innerBitXor(AviatorObject other) {
this.ensureLong(other);
AviatorLong otherLong = (AviatorLong) other;
return AviatorLong.valueOf(this.number.longValue() ^ otherLong.longValue());
}
protected AviatorObject innerShiftLeft(AviatorObject other) {
this.ensureLong(other);
AviatorLong otherLong = (AviatorLong) other;
return AviatorLong.valueOf(this.number.longValue() << otherLong.longValue());
}
protected AviatorObject innerShiftRight(AviatorObject other) {
this.ensureLong(other);
AviatorLong otherLong = (AviatorLong) other;
return AviatorLong.valueOf(this.number.longValue() >> otherLong.longValue());
}
protected AviatorObject innerUnsignedShiftRight(AviatorObject other) {
this.ensureLong(other);
AviatorLong otherLong = (AviatorLong) other;
return AviatorLong.valueOf(this.number.longValue() >>> otherLong.longValue());
}
@Override
public AviatorObject bitNot(Map<String, Object> env) {
return AviatorLong.valueOf(~this.number.longValue());
}
@Override
public AviatorObject bitOr(AviatorObject other, Map<String, Object> env) {
switch (other.getAviatorType()) {
case BigInt:
case Decimal:
case Long:
case Double:
return this.innerBitOr(other);
case JavaType:
AviatorJavaType otherJavaType = (AviatorJavaType) other;
final Object otherValue = otherJavaType.getValue(env);
if (otherValue instanceof Number) {
return this.innerBitOr(AviatorNumber.valueOf(otherValue));
}
else {
return super.bitOr(other, env);
}
default:
return super.bitOr(other, env);
}
}
@Override
public AviatorObject bitXor(AviatorObject other, Map<String, Object> env) {
switch (other.getAviatorType()) {
case BigInt:
case Decimal:
case Long:
case Double:
return this.innerBitXor(other);
case JavaType:
AviatorJavaType otherJavaType = (AviatorJavaType) other;
final Object otherValue = otherJavaType.getValue(env);
if (otherValue instanceof Number) {
return this.innerBitXor(AviatorNumber.valueOf(otherValue));
}
else {
return super.bitXor(other, env);
}
default:
return super.bitXor(other, env);
}
}
@Override
public AviatorObject shiftLeft(AviatorObject other, Map<String, Object> env) {
switch (other.getAviatorType()) {
case BigInt:
case Decimal:
case Long:
case Double:
return this.innerShiftLeft(other);
case JavaType:
AviatorJavaType otherJavaType = (AviatorJavaType) other;
final Object otherValue = otherJavaType.getValue(env);
if (otherValue instanceof Number) {
return this.innerShiftLeft(AviatorNumber.valueOf(otherValue));
}
else {
return super.shiftLeft(other, env);
}
default:
return super.shiftLeft(other, env);
}
}
@Override
public AviatorObject shiftRight(AviatorObject other, Map<String, Object> env) {
switch (other.getAviatorType()) {
case BigInt:
case Decimal:
case Long:
case Double:
return this.innerShiftRight(other);
case JavaType:
AviatorJavaType otherJavaType = (AviatorJavaType) other;
final Object otherValue = otherJavaType.getValue(env);
if (otherValue instanceof Number) {
return this.innerShiftRight(AviatorNumber.valueOf(otherValue));
}
else {
return super.shiftRight(other, env);
}
default:
return super.shiftRight(other, env);
}
}
@Override
public AviatorObject unsignedShiftRight(AviatorObject other, Map<String, Object> env) {
switch (other.getAviatorType()) {
case BigInt:
case Decimal:
case Long:
case Double:
return this.innerUnsignedShiftRight(other);
case JavaType:
AviatorJavaType otherJavaType = (AviatorJavaType) other;
final Object otherValue = otherJavaType.getValue(env);
if (otherValue instanceof Number) {
return this.innerUnsignedShiftRight(AviatorNumber.valueOf(otherValue));
}
else {
return super.unsignedShiftRight(other, env);
}
default:
return super.unsignedShiftRight(other, env);
}
}
@Override
public AviatorObject innerSub(AviatorNumber other) {
switch (other.getAviatorType()) {
case BigInt:
return AviatorBigInt.valueOf(this.toBigInt().subtract(other.toBigInt()));
case Decimal:
return AviatorDecimal.valueOf(this.toDecimal().subtract(other.toDecimal(),
AviatorEvaluator.getMathContext()));
case Long:
return AviatorLong.valueOf(this.number.longValue() - other.longValue());
default:
return new AviatorDouble(this.number.longValue() - other.doubleValue());
}
}
@Override
public AviatorType getAviatorType() {
return AviatorType.Long;
}
}