1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.lang3;
19
20 /**
21 * Supports operations on bit-mapped fields. Instances of this class can be used to store a flag or data within an {@code int}, {@code short} or {@code byte}.
22 * <p>
23 * Each {@link BitField} is constructed with a mask value, which indicates the bits that will be used to store and retrieve the data for that field. For
24 * instance, the mask {@code 0xFF} indicates the least-significant byte should be used to store the data.
25 * </p>
26 * <p>
27 * As an example, consider a car painting machine that accepts paint instructions as integers. Bit fields can be used to encode this:
28 * </p>
29 *
30 * <pre>
31 *
32 * // blue, green and red are 1 byte values (0-255) stored in the three least
33 * // significant bytes
34 * BitField blue = new BitField(0xFF);
35 *
36 * BitField green = new BitField(0xFF00);
37 *
38 * BitField red = new BitField(0xFF0000);
39 *
40 * // anyColor is a flag triggered if any color is used
41 * BitField anyColor = new BitField(0xFFFFFF);
42 *
43 * // isMetallic is a single bit flag
44 * BitField isMetallic = new BitField(0x1000000);
45 * </pre>
46 * <p>
47 * Using these {@link BitField} instances, a paint instruction can be encoded into an integer:
48 * </p>
49 *
50 * <pre>
51 * int paintInstruction = 0;
52 * paintInstruction = red.setValue(paintInstruction, 35);
53 * paintInstruction = green.setValue(paintInstruction, 100);
54 * paintInstruction = blue.setValue(paintInstruction, 255);
55 * </pre>
56 * <p>
57 * Flags and data can be retrieved from the integer:
58 * </p>
59 *
60 * <pre>
61 * // Prints true if red, green or blue is non-zero
62 * System.out.println(anyColor.isSet(paintInstruction)); // prints true
63 * // Prints value of red, green and blue
64 * System.out.println(red.getValue(paintInstruction)); // prints 35
65 * System.out.println(green.getValue(paintInstruction)); // prints 100
66 * System.out.println(blue.getValue(paintInstruction)); // prints 255
67 * // Prints true if isMetallic was set
68 * System.out.println(isMetallic.isSet(paintInstruction)); // prints false
69 * </pre>
70 *
71 * @since 2.0
72 */
73 public class BitField {
74
75 private final long mask;
76
77 private final int shiftCount;
78
79 /**
80 * Creates a BitField instance.
81 *
82 * @param mask The mask specifying which bits apply to this BitField. Bits that are set in this mask are the bits that this BitField operates on.
83 */
84 public BitField(final int mask) {
85 this.mask = Integer.toUnsignedLong(mask);
86 this.shiftCount = this.mask == 0 ? 0 : Long.numberOfTrailingZeros(this.mask);
87 }
88
89 /**
90 * Creates a BitField instance.
91 * <p>
92 * If any bit above bit 31 is set in the mask, the resulting field can only be used with the {@code long} holder accessors; the {@code int}, {@code short}
93 * and {@code byte} holder accessors throw {@link IllegalStateException} for such a field, because those holder types cannot contain the masked bits and
94 * would otherwise silently answer wrongly (shift counts are truncated mod 32 and negative holders are sign-extended into bits 32-63).
95 * </p>
96 *
97 * @param mask The mask specifying which bits apply to this BitField. Bits that are set in this mask are the bits that this BitField operates on.
98 * @since 3.21.0
99 */
100 public BitField(final long mask) {
101 this.mask = mask;
102 this.shiftCount = mask == 0 ? 0 : Long.numberOfTrailingZeros(mask);
103 }
104
105 /**
106 * Clears the bits.
107 *
108 * @param holder The int data containing the bits we're interested in.
109 * @return The value of holder with the specified bits cleared (set to {@code 0}).
110 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
111 * represented in this holder type.
112 */
113 public int clear(final int holder) {
114 return (int) (holder & ~intMask());
115 }
116
117 /**
118 * Clears the bits.
119 *
120 * @param holder The long data containing the bits we're interested in.
121 * @return The value of holder with the specified bits cleared (set to {@code 0}).
122 * @since 3.21.0
123 */
124 public long clear(final long holder) {
125 return holder & ~mask;
126 }
127
128 /**
129 * Clears the bits.
130 *
131 * @param holder The byte data containing the bits we're interested in.
132 * @return The value of holder with the specified bits cleared (set to {@code 0}).
133 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
134 * represented in this holder type.
135 */
136 public byte clearByte(final byte holder) {
137 return (byte) clear(holder);
138 }
139
140 /**
141 * Clears the bits.
142 *
143 * @param holder The short data containing the bits we're interested in.
144 * @return The value of holder with the specified bits cleared (set to {@code 0}).
145 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
146 * represented in this holder type.
147 */
148 public short clearShort(final short holder) {
149 return (short) clear(holder);
150 }
151
152 /**
153 * Gets the value for the specified BitField, unshifted.
154 *
155 * @param holder The int data containing the bits we're interested in.
156 * @return The selected bits.
157 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
158 * represented in this holder type.
159 */
160 public int getRawValue(final int holder) {
161 return (int) (holder & intMask());
162 }
163
164 /**
165 * Gets the value for the specified BitField, unshifted.
166 *
167 * @param holder The long data containing the bits we're interested in.
168 * @return The selected bits.
169 * @since 3.21.0
170 */
171 public long getRawValue(final long holder) {
172 return holder & mask;
173 }
174
175 /**
176 * Gets the value for the specified BitField, unshifted.
177 *
178 * @param holder The short data containing the bits we're interested in.
179 * @return The selected bits.
180 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
181 * represented in this holder type.
182 */
183 public short getShortRawValue(final short holder) {
184 return (short) getRawValue(holder);
185 }
186
187 /**
188 * Gets the value for the specified BitField, appropriately shifted right, as a short.
189 * <p>
190 * Many users of a BitField will want to treat the specified bits as an int value, and will not want to be aware that the value is stored as a BitField (and
191 * so shifted left so many bits).
192 * </p>
193 *
194 * @param holder The short data containing the bits we're interested in.
195 * @return The selected bits, shifted right appropriately.
196 * @see #setShortValue(short,short)
197 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
198 * represented in this holder type.
199 */
200 public short getShortValue(final short holder) {
201 return (short) getValue(holder);
202 }
203
204 /**
205 * Gets the value for the specified BitField, appropriately shifted right.
206 * <p>
207 * Many users of a BitField will want to treat the specified bits as an int value, and will not want to be aware that the value is stored as a BitField (and
208 * so shifted left so many bits).
209 * </p>
210 *
211 * @param holder The int data containing the bits we're interested in.
212 * @return The selected bits, shifted right appropriately.
213 * @see #setValue(int,int)
214 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
215 * represented in this holder type.
216 */
217 public int getValue(final int holder) {
218 return getRawValue(holder) >>> shiftCount;
219 }
220
221 /**
222 * Gets the value for the specified BitField, appropriately shifted right.
223 * <p>
224 * Many users of a BitField will want to treat the specified bits as an long value, and will not want to be aware that the value is stored as a BitField (and
225 * so shifted left so many bits).
226 * </p>
227 *
228 * @param holder The long data containing the bits we're interested in.
229 * @return The selected bits, shifted right appropriately.
230 * @see #setValue(long,long)
231 * @since 3.21.0
232 */
233 public long getValue(final long holder) {
234 return getRawValue(holder) >>> shiftCount;
235 }
236
237 /**
238 * Verifies that this field's mask fits in an {@code int} holder before an {@code int}, {@code short} or {@code byte} accessor uses it.
239 * <p>
240 * Without this check, a mask with bits above bit 31 makes the narrow accessors silently wrong: the {@code int} shift count is truncated mod 32, and a
241 * negative narrow holder is sign-extended to 64 bits before the {@code long} mask is applied, reporting above-bit-31 flags as set even though the holder
242 * type cannot contain them.
243 * </p>
244 *
245 * @return the mask, guaranteed to fit in 32 bits.
246 * @throws IllegalStateException Thrown if the mask has bits set above bit 31.
247 */
248 private long intMask() {
249 if (mask >>> Integer.SIZE != 0) {
250 throw new IllegalStateException("BitField mask 0x" + Long.toHexString(mask) + " exceeds 32 bits; use the long accessors for this field.");
251 }
252 return mask;
253 }
254
255 /**
256 * Tests whether all of the bits are set or not.
257 * <p>
258 * This is a stricter test than {@link #isSet(int)}, in that all of the bits in a multi-bit set must be set for this method to return {@code true}.
259 * </p>
260 *
261 * @param holder The int data containing the bits we're interested in.
262 * @return {@code true} if all of the bits are set, else {@code false}.
263 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
264 * represented in this holder type.
265 */
266 public boolean isAllSet(final int holder) {
267 final long intMask = intMask();
268 return (holder & intMask) == intMask;
269 }
270
271 /**
272 * Tests whether all of the bits are set or not.
273 * <p>
274 * This is a stricter test than {@link #isSet(long)}, in that all of the bits in a multi-bit set must be set for this method to return {@code true}.
275 * </p>
276 *
277 * @param holder The long data containing the bits we're interested in.
278 * @return {@code true} if all of the bits are set, else {@code false}.
279 * @since 3.21.0
280 */
281 public boolean isAllSet(final long holder) {
282 return (holder & mask) == mask;
283 }
284
285 /**
286 * Tests whether the field is set or not.
287 * <p>
288 * This is most commonly used for a single-bit field, which is often used to represent a boolean value; the results of using it for a multi-bit field is to
289 * determine whether <em>any</em> of its bits are set.
290 * </p>
291 *
292 * @param holder The int data containing the bits we're interested in
293 * @return {@code true} if any of the bits are set, else {@code false}
294 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
295 * represented in this holder type.
296 */
297 public boolean isSet(final int holder) {
298 return (holder & intMask()) != 0;
299 }
300
301 /**
302 * Tests whether the field is set or not.
303 * <p>
304 * This is most commonly used for a single-bit field, which is often used to represent a boolean value; the results of using it for a multi-bit field is to
305 * determine whether <em>any</em> of its bits are set.
306 * </p>
307 *
308 * @param holder The long data containing the bits we're interested in
309 * @return {@code true} if any of the bits are set, else {@code false}
310 * @since 3.21.0
311 */
312 public boolean isSet(final long holder) {
313 return (holder & mask) != 0;
314 }
315
316 /**
317 * Sets the bits.
318 *
319 * @param holder The int data containing the bits we're interested in.
320 * @return The value of holder with the specified bits set to {@code 1}.
321 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
322 * represented in this holder type.
323 */
324 public int set(final int holder) {
325 return (int) (holder | intMask());
326 }
327
328 /**
329 * Sets the bits.
330 *
331 * @param holder The long data containing the bits we're interested in.
332 * @return The value of holder with the specified bits set to {@code 1}.
333 * @since 3.21.0
334 */
335 public long set(final long holder) {
336 return holder | mask;
337 }
338
339 /**
340 * Sets a boolean BitField.
341 *
342 * @param holder The int data containing the bits we're interested in.
343 * @param flag indicating whether to set or clear the bits.
344 * @return The value of holder with the specified bits set or cleared.
345 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
346 * represented in this holder type.
347 */
348 public int setBoolean(final int holder, final boolean flag) {
349 return flag ? set(holder) : clear(holder);
350 }
351
352 /**
353 * Sets a boolean BitField.
354 *
355 * @param holder The long data containing the bits we're interested in.
356 * @param flag indicating whether to set or clear the bits.
357 * @return The value of holder with the specified bits set or cleared.
358 * @since 3.21.0
359 */
360 public long setBoolean(final long holder, final boolean flag) {
361 return flag ? set(holder) : clear(holder);
362 }
363
364 /**
365 * Sets the bits.
366 *
367 * @param holder The byte data containing the bits we're interested in
368 * @return The value of holder with the specified bits set to {@code 1}
369 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
370 * represented in this holder type.
371 */
372 public byte setByte(final byte holder) {
373 return (byte) set(holder);
374 }
375
376 /**
377 * Sets a boolean BitField.
378 *
379 * @param holder The byte data containing the bits we're interested in.
380 * @param flag indicating whether to set or clear the bits.
381 * @return The value of holder with the specified bits set or cleared.
382 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
383 * represented in this holder type.
384 */
385 public byte setByteBoolean(final byte holder, final boolean flag) {
386 return flag ? setByte(holder) : clearByte(holder);
387 }
388
389 /**
390 * Sets the bits.
391 *
392 * @param holder The short data containing the bits we're interested in.
393 * @return The value of holder with the specified bits set to {@code 1}.
394 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
395 * represented in this holder type.
396 */
397 public short setShort(final short holder) {
398 return (short) set(holder);
399 }
400
401 /**
402 * Sets a boolean BitField.
403 *
404 * @param holder The short data containing the bits we're interested in.
405 * @param flag indicating whether to set or clear the bits.
406 * @return The value of holder with the specified bits set or cleared.
407 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
408 * represented in this holder type.
409 */
410 public short setShortBoolean(final short holder, final boolean flag) {
411 return flag ? setShort(holder) : clearShort(holder);
412 }
413
414 /**
415 * Sets the bits with new values.
416 *
417 * @param holder The short data containing the bits we're interested in
418 * @param value The new value for the specified bits
419 * @return The value of holder with the bits from the value parameter replacing the old bits
420 * @see #getShortValue(short)
421 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
422 * represented in this holder type.
423 */
424 public short setShortValue(final short holder, final short value) {
425 return (short) setValue(holder, value);
426 }
427
428 /**
429 * Sets the bits with new values.
430 *
431 * @param holder The int data containing the bits we're interested in.
432 * @param value The new value for the specified bits.
433 * @return The value of holder with the bits from the value parameter replacing the old bits.
434 * @see #getValue(int)
435 * @throws IllegalStateException Thrown if this field's mask has bits set above bit 31 (only possible via {@link #BitField(long)}) and so cannot be
436 * represented in this holder type.
437 */
438 public int setValue(final int holder, final int value) {
439 final long intMask = intMask();
440 return (int) (holder & ~intMask | value << shiftCount & intMask);
441 }
442
443 /**
444 * Sets the bits with new values.
445 *
446 * @param holder The long data containing the bits we're interested in.
447 * @param value The new value for the specified bits.
448 * @return The value of holder with the bits from the value parameter replacing the old bits.
449 * @see #getValue(long)
450 * @since 3.21.0
451 */
452 public long setValue(final long holder, final long value) {
453 return holder & ~mask | value << shiftCount & mask;
454 }
455 }