1 /******************************************************************************* 2 * Copyright (c) 2009, 2015 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 */ ExecutionData(final long id, final String name, final boolean[] probes)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 */ ExecutionData(final long id, final String name, final int probeCount)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 */ getId()71 public long getId() { 72 return id; 73 } 74 75 /** 76 * The VM name of the class. 77 * 78 * @return VM name 79 */ getName()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 */ getProbes()90 public boolean[] getProbes() { 91 return probes; 92 } 93 94 /** 95 * Sets all probes to <code>false</code>. 96 */ reset()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 */ merge(final ExecutionData other)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 */ merge(final ExecutionData other, final boolean flag)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 */ assertCompatibility(final long id, final String name, final int probecount)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 toString()188 public String toString() { 189 return String.format("ExecutionData[name=%s, id=%016x]", name, 190 Long.valueOf(id)); 191 } 192 } 193