BitMaps.java

  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.  * Contains functions to convert {@code int} indices into Bloom filter bit positions and visa versa.
  20.  *
  21.  * <p>The functions view an array of longs as a collection of bit maps each containing 64 bits. The bits are arranged
  22.  * in memory as a little-endian long value. This matches the requirements of the BitMapExtractor interface.</p>
  23.  *
  24.  * @since 4.5.0-M2
  25.  */
  26. public class BitMaps {

  27.     /** A bit shift to apply to an integer to divided by 64 (2^6). */
  28.     private static final int DIVIDE_BY_64 = 6;

  29.     /**
  30.      * Checks if the specified index bit is enabled in the array of bit maps.
  31.      * <p>
  32.      * If the bit specified by bitIndex is not in the bit map false is returned.
  33.      * </p>
  34.      *
  35.      * @param bitMaps  The array of bit maps.
  36.      * @param bitIndex the index of the bit to locate.
  37.      * @return {@code true} if the bit is enabled, {@code false} otherwise.
  38.      * @throws IndexOutOfBoundsException if bitIndex specifies a bit not in the range being tracked.
  39.      */
  40.     public static boolean contains(final long[] bitMaps, final int bitIndex) {
  41.         return (bitMaps[getLongIndex(bitIndex)] & getLongBit(bitIndex)) != 0;
  42.     }

  43.     /**
  44.      * Gets the filter bit mask for the specified bit index assuming the filter is using 64-bit
  45.      * longs to store bits starting at index 0. The returned value is a {@code long} with only
  46.      * 1 bit set.
  47.      *
  48.      * <p>The index is assumed to be positive. For a positive index the result will match
  49.      * {@code 1L << (bitIndex % 64)}.</p>
  50.      *
  51.      * <p><em>If the input is negative the behavior is not defined.</em></p>
  52.      *
  53.      * @param bitIndex the bit index (assumed to be positive)
  54.      * @return the filter bit
  55.      */
  56.     public static long getLongBit(final int bitIndex) {
  57.         // Bit shifts only use the first 6 bits. Thus it is not necessary to mask this
  58.         // using 0x3f (63) or compute bitIndex % 64.
  59.         // Note: If the index is negative the shift will be (64 - (bitIndex & 0x3f)) and
  60.         // this will identify an incorrect bit.
  61.         return 1L << bitIndex;
  62.     }

  63.     /**
  64.      * Gets the filter index for the specified bit index assuming the filter is using 64-bit longs
  65.      * to store bits starting at index 0.
  66.      *
  67.      * <p>The index is assumed to be positive. For a positive index the result will match
  68.      * {@code bitIndex / 64}.</p>
  69.      *
  70.      * <p><em>The divide is performed using bit shifts. If the input is negative the behavior
  71.      * is not defined.</em></p>
  72.      *
  73.      * @param bitIndex the bit index (assumed to be positive)
  74.      * @return the index of the bit map in an array of bit maps.
  75.      */
  76.     public static int getLongIndex(final int bitIndex) {
  77.         // An integer divide by 64 is equivalent to a shift of 6 bits if the integer is
  78.         // positive.
  79.         // We do not explicitly check for a negative here. Instead we use a
  80.         // signed shift. Any negative index will produce a negative value
  81.         // by sign-extension and if used as an index into an array it will throw an
  82.         // exception.
  83.         return bitIndex >> DIVIDE_BY_64;
  84.     }

  85.     /**
  86.      * Performs a modulus calculation on an unsigned long and a positive integer divisor.
  87.      *
  88.      * <p>This method computes the same result as {@link Long#remainderUnsigned(long, long)}
  89.      * but assumes that the divisor is an integer in the range 1 to 2<sup>31</sup> - 1 inclusive,
  90.      * that is a strictly positive integer size.
  91.      *
  92.      * <p><em>If the divisor is negative the behavior is not defined.</em></p>
  93.      *
  94.      * @param dividend an unsigned long value to calculate the modulus of.
  95.      * @param divisor the divisor for the modulus calculation, must be strictly positive.
  96.      * @return the remainder or modulus value.
  97.      * @throws ArithmeticException if the divisor is zero
  98.      * @see Long#remainderUnsigned(long, long)
  99.      */
  100.     public static int mod(final long dividend, final int divisor) {
  101.         // See Hacker's Delight (2nd ed), section 9.3.
  102.         // Assume divisor is positive.
  103.         // Divide half the unsigned number and then double the quotient result.
  104.         final long quotient = (dividend >>> 1) / divisor << 1;
  105.         final long remainder = dividend - quotient * divisor;
  106.         // remainder in [0, 2 * divisor)
  107.         return (int) (remainder >= divisor ? remainder - divisor : remainder);
  108.     }

  109.     /**
  110.      * Creates a new bitmap for the number of bit maps (longs) required for the numberOfBits parameter.
  111.      *
  112.      * <p><em>If the input is negative the behavior is not defined.</em></p>
  113.      *
  114.      * @param numberOfBits the number of bits to store in the array of bit maps.
  115.      * @return a new bitmap.
  116.      */
  117.     static long[] newBitMap(final int numberOfBits) {
  118.         return new long[numberOfBitMaps(numberOfBits)];
  119.     }

  120.     /**
  121.      * Creates a new bitmap for given shape parameter.
  122.      *
  123.      * @param shape the shape.
  124.      * @return a new bitmap.
  125.      */
  126.     static long[] newBitMap(final Shape shape) {
  127.         return newBitMap(shape.getNumberOfBits());
  128.     }

  129.     /**
  130.      * Calculates the number of bit maps (longs) required for the numberOfBits parameter.
  131.      *
  132.      * <p><em>If the input is negative the behavior is not defined.</em></p>
  133.      *
  134.      * @param numberOfBits the number of bits to store in the array of bit maps.
  135.      * @return the number of bit maps necessary.
  136.      */
  137.     public static int numberOfBitMaps(final int numberOfBits) {
  138.         return (numberOfBits - 1 >> DIVIDE_BY_64) + 1;
  139.     }

  140.     /**
  141.      * Calculates the number of bit maps (longs) required for the shape parameter.
  142.      *
  143.      * @param shape the shape.
  144.      * @return the number of bit maps necessary.
  145.      */
  146.     static int numberOfBitMaps(final Shape shape) {
  147.         return numberOfBitMaps(shape.getNumberOfBits());
  148.     }

  149.     /**
  150.      * Sets the bit in the bit maps.
  151.      * <p><em>Does not perform range checking</em></p>
  152.      *
  153.      * @param bitMaps  The array of bit maps.
  154.      * @param bitIndex the index of the bit to set.
  155.      * @throws IndexOutOfBoundsException if bitIndex specifies a bit not in the range being tracked.
  156.      */
  157.     public static void set(final long[] bitMaps, final int bitIndex) {
  158.         bitMaps[getLongIndex(bitIndex)] |= getLongBit(bitIndex);
  159.     }

  160.     /** Do not instantiate. */
  161.     private BitMaps() {
  162.     }
  163. }