/******************************************************************************* * Copyright (c) 2006 Mountainminds GmbH & Co. KG * This software is provided under the terms of the Eclipse Public License v1.0 * See http://www.eclipse.org/legal/epl-v10.html. * * $Id: Counter.java 871 2010-01-24 20:48:38Z mtnminds $ ******************************************************************************/ package com.mountainminds.eclemma.internal.core.analysis; import com.mountainminds.eclemma.core.analysis.ICounter; /** * ICounter implementations. Implementing a factory pattern allows to share * counter instances. * * @author Marc R. Hoffmann * @version $Revision: 871 $ */ public abstract class Counter implements ICounter { /** Max counter value for which singletons are created */ private static final int SINGLETON_LIMIT = 10; private static final Counter[][] SINGLETONS = new Counter[SINGLETON_LIMIT + 1][]; static { for (int i = 0; i <= SINGLETON_LIMIT; i++) { SINGLETONS[i] = new Counter[i + 1]; for (int j = 0; j <= i; j++) SINGLETONS[i][j] = new Fix(i, j); } } /** Constant for Counter with 0/0 values. */ public static final Counter COUNTER_0_0 = SINGLETONS[0][0]; /** * Mutable version of the counter. */ private static class Var extends Counter { public Var(long total, long covered) { super(total, covered); } public Counter increment(int total, int covered) { this.total += total; this.covered += covered; return this; } } /** * Immutable version of the counter. */ private static class Fix extends Counter { public Fix(long total, long covered) { super(total, covered); } public Counter increment(int total, int covered) { return getInstance(this.total + total, this.covered + covered); } } /** * Factory method to retrieve a counter with the given number of items. * * @param total * total number of items * @param covered * covered number of items * @return counter instance */ public static Counter getInstance(long total, long covered) { if (total <= SINGLETON_LIMIT && covered <= total) { return SINGLETONS[(int) total][(int) covered]; } else { return new Var(total, covered); } } protected long total; protected long covered; protected Counter(long total, long covered) { this.total = total; this.covered = covered; } /** * Returns a counter with incremented values. It is up to the implementation * whether this conter instance is modified or a new instance is returned. * * @param total * number of additional total items * @param covered * number of additional covered items * @return counter instance with incremented values */ public abstract Counter increment(int total, int covered); // ICounter implementation public long getTotalCount() { return total; } public long getCoveredCount() { return covered; } public long getMissedCount() { return total - covered; } public double getRatio() { return (double) covered / (double) total; } public int compareTo(Object obj) { ICounter counter = (ICounter) obj; return Double.compare(getRatio(), counter.getRatio()); } public boolean equals(Object obj) { if (obj instanceof ICounter) { ICounter counter = (ICounter) obj; return getTotalCount() == counter.getTotalCount() && getCoveredCount() == counter.getCoveredCount(); } else { return false; } } public int hashCode() { long t = getTotalCount(); long c = 17 * getCoveredCount(); return (int) (t ^ (t >>> 32) ^ c ^ (c >>> 32)); } public String toString() { StringBuffer b = new StringBuffer("Counter["); //$NON-NLS-1$ b.append(getCoveredCount()); b.append('/').append(getTotalCount()); b.append(']'); return b.toString(); } }