com.madvay.tools.android.perf.common.Table.java Source code

Java tutorial

Introduction

Here is the source code for com.madvay.tools.android.perf.common.Table.java

Source

/*
 * Copyright (c) 2015 by Advay Mengle.
 *
 * 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 com.madvay.tools.android.perf.common;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.*;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.regex.Pattern;

/**
 *
 */
public abstract class Table<T extends Row> {
    private List<T> rows;

    public Table(List<T> rows) {
        this.rows = rows;
    }

    public void setRows(List<T> rows) {
        this.rows = rows;
    }

    public List<T> getRows() {
        return rows;
    }

    public abstract RowAdapter<T> getAdapter();

    public void sortOn(List<String> cols) {
        Ordering<T> order = null;
        for (String colSpec : cols) {
            String col = colSpec.startsWith("-") ? colSpec.substring(1) : colSpec;
            Ordering<T> cur = new ColumnOrdering(col);
            if (colSpec.startsWith("-")) {
                cur = cur.reverse();
            }
            if (order == null) {
                order = cur;
            } else {
                order = order.compound(cur);
            }
        }
        rows = order.sortedCopy(rows);
    }

    public void sample(int n) {
        if (n < 0 || n >= rows.size()) {
            return;
        }
        List<T> nextRows = Lists.newArrayList();
        Random rnd = new Random(3493);
        while (n > 0) {
            T row = null;
            do {
                int i = rnd.nextInt(rows.size());
                row = rows.get(i);
            } while (nextRows.contains(row));
            nextRows.add(row);
            n--;
        }
        rows = nextRows;
    }

    public void matching(FilterSpec spec) {
        final FilterSpec filterSpec = spec;
        rows = Lists.newArrayList(Collections2.filter(rows, new RowFilter(filterSpec)));
    }

    public enum AggregationType {
        /** The number of rows */
        COUNT,
        /** The number of rows with unique values for this column */
        UNIQUE,
        /** The sum/concatenation of values in this column. */
        SUM
    }

    public Table<AggregateRow> groupAndAggregate(final String groupByColumn, final String weightColumn,
            final AggregationType aggregationType) {
        final RowAdapter<T> adapter = getAdapter();
        final boolean groupNumeric = adapter.types
                .get(adapter.columns.indexOf(groupByColumn)) == RowAdapter.CoerceType.NUMERIC;
        boolean weightNumeric = adapter.types
                .get(adapter.columns.indexOf(weightColumn)) == RowAdapter.CoerceType.NUMERIC;
        ImmutableListMultimap<Object, T> indexed = Multimaps.index(rows, new Function<T, Object>() {
            @Override
            public Object apply(T input) {
                return adapter.get(input, groupByColumn).toString();
            }
        });
        Map<Object, Long> map = Maps.transformEntries(Multimaps.asMap(indexed),
                new Maps.EntryTransformer<Object, List<T>, Long>() {
                    @Override
                    public Long transformEntry(Object key, List<T> value) {
                        switch (aggregationType) {
                        case COUNT:
                            return (long) value.size();
                        case SUM: {
                            long l = 0;
                            for (T t : value) {
                                l += Long.parseLong(adapter.get(t, weightColumn).toString());
                            }
                            return l;
                        }
                        case UNIQUE: {
                            Set<String> set = new HashSet<>();
                            for (T t : value) {
                                set.add(adapter.get(t, weightColumn).toString());
                            }
                            return (long) set.size();
                        }
                        }
                        throw new IllegalArgumentException();
                    }
                });
        List<AggregateRow> newRows = Lists.newArrayList(
                Iterables.transform(map.entrySet(), new Function<Map.Entry<Object, Long>, AggregateRow>() {
                    @Override
                    public AggregateRow apply(Map.Entry<Object, Long> input) {
                        return new AggregateRow(input.getValue(), input.getKey());
                    }
                }));
        Table<AggregateRow> ret = new Table<AggregateRow>(newRows) {
            final RowAdapter<AggregateRow> adap = new AggregateRow.Adapter(groupNumeric);

            @Override
            public RowAdapter<AggregateRow> getAdapter() {
                return adap;
            }
        };
        return ret;
    }

    private final class ColumnOrdering extends Ordering<T> {

        private final String col;

        public ColumnOrdering(String col) {
            this.col = col;
        }

        @Override
        public int compare(T left, T right) {
            Comparable l = (Comparable) getAdapter().get(left, col);
            Comparable r = (Comparable) getAdapter().get(right, col);
            return Ordering.natural().compare(l, r);
        }
    }

    private final class RowFilter implements Predicate<T> {
        private final Pattern pat;
        private final FilterSpec filterSpec;

        public RowFilter(FilterSpec filterSpec) {
            this.filterSpec = filterSpec;
            pat = filterSpec.filterType == FilterSpec.FilterType.RE_MATCH
                    || filterSpec.filterType == FilterSpec.FilterType.NOT_RE_MATCH ? Pattern.compile(filterSpec.rhs)
                            : null;
        }

        @Override
        public boolean apply(T input) {
            RowAdapter<T> adapter = getAdapter();
            Object lhsRaw = adapter.get(input, filterSpec.columnName);
            String lhsStr = lhsRaw.toString();
            int i = adapter.columns.indexOf(filterSpec.columnName);
            switch (adapter.types.get(i)) {
            case NUMERIC: {
                long lhs = Long.parseLong(lhsStr);
                long rhs = Long.parseLong(filterSpec.rhs);
                long c = Long.compare(lhs, rhs);
                return doCompare(lhsStr, c, filterSpec.rhs);
            }
            case TEXT: {
                return doCompare(lhsStr, lhsStr.compareTo(filterSpec.rhs), filterSpec.rhs);
            }
            default:
                throw new IllegalArgumentException("Bad coerceType: " + adapter.types.get(i));
            }
        }

        private boolean doCompare(String lhsStr, long c, String rhsStr) {
            switch (filterSpec.filterType) {
            case GEQ:
                return c >= 0;
            case GREATER:
                return c > 0;
            case LEQ:
                return c <= 0;
            case LESS:
                return c < 0;
            case EQUALS:
                return c == 0;
            case NOT_EQUALS:
                return c != 0;
            case RE_MATCH:
                return pat.matcher(lhsStr).matches();
            case NOT_RE_MATCH:
                return !pat.matcher(lhsStr).matches();
            case CONTAINS:
                return lhsStr.contains(rhsStr);
            case NOT_CONTAINS:
                return !lhsStr.contains(rhsStr);
            default:
                throw new IllegalArgumentException("Bad filterType: " + filterSpec.filterType);
            }
        }
    }
}