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    *      http://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  package org.apache.commons.collections4.bloomfilter;
18  
19  /**
20   * Contains functions to convert {@code int} indices into Bloom filter bit positions and visa versa.
21   *
22   * <p>The functions view an array of longs as a collection of bit maps each containing 64 bits. The bits are arranged
23   * in memory as a little-endian long value. This matches the requirements of the BitMapProducer interface.</p>
24   *
25   * @since 4.5
26   */
27  public class BitMap {
28      /** A bit shift to apply to an integer to divided by 64 (2^6). */
29      private static final int DIVIDE_BY_64 = 6;
30  
31      /**
32       * Checks if the specified index bit is enabled in the array of bit maps.
33       *
34       * If the bit specified by bitIndex is not in the bit map false is returned.
35       *
36       * @param bitMaps  The array of bit maps.
37       * @param bitIndex the index of the bit to locate.
38       * @return {@code true} if the bit is enabled, {@code false} otherwise.
39       * @throws IndexOutOfBoundsException if bitIndex specifies a bit not in the range being tracked.
40       */
41      public static boolean contains(final long[] bitMaps, final int bitIndex) {
42          return (bitMaps[getLongIndex(bitIndex)] & getLongBit(bitIndex)) != 0;
43      }
44  
45      /**
46       * Gets the filter bit mask for the specified bit index assuming the filter is using 64-bit
47       * longs to store bits starting at index 0. The returned value is a {@code long} with only
48       * 1 bit set.
49       *
50       * <p>The index is assumed to be positive. For a positive index the result will match
51       * {@code 1L << (bitIndex % 64)}.</p>
52       *
53       * <p><em>If the input is negative the behavior is not defined.</em></p>
54       *
55       * @param bitIndex the bit index (assumed to be positive)
56       * @return the filter bit
57       */
58      public static long getLongBit(final int bitIndex) {
59          // Bit shifts only use the first 6 bits. Thus it is not necessary to mask this
60          // using 0x3f (63) or compute bitIndex % 64.
61          // Note: If the index is negative the shift will be (64 - (bitIndex & 0x3f)) and
62          // this will identify an incorrect bit.
63          return 1L << bitIndex;
64      }
65  
66      /**
67       * Gets the filter index for the specified bit index assuming the filter is using 64-bit longs
68       * to store bits starting at index 0.
69       *
70       * <p>The index is assumed to be positive. For a positive index the result will match
71       * {@code bitIndex / 64}.</p>
72       *
73       * <p><em>The divide is performed using bit shifts. If the input is negative the behavior
74       * is not defined.</em></p>
75       *
76       * @param bitIndex the bit index (assumed to be positive)
77       * @return the index of the bit map in an array of bit maps.
78       */
79      public static int getLongIndex(final int bitIndex) {
80          // An integer divide by 64 is equivalent to a shift of 6 bits if the integer is
81          // positive.
82          // We do not explicitly check for a negative here. Instead we use a
83          // signed shift. Any negative index will produce a negative value
84          // by sign-extension and if used as an index into an array it will throw an
85          // exception.
86          return bitIndex >> DIVIDE_BY_64;
87      }
88  
89      /**
90       * Performs a modulus calculation on an unsigned long and a positive integer divisor.
91       *
92       * <p>This method computes the same result as {@link Long#remainderUnsigned(long, long)}
93       * but assumes that the divisor is an integer in the range 1 to 2<sup>31</sup> - 1 inclusive,
94       * that is a strictly positive integer size.
95       *
96       * <p><em>If the divisor is negative the behavior is not defined.</em></p>
97       *
98       * @param dividend an unsigned long value to calculate the modulus of.
99       * @param divisor the divisor for the modulus calculation, must be strictly positive.
100      * @return the remainder or modulus value.
101      * @throws ArithmeticException if the divisor is zero
102      * @see Long#remainderUnsigned(long, long)
103      */
104     public static int mod(final long dividend, final int divisor) {
105         // See Hacker's Delight (2nd ed), section 9.3.
106         // Assume divisor is positive.
107         // Divide half the unsigned number and then double the quotient result.
108         final long quotient = (dividend >>> 1) / divisor << 1;
109         final long remainder = dividend - quotient * divisor;
110         // remainder in [0, 2 * divisor)
111         return (int) (remainder >= divisor ? remainder - divisor : remainder);
112     }
113 
114     /**
115      * Calculates the number of bit maps (longs) required for the numberOfBits parameter.
116      *
117      * <p><em>If the input is negative the behavior is not defined.</em></p>
118      *
119      * @param numberOfBits the number of bits to store in the array of bit maps.
120      * @return the number of bit maps necessary.
121      */
122     public static int numberOfBitMaps(final int numberOfBits) {
123         return (numberOfBits - 1 >> DIVIDE_BY_64) + 1;
124     }
125 
126     /**
127      * Sets the bit in the bit maps.
128      * <p><em>Does not perform range checking</em></p>
129      *
130      * @param bitMaps  The array of bit maps.
131      * @param bitIndex the index of the bit to set.
132      * @throws IndexOutOfBoundsException if bitIndex specifies a bit not in the range being tracked.
133      */
134     public static void set(final long[] bitMaps, final int bitIndex) {
135         bitMaps[getLongIndex(bitIndex)] |= getLongBit(bitIndex);
136     }
137 
138     /** Do not instantiate. */
139     private BitMap() {
140     }
141 }