View Javadoc
1   package nl.tudelft.simulation.language.util;
2   
3   import java.math.BigInteger;
4   import java.util.BitSet;
5   
6   import org.djutils.exceptions.Throw;
7   
8   /**
9    * Utilities for the BitSet class.
10   * <p>
11   * Copyright (c) 2009-2025 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
12   * for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The DSOL
13   * project is distributed under a three-clause BSD-style license, which can be found at
14   * <a href="https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
15   * </p>
16   * @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs </a>
17   * @author <a href="https://github.com/averbraeck" target="_blank"> Alexander Verbraeck</a>
18   */
19  public final class BitUtil
20  {
21      /** Constructor is not called for utility class. */
22      private BitUtil()
23      {
24          // Utility class
25      }
26  
27      /**
28       * @param bits the bitset to convert
29       * @return Returns a byte array of at least length 1. The most significant bit in the result is guaranteed not to be a 1
30       *         (since BitSet does not support sign extension). The byte-ordering of the result is big-endian which means the
31       *         most significant bit is in element 0. The bit at index 0 of the bit set is assumed to be the least significant
32       *         bit.
33       */
34      public static byte[] toByteArray(final BitSet bits)
35      {
36          synchronized (bits)
37          {
38              byte[] bytes = new byte[bits.length() / 8 + 1];
39              for (int i = 0; i < bits.length(); i++)
40              {
41                  if (bits.get(i))
42                  {
43                      bytes[bytes.length - i / 8 - 1] |= 1 << (i % 8);
44                  }
45              }
46              return bytes;
47          }
48      }
49  
50      /**
51       * returns the bitset of an integer value.
52       * @param value the value
53       * @param length the length of the bitSet to produce
54       * @return the BitSet
55       */
56      public static BitSet fromInt(final int value, final int length)
57      {
58          return BitUtil.fromInteger(Integer.valueOf(value), length);
59      }
60  
61      /**
62       * returns the bitset of an integer value.
63       * @param value the value
64       * @param length the length of
65       * @return the BitSet
66       */
67      public static BitSet fromInteger(final Integer value, final int length)
68      {
69          Throw.when(length <= 0, IllegalArgumentException.class, "BitUtil.fromInt should have a positive number of bits");
70          Throw.when(length > 31, IllegalArgumentException.class, "BitUtil.fromInt can have maximum 31 bits");
71          Throw.when(value.intValue() < 0, IllegalArgumentException.class, "BitUtil.fromInt can have only positive values");
72          return BitUtil.fromByteArray(new BigInteger(value.toString()).toByteArray());
73      }
74  
75      /**
76       * @param bits the bitset to convert
77       * @param length the length of the set
78       * @return Returns an int. The most significant bit in the result is guaranteed not to be a 1 (since BitSet does not support
79       *         sign extension). The int-ordering of the result is big-endian which means the most significant bit is in element
80       *         0. The bit at index 0 of the bit set is assumed to be the least significant bit.
81       */
82      public static int toInt(final BitSet bits, final int length)
83      {
84          Throw.when(length <= 0, IllegalArgumentException.class, "BitUtil.toInt should have a positive number of bits");
85          Throw.when(length > 31, IllegalArgumentException.class, "BitUtil.toInt can have maximum 31 bits");
86          byte[] bytes = BitUtil.toByteArray(bits);
87          return new BigInteger(bytes).intValue();
88      }
89  
90      /**
91       * constructs a new BitSet from a string in the "110110" format, or the {0, 1, 3, 5, 8, 12} format. Note that for the binary
92       * representation, the LEAST SIGNIFICANT BIT COMES FIRST. So, 001 represents the value 4 and not 1.
93       * @param value the value
94       * @return the BitSet
95       */
96      public static BitSet fromString(final String value)
97      {
98          if (!value.trim().startsWith("{"))
99          {
100             BitSet set = new BitSet(value.length());
101             for (int i = 0; i < value.length(); i++)
102             {
103                 if (value.charAt(i) == '1')
104                 {
105                     set.set(i, true);
106                 }
107                 else if (value.charAt(i) == '0')
108                 {
109                     set.set(i, false);
110                 }
111                 else
112                 {
113                     throw new IllegalArgumentException("value should only contain ones and zeros. Try 110011");
114                 }
115             }
116             return set;
117         }
118         BitSet set = new BitSet();
119         String array = value.trim();
120         if (!array.endsWith("}"))
121         {
122             throw new IllegalArgumentException("value that starts with { should end with }");
123         }
124         array = array.substring(1, array.length() - 1).trim();
125         if (array.length() == 0)
126         {
127             return set;
128         }
129         String[] bits = array.split(",");
130         for (int i = 0; i < bits.length; i++)
131         {
132             bits[i] = bits[i].trim();
133             set.set(Integer.valueOf(bits[i]).intValue());
134         }
135         return set;
136     }
137 
138     /**
139      * @param bytes the byteArray
140      * @return Returns a bitset containing the values in bytes.The byte-ordering of bytes must be big-endian which means the
141      *         most significant bit is in element 0.
142      */
143     public static BitSet fromByteArray(final byte[] bytes)
144     {
145         BitSet bits = new BitSet();
146         for (int i = 0; i < bytes.length * 8; i++)
147         {
148             if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0)
149             {
150                 bits.set(i);
151             }
152         }
153         return bits;
154     }
155 
156     /**
157      * returns a one-size BitSet with value.
158      * @param value the value of the bitSet
159      * @return the BitSet
160      */
161     public static BitSet fromBoolean(final boolean value)
162     {
163         BitSet result = new BitSet(1);
164         result.set(0, value);
165         return result;
166     }
167 }