1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 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 static java.lang.String.format; 15 16 import 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 */ 23 public 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 * Checks whether any probe has been hit. 103 * 104 * @return <code>true</code>, if at least one probe has been hit 105 */ 106 public boolean hasHits() { 107 for (final boolean p : probes) { 108 if (p) { 109 return true; 110 } 111 } 112 return false; 113 } 114 115 /** 116 * Merges the given execution data into the probe data of this object. I.e. 117 * a probe entry in this object is marked as executed (<code>true</code>) if 118 * this probe or the corresponding other probe was executed. So the result 119 * is 120 * 121 * <pre> 122 * A or B 123 * </pre> 124 * 125 * The probe array of the other object is not modified. 126 * 127 * @param other 128 * execution data to merge 129 */ 130 public void merge(final ExecutionData other) { 131 merge(other, true); 132 } 133 134 /** 135 * Merges the given execution data into the probe data of this object. A 136 * probe in this object is set to the value of <code>flag</code> if the 137 * corresponding other probe was executed. For <code>flag==true</code> this 138 * corresponds to 139 * 140 * <pre> 141 * A or B 142 * </pre> 143 * 144 * For <code>flag==false</code> this can be considered as a subtraction 145 * 146 * <pre> 147 * A and not B 148 * </pre> 149 * 150 * The probe array of the other object is not modified. 151 * 152 * @param other 153 * execution data to merge 154 * @param flag 155 * merge mode 156 */ 157 public void merge(final ExecutionData other, final boolean flag) { 158 assertCompatibility(other.getId(), other.getName(), 159 other.getProbes().length); 160 final boolean[] otherData = other.getProbes(); 161 for (int i = 0; i < probes.length; i++) { 162 if (otherData[i]) { 163 probes[i] = flag; 164 } 165 } 166 } 167 168 /** 169 * Asserts that this execution data object is compatible with the given 170 * parameters. The purpose of this check is to detect a very unlikely class 171 * id collision. 172 * 173 * @param id 174 * other class id, must be the same 175 * @param name 176 * other name, must be equal to this name 177 * @param probecount 178 * probe data length, must be the same as for this data 179 * @throws IllegalStateException 180 * if the given parameters do not match this instance 181 */ 182 public void assertCompatibility(final long id, final String name, 183 final int probecount) throws IllegalStateException { 184 if (this.id != id) { 185 throw new IllegalStateException(format( 186 "Different ids (%016x and %016x).", Long.valueOf(this.id), 187 Long.valueOf(id))); 188 } 189 if (!this.name.equals(name)) { 190 throw new IllegalStateException(format( 191 "Different class names %s and %s for id %016x.", this.name, 192 name, Long.valueOf(id))); 193 } 194 if (this.probes.length != probecount) { 195 throw new IllegalStateException(format( 196 "Incompatible execution data for class %s with id %016x.", 197 name, Long.valueOf(id))); 198 } 199 } 200 201 @Override 202 public String toString() { 203 return String.format("ExecutionData[name=%s, id=%016x]", name, 204 Long.valueOf(id)); 205 } 206 207 } 208