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}