• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors
3  * This program and the accompanying materials are made available under
4  * the terms of the Eclipse Public License 2.0 which is available at
5  * http://www.eclipse.org/legal/epl-2.0
6  *
7  * SPDX-License-Identifier: EPL-2.0
8  *
9  * Contributors:
10  *    Marc R. Hoffmann - initial API and implementation
11  *
12  *******************************************************************************/
13 package org.jacoco.core.internal.analysis;
14 
15 import org.jacoco.core.analysis.ICounter;
16 
17 /**
18  * {@link ICounter} implementations. Implementing a factory pattern allows to
19  * share counter instances.
20  */
21 public abstract class CounterImpl implements ICounter {
22 
23 	/** Max counter value for which singletons are created */
24 	private static final int SINGLETON_LIMIT = 30;
25 
26 	private static final CounterImpl[][] SINGLETONS = new CounterImpl[SINGLETON_LIMIT
27 			+ 1][];
28 
29 	static {
30 		for (int i = 0; i <= SINGLETON_LIMIT; i++) {
31 			SINGLETONS[i] = new CounterImpl[SINGLETON_LIMIT + 1];
32 			for (int j = 0; j <= SINGLETON_LIMIT; j++) {
33 				SINGLETONS[i][j] = new Fix(i, j);
34 			}
35 		}
36 	}
37 
38 	/** Constant for Counter with 0/0 values. */
39 	public static final CounterImpl COUNTER_0_0 = SINGLETONS[0][0];
40 
41 	/** Constant for Counter with 1/0 values. */
42 	public static final CounterImpl COUNTER_1_0 = SINGLETONS[1][0];
43 
44 	/** Constant for Counter with 0/1 values. */
45 	public static final CounterImpl COUNTER_0_1 = SINGLETONS[0][1];
46 
47 	/**
48 	 * Mutable version of the counter.
49 	 */
50 	private static class Var extends CounterImpl {
Var(final int missed, final int covered)51 		public Var(final int missed, final int covered) {
52 			super(missed, covered);
53 		}
54 
55 		@Override
increment(final int missed, final int covered)56 		public CounterImpl increment(final int missed, final int covered) {
57 			this.missed += missed;
58 			this.covered += covered;
59 			return this;
60 		}
61 	}
62 
63 	/**
64 	 * Immutable version of the counter.
65 	 */
66 	private static class Fix extends CounterImpl {
Fix(final int missed, final int covered)67 		public Fix(final int missed, final int covered) {
68 			super(missed, covered);
69 		}
70 
71 		@Override
increment(final int missed, final int covered)72 		public CounterImpl increment(final int missed, final int covered) {
73 			return getInstance(this.missed + missed, this.covered + covered);
74 		}
75 	}
76 
77 	/**
78 	 * Factory method to retrieve a counter with the given number of items.
79 	 *
80 	 * @param missed
81 	 *            number of missed items
82 	 * @param covered
83 	 *            number of covered items
84 	 * @return counter instance
85 	 */
getInstance(final int missed, final int covered)86 	public static CounterImpl getInstance(final int missed, final int covered) {
87 		if (missed <= SINGLETON_LIMIT && covered <= SINGLETON_LIMIT) {
88 			return SINGLETONS[missed][covered];
89 		} else {
90 			return new Var(missed, covered);
91 		}
92 	}
93 
94 	/**
95 	 * Factory method to retrieve a clone of the given counter.
96 	 *
97 	 * @param counter
98 	 *            counter to copy
99 	 * @return counter instance
100 	 */
getInstance(final ICounter counter)101 	public static CounterImpl getInstance(final ICounter counter) {
102 		return getInstance(counter.getMissedCount(), counter.getCoveredCount());
103 	}
104 
105 	/** number of missed items */
106 	protected int missed;
107 
108 	/** number of covered items */
109 	protected int covered;
110 
111 	/**
112 	 * Creates a new instance with the given numbers.
113 	 *
114 	 * @param missed
115 	 *            number of missed items
116 	 * @param covered
117 	 *            number of covered items
118 	 */
CounterImpl(final int missed, final int covered)119 	protected CounterImpl(final int missed, final int covered) {
120 		this.missed = missed;
121 		this.covered = covered;
122 	}
123 
124 	/**
125 	 * Returns a counter with values incremented by the numbers of the given
126 	 * counter. It is up to the implementation whether this counter instance is
127 	 * modified or a new instance is returned.
128 	 *
129 	 * @param counter
130 	 *            number of additional total and covered items
131 	 * @return counter instance with incremented values
132 	 */
increment(final ICounter counter)133 	public CounterImpl increment(final ICounter counter) {
134 		return increment(counter.getMissedCount(), counter.getCoveredCount());
135 	}
136 
137 	/**
138 	 * Returns a counter with values incremented by the given numbers. It is up
139 	 * to the implementation whether this counter instance is modified or a new
140 	 * instance is returned.
141 	 *
142 	 * @param missed
143 	 *            number of missed items
144 	 * @param covered
145 	 *            number of covered items
146 	 * @return counter instance with incremented values
147 	 */
increment(int missed, int covered)148 	public abstract CounterImpl increment(int missed, int covered);
149 
150 	// === ICounter implementation ===
151 
getValue(final CounterValue value)152 	public double getValue(final CounterValue value) {
153 		switch (value) {
154 		case TOTALCOUNT:
155 			return getTotalCount();
156 		case MISSEDCOUNT:
157 			return getMissedCount();
158 		case COVEREDCOUNT:
159 			return getCoveredCount();
160 		case MISSEDRATIO:
161 			return getMissedRatio();
162 		case COVEREDRATIO:
163 			return getCoveredRatio();
164 		default:
165 			throw new AssertionError(value);
166 		}
167 	}
168 
getTotalCount()169 	public int getTotalCount() {
170 		return missed + covered;
171 	}
172 
getCoveredCount()173 	public int getCoveredCount() {
174 		return covered;
175 	}
176 
getMissedCount()177 	public int getMissedCount() {
178 		return missed;
179 	}
180 
getCoveredRatio()181 	public double getCoveredRatio() {
182 		return (double) covered / (missed + covered);
183 	}
184 
getMissedRatio()185 	public double getMissedRatio() {
186 		return (double) missed / (missed + covered);
187 	}
188 
getStatus()189 	public int getStatus() {
190 		int status = covered > 0 ? FULLY_COVERED : EMPTY;
191 		if (missed > 0) {
192 			status |= NOT_COVERED;
193 		}
194 		return status;
195 	}
196 
197 	@Override
equals(final Object obj)198 	public boolean equals(final Object obj) {
199 		if (obj instanceof ICounter) {
200 			final ICounter that = (ICounter) obj;
201 			return this.missed == that.getMissedCount()
202 					&& this.covered == that.getCoveredCount();
203 		} else {
204 			return false;
205 		}
206 	}
207 
208 	@Override
hashCode()209 	public int hashCode() {
210 		return missed ^ covered * 17;
211 	}
212 
213 	@Override
toString()214 	public String toString() {
215 		final StringBuilder b = new StringBuilder("Counter["); //$NON-NLS-1$
216 		b.append(getMissedCount());
217 		b.append('/').append(getCoveredCount());
218 		b.append(']');
219 		return b.toString();
220 	}
221 
222 }
223