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.collections4.bloomfilter;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Objects;
22 import java.util.function.BiPredicate;
23 import java.util.function.Predicate;
24
25 /**
26 * Produces Bloom filters from a collection (e.g. LayeredBloomFilter).
27 *
28 * @since 4.5
29 */
30 public interface BloomFilterProducer {
31
32 /**
33 * Creates a BloomFilterProducer from an array of Bloom filters.
34 *
35 * <ul>
36 * <li>The asBloomFilterArray() method returns a copy of the original array
37 * with references to the original filters.</li>
38 * <li>The forEachBloomFilterPair() method uses references to the original filters.</li>
39 * </ul>
40 * <p><em>All modifications to the Bloom filters are reflected in the original filters</em></p>
41 *
42 * @param filters The filters to be returned by the producer.
43 * @return THe BloomFilterProducer containing the filters.
44 */
45 static BloomFilterProducer fromBloomFilterArray(BloomFilter... filters) {
46 Objects.requireNonNull(filters, "filters");
47 return new BloomFilterProducer() {
48 /**
49 * This implementation returns a copy the original array, the contained Bloom filters
50 * are references to the originals, any modifications to them are reflected in the original
51 * filters.
52 */
53 @Override
54 public BloomFilter[] asBloomFilterArray() {
55 return filters.clone();
56 }
57
58 @Override
59 public boolean forEachBloomFilter(final Predicate<BloomFilter> predicate) {
60 for (final BloomFilter filter : filters) {
61 if (!predicate.test(filter)) {
62 return false;
63 }
64 }
65 return true;
66 }
67
68 /**
69 * This implementation uses references to the original filters. Any modifications to the
70 * filters are reflected in the originals.
71 */
72 @Override
73 public boolean forEachBloomFilterPair(final BloomFilterProducer other,
74 final BiPredicate<BloomFilter, BloomFilter> func) {
75 final CountingPredicate<BloomFilter> p = new CountingPredicate<>(filters, func);
76 return other.forEachBloomFilter(p) && p.forEachRemaining();
77 }
78 };
79 }
80
81 /**
82 * Return an array of the Bloom filters in the collection.
83 * <p><em>Implementations should specify if the array contains deep copies, immutable instances,
84 * or references to the filters in the collection.</em></p>
85 * <p>The default method returns a deep copy of the enclosed filters.</p>
86 *
87 * @return An array of Bloom filters.
88 */
89 default BloomFilter[] asBloomFilterArray() {
90 final List<BloomFilter> filters = new ArrayList<>();
91 forEachBloomFilter(f -> filters.add(f.copy()));
92 return filters.toArray(new BloomFilter[0]);
93 }
94
95 /**
96 * Create a standard (non-layered) Bloom filter by merging all of the layers. If
97 * the filter is empty this method will return an empty Bloom filter.
98 *
99 * @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 }