blob: 6df4f0c05631cf29e9deed8739f6688094102f6f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2020 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
* Andrew Johnson/IBM Corporation - also total sizes (Bytes)
*******************************************************************************/
package org.eclipse.mat.query.refined;
import java.text.Format;
import java.util.List;
import org.eclipse.mat.collect.ArrayInt;
import org.eclipse.mat.query.Bytes;
import org.eclipse.mat.query.BytesFormat;
import org.eclipse.mat.query.Column;
import org.eclipse.mat.query.IStructuredResult;
import org.eclipse.mat.util.IProgressListener;
/* package */class TotalsCalculator
{
/* package */static final TotalsCalculator create(RefinedStructuredResult refined)
{
boolean needToCalculate = false;
ArrayInt numericColumns = new ArrayInt(refined.columns.size());
for (int ii = 0; ii < refined.columns.size(); ii++)
{
Column col = refined.columns.get(ii);
if (col.getCalculateTotals() && col.isNumeric())
{
numericColumns.add(ii);
needToCalculate = true;
}
}
return new TotalsCalculator(refined.columns, refined.columns.size(), needToCalculate, numericColumns);
}
private final List<Column> columns;
private final int noOfColumns;
private final boolean needToCalculate;
private final ArrayInt numericColumns;
private TotalsCalculator(List<Column> columns, int noOfColumns, boolean needToCalculate, ArrayInt numericColumns)
{
this.columns = columns;
this.noOfColumns = noOfColumns;
this.needToCalculate = needToCalculate;
this.numericColumns = numericColumns;
}
public TotalsResult[] calculate(IStructuredResult result, List<?> elements, IProgressListener listener)
{
TotalsResult[] answer = new TotalsResult[noOfColumns];
if (!needToCalculate)
return answer;
// Local copy needed as possibly skip columns if the values turn out
// not to be numeric. However, we do NOT want to skip this column
// from now on always.
ArrayInt thisNumericColumns = new ArrayInt(numericColumns);
double[] sums = new double[thisNumericColumns.size()];
Filter.ValueConverter converters[] = new Filter.ValueConverter[thisNumericColumns.size()];
for (int ii = 0; ii < thisNumericColumns.size(); ii++)
{
int columnIndex = thisNumericColumns.get(ii);
if (columnIndex < 0)
continue;
converters[ii] = (Filter.ValueConverter)columns.get(columnIndex).getData(Filter.ValueConverter.class);
}
int counter = 0;
ForEachRowLoop: for (Object row : elements)
{
// check if canceled
if (++counter % 100 == 0)
if (listener.isCanceled())
return answer;
for (int ii = 0; ii < thisNumericColumns.size(); ii++)
{
int columnIndex = thisNumericColumns.get(ii);
if (columnIndex < 0)
continue;
Object o = result.getColumnValue(row, columnIndex);
double v = 0;
if (o == null)
{
v = Double.valueOf(0);
}
else if (o instanceof Number)
{
v = ((Number) o).doubleValue();
}
else if (o instanceof Bytes)
v = ((Bytes) o).getValue();
else
{
try
{
v = Double.parseDouble(o.toString());
}
catch (NumberFormatException e)
{
// $JL-EXC$
// not a number -> ignore this column from now on
thisNumericColumns.set(ii, -1);
// check whether all the columns are non-numeric and
// exit the loop in this case
boolean needToCalculate = false;
for (int jj = 0; jj < thisNumericColumns.size(); jj++)
needToCalculate = needToCalculate || thisNumericColumns.get(jj) >= 0;
if (!needToCalculate)
break ForEachRowLoop;
}
}
if (converters[ii] != null)
v = converters[ii].convert(v);
sums[ii] += v;
}
}
// prepare result
for (int index = 0; index < sums.length; index++)
{
int columnIndex = thisNumericColumns.get(index);
if (columnIndex < 0)
continue;
Column col = columns.get(columnIndex);
Format formatter = col.getFormatter();
Object val;
if (formatter instanceof BytesFormat) {
// We can assume that if a column's formatter is BytesFormat,
// then the value must have been a long, number of bytes.
val = new Bytes((long)sums[index]);
} else {
val = sums[index];
}
answer[columnIndex] = new TotalsResult(val, formatter);
}
return answer;
}
}