View Javadoc
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 }