BitIndexUpdatingInterval.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.numbers.arrays;

  18. /**
  19.  * An {@link UpdatingInterval} backed by a fixed size of bits.
  20.  *
  21.  * <p>This is a specialised class to implement a reduced API similar to a
  22.  * {@link java.util.BitSet}. It uses no bounds range checks and supports only
  23.  * the methods required to implement the {@link UpdatingInterval} API.
  24.  *
  25.  * <p>An offset is supported to allow the fixed size to cover a range of indices starting
  26.  * above 0 with the most efficient usage of storage.
  27.  *
  28.  * <p>See the BloomFilter code in Commons Collections for use of long[] data to store
  29.  * bits.
  30.  *
  31.  * @since 1.2
  32.  */
  33. final class BitIndexUpdatingInterval implements UpdatingInterval {
  34.     /** All 64-bits bits set. */
  35.     private static final long LONG_MASK = -1L;
  36.     /** A bit shift to apply to an integer to divided by 64 (2^6). */
  37.     private static final int DIVIDE_BY_64 = 6;

  38.     /** Bit indexes. */
  39.     private final long[] data;

  40.     /** Index offset. */
  41.     private final int offset;
  42.     /** Left bound of the support. */
  43.     private int left;
  44.     /** Right bound of the support. */
  45.     private int right;

  46.     /**
  47.      * Create an instance to store indices within the range {@code [left, right]}.
  48.      * The range is not validated.
  49.      *
  50.      * @param left Lower bound (inclusive).
  51.      * @param right Upper bound (inclusive).
  52.      */
  53.     BitIndexUpdatingInterval(int left, int right) {
  54.         this.offset = left;
  55.         this.left = left;
  56.         this.right = right;
  57.         // Allocate storage to store index==right
  58.         // Note: This may allow directly writing to index > right if there
  59.         // is extra capacity.
  60.         data = new long[getLongIndex(right - offset) + 1];
  61.     }

  62.     /**
  63.      * Create an instance with the range {@code [left, right]} and reusing the provided
  64.      * index {@code data}.
  65.      *
  66.      * @param data Data.
  67.      * @param offset Index offset.
  68.      * @param left Lower bound (inclusive).
  69.      * @param right Upper bound (inclusive).
  70.      */
  71.     private BitIndexUpdatingInterval(long[] data, int offset, int left, int right) {
  72.         this.data = data;
  73.         this.offset = offset;
  74.         this.left = left;
  75.         this.right = right;
  76.     }

  77.     /**
  78.      * Gets the filter index for the specified bit index assuming the filter is using
  79.      * 64-bit longs to store bits starting at index 0.
  80.      *
  81.      * <p>The index is assumed to be positive. For a positive index the result will match
  82.      * {@code bitIndex / 64}.</p>
  83.      *
  84.      * <p><em>The divide is performed using bit shifts. If the input is negative the
  85.      * behavior is not defined.</em></p>
  86.      *
  87.      * @param bitIndex the bit index (assumed to be positive)
  88.      * @return the index of the bit map in an array of bit maps.
  89.      */
  90.     private static int getLongIndex(final int bitIndex) {
  91.         // An integer divide by 64 is equivalent to a shift of 6 bits if the integer is
  92.         // positive.
  93.         // We do not explicitly check for a negative here. Instead we use a
  94.         // signed shift. Any negative index will produce a negative value
  95.         // by sign-extension and if used as an index into an array it will throw an
  96.         // exception.
  97.         return bitIndex >> DIVIDE_BY_64;
  98.     }

  99.     /**
  100.      * Gets the filter bit mask for the specified bit index assuming the filter is using
  101.      * 64-bit longs to store bits starting at index 0. The returned value is a
  102.      * {@code long} with only 1 bit set.
  103.      *
  104.      * <p>The index is assumed to be positive. For a positive index the result will match
  105.      * {@code 1L << (bitIndex % 64)}.</p>
  106.      *
  107.      * <p><em>If the input is negative the behavior is not defined.</em></p>
  108.      *
  109.      * @param bitIndex the bit index (assumed to be positive)
  110.      * @return the filter bit
  111.      */
  112.     private static long getLongBit(final int bitIndex) {
  113.         // Bit shifts only use the first 6 bits. Thus it is not necessary to mask this
  114.         // using 0x3f (63) or compute bitIndex % 64.
  115.         // Note: If the index is negative the shift will be (64 - (bitIndex & 0x3f)) and
  116.         // this will identify an incorrect bit.
  117.         return 1L << bitIndex;
  118.     }

  119.     /**
  120.      * Sets the bit at the specified index to {@code true}.
  121.      *
  122.      * <p>Warning: This has no range checks.
  123.      *
  124.      * @param bitIndex the bit index (assumed to be positive)
  125.      */
  126.     void set(int bitIndex) {
  127.         // WARNING: No range checks !!!
  128.         final int index = bitIndex - offset;
  129.         final int i = getLongIndex(index);
  130.         final long m = getLongBit(index);
  131.         data[i] |= m;
  132.     }

  133.     /**
  134.      * Returns the index of the first bit that is set to {@code true} that occurs on or
  135.      * after the specified starting index.
  136.      *
  137.      * <p>Warning: This has no range checks. It is assumed that {@code left <= k <= right},
  138.      * that is there is a set bit on or after {@code k}.
  139.      *
  140.      * @param k Index to start checking from (inclusive).
  141.      * @return the index of the next set bit
  142.      */
  143.     private int nextIndex(int k) {
  144.         // left <= k <= right

  145.         final int index = k - offset;
  146.         int i = getLongIndex(index);

  147.         // Mask bits after the bit index
  148.         // mask = 11111000 = -1L << (index % 64)
  149.         long bits = data[i] & (LONG_MASK << index);
  150.         for (;;) {
  151.             if (bits != 0) {
  152.                 //(i+1)       i
  153.                 // |    index |
  154.                 // |      |   |
  155.                 // 0  001010000
  156.                 return i * Long.SIZE + Long.numberOfTrailingZeros(bits) + offset;
  157.             }
  158.             // Unsupported: the interval should contain k
  159.             //if (++i == data.length)
  160.             //    return right + 1
  161.             bits = data[++i];
  162.         }
  163.     }

  164.     /**
  165.      * Returns the index of the first bit that is set to {@code true} that occurs on or
  166.      * before the specified starting index.
  167.      *
  168.      * <p>Warning: This has no range checks. It is assumed that {@code left <= k <= right},
  169.      * that is there is a set bit on or before {@code k}.
  170.      *
  171.      * @param k Index to start checking from (inclusive).
  172.      * @return the index of the previous set bit
  173.      */
  174.     private int previousIndex(int k) {
  175.         // left <= k <= right

  176.         final int index = k - offset;
  177.         int i = getLongIndex(index);

  178.         // Mask bits before the bit index
  179.         // mask = 00011111 = -1L >>> (64 - ((index + 1) % 64))
  180.         long bits = data[i] & (LONG_MASK >>> -(index + 1));
  181.         for (;;) {
  182.             if (bits != 0) {
  183.                 //(i+1)       i
  184.                 // |  index   |
  185.                 // |    |     |
  186.                 // 0  001010000
  187.                 return (i + 1) * Long.SIZE - Long.numberOfLeadingZeros(bits) - 1 + offset;
  188.             }
  189.             // Unsupported: the interval should contain k
  190.             //if (i == 0)
  191.             //    return left - 1
  192.             bits = data[--i];
  193.         }
  194.     }

  195.     @Override
  196.     public int left() {
  197.         return left;
  198.     }

  199.     @Override
  200.     public int right() {
  201.         return right;
  202.     }

  203.     @Override
  204.     public int updateLeft(int k) {
  205.         // Assume left < k= < right
  206.         return left = nextIndex(k);
  207.     }

  208.     @Override
  209.     public int updateRight(int k) {
  210.         // Assume left <= k < right
  211.         return right = previousIndex(k);
  212.     }

  213.     @Override
  214.     public UpdatingInterval splitLeft(int ka, int kb) {
  215.         // Assume left < ka <= kb < right
  216.         final int lower = left;
  217.         left = nextIndex(kb + 1);
  218.         return new BitIndexUpdatingInterval(data, offset, lower, previousIndex(ka - 1));
  219.     }
  220. }