blob: c9c9bd07f91a5e0e5d48f8e75df46b2fdee9b93d [file] [log] [blame]
Yue Ganaf3c4122016-12-05 14:36:02 +00001// Copyright 2016 The Bazel Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.testing.coverage;
16
17import java.util.Arrays;
Yue Ganaf3c4122016-12-05 14:36:02 +000018
19/**
20 * Abstracts bit field operations.
21 */
22public class BitField {
23
24 private byte[] bytes;
25
26 private static final int[] BIT_COUNT_LOOKUP = new int[256];
27
28 static {
29 BIT_COUNT_LOOKUP[0] = 0;
30 BIT_COUNT_LOOKUP[1] = 1;
31 for (int i = 2; i < 256; i += 2) {
32 int count = BIT_COUNT_LOOKUP[i / 2];
33 BIT_COUNT_LOOKUP[i] = count;
34 BIT_COUNT_LOOKUP[i + 1] = count + 1;
35 }
36 }
37
38 public BitField() {
39 this(new byte[0]);
40 }
41
42 public BitField(byte[] bytes) {
43 this.bytes = bytes.clone();
44 }
45
46 /**
47 * Returns a copy of the underlying byte array.
48 *
49 * @return byte array copy
50 */
51 public byte[] getBytes() {
52 return bytes.clone();
53 }
54
55 /**
56 * Sets or clears a bit at the given index.
57 *
58 * @param index bit index
59 */
60 public void setBit(int index) {
61 setBit(index, true);
62 }
63
64 /**
65 * Clears a bit at the given index
66 *
67 * @param index bit index
68 */
69 public void clearBit(int index) {
70 setBit(index, false);
71 }
72
73 /**
74 * Sets or clears a bit at the given index.
75 *
76 * @param index bit index
77 */
78 private void setBit(int index, boolean isSet) {
79 int byteIndex = index / 8;
80 int newByteSize = byteIndex + 1;
81 if (bytes.length < newByteSize) {
82 bytes = Arrays.copyOf(bytes, newByteSize);
83 }
84
85 int bitIndex = index % 8;
86 int mask = 1 << bitIndex;
87
88 if (isSet) {
89 bytes[byteIndex] = (byte) (bytes[byteIndex] | mask);
90 } else {
91 bytes[byteIndex] = (byte) (bytes[byteIndex] & ~mask);
92 }
93 }
94
95 /**
96 * Checks whether a bit at the given index is set.
97 *
98 * @param index bit index
99 * @return true if set, false otherwise
100 */
101 public boolean isBitSet(int index) {
102 int byteIndex = index / 8;
103
104 if (byteIndex >= bytes.length) {
105 return false;
106 }
107
108 int bitIndex = index % 8;
109 int mask = 1 << bitIndex;
110 return (bytes[byteIndex] & mask) != 0;
111 }
112
113 /** Performs a non-destructive bit-wise "and" of this bit field with another one. */
114 public BitField and(BitField other) {
115 int size = Math.min(bytes.length, other.bytes.length);
116 byte[] result = new byte[size];
117
118 for (int i = 0; i < size; i++) {
119 result[i] = (byte) (bytes[i] & other.bytes[i]);
120 }
121
122 return new BitField(result);
123 }
124
125 /**
126 * Performs a non-destructive bit-wise merge of this bit field and another one.
127 *
128 * @param other the other bit field
129 * @return this bit field
130 */
131 public BitField or(BitField other) {
132 byte[] largerArray, smallerArray;
133 if (bytes.length < other.bytes.length) {
134 largerArray = other.bytes;
135 smallerArray = bytes;
136 } else {
137 largerArray = bytes;
138 smallerArray = other.bytes;
139 }
140
141 // Start out with a copy of the larger of the two arrays.
142 byte[] result = Arrays.copyOf(largerArray, largerArray.length);
143
144 for (int i = 0; i < smallerArray.length; i++) {
145 result[i] |= smallerArray[i];
146 }
147
148 return new BitField(result);
149 }
150
151 /**
152 * Compares two bit fields for equality.
153 *
154 * @param obj another object
155 * @return true if the other object is a bit field with the same bits set
156 */
157 @Override
158 public boolean equals(Object obj) {
ulfjack262946b2017-08-01 18:29:39 +0200159 if (obj == this) {
160 return true;
161 }
162 if (!(obj instanceof BitField)) {
163 return false;
164 }
165 return Arrays.equals(bytes, ((BitField) obj).bytes);
Yue Ganaf3c4122016-12-05 14:36:02 +0000166 }
167
168 /**
169 * Compare a BitField object with an array of bytes
170 *
171 * @param other a byte array to compare to
172 * @return true if the underlying byte array is equal to the given byte array
173 */
174 public boolean equals(byte[] other) {
175 return Arrays.equals(bytes, other);
176 }
177
178 @Override
179 public int hashCode() {
ulfjack262946b2017-08-01 18:29:39 +0200180 return Arrays.hashCode(bytes);
Yue Ganaf3c4122016-12-05 14:36:02 +0000181 }
182
183 public int countBitsSet() {
184 int count = 0;
185 for (byte b : bytes) {
186 // JAVA doesn't have the concept of unsigned byte; need to & with 255
187 // to avoid exception of IndexOutOfBoundException when b < 0.
188 count += BIT_COUNT_LOOKUP[0xFF & b];
189 }
190 return count;
191 }
192
193 public BitField not() {
194 byte[] invertedBytes = new byte[bytes.length];
195 for (int i = 0; i < bytes.length; i++) {
196 invertedBytes[i] = Integer.valueOf(~bytes[i]).byteValue();
197 }
198 return new BitField(invertedBytes);
199 }
200
201 public int sizeInBits() {
202 return bytes.length * 8;
203 }
204
205 public boolean any() {
206 for (int i = 0; i < bytes.length; i++) {
207 if (bytes[i] != (byte) 0) {
208 return true;
209 }
210 }
211 return false;
212 }
213}