package org.infinispan.objectfilter.impl.aggregation;
import org.infinispan.objectfilter.impl.logging.Log;
import org.jboss.logging.Logger;
/**
* Computes the average of {@link Number}s. The output type is always a {@link Double}. 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}.
* <p>
* The implementation uses compensated summation in order to reduce the error bound in the numerical sum compared to a
* simple summation of {@code double} values similar to the way {@link java.util.DoubleSummaryStatistics} works.
*
* @author anistor@redhat.com
* @since 8.0
*/
final class AvgAccumulator extends FieldAccumulator {
private static final Log log = Logger.getMessageLogger(Log.class, AvgAccumulator.class.getName());
AvgAccumulator(int inPos, int outPos, Class<?> fieldType) {
super(inPos, outPos);
if (!Number.class.isAssignableFrom(fieldType)) {
throw log.getAVGCannotBeAppliedToPropertyOfType(fieldType.getName());
}
}
@Override
public void init(Object[] accRow) {
accRow[outPos] = new DoubleStat();
}
@Override
public void update(Object[] accRow, Object value) {
if (value != null) {
((DoubleStat) accRow[outPos]).update(((Number) value).doubleValue());
}
}
@Override
protected void merge(Object[] accRow, Object value) {
if (value instanceof DoubleStat) {
DoubleStat avgVal = (DoubleStat) value;
if (avgVal.getCount() > 0) {
((DoubleStat) accRow[outPos]).update(avgVal.getSum(), avgVal.getCount());
}
} else {
update(accRow, value);
}
}
@Override
protected void finish(Object[] accRow) {
accRow[outPos] = ((DoubleStat) accRow[outPos]).getAvg();
}
}