View Javadoc
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 }