public IndexExtractor indices()

in src/main/java/org/apache/commons/collections4/bloomfilter/EnhancedDoubleHasher.java [138:221]


    public IndexExtractor indices(final Shape shape) {
        Objects.requireNonNull(shape, "shape");

        return new IndexExtractor() {

            @Override
            public int[] asIndexArray() {
                final int[] result = new int[shape.getNumberOfHashFunctions()];
                final int[] idx = new int[1];

                // This method needs to return duplicate indices

                processIndices(i -> {
                    result[idx[0]++] = i;
                    return true;
                });
                return result;
            }

            @Override
            public boolean processIndices(final IntPredicate consumer) {
                Objects.requireNonNull(consumer, "consumer");
                final int bits = shape.getNumberOfBits();
                // Enhanced double hashing:
                // hash[i] = ( h1(x) + i*h2(x) + (i*i*i - i)/6 ) mod bits
                // See: https://en.wikipedia.org/wiki/Double_hashing#Enhanced_double_hashing
                //
                // Essentially this is computing a wrapped modulus from a start point and an
                // increment and an additional term as a tetrahedral number.
                // You only need two modulus operations before the loop. Within the loop
                // the modulus is handled using the sign bit to detect wrapping to ensure:
                // 0 <= index < bits
                // 0 <= inc < bits
                // The final hash is:
                // hash[i] = ( h1(x) - i*h2(x) - (i*i*i - i)/6 ) wrapped in [0, bits)

                int index = BitMaps.mod(initial, bits);
                if (!consumer.test(index)) {
                    return false;
                }
                int inc = BitMaps.mod(increment, bits);

                final int k = shape.getNumberOfHashFunctions();

                if (k >= bits) {
                    // the tetraheadral incrementer.  We need to ensure that this
                    // number does not exceed bits-1 or we may end up with an index > bits.
                    int tet = 1;
                    for (int i = 1; i < k; i++) {
                        // Update index and handle wrapping
                        index -= inc;
                        index = index < 0 ? index + bits : index;
                        if (!consumer.test(index)) {
                            return false;
                        }

                        // Incorporate the counter into the increment to create a
                        // tetrahedral number additional term, and handle wrapping.
                        inc -= tet;
                        inc = inc < 0 ? inc + bits : inc;
                        if (++tet == bits) {
                            tet = 0;
                        }
                    }
                } else {
                    for (int i = 1; i < k; i++) {
                        // Update index and handle wrapping
                        index -= inc;
                        index = index < 0 ? index + bits : index;
                        if (!consumer.test(index)) {
                            return false;
                        }

                        // Incorporate the counter into the increment to create a
                        // tetrahedral number additional term, and handle wrapping.
                        inc -= i;
                        inc = inc < 0 ? inc + bits : inc;
                    }

                }
                return true;
            }
        };
    }