ExecutionData.java revision 283abfa148b749678924b5e75eabd35a2d58f9f8
1/*******************************************************************************
2 * Copyright (c) 2009, 2014 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.core.data;
13
14import static java.lang.String.format;
15
16import java.util.Arrays;
17
18/**
19 * Execution data for a single Java class. While instances are immutable care
20 * has to be taken about the probe data array of type <code>boolean[]</code>
21 * which can be modified.
22 */
23public final class ExecutionData {
24
25	private final long id;
26
27	private final String name;
28
29	private final boolean[] probes;
30
31	/**
32	 * Creates a new {@link ExecutionData} object with the given probe data.
33	 *
34	 * @param id
35	 *            class identifier
36	 * @param name
37	 *            VM name
38	 * @param probes
39	 *            probe data
40	 */
41	public ExecutionData(final long id, final String name,
42			final boolean[] probes) {
43		this.id = id;
44		this.name = name;
45		this.probes = probes;
46	}
47
48	/**
49	 * Creates a new {@link ExecutionData} object with the given probe data
50	 * length. All probes are set to <code>false</code>.
51	 *
52	 * @param id
53	 *            class identifier
54	 * @param name
55	 *            VM name
56	 * @param probeCount
57	 *            probe count
58	 */
59	public ExecutionData(final long id, final String name, final int probeCount) {
60		this.id = id;
61		this.name = name;
62		this.probes = new boolean[probeCount];
63	}
64
65	/**
66	 * Return the unique identifier for this class. The identifier is the CRC64
67	 * checksum of the raw class file definition.
68	 *
69	 * @return class identifier
70	 */
71	public long getId() {
72		return id;
73	}
74
75	/**
76	 * The VM name of the class.
77	 *
78	 * @return VM name
79	 */
80	public String getName() {
81		return name;
82	}
83
84	/**
85	 * Returns the execution data probes. A value of <code>true</code> indicates
86	 * that the corresponding probe was executed.
87	 *
88	 * @return probe data
89	 */
90	public boolean[] getProbes() {
91		return probes;
92	}
93
94	/**
95	 * Sets all probes to <code>false</code>.
96	 */
97	public void reset() {
98		Arrays.fill(probes, false);
99	}
100
101	/**
102	 * Merges the given execution data into the probe data of this object. I.e.
103	 * a probe entry in this object is marked as executed (<code>true</code>) if
104	 * this probe or the corresponding other probe was executed. So the result
105	 * is
106	 *
107	 * <pre>
108	 * A or B
109	 * </pre>
110	 *
111	 * The probe array of the other object is not modified.
112	 *
113	 * @param other
114	 *            execution data to merge
115	 */
116	public void merge(final ExecutionData other) {
117		merge(other, true);
118	}
119
120	/**
121	 * Merges the given execution data into the probe data of this object. A
122	 * probe in this object is set to the value of <code>flag</code> if the
123	 * corresponding other probe was executed. For <code>flag==true</code> this
124	 * corresponds to
125	 *
126	 * <pre>
127	 * A or B
128	 * </pre>
129	 *
130	 * For <code>flag==true</code> this can be considered as a subtraction
131	 *
132	 * <pre>
133	 * A and not B
134	 * </pre>
135	 *
136	 * The probe array of the other object is not modified.
137	 *
138	 * @param other
139	 *            execution data to merge
140	 * @param flag
141	 *            merge mode
142	 */
143	public void merge(final ExecutionData other, final boolean flag) {
144		assertCompatibility(other.getId(), other.getName(),
145				other.getProbes().length);
146		final boolean[] otherData = other.getProbes();
147		for (int i = 0; i < probes.length; i++) {
148			if (otherData[i]) {
149				probes[i] = flag;
150			}
151		}
152	}
153
154	/**
155	 * Asserts that this execution data object is compatible with the given
156	 * parameters. The purpose of this check is to detect a very unlikely class
157	 * id collision.
158	 *
159	 * @param id
160	 *            other class id, must be the same
161	 * @param name
162	 *            other name, must be equal to this name
163	 * @param probecount
164	 *            probe data length, must be the same as for this data
165	 * @throws IllegalStateException
166	 *             if the given parameters do not match this instance
167	 */
168	public void assertCompatibility(final long id, final String name,
169			final int probecount) throws IllegalStateException {
170		if (this.id != id) {
171			throw new IllegalStateException(format(
172					"Different ids (%016x and %016x).", Long.valueOf(this.id),
173					Long.valueOf(id)));
174		}
175		if (!this.name.equals(name)) {
176			throw new IllegalStateException(format(
177					"Different class names %s and %s for id %016x.", this.name,
178					name, Long.valueOf(id)));
179		}
180		if (this.probes.length != probecount) {
181			throw new IllegalStateException(format(
182					"Incompatible execution data for class %s with id %016x.",
183					name, Long.valueOf(id)));
184		}
185	}
186
187	@Override
188	public String toString() {
189		return String.format("ExecutionData[name=%s, id=%016x]", name,
190				Long.valueOf(id));
191	}
192}
193