• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2009, 2019 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  *******************************************************************************/
12 package org.jacoco.core.data;
13 
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Map;
19 import java.util.Set;
20 
21 /**
22  * In-memory data store for execution data. The data can be added through its
23  * {@link IExecutionDataVisitor} interface. If execution data is provided
24  * multiple times for the same class the data is merged, i.e. a probe is marked
25  * as executed if it is reported as executed at least once. This allows to merge
26  * coverage date from multiple runs. A instance of this class is not thread
27  * safe.
28  */
29 public final class ExecutionDataStore implements IExecutionDataVisitor {
30 
31 	// BEGIN android-change
32 	private final Map<Long, IExecutionData> entries = new HashMap<Long, IExecutionData>();
33 	// END android-change
34 
35 	private final Set<String> names = new HashSet<String>();
36 
37 	/**
38 	 * Adds the given {@link ExecutionData} object into the store. If there is
39 	 * already execution data with this same class id, this structure is merged
40 	 * with the given one.
41 	 *
42 	 * @param data
43 	 *            execution data to add or merge
44 	 * @throws IllegalStateException
45 	 *             if the given {@link ExecutionData} object is not compatible
46 	 *             to a corresponding one, that is already contained
47 	 * @see ExecutionData#assertCompatibility(long, String, int)
48 	 */
49 	// BEGIN android-change
put(final IExecutionData data)50 	public void put(final IExecutionData data) throws IllegalStateException {
51 		final Long id = Long.valueOf(data.getId());
52 		final IExecutionData entry = entries.get(id);
53 		// END android-change
54 		if (entry == null) {
55 			entries.put(id, data);
56 			names.add(data.getName());
57 		} else {
58 			entry.merge(data);
59 		}
60 	}
61 
62 	/**
63 	 * Subtracts the probes in the given {@link ExecutionData} object from the
64 	 * store. I.e. for all set probes in the given data object the corresponding
65 	 * probes in this store will be unset. If there is no execution data with id
66 	 * of the given data object this operation will have no effect.
67 	 *
68 	 * @param data
69 	 *            execution data to subtract
70 	 * @throws IllegalStateException
71 	 *             if the given {@link ExecutionData} object is not compatible
72 	 *             to a corresponding one, that is already contained
73 	 * @see ExecutionData#assertCompatibility(long, String, int)
74 	 */
75 	// BEGIN android-change
subtract(final IExecutionData data)76 	public void subtract(final IExecutionData data) throws IllegalStateException {
77 		final Long id = Long.valueOf(data.getId());
78 		final IExecutionData entry = entries.get(id);
79 		// END android-change
80 		if (entry != null) {
81 			entry.merge(data, false);
82 		}
83 	}
84 
85 	/**
86 	 * Subtracts all probes in the given execution data store from this store.
87 	 *
88 	 * @param store
89 	 *            execution data store to subtract
90 	 * @see #subtract(ExecutionData)
91 	 */
subtract(final ExecutionDataStore store)92 	public void subtract(final ExecutionDataStore store) {
93 		// BEGIN android-change
94 		for (final IExecutionData data : store.getContents()) {
95 		// END android-change
96 			subtract(data);
97 		}
98 	}
99 
100 	/**
101 	 * Returns the {@link ExecutionData} entry with the given id if it exists in
102 	 * this store.
103 	 *
104 	 * @param id
105 	 *            class id
106 	 * @return execution data or <code>null</code>
107 	 */
108 	// BEGIN android-change
get(final long id)109 	public IExecutionData get(final long id) {
110 	// END android-change
111 		return entries.get(Long.valueOf(id));
112 	}
113 
114 	/**
115 	 * Checks whether execution data for classes with the given name are
116 	 * contained in the store.
117 	 *
118 	 * @param name
119 	 *            VM name
120 	 * @return <code>true</code> if at least one class with the name is
121 	 *         contained.
122 	 */
contains(final String name)123 	public boolean contains(final String name) {
124 		return names.contains(name);
125 	}
126 
127 	/**
128 	 * Returns the coverage data for the class with the given identifier. If
129 	 * there is no data available under the given id a new entry is created.
130 	 *
131 	 * @param id
132 	 *            class identifier
133 	 * @param name
134 	 *            VM name of the class
135 	 * @param probecount
136 	 *            probe data length
137 	 * @return execution data
138 	 */
139 	// BEGIN android-change
get(final Long id, final String name, final int probecount)140 	public IExecutionData get(final Long id, final String name,
141 			final int probecount) {
142 		IExecutionData entry = entries.get(id);
143 		// END android-change
144 		if (entry == null) {
145 			entry = new ExecutionData(id.longValue(), name, probecount);
146 			entries.put(id, entry);
147 			names.add(name);
148 		} else {
149 			entry.assertCompatibility(id.longValue(), name, probecount);
150 		}
151 		return entry;
152 	}
153 
154 	/**
155 	 * Resets all execution data probes, i.e. marks them as not executed. The
156 	 * execution data objects itself are not removed.
157 	 */
reset()158 	public void reset() {
159 		// BEGIN android-change
160 		for (final IExecutionData executionData : this.entries.values()) {
161 		// END android-change
162 			executionData.reset();
163 		}
164 	}
165 
166 	/**
167 	 * Returns a collection that represents current contents of the store.
168 	 *
169 	 * @return current contents
170 	 */
171 	// BEGIN android-change
getContents()172 	public Collection<IExecutionData> getContents() {
173 		return new ArrayList<IExecutionData>(entries.values());
174 	}
175 	// END android-change
176 
177 	/**
178 	 * Writes the content of the store to the given visitor interface.
179 	 *
180 	 * @param visitor
181 	 *            interface to write content to
182 	 */
accept(final IExecutionDataVisitor visitor)183 	public void accept(final IExecutionDataVisitor visitor) {
184 		// BEGIN android-change
185 		for (final IExecutionData data : getContents()) {
186 		// END android-change
187 			visitor.visitClassExecution(data);
188 		}
189 	}
190 
191 	// === IExecutionDataVisitor ===
192 
193 	// BEGIN android-change
visitClassExecution(final IExecutionData data)194 	public void visitClassExecution(final IExecutionData data) {
195 	// END android-change
196 		put(data);
197 	}
198 }
199