    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.collections4.bloomfilter;
    018
    019import java.util.ArrayList;
    020import java.util.List;
    021import java.util.Objects;
    022import java.util.function.BiPredicate;
    023import java.util.function.Predicate;
    024
    025/**
    026 * Produces Bloom filters from a collection (e.g. LayeredBloomFilter).
    027 *
    028 * @since 4.5
    029 */
    030public interface BloomFilterProducer {
    031
    032    /**
    033     * Creates a BloomFilterProducer from an array of Bloom filters.
    034     *
    035     * <ul>
    036     * <li>The asBloomFilterArray() method returns a copy of the original array
    037     * with references to the original filters.</li>
    038     * <li>The forEachBloomFilterPair() method uses references to the original filters.</li>
    039     * </ul>
    040     * <p><em>All modifications to the Bloom filters are reflected in the original filters</em></p>
    041     *
    042     * @param filters The filters to be returned by the producer.
    043     * @return THe BloomFilterProducer containing the filters.
    044     */
    045    static BloomFilterProducer fromBloomFilterArray(BloomFilter... filters) {
    046        Objects.requireNonNull(filters, "filters");
    047        return new BloomFilterProducer() {
    048            /**
    049             * This implementation returns a copy the original array, the contained Bloom filters
    050             * are references to the originals, any modifications to them are reflected in the original
    051             * filters.
    052             */
    053            @Override
    054            public BloomFilter[] asBloomFilterArray() {
    055                return filters.clone();
    056            }
    057
    058            @Override
    059            public boolean forEachBloomFilter(final Predicate<BloomFilter> predicate) {
    060                for (final BloomFilter filter : filters) {
    061                    if (!predicate.test(filter)) {
    062                        return false;
    063                    }
    064                }
    065                return true;
    066            }
    067
    068            /**
    069             * This implementation uses references to the original filters.  Any modifications to the
    070             * filters are reflected in the originals.
    071             */
    072            @Override
    073            public boolean forEachBloomFilterPair(final BloomFilterProducer other,
    074                    final BiPredicate<BloomFilter, BloomFilter> func) {
    075                final CountingPredicate<BloomFilter> p = new CountingPredicate<>(filters, func);
    076                return other.forEachBloomFilter(p) && p.forEachRemaining();
    077            }
    078        };
    079    }
    080
    081    /**
    082     * Return an array of the Bloom filters in the collection.
    083     * <p><em>Implementations should specify if the array contains deep copies, immutable instances,
    084     * or references to the filters in the collection.</em></p>
    085     * <p>The default method returns a deep copy of the enclosed filters.</p>
    086     *
    087     * @return An array of Bloom filters.
    088     */
    089    default BloomFilter[] asBloomFilterArray() {
    090        final List<BloomFilter> filters = new ArrayList<>();
    091        forEachBloomFilter(f -> filters.add(f.copy()));
    092        return filters.toArray(new BloomFilter[0]);
    093    }
    094
    095    /**
    096     * Create a standard (non-layered) Bloom filter by merging all of the layers. If
    097     * the filter is empty this method will return an empty Bloom filter.
    098     *
    099     * @return the merged bloom filter.
    100     */
    101    default BloomFilter flatten() {
    102        BloomFilter[] bf = {null};
    103        forEachBloomFilter( x -> {
    104            if (bf[0] == null) {
    105                bf[0] = new SimpleBloomFilter( x.getShape());
    106            }
    107            return bf[0].merge( x );
    108        });
    109        return bf[0];
    110    }
    111
    112    /**
    113     * Executes a Bloom filter Predicate on each Bloom filter in the collection. The
    114     * ordering of the Bloom filters is not specified by this interface.
    115     *
    116     * @param bloomFilterPredicate the predicate to evaluate each Bloom filter with.
    117     * @return {@code false} when the first filter fails the predicate test. Returns
    118     *         {@code true} if all filters pass the test.
    119     */
    120    boolean forEachBloomFilter(Predicate<BloomFilter> bloomFilterPredicate);
    121
    122    /**
    123     * Applies the {@code func} to each Bloom filter pair in order. Will apply all
    124     * of the Bloom filters from the other BloomFilterProducer to this producer. If
    125     * either {@code this} producer or {@code other} producer has fewer BloomFilters
    126     * ths method will provide {@code null} for all excess calls to the {@code func}.
    127     *
    128     * <p><em>This implementation returns references to the Bloom filter.  Other implementations
    129     * should specify if the array contains deep copies, immutable instances,
    130     * or references to the filters in the collection.</em></p>
    131     *
    132     * @param other The other BloomFilterProducer that provides the y values in the
    133     *              (x,y) pair.
    134     * @param func  The function to apply.
    135     * @return {@code true} if the {@code func} returned {@code true} for every pair,
    136     *         {@code false} otherwise.
    137     */
    138    default boolean forEachBloomFilterPair(final BloomFilterProducer other,
    139            final BiPredicate<BloomFilter, BloomFilter> func) {
    140        final CountingPredicate<BloomFilter> p = new CountingPredicate<>(asBloomFilterArray(), func);
    141        return other.forEachBloomFilter(p) && p.forEachRemaining();
    142    }
    143}