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