LinesImpl.java
1/*******************************************************************************
2 * Copyright (c) 2009 Mountainminds GmbH & Co. KG and others
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 * $Id: $
12 *******************************************************************************/
13package org.jacoco.core.analysis;
14
15
16/**
17 * {@link ILines} implementation.
18 *
19 * @author Marc R. Hoffmann
20 * @version $Revision: $
21 */
22public class LinesImpl extends AbstractCounter implements ILines {
23
24 /** status for each line */
25 private byte[] status;
26
27 /** first line number in lines */
28 private int offset;
29
30 /**
31 * Creates an empty line counter.
32 */
33 public LinesImpl() {
34 super(0, 0);
35 status = null;
36 offset = -1;
37 }
38
39 /**
40 * Created a line counter with the given lines
41 *
42 * @param lines
43 * line numbers to add
44 * @param covered
45 * <code>true</code> if all lines are covered
46 *
47 */
48 public LinesImpl(final int[] lines, final boolean covered) {
49 this();
50 increment(lines, covered);
51 }
52
53 private void ensureCapacity(final int first, final int last) {
54 if (status == null) {
55 offset = first;
56 status = new byte[last - first + 1];
57 } else {
58 final int newFirst = Math.min(getFirstLine(), first);
59 final int newLast = Math.max(getLastLine(), last);
60 final int newLength = newLast - newFirst + 1;
61 if (newLength > status.length) {
62 final byte[] newStatus = new byte[newLength];
63 System.arraycopy(status, 0, newStatus, offset - newFirst,
64 status.length);
65 offset = newFirst;
66 status = newStatus;
67 }
68 }
69 }
70
71 /**
72 * Adds the given lines as fully covered or not covered.
73 *
74 * @param lines
75 * line numbers to add
76 * @param covered
77 * <code>true</code> if all lines are covered
78 *
79 */
80 public void increment(final int[] lines, final boolean covered) {
81 if (lines.length > 0) {
82 ensureCapacity(lines[0], lines[lines.length - 1]);
83 final byte newStatus = covered ? FULLY_COVERED : NOT_COVERED;
84 for (final int line : lines) {
85 incrementLine(line, newStatus);
86 }
87 }
88 }
89
90 /**
91 * Adds the lines of the given line counter. The states are updated
92 * accordingly.
93 *
94 * @param counter
95 * line counter to add
96 */
97 public void increment(final ILines counter) {
98 if (counter.getTotalCount() == 0) {
99 return;
100 }
101 ensureCapacity(counter.getFirstLine(), counter.getLastLine());
102 for (int line = counter.getFirstLine(); line <= counter.getLastLine(); line++) {
103 incrementLine(line, counter.getStatus(line));
104 }
105 }
106
107 private void incrementLine(final int line, final byte newStatus) {
108 final byte oldStatus = status[line - offset];
109 status[line - offset] = (byte) (oldStatus | newStatus);
110 if (oldStatus == NO_CODE && newStatus != NO_CODE) {
111 total++;
112 }
113 if ((oldStatus == NO_CODE || oldStatus == NOT_COVERED)
114 && (newStatus == PARTLY_COVERED || newStatus == FULLY_COVERED)) {
115 covered++;
116 }
117 }
118
119 // === ILineCounter ===
120
121 public int getFirstLine() {
122 return offset;
123 }
124
125 public int getLastLine() {
126 return status == null ? -1 : (offset + status.length - 1);
127 }
128
129 public byte getStatus(final int line) {
130 if (status == null || line < getFirstLine() || line > getLastLine()) {
131 return NO_CODE;
132 }
133 return status[line - offset];
134 }
135
136}