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 */ 030@FunctionalInterface 031public interface BloomFilterExtractor { 032 033 /** 034 * Creates a BloomFilterExtractor from an array of Bloom filters. 035 * 036 * <ul> 037 * <li>The asBloomFilterArray() method returns a copy of the original array 038 * with references to the original filters.</li> 039 * <li>The forEachBloomFilterPair() method uses references to the original filters.</li> 040 * </ul> 041 * <p><em>All modifications to the Bloom filters are reflected in the original filters</em></p> 042 * 043 * @param filters The filters to be returned by the extractor. 044 * @return THe BloomFilterExtractor containing the filters. 045 */ 046 static BloomFilterExtractor fromBloomFilterArray(final BloomFilter... filters) { 047 Objects.requireNonNull(filters, "filters"); 048 return new BloomFilterExtractor() { 049 /** 050 * This implementation returns a copy the original array, the contained Bloom filters 051 * are references to the originals, any modifications to them are reflected in the original 052 * filters. 053 */ 054 @Override 055 public BloomFilter[] asBloomFilterArray() { 056 return filters.clone(); 057 } 058 059 @Override 060 public boolean processBloomFilters(final Predicate<BloomFilter> predicate) { 061 for (final BloomFilter filter : filters) { 062 if (!predicate.test(filter)) { 063 return false; 064 } 065 } 066 return true; 067 } 068 069 /** 070 * This implementation uses references to the original filters. Any modifications to the 071 * filters are reflected in the originals. 072 */ 073 @Override 074 public boolean processBloomFilterPair(final BloomFilterExtractor other, 075 final BiPredicate<BloomFilter, BloomFilter> func) { 076 final CountingPredicate<BloomFilter> p = new CountingPredicate<>(filters, func); 077 return other.processBloomFilters(p) && p.processRemaining(); 078 } 079 }; 080 } 081 082 /** 083 * Return an array of the Bloom filters in the collection. 084 * <p><em>Implementations should specify if the array contains deep copies, immutable instances, 085 * or references to the filters in the collection.</em></p> 086 * <p>The default method returns a deep copy of the enclosed filters.</p> 087 * 088 * @return An array of Bloom filters. 089 */ 090 default BloomFilter[] asBloomFilterArray() { 091 final List<BloomFilter> filters = new ArrayList<>(); 092 processBloomFilters(f -> filters.add(f.copy())); 093 return filters.toArray(new BloomFilter[0]); 094 } 095 096 /** 097 * Create a standard (non-layered) Bloom filter by merging all of the layers. If 098 * the filter is empty this method will return an empty Bloom filter. 099 * 100 * @return the merged bloom filter. 101 */ 102 default BloomFilter flatten() { 103 final BloomFilter[] bf = {null}; 104 processBloomFilters(x -> { 105 if (bf[0] == null) { 106 bf[0] = new SimpleBloomFilter( x.getShape()); 107 } 108 return bf[0].merge( x ); 109 }); 110 return bf[0]; 111 } 112 113 /** 114 * Executes a Bloom filter Predicate on each Bloom filter in the collection. The 115 * ordering of the Bloom filters is not specified by this interface. 116 * 117 * @param bloomFilterPredicate the predicate to evaluate each Bloom filter with. 118 * @return {@code false} when the first filter fails the predicate test. Returns 119 * {@code true} if all filters pass the test. 120 */ 121 boolean processBloomFilters(Predicate<BloomFilter> bloomFilterPredicate); 122 123 /** 124 * Applies the {@code func} to each Bloom filter pair in order. Will apply all 125 * of the Bloom filters from the other BloomFilterExtractor to this extractor. If 126 * either {@code this} extractor or {@code other} extractor has fewer BloomFilters 127 * ths method will provide {@code null} for all excess calls to the {@code func}. 128 * 129 * <p><em>This implementation returns references to the Bloom filter. Other implementations 130 * should specify if the array contains deep copies, immutable instances, 131 * or references to the filters in the collection.</em></p> 132 * 133 * @param other The other BloomFilterExtractor that provides the y values in the 134 * (x,y) pair. 135 * @param func The function to apply. 136 * @return {@code true} if the {@code func} returned {@code true} for every pair, 137 * {@code false} otherwise. 138 */ 139 default boolean processBloomFilterPair(final BloomFilterExtractor other, 140 final BiPredicate<BloomFilter, BloomFilter> func) { 141 final CountingPredicate<BloomFilter> p = new CountingPredicate<>(asBloomFilterArray(), func); 142 return other.processBloomFilters(p) && p.processRemaining(); 143 } 144}