package org.infinispan.objectfilter.impl.aggregation; import java.math.BigDecimal; import java.math.BigInteger; /** * Computes the sum of {@link Number}s. Returns {@link Long} when applied to fields of integral types (other than * BigInteger); Double when applied to state-fields of floating point types; BigInteger when applied to state-fields of * type BigInteger; and BigDecimal when applied to state-fields of type BigDecimal. Nulls are excluded from the * computation. If there are no remaining non-null values to which the aggregate function can be applied, the result of * the aggregate function is {@code null}. * * @author anistor@redhat.com * @since 8.0 */ final class SumAccumulator extends FieldAccumulator { private final Class<? extends Number> fieldType; SumAccumulator(int inPos, int outPos, Class<?> fieldType) { super(inPos, outPos); if (!Number.class.isAssignableFrom(fieldType)) { throw new IllegalStateException("Aggregation SUM cannot be applied to property of type " + fieldType.getName()); } this.fieldType = (Class<? extends Number>) fieldType; } @Override public void init(Object[] accRow) { if (fieldType == Double.class || fieldType == Float.class) { accRow[outPos] = new DoubleStat(); } } @Override public void update(Object[] accRow, Object val) { if (val != null) { Number value = (Number) val; if (fieldType == Double.class || fieldType == Float.class) { ((DoubleStat) accRow[outPos]).update(value.doubleValue()); } else if (fieldType == Long.class || fieldType == Integer.class || fieldType == Byte.class || fieldType == Short.class) { value = value.longValue(); Number sum = (Number) accRow[outPos]; if (sum != null) { if (fieldType == Long.class) { value = sum.longValue() + value.longValue(); } else if (fieldType == BigInteger.class) { value = ((BigInteger) sum).add((BigInteger) value); } else if (fieldType == BigDecimal.class) { value = ((BigDecimal) sum).add((BigDecimal) value); } else { // byte, short, int value = sum.intValue() + value.intValue(); } } accRow[outPos] = value; } } } @Override protected void merge(Object[] accRow, Object value) { if (value instanceof DoubleStat) { value = ((DoubleStat) value).getSum(); } else if (value instanceof Counter) { value = ((Counter) value).getValue(); } update(accRow, value); } @Override protected void finish(Object[] accRow) { if (fieldType == Double.class || fieldType == Float.class) { accRow[outPos] = ((DoubleStat) accRow[outPos]).getSum(); } } /** * Determine the output type of this accumulator. */ static Class<?> getOutputType(Class<?> fieldType) { if (!Number.class.isAssignableFrom(fieldType)) { throw new IllegalStateException("Aggregation SUM cannot be applied to property of type " + fieldType.getName()); } if (fieldType == Double.class || fieldType == Float.class) { return Double.class; } if (fieldType == Long.class || fieldType == Integer.class || fieldType == Byte.class || fieldType == Short.class) { return Long.class; } return fieldType; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || o.getClass() != getClass()) return false; SumAccumulator other = (SumAccumulator) o; return inPos == other.inPos && outPos == other.outPos && fieldType == other.fieldType; } @Override public int hashCode() { return 31 * super.hashCode() + fieldType.hashCode(); } }