/* * © Copyright FOCONIS AG, 2014 * * 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.openntf.formula; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * Valueholder to hold single or multiple values. * * When evaluating a formula, every String/int/double value is wrapped in a "ValueHolder". The holder has several get-methods to return the * different types. You always must check the datatype before calling one of the getters, because a ValueHolder that contains Strings cannot * return * * The code itself might look strange, but this was done to be as fast as possible * * @author Roland Praml, Foconis AG * */ public class ValueHolderNumber extends ValueHolder implements Serializable { private static final long serialVersionUID = 8290517470597891417L; private final int valuesI[]; private final double valuesD[]; ValueHolderNumber(final int size) { valuesI = new int[size]; valuesD = new double[size]; } @Override public Number getObject(final int i) { switch (dataType) { //case ERROR: // throw currentError; case INTEGER: return getInt(i); case DOUBLE: return getDouble(i); default: throw new IllegalStateException(dataType + " is not supported here"); } } /* (non-Javadoc) * @see org.openntf.formula.ValueHolder#getInt(int) */ @Override public int getInt(final int i) { switch (dataType) { //case ERROR: // throw currentError; case INTEGER: if (i < size) { return valuesI[i]; } else { return valuesI[size - 1]; } case DOUBLE: if (i < size) { return (int) valuesD[i]; } else { return (int) valuesD[size - 1]; } default: throw new IllegalStateException(dataType + " is not supported here"); } } /* (non-Javadoc) * @see org.openntf.formula.ValueHolder#getDouble(int) */ @Override public double getDouble(final int i) { switch (dataType) { //case ERROR: // throw currentError; case INTEGER: if (i < size) { return valuesI[i]; } else { return valuesI[size - 1]; } case DOUBLE: if (i < size) { return valuesD[i]; } else { return valuesD[size - 1]; } default: throw new IllegalStateException(dataType + " is not supported here"); } } /* (non-Javadoc) * @see org.openntf.formula.ValueHolder#add(java.lang.Boolean) */ @Override public boolean add(final int i) { checkImmutable(); switch (dataType) { case ERROR: return false; case _UNSET: dataType = DataType.INTEGER; // fall through case INTEGER: valuesI[size] = i; break; case DOUBLE: break; default: return super.add(i); } valuesD[size++] = i; // We also save the int as double return true; } /* (non-Javadoc) * @see org.openntf.formula.ValueHolder#add(java.lang.Boolean) */ @Override public boolean add(final double d) { checkImmutable(); switch (dataType) { case ERROR: return false; case _UNSET: case INTEGER: if (Integer.MIN_VALUE < d && d < Integer.MAX_VALUE && d == (valuesI[size] = (int) d)) { dataType = DataType.INTEGER; } else { dataType = DataType.DOUBLE; // upconvert to double } break; case DOUBLE: break; default: return super.add(d); } valuesD[size++] = d; // We also save the int as double return true; } @Override public boolean addAll(final ValueHolder other) { checkImmutable(); if (dataType == DataType.ERROR) return false; switch (other.dataType) { case _UNSET: return false; // we do not add unset case DOUBLE: dataType = DataType.DOUBLE; break; case INTEGER: if (dataType != DataType.DOUBLE) { // do not downconvert dataType = DataType.INTEGER; } break; default: return super.addAll(other); } ValueHolderNumber toAdd = (ValueHolderNumber) other; System.arraycopy(toAdd.valuesI, 0, valuesI, size, toAdd.size); System.arraycopy(toAdd.valuesD, 0, valuesD, size, toAdd.size); size += other.size; return true; } @Override public List<Object> toList() throws EvaluateException { throwError(); List<Object> ret = new ArrayList<Object>(size); if (dataType == DataType.INTEGER) { for (int i = 0; i < size; i++) { ret.add(valuesI[i]); } } else { for (int i = 0; i < size; i++) { ret.add(valuesD[i]); } } return ret; } @Override public ValueHolder newInstance(final int size) { return new ValueHolderNumber(size); } @Override public void swap(final int i, final int j) { int tmpI = valuesI[i]; valuesI[i] = valuesI[j]; valuesI[j] = tmpI; double tmpD = valuesD[i]; valuesD[i] = valuesD[j]; valuesD[j] = tmpD; } @Override public String quoteValue() throws EvaluateException { throwError(); StringBuilder sb = new StringBuilder(); if (dataType == DataType.DOUBLE) { // TODO: this does not work yet for DE throw new UnsupportedOperationException("This is not yet locale compatible. So it is not implemented."); } sb.append(getInt(0)); for (int i = 1; i < valuesD.length; i++) { sb.append(':'); sb.append(getInt(i)); } return sb.toString(); } }