Fix generic typing for BloomFilter.copy()
Avoids guaranteed exceptions. For example: SparseBloomFilter filter = new SimpleBloomFilter(Shape.fromNP(10000, 0.01)).copy(); After this commit, this type of broken code won't even compile.
This commit is contained in:
parent
32a0b7783a
commit
5479a7d765
|
@ -160,6 +160,11 @@ public final class ArrayCountingBloomFilter implements CountingBloomFilter {
|
|||
return indexExtractor.processIndices(idx -> cells[idx] != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this {@link ArrayCountingBloomFilter} with the same properties as the current one.
|
||||
*
|
||||
* @return a copy of this BloomFilter.
|
||||
*/
|
||||
@Override
|
||||
public ArrayCountingBloomFilter copy() {
|
||||
return new ArrayCountingBloomFilter(this);
|
||||
|
|
|
@ -23,11 +23,13 @@ import java.util.Objects;
|
|||
* <p>
|
||||
* <em>See implementation notes for {@link BitMapExtractor} and {@link IndexExtractor}.</em>
|
||||
* </p>
|
||||
*
|
||||
* @param <T> The BloomFilter type.
|
||||
* @see BitMapExtractor
|
||||
* @see IndexExtractor
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public interface BloomFilter extends IndexExtractor, BitMapExtractor {
|
||||
public interface BloomFilter<T extends BloomFilter<T>> extends IndexExtractor, BitMapExtractor {
|
||||
|
||||
/**
|
||||
* The sparse characteristic used to determine the best method for matching.
|
||||
|
@ -84,7 +86,7 @@ public interface BloomFilter extends IndexExtractor, BitMapExtractor {
|
|||
* @param other the other Bloom filter
|
||||
* @return true if all enabled bits in the other filter are enabled in this filter.
|
||||
*/
|
||||
default boolean contains(final BloomFilter other) {
|
||||
default boolean contains(final BloomFilter<?> other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
return (characteristics() & SPARSE) != 0 ? contains((IndexExtractor) other) : contains((BitMapExtractor) other);
|
||||
}
|
||||
|
@ -117,12 +119,11 @@ public interface BloomFilter extends IndexExtractor, BitMapExtractor {
|
|||
boolean contains(IndexExtractor indexExtractor);
|
||||
|
||||
/**
|
||||
* Creates a new instance of the BloomFilter with the same properties as the current one.
|
||||
* Creates a new instance of this {@link BloomFilter} with the same properties as the current one.
|
||||
*
|
||||
* @param <T> Type of BloomFilter.
|
||||
* @return a copy of this BloomFilter
|
||||
* @return a copy of this {@link BloomFilter}.
|
||||
*/
|
||||
<T extends BloomFilter> T copy();
|
||||
T copy();
|
||||
|
||||
// update operations
|
||||
|
||||
|
@ -142,7 +143,7 @@ public interface BloomFilter extends IndexExtractor, BitMapExtractor {
|
|||
* @see #estimateN()
|
||||
* @see Shape
|
||||
*/
|
||||
default int estimateIntersection(final BloomFilter other) {
|
||||
default int estimateIntersection(final BloomFilter<?> other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
final double eThis = getShape().estimateN(cardinality());
|
||||
final double eOther = getShape().estimateN(other.cardinality());
|
||||
|
@ -157,7 +158,7 @@ public interface BloomFilter extends IndexExtractor, BitMapExtractor {
|
|||
} else if (Double.isInfinite(eOther)) {
|
||||
estimate = Math.round(eThis);
|
||||
} else {
|
||||
final BloomFilter union = this.copy();
|
||||
final T union = this.copy();
|
||||
union.merge(other);
|
||||
final double eUnion = getShape().estimateN(union.cardinality());
|
||||
if (Double.isInfinite(eUnion)) {
|
||||
|
@ -220,11 +221,11 @@ public interface BloomFilter extends IndexExtractor, BitMapExtractor {
|
|||
* @see #estimateN()
|
||||
* @see Shape
|
||||
*/
|
||||
default int estimateUnion(final BloomFilter other) {
|
||||
default int estimateUnion(final BloomFilter<?> other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
final BloomFilter cpy = this.copy();
|
||||
cpy.merge(other);
|
||||
return cpy.estimateN();
|
||||
final T copy = this.copy();
|
||||
copy.merge(other);
|
||||
return copy.estimateN();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -290,7 +291,7 @@ public interface BloomFilter extends IndexExtractor, BitMapExtractor {
|
|||
* @param other The bloom filter to merge into this one.
|
||||
* @return true if the merge was successful
|
||||
*/
|
||||
default boolean merge(final BloomFilter other) {
|
||||
default boolean merge(final BloomFilter<?> other) {
|
||||
return (characteristics() & SPARSE) != 0 ? merge((IndexExtractor) other) : merge((BitMapExtractor) other);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,12 +41,14 @@ public interface BloomFilterExtractor {
|
|||
* </ul>
|
||||
* <p><em>All modifications to the Bloom filters are reflected in the original filters</em></p>
|
||||
*
|
||||
* @param <T> The BloomFilter type.
|
||||
* @param filters The filters to be returned by the extractor.
|
||||
* @return THe BloomFilterExtractor containing the filters.
|
||||
*/
|
||||
static BloomFilterExtractor fromBloomFilterArray(final BloomFilter... filters) {
|
||||
static <T extends BloomFilter<T>> BloomFilterExtractor fromBloomFilterArray(final BloomFilter<?>... filters) {
|
||||
Objects.requireNonNull(filters, "filters");
|
||||
return new BloomFilterExtractor() {
|
||||
|
||||
/**
|
||||
* This implementation returns a copy the original array, the contained Bloom filters
|
||||
* are references to the originals, any modifications to them are reflected in the original
|
||||
|
|
|
@ -54,7 +54,7 @@ import java.util.Objects;
|
|||
* @see CellExtractor
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public interface CountingBloomFilter extends BloomFilter, CellExtractor {
|
||||
public interface CountingBloomFilter extends BloomFilter<CountingBloomFilter>, CellExtractor {
|
||||
|
||||
// Query Operations
|
||||
|
||||
|
@ -74,13 +74,6 @@ public interface CountingBloomFilter extends BloomFilter, CellExtractor {
|
|||
*/
|
||||
boolean add(CellExtractor other);
|
||||
|
||||
/**
|
||||
* Creates a new instance of the CountingBloomFilter with the same properties as the current one.
|
||||
* @return a copy of this CountingBloomFilter
|
||||
*/
|
||||
@Override
|
||||
CountingBloomFilter copy();
|
||||
|
||||
/**
|
||||
* Returns the maximum allowable value for a cell count in this Counting filter.
|
||||
* @return the maximum allowable value for a cell count in this Counting filter.
|
||||
|
@ -114,7 +107,7 @@ public interface CountingBloomFilter extends BloomFilter, CellExtractor {
|
|||
* @param bloomFilter the Bloom filter the check for.
|
||||
* @return the maximum number of times the Bloom filter could have been inserted.
|
||||
*/
|
||||
default int getMaxInsert(final BloomFilter bloomFilter) {
|
||||
default int getMaxInsert(final BloomFilter<?> bloomFilter) {
|
||||
return getMaxInsert((BitMapExtractor) bloomFilter);
|
||||
}
|
||||
|
||||
|
@ -204,7 +197,7 @@ public interface CountingBloomFilter extends BloomFilter, CellExtractor {
|
|||
* @see #add(CellExtractor)
|
||||
*/
|
||||
@Override
|
||||
default boolean merge(final BloomFilter other) {
|
||||
default boolean merge(final BloomFilter<?> other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
return merge((IndexExtractor) other);
|
||||
}
|
||||
|
@ -288,7 +281,7 @@ public interface CountingBloomFilter extends BloomFilter, CellExtractor {
|
|||
* @see #isValid()
|
||||
* @see #subtract(CellExtractor)
|
||||
*/
|
||||
default boolean remove(final BloomFilter other) {
|
||||
default boolean remove(final BloomFilter<?> other) {
|
||||
return remove((IndexExtractor) other);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,14 +53,14 @@ import java.util.function.Supplier;
|
|||
* @param <T> the {@link BloomFilter} type.
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor {
|
||||
public class LayerManager<T extends BloomFilter<T>> implements BloomFilterExtractor {
|
||||
|
||||
/**
|
||||
* Builds new instances of {@link LayerManager}.
|
||||
*
|
||||
* @param <T> the {@link BloomFilter} type.
|
||||
*/
|
||||
public static class Builder<T extends BloomFilter> implements Supplier<LayerManager<T>> {
|
||||
public static class Builder<T extends BloomFilter<T>> implements Supplier<LayerManager<T>> {
|
||||
|
||||
private Predicate<LayerManager<T>> extendCheck;
|
||||
private Supplier<T> supplier;
|
||||
|
@ -131,7 +131,7 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @param <T> Type of BloomFilter.
|
||||
* @return A Consumer suitable for the LayerManager {@code cleanup} parameter.
|
||||
*/
|
||||
public static <T extends BloomFilter> Consumer<Deque<T>> noCleanup() {
|
||||
public static <T extends BloomFilter<T>> Consumer<Deque<T>> noCleanup() {
|
||||
return x -> {
|
||||
// empty
|
||||
};
|
||||
|
@ -147,7 +147,7 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @return A Consumer suitable for the LayerManager {@code cleanup} parameter.
|
||||
* @throws IllegalArgumentException if {@code maxSize <= 0}.
|
||||
*/
|
||||
public static <T extends BloomFilter> Consumer<Deque<T>> onMaxSize(final int maxSize) {
|
||||
public static <T extends BloomFilter<T>> Consumer<Deque<T>> onMaxSize(final int maxSize) {
|
||||
if (maxSize <= 0) {
|
||||
throw new IllegalArgumentException("'maxSize' must be greater than 0");
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @param <T> Type of BloomFilter.
|
||||
* @return A Consumer suitable for the LayerManager {@code cleanup} parameter.
|
||||
*/
|
||||
public static <T extends BloomFilter> Consumer<Deque<T>> removeEmptyTarget() {
|
||||
public static <T extends BloomFilter<T>> Consumer<Deque<T>> removeEmptyTarget() {
|
||||
return x -> {
|
||||
if (!x.isEmpty() && x.getLast().isEmpty()) {
|
||||
x.removeLast();
|
||||
|
@ -180,7 +180,7 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @param test Predicate.
|
||||
* @return A Consumer suitable for the LayerManager {@code cleanup} parameter.
|
||||
*/
|
||||
public static <T extends BloomFilter> Consumer<Deque<T>> removeIf(final Predicate<? super T> test) {
|
||||
public static <T extends BloomFilter<T>> Consumer<Deque<T>> removeIf(final Predicate<? super T> test) {
|
||||
return x -> x.removeIf(test);
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @return A Predicate suitable for the LayerManager {@code extendCheck} parameter.
|
||||
* @throws IllegalArgumentException if {@code breakAt <= 0}
|
||||
*/
|
||||
public static <T extends BloomFilter> Predicate<LayerManager<T>> advanceOnCount(final int breakAt) {
|
||||
public static <T extends BloomFilter<T>> Predicate<LayerManager<T>> advanceOnCount(final int breakAt) {
|
||||
if (breakAt <= 0) {
|
||||
throw new IllegalArgumentException("'breakAt' must be greater than 0");
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @param <T> Type of BloomFilter.
|
||||
* @return A Predicate suitable for the LayerManager {@code extendCheck} parameter.
|
||||
*/
|
||||
public static <T extends BloomFilter> Predicate<LayerManager<T>> advanceOnPopulated() {
|
||||
public static <T extends BloomFilter<T>> Predicate<LayerManager<T>> advanceOnPopulated() {
|
||||
return lm -> !lm.last().isEmpty();
|
||||
}
|
||||
|
||||
|
@ -242,12 +242,12 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @return A Predicate suitable for the LayerManager {@code extendCheck} parameter.
|
||||
* @throws IllegalArgumentException if {@code maxN <= 0}
|
||||
*/
|
||||
public static <T extends BloomFilter> Predicate<LayerManager<T>> advanceOnSaturation(final double maxN) {
|
||||
public static <T extends BloomFilter<T>> Predicate<LayerManager<T>> advanceOnSaturation(final double maxN) {
|
||||
if (maxN <= 0) {
|
||||
throw new IllegalArgumentException("'maxN' must be greater than 0");
|
||||
}
|
||||
return manager -> {
|
||||
final BloomFilter bf = manager.last();
|
||||
final T bf = manager.last();
|
||||
return maxN <= bf.getShape().estimateN(bf.cardinality());
|
||||
};
|
||||
}
|
||||
|
@ -259,13 +259,14 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @param <T> Type of BloomFilter.
|
||||
* @return A Predicate suitable for the LayerManager {@code extendCheck} parameter.
|
||||
*/
|
||||
public static <T extends BloomFilter> Predicate<LayerManager<T>> neverAdvance() {
|
||||
public static <T extends BloomFilter<T>> Predicate<LayerManager<T>> neverAdvance() {
|
||||
return x -> false;
|
||||
}
|
||||
|
||||
private ExtendCheck() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Builder with defaults of {@code ExtendCheck.neverAdvance()} and
|
||||
* {@code Cleanup.noCleanup()}.
|
||||
|
@ -275,7 +276,7 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
* @see ExtendCheck#neverAdvance()
|
||||
* @see Cleanup#noCleanup()
|
||||
*/
|
||||
public static <T extends BloomFilter> Builder<T> builder() {
|
||||
public static <T extends BloomFilter<T>> Builder<T> builder() {
|
||||
return new Builder<>();
|
||||
}
|
||||
|
||||
|
@ -337,13 +338,15 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a deep copy of this LayerManager.
|
||||
* <p><em>Filters in the copy are deep copies, not references, so changes in the copy
|
||||
* are NOT reflected in the original.</em></p>
|
||||
* <p>The {@code filterSupplier}, {@code extendCheck}, and the {@code filterCleanup} are shared between
|
||||
* the copy and this instance.</p>
|
||||
* Creates a deep copy of this {@link LayerManager}.
|
||||
* <p>
|
||||
* <em>Filters in the copy are deep copies, not references, so changes in the copy are NOT reflected in the original.</em>
|
||||
* </p>
|
||||
* <p>
|
||||
* The {@code filterSupplier}, {@code extendCheck}, and the {@code filterCleanup} are shared between the copy and this instance.
|
||||
* </p>
|
||||
*
|
||||
* @return a copy of this layer Manager.
|
||||
* @return a copy of this {@link LayerManager}.
|
||||
*/
|
||||
public LayerManager<T> copy() {
|
||||
final LayerManager<T> newMgr = new LayerManager<>(filterSupplier, extendCheck, filterCleanup, false);
|
||||
|
@ -438,7 +441,7 @@ public class LayerManager<T extends BloomFilter> implements BloomFilterExtractor
|
|||
*/
|
||||
@Override
|
||||
public boolean processBloomFilters(final Predicate<BloomFilter> bloomFilterPredicate) {
|
||||
for (final BloomFilter bf : filters) {
|
||||
for (final T bf : filters) {
|
||||
if (!bloomFilterPredicate.test(bf)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -59,10 +59,11 @@ import java.util.function.Predicate;
|
|||
* removes them. It also checks it a new layer should be added, and if so adds
|
||||
* it and sets the {@code target} before the operation.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> The type of Bloom Filter that is used for the layers.
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public class LayeredBloomFilter<T extends BloomFilter> implements BloomFilter, BloomFilterExtractor {
|
||||
public class LayeredBloomFilter<T extends BloomFilter<T>> implements BloomFilter<LayeredBloomFilter<T>>, BloomFilterExtractor {
|
||||
/**
|
||||
* A class used to locate matching filters across all the layers.
|
||||
*/
|
||||
|
@ -70,9 +71,9 @@ public class LayeredBloomFilter<T extends BloomFilter> implements BloomFilter, B
|
|||
int[] result = new int[layerManager.getDepth()];
|
||||
int bfIdx;
|
||||
int resultIdx;
|
||||
BloomFilter bf;
|
||||
BloomFilter<?> bf;
|
||||
|
||||
Finder(final BloomFilter bf) {
|
||||
Finder(final BloomFilter<?> bf) {
|
||||
this.bf = bf;
|
||||
}
|
||||
|
||||
|
@ -180,6 +181,11 @@ public class LayeredBloomFilter<T extends BloomFilter> implements BloomFilter, B
|
|||
return contains(createFilter(indexExtractor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this {@link LayeredBloomFilter} with the same properties as the current one.
|
||||
*
|
||||
* @return a copy of this {@link LayeredBloomFilter}.
|
||||
*/
|
||||
@Override
|
||||
public LayeredBloomFilter<T> copy() {
|
||||
return new LayeredBloomFilter<>(shape, layerManager.copy());
|
||||
|
@ -191,7 +197,7 @@ public class LayeredBloomFilter<T extends BloomFilter> implements BloomFilter, B
|
|||
* @param bitMapExtractor the BitMapExtractor to create the filter from.
|
||||
* @return the BloomFilter.
|
||||
*/
|
||||
private BloomFilter createFilter(final BitMapExtractor bitMapExtractor) {
|
||||
private SimpleBloomFilter createFilter(final BitMapExtractor bitMapExtractor) {
|
||||
final SimpleBloomFilter bf = new SimpleBloomFilter(shape);
|
||||
bf.merge(bitMapExtractor);
|
||||
return bf;
|
||||
|
@ -203,7 +209,7 @@ public class LayeredBloomFilter<T extends BloomFilter> implements BloomFilter, B
|
|||
* @param hasher the hasher to create the filter from.
|
||||
* @return the BloomFilter.
|
||||
*/
|
||||
private BloomFilter createFilter(final Hasher hasher) {
|
||||
private SimpleBloomFilter createFilter(final Hasher hasher) {
|
||||
final SimpleBloomFilter bf = new SimpleBloomFilter(shape);
|
||||
bf.merge(hasher);
|
||||
return bf;
|
||||
|
@ -215,7 +221,7 @@ public class LayeredBloomFilter<T extends BloomFilter> implements BloomFilter, B
|
|||
* @param indexExtractor the IndexExtractor to create the filter from.
|
||||
* @return the BloomFilter.
|
||||
*/
|
||||
private BloomFilter createFilter(final IndexExtractor indexExtractor) {
|
||||
private SimpleBloomFilter createFilter(final IndexExtractor indexExtractor) {
|
||||
final SimpleBloomFilter bf = new SimpleBloomFilter(shape);
|
||||
bf.merge(indexExtractor);
|
||||
return bf;
|
||||
|
@ -289,8 +295,8 @@ public class LayeredBloomFilter<T extends BloomFilter> implements BloomFilter, B
|
|||
* @return the merged bloom filter.
|
||||
*/
|
||||
@Override
|
||||
public BloomFilter flatten() {
|
||||
final BloomFilter bf = new SimpleBloomFilter(shape);
|
||||
public SimpleBloomFilter flatten() {
|
||||
final SimpleBloomFilter bf = new SimpleBloomFilter(shape);
|
||||
processBloomFilters(bf::merge);
|
||||
return bf;
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ public final class SetOperations {
|
|||
* @param second the second Bloom filter.
|
||||
* @return the Cosine similarity.
|
||||
*/
|
||||
public static double cosineSimilarity(final BloomFilter first, final BloomFilter second) {
|
||||
public static double cosineSimilarity(final BloomFilter<?> first, final BloomFilter<?> second) {
|
||||
final int numerator = andCardinality(first, second);
|
||||
// Given that the cardinality is an int then the product as a double will not
|
||||
// overflow, we can use one sqrt:
|
||||
|
|
|
@ -24,9 +24,10 @@ import java.util.function.LongPredicate;
|
|||
/**
|
||||
* A bloom filter using an array of bit maps to track enabled bits. This is a standard
|
||||
* implementation and should work well for most Bloom filters.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public final class SimpleBloomFilter implements BloomFilter {
|
||||
public final class SimpleBloomFilter implements BloomFilter<SimpleBloomFilter> {
|
||||
|
||||
/**
|
||||
* The array of bit map longs that defines this Bloom filter. Will be null if the filter is empty.
|
||||
|
@ -96,6 +97,11 @@ public final class SimpleBloomFilter implements BloomFilter {
|
|||
return indexExtractor.processIndices(idx -> BitMaps.contains(bitMap, idx));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this {@link SimpleBloomFilter} with the same properties as the current one.
|
||||
*
|
||||
* @return a copy of this {@link SimpleBloomFilter}.
|
||||
*/
|
||||
@Override
|
||||
public SimpleBloomFilter copy() {
|
||||
return new SimpleBloomFilter(this);
|
||||
|
@ -140,7 +146,7 @@ public final class SimpleBloomFilter implements BloomFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean merge(final BloomFilter other) {
|
||||
public boolean merge(final BloomFilter<?> other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
if ((other.characteristics() & SPARSE) != 0) {
|
||||
merge((IndexExtractor) other);
|
||||
|
|
|
@ -26,7 +26,7 @@ import java.util.function.LongPredicate;
|
|||
* implementation and should work well for most low cardinality Bloom filters.
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public final class SparseBloomFilter implements BloomFilter {
|
||||
public final class SparseBloomFilter implements BloomFilter<SparseBloomFilter> {
|
||||
|
||||
/**
|
||||
* The bitSet that defines this BloomFilter.
|
||||
|
@ -98,6 +98,11 @@ public final class SparseBloomFilter implements BloomFilter {
|
|||
return indexExtractor.processIndices(indices::contains);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this {@link SparseBloomFilter} with the same properties as the current one.
|
||||
*
|
||||
* @return a copy of this {@link SparseBloomFilter}.
|
||||
*/
|
||||
@Override
|
||||
public SparseBloomFilter copy() {
|
||||
return new SparseBloomFilter(this);
|
||||
|
@ -120,7 +125,7 @@ public final class SparseBloomFilter implements BloomFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean merge(final BloomFilter other) {
|
||||
public boolean merge(final BloomFilter<?> other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
final IndexExtractor indexExtractor = (other.characteristics() & SPARSE) != 0 ? (IndexExtractor) other : IndexExtractor.fromBitMapExtractor(other);
|
||||
merge(indexExtractor);
|
||||
|
|
|
@ -22,17 +22,20 @@ import java.util.function.LongPredicate;
|
|||
/**
|
||||
* An abstract class to assist in implementing Bloom filter decorators.
|
||||
*
|
||||
* @param <T> The WrappedBloomFilter type.
|
||||
* @param <W> The <em>wrapped</em> BloomFilter type.
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public abstract class WrappedBloomFilter implements BloomFilter {
|
||||
private final BloomFilter wrapped;
|
||||
public abstract class WrappedBloomFilter<T extends WrappedBloomFilter<T, W>, W extends BloomFilter<W>> implements BloomFilter<T> {
|
||||
|
||||
private final W wrapped;
|
||||
|
||||
/**
|
||||
* Wraps a Bloom filter. The wrapped filter is maintained as a reference
|
||||
* not a copy. Changes in one will be reflected in the other.
|
||||
* @param wrapped The Bloom filter.
|
||||
*/
|
||||
public WrappedBloomFilter(final BloomFilter wrapped) {
|
||||
public WrappedBloomFilter(final W wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
@ -67,7 +70,7 @@ public abstract class WrappedBloomFilter implements BloomFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(final BloomFilter other) {
|
||||
public boolean contains(final BloomFilter<?> other) {
|
||||
return wrapped.contains(other);
|
||||
}
|
||||
|
||||
|
@ -82,7 +85,7 @@ public abstract class WrappedBloomFilter implements BloomFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int estimateIntersection(final BloomFilter other) {
|
||||
public int estimateIntersection(final BloomFilter<?> other) {
|
||||
return wrapped.estimateIntersection(other);
|
||||
}
|
||||
|
||||
|
@ -92,7 +95,7 @@ public abstract class WrappedBloomFilter implements BloomFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int estimateUnion(final BloomFilter other) {
|
||||
public int estimateUnion(final BloomFilter<?> other) {
|
||||
return wrapped.estimateUnion(other);
|
||||
}
|
||||
|
||||
|
@ -106,7 +109,7 @@ public abstract class WrappedBloomFilter implements BloomFilter {
|
|||
*
|
||||
* @return the wrapped BloomFilter.
|
||||
*/
|
||||
protected BloomFilter getWrapped() {
|
||||
protected W getWrapped() {
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
|
@ -121,7 +124,7 @@ public abstract class WrappedBloomFilter implements BloomFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean merge(final BloomFilter other) {
|
||||
public boolean merge(final BloomFilter<?> other) {
|
||||
return wrapped.merge(other);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.junit.jupiter.api.Test;
|
|||
public abstract class AbstractBloomFilterExtractorTest {
|
||||
private final Shape shape = Shape.fromKM(17, 72);
|
||||
|
||||
BloomFilter one = new SimpleBloomFilter(shape);
|
||||
BloomFilter two = new SimpleBloomFilter(shape);
|
||||
SimpleBloomFilter one = new SimpleBloomFilter(shape);
|
||||
SimpleBloomFilter two = new SimpleBloomFilter(shape);
|
||||
int[] nullCount = { 0, 0 };
|
||||
int[] equalityCount = { 0 };
|
||||
BiPredicate<BloomFilter, BloomFilter> counter = (x, y) -> {
|
||||
|
|
|
@ -24,8 +24,8 @@ public class BitMapExtractorFromWrappedBloomFilterTest extends AbstractBitMapExt
|
|||
protected BitMapExtractor createEmptyExtractor() {
|
||||
return new WrappedBloomFilter(new DefaultBloomFilterTest.SparseDefaultBloomFilter(shape)) {
|
||||
@Override
|
||||
public BloomFilter copy() {
|
||||
final BloomFilter result = new DefaultBloomFilterTest.SparseDefaultBloomFilter(shape);
|
||||
public DefaultBloomFilterTest.SparseDefaultBloomFilter copy() {
|
||||
final DefaultBloomFilterTest.SparseDefaultBloomFilter result = new DefaultBloomFilterTest.SparseDefaultBloomFilter(shape);
|
||||
result.merge(getWrapped());
|
||||
return result;
|
||||
}
|
||||
|
@ -35,10 +35,10 @@ public class BitMapExtractorFromWrappedBloomFilterTest extends AbstractBitMapExt
|
|||
@Override
|
||||
protected BitMapExtractor createExtractor() {
|
||||
final Hasher hasher = new IncrementingHasher(0, 1);
|
||||
final BloomFilter bf = new WrappedBloomFilter(new DefaultBloomFilterTest.SparseDefaultBloomFilter(shape)) {
|
||||
final WrappedBloomFilter bf = new WrappedBloomFilter(new DefaultBloomFilterTest.SparseDefaultBloomFilter(shape)) {
|
||||
@Override
|
||||
public BloomFilter copy() {
|
||||
final BloomFilter result = new DefaultBloomFilterTest.SparseDefaultBloomFilter(shape);
|
||||
public DefaultBloomFilterTest.SparseDefaultBloomFilter copy() {
|
||||
final DefaultBloomFilterTest.SparseDefaultBloomFilter result = new DefaultBloomFilterTest.SparseDefaultBloomFilter(shape);
|
||||
result.merge(getWrapped());
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -24,13 +24,15 @@ public class BloomFilterExtractorFromLayeredBloomFilterTest extends AbstractBloo
|
|||
@Override
|
||||
protected BloomFilterExtractor createUnderTest(final BloomFilter... filters) {
|
||||
final Builder<SimpleBloomFilter> builder = LayerManager.<SimpleBloomFilter>builder();
|
||||
if (!ArrayUtils.isEmpty(filters)) {
|
||||
final BloomFilter bloomFilter0 = ArrayUtils.get(filters, 0);
|
||||
final Shape shape0 = bloomFilter0 != null ? bloomFilter0.getShape() : null;
|
||||
if (shape0 != null) {
|
||||
// Avoid an NPE in test code and let the domain classes decide what to do when there is no supplier set.
|
||||
builder.setSupplier(() -> new SimpleBloomFilter(filters[0].getShape()));
|
||||
builder.setSupplier(() -> new SimpleBloomFilter(shape0));
|
||||
}
|
||||
final LayerManager<SimpleBloomFilter> layerManager = builder.setExtendCheck(LayerManager.ExtendCheck.advanceOnPopulated())
|
||||
.setCleanup(LayerManager.Cleanup.noCleanup()).get();
|
||||
final LayeredBloomFilter underTest = new LayeredBloomFilter(filters[0].getShape(), layerManager);
|
||||
final LayeredBloomFilter underTest = new LayeredBloomFilter(shape0, layerManager);
|
||||
for (final BloomFilter bf : filters) {
|
||||
underTest.merge(bf);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,9 @@ import org.junit.jupiter.api.Test;
|
|||
* Tests for the {@link BloomFilter}.
|
||||
*/
|
||||
public class DefaultBloomFilterTest extends AbstractBloomFilterTest<DefaultBloomFilterTest.AbstractDefaultBloomFilter> {
|
||||
abstract static class AbstractDefaultBloomFilter implements BloomFilter {
|
||||
|
||||
abstract static class AbstractDefaultBloomFilter<T extends AbstractDefaultBloomFilter<T>> implements BloomFilter<T> {
|
||||
|
||||
private final Shape shape;
|
||||
protected TreeSet<Integer> indices;
|
||||
|
||||
|
@ -146,7 +148,7 @@ public class DefaultBloomFilterTest extends AbstractBloomFilterTest<DefaultBloom
|
|||
/**
|
||||
* A default implementation of a Sparse bloom filter.
|
||||
*/
|
||||
public static class SparseDefaultBloomFilter extends AbstractDefaultBloomFilter {
|
||||
public static class SparseDefaultBloomFilter extends AbstractDefaultBloomFilter<SparseDefaultBloomFilter> {
|
||||
|
||||
public SparseDefaultBloomFilter(final Shape shape) {
|
||||
super(shape);
|
||||
|
@ -158,8 +160,8 @@ public class DefaultBloomFilterTest extends AbstractBloomFilterTest<DefaultBloom
|
|||
}
|
||||
|
||||
@Override
|
||||
public AbstractDefaultBloomFilter copy() {
|
||||
final AbstractDefaultBloomFilter result = new SparseDefaultBloomFilter(getShape());
|
||||
public SparseDefaultBloomFilter copy() {
|
||||
final SparseDefaultBloomFilter result = new SparseDefaultBloomFilter(getShape());
|
||||
result.indices.addAll(indices);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -45,8 +45,8 @@ public class LayerManagerTest {
|
|||
@ParameterizedTest
|
||||
@ValueSource(ints = {4, 10, 2, 1})
|
||||
public void testAdvanceOnCount(final int breakAt) {
|
||||
final Predicate<LayerManager<BloomFilter>> underTest = LayerManager.ExtendCheck.advanceOnCount(breakAt);
|
||||
final LayerManager<BloomFilter> layerManager = testingBuilder().get();
|
||||
final Predicate<LayerManager<SimpleBloomFilter>> underTest = LayerManager.ExtendCheck.advanceOnCount(breakAt);
|
||||
final LayerManager<SimpleBloomFilter> layerManager = testingBuilder().get();
|
||||
for (int i = 0; i < breakAt - 1; i++) {
|
||||
assertFalse(underTest.test(layerManager), "at " + i);
|
||||
layerManager.getTarget().merge(TestingHashers.FROM1);
|
||||
|
@ -62,8 +62,8 @@ public class LayerManagerTest {
|
|||
|
||||
@Test
|
||||
public void testAdvanceOnPopulated() {
|
||||
final Predicate<LayerManager<BloomFilter>> underTest = LayerManager.ExtendCheck.advanceOnPopulated();
|
||||
final LayerManager<BloomFilter> layerManager = testingBuilder().get();
|
||||
final Predicate<LayerManager<SimpleBloomFilter>> underTest = LayerManager.ExtendCheck.advanceOnPopulated();
|
||||
final LayerManager<SimpleBloomFilter> layerManager = testingBuilder().get();
|
||||
assertFalse(underTest.test(layerManager));
|
||||
layerManager.getTarget().merge(TestingHashers.FROM1);
|
||||
assertTrue(underTest.test(layerManager));
|
||||
|
@ -73,8 +73,8 @@ public class LayerManagerTest {
|
|||
public void testAdvanceOnSaturation() {
|
||||
final double maxN = shape.estimateMaxN();
|
||||
int hashStart = 0;
|
||||
final Predicate<LayerManager<BloomFilter>> underTest = LayerManager.ExtendCheck.advanceOnSaturation(maxN);
|
||||
final LayerManager<BloomFilter> layerManager = testingBuilder().get();
|
||||
final Predicate<LayerManager<SimpleBloomFilter>> underTest = LayerManager.ExtendCheck.advanceOnSaturation(maxN);
|
||||
final LayerManager<SimpleBloomFilter> layerManager = testingBuilder().get();
|
||||
while (layerManager.getTarget().getShape().estimateN(layerManager.getTarget().cardinality()) < maxN) {
|
||||
assertFalse(underTest.test(layerManager));
|
||||
layerManager.getTarget().merge(new IncrementingHasher(hashStart, shape.getNumberOfHashFunctions()));
|
||||
|
@ -87,7 +87,7 @@ public class LayerManagerTest {
|
|||
|
||||
@Test
|
||||
public void testBuilder() {
|
||||
final LayerManager.Builder<BloomFilter> underTest = LayerManager.builder();
|
||||
final LayerManager.Builder<SimpleBloomFilter> underTest = LayerManager.builder();
|
||||
NullPointerException npe = assertThrows(NullPointerException.class, underTest::get);
|
||||
assertTrue(npe.getMessage().contains("filterSupplier"));
|
||||
underTest.setSupplier(() -> null).setCleanup(null);
|
||||
|
@ -105,7 +105,7 @@ public class LayerManagerTest {
|
|||
|
||||
@Test
|
||||
public void testClear() {
|
||||
final LayerManager<BloomFilter> underTest = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape)).get();
|
||||
final LayerManager<SimpleBloomFilter> underTest = LayerManager.<SimpleBloomFilter>builder().setSupplier(() -> new SimpleBloomFilter(shape)).get();
|
||||
underTest.getTarget().merge(TestingHashers.randomHasher());
|
||||
underTest.next();
|
||||
underTest.getTarget().merge(TestingHashers.randomHasher());
|
||||
|
@ -119,7 +119,7 @@ public class LayerManagerTest {
|
|||
|
||||
@Test
|
||||
public void testCopy() {
|
||||
final LayerManager<BloomFilter> underTest = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape)).get();
|
||||
final LayerManager<SimpleBloomFilter> underTest = LayerManager.<SimpleBloomFilter>builder().setSupplier(() -> new SimpleBloomFilter(shape)).get();
|
||||
underTest.getTarget().merge(TestingHashers.randomHasher());
|
||||
underTest.next();
|
||||
underTest.getTarget().merge(TestingHashers.randomHasher());
|
||||
|
@ -127,7 +127,7 @@ public class LayerManagerTest {
|
|||
underTest.getTarget().merge(TestingHashers.randomHasher());
|
||||
assertEquals(3, underTest.getDepth());
|
||||
|
||||
final LayerManager<BloomFilter> copy = underTest.copy();
|
||||
final LayerManager<SimpleBloomFilter> copy = underTest.copy();
|
||||
assertNotSame(underTest, copy);
|
||||
// object equals not implemented
|
||||
assertNotEquals(underTest, copy);
|
||||
|
@ -139,12 +139,12 @@ public class LayerManagerTest {
|
|||
|
||||
@Test
|
||||
public void testForEachBloomFilter() {
|
||||
final LayerManager<BloomFilter> underTest = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape))
|
||||
final LayerManager<SimpleBloomFilter> underTest = LayerManager.<SimpleBloomFilter>builder().setSupplier(() -> new SimpleBloomFilter(shape))
|
||||
.setExtendCheck(LayerManager.ExtendCheck.advanceOnPopulated()).get();
|
||||
|
||||
final List<BloomFilter> lst = new ArrayList<>();
|
||||
final List<SimpleBloomFilter> lst = new ArrayList<>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
final BloomFilter bf = new SimpleBloomFilter(shape);
|
||||
final SimpleBloomFilter bf = new SimpleBloomFilter(shape);
|
||||
bf.merge(TestingHashers.randomHasher());
|
||||
lst.add(bf);
|
||||
underTest.getTarget().merge(bf);
|
||||
|
@ -161,21 +161,21 @@ public class LayerManagerTest {
|
|||
@Test
|
||||
public void testGet() {
|
||||
final SimpleBloomFilter f = new SimpleBloomFilter(shape);
|
||||
final LayerManager<BloomFilter> underTest = LayerManager.builder().setSupplier(() -> f).get();
|
||||
final LayerManager<SimpleBloomFilter> underTest = LayerManager.<SimpleBloomFilter>builder().setSupplier(() -> f).get();
|
||||
assertEquals(1, underTest.getDepth());
|
||||
assertSame(f, underTest.get(0));
|
||||
assertThrows(NoSuchElementException.class, () -> underTest.get(-1));
|
||||
assertThrows(NoSuchElementException.class, () -> underTest.get(1));
|
||||
}
|
||||
|
||||
private LayerManager.Builder<BloomFilter> testingBuilder() {
|
||||
return LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape));
|
||||
private LayerManager.Builder<SimpleBloomFilter> testingBuilder() {
|
||||
return LayerManager.<SimpleBloomFilter>builder().setSupplier(() -> new SimpleBloomFilter(shape));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeverAdvance() {
|
||||
final Predicate<LayerManager<BloomFilter>> underTest = LayerManager.ExtendCheck.neverAdvance();
|
||||
final LayerManager<BloomFilter> layerManager = testingBuilder().get();
|
||||
final Predicate<LayerManager<SimpleBloomFilter>> underTest = LayerManager.ExtendCheck.neverAdvance();
|
||||
final LayerManager<SimpleBloomFilter> layerManager = testingBuilder().get();
|
||||
assertFalse(underTest.test(layerManager));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
layerManager.getTarget().merge(TestingHashers.randomHasher());
|
||||
|
@ -185,7 +185,7 @@ public class LayerManagerTest {
|
|||
|
||||
@Test
|
||||
public void testNextAndGetDepth() {
|
||||
final LayerManager<BloomFilter> underTest = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape)).get();
|
||||
final LayerManager<SimpleBloomFilter> underTest = LayerManager.<SimpleBloomFilter>builder().setSupplier(() -> new SimpleBloomFilter(shape)).get();
|
||||
assertEquals(1, underTest.getDepth());
|
||||
underTest.getTarget().merge(TestingHashers.randomHasher());
|
||||
assertEquals(1, underTest.getDepth());
|
||||
|
@ -195,8 +195,8 @@ public class LayerManagerTest {
|
|||
|
||||
@Test
|
||||
public void testNoCleanup() {
|
||||
final Consumer<Deque<BloomFilter>> underTest = LayerManager.Cleanup.noCleanup();
|
||||
final Deque<BloomFilter> list = new LinkedList<>();
|
||||
final Consumer<Deque<SimpleBloomFilter>> underTest = LayerManager.Cleanup.noCleanup();
|
||||
final Deque<SimpleBloomFilter> list = new LinkedList<>();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
assertEquals(i, list.size());
|
||||
list.add(new SimpleBloomFilter(shape));
|
||||
|
@ -207,8 +207,8 @@ public class LayerManagerTest {
|
|||
@ParameterizedTest
|
||||
@ValueSource(ints = {5, 100, 2, 1})
|
||||
public void testOnMaxSize(final int maxSize) {
|
||||
final Consumer<Deque<BloomFilter>> underTest = LayerManager.Cleanup.onMaxSize(maxSize);
|
||||
final LinkedList<BloomFilter> list = new LinkedList<>();
|
||||
final Consumer<Deque<SimpleBloomFilter>> underTest = LayerManager.Cleanup.onMaxSize(maxSize);
|
||||
final LinkedList<SimpleBloomFilter> list = new LinkedList<>();
|
||||
for (int i = 0; i < maxSize; i++) {
|
||||
assertEquals(i, list.size());
|
||||
list.add(new SimpleBloomFilter(shape));
|
||||
|
@ -231,11 +231,11 @@ public class LayerManagerTest {
|
|||
|
||||
@Test
|
||||
public void testRemoveEmptyTarget() {
|
||||
final Consumer<Deque<BloomFilter>> underTest = LayerManager.Cleanup.removeEmptyTarget();
|
||||
final LinkedList<BloomFilter> list = new LinkedList<>();
|
||||
final Consumer<Deque<SimpleBloomFilter>> underTest = LayerManager.Cleanup.removeEmptyTarget();
|
||||
final LinkedList<SimpleBloomFilter> list = new LinkedList<>();
|
||||
|
||||
// removes an empty filter
|
||||
final BloomFilter bf = new SimpleBloomFilter(shape);
|
||||
final SimpleBloomFilter bf = new SimpleBloomFilter(shape);
|
||||
list.add(bf);
|
||||
assertEquals(bf, list.get(0));
|
||||
underTest.accept(list);
|
||||
|
@ -273,7 +273,7 @@ public class LayerManagerTest {
|
|||
final boolean[] extendCheckCalled = { false };
|
||||
final boolean[] cleanupCalled = { false };
|
||||
final int[] supplierCount = { 0 };
|
||||
final LayerManager<BloomFilter> underTest = LayerManager.builder().setSupplier(() -> {
|
||||
final LayerManager<SimpleBloomFilter> underTest = LayerManager.<SimpleBloomFilter>builder().setSupplier(() -> {
|
||||
supplierCount[0]++;
|
||||
return new SimpleBloomFilter(shape);
|
||||
}).setExtendCheck(lm -> {
|
||||
|
|
|
@ -40,7 +40,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
/**
|
||||
* A Predicate that advances after a quantum of time.
|
||||
*/
|
||||
static class AdvanceOnTimeQuanta implements Predicate<LayerManager<TimestampedBloomFilter>> {
|
||||
static class AdvanceOnTimeQuanta<T extends BloomFilter<T>> implements Predicate<LayerManager<TimestampedBloomFilter<T>>> {
|
||||
Duration quanta;
|
||||
|
||||
AdvanceOnTimeQuanta(final Duration quanta) {
|
||||
|
@ -48,7 +48,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean test(final LayerManager<TimestampedBloomFilter> layerManager) {
|
||||
public boolean test(final LayerManager<TimestampedBloomFilter<T>> layerManager) {
|
||||
// can not use getTarget() as it causes recursion.
|
||||
return layerManager.last().getTimestamp().plus(quanta).isBefore(Instant.now());
|
||||
}
|
||||
|
@ -80,9 +80,11 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
}
|
||||
}
|
||||
|
||||
static class NumberedBloomFilter extends WrappedBloomFilter {
|
||||
static class NumberedBloomFilter extends WrappedBloomFilter<NumberedBloomFilter, SimpleBloomFilter> {
|
||||
|
||||
int value;
|
||||
int sequence;
|
||||
|
||||
NumberedBloomFilter(final Shape shape, final int value, final int sequence) {
|
||||
super(new SimpleBloomFilter(shape));
|
||||
this.value = value;
|
||||
|
@ -90,7 +92,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
}
|
||||
|
||||
@Override
|
||||
public BloomFilter copy() {
|
||||
public NumberedBloomFilter copy() {
|
||||
return new NumberedBloomFilter(getShape(), value, sequence);
|
||||
}
|
||||
}
|
||||
|
@ -98,22 +100,22 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
/**
|
||||
* A Bloom filter implementation that tracks the creation time.
|
||||
*/
|
||||
public static class TimestampedBloomFilter extends WrappedBloomFilter {
|
||||
public static class TimestampedBloomFilter<T extends BloomFilter<T>> extends WrappedBloomFilter<TimestampedBloomFilter<T>, T> {
|
||||
|
||||
private final Instant timestamp;
|
||||
|
||||
TimestampedBloomFilter(final BloomFilter bf) {
|
||||
TimestampedBloomFilter(final T bf) {
|
||||
this(bf, Instant.now());
|
||||
}
|
||||
|
||||
TimestampedBloomFilter(final BloomFilter bf, final Instant timestamp) {
|
||||
TimestampedBloomFilter(final T bf, final Instant timestamp) {
|
||||
super(bf);
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimestampedBloomFilter copy() {
|
||||
return new TimestampedBloomFilter(getWrapped().copy(), timestamp);
|
||||
public TimestampedBloomFilter<T> copy() {
|
||||
return new TimestampedBloomFilter<>(getWrapped().copy(), timestamp);
|
||||
}
|
||||
|
||||
public Instant getTimestamp() {
|
||||
|
@ -135,11 +137,11 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
* will span at most this much time.
|
||||
* @return LayeredBloomFilter with the above properties.
|
||||
*/
|
||||
static LayeredBloomFilter<TimestampedBloomFilter> createTimedLayeredFilter(final Shape shape, final Duration duration, final Duration quanta) {
|
||||
final LayerManager.Builder<TimestampedBloomFilter> builder = LayerManager.builder();
|
||||
final Consumer<Deque<TimestampedBloomFilter>> cleanup = Cleanup.removeEmptyTarget().andThen(new CleanByTime(duration));
|
||||
final LayerManager<TimestampedBloomFilter> layerManager = builder
|
||||
.setSupplier(() -> new TimestampedBloomFilter(new SimpleBloomFilter(shape)))
|
||||
static LayeredBloomFilter<TimestampedBloomFilter<SimpleBloomFilter>> createTimedLayeredFilter(final Shape shape, final Duration duration, final Duration quanta) {
|
||||
final LayerManager.Builder<TimestampedBloomFilter<SimpleBloomFilter>> builder = LayerManager.builder();
|
||||
final Consumer<Deque<TimestampedBloomFilter<SimpleBloomFilter>>> cleanup = Cleanup.removeEmptyTarget().andThen(new CleanByTime(duration));
|
||||
final LayerManager<TimestampedBloomFilter<SimpleBloomFilter>> layerManager = builder
|
||||
.setSupplier(() -> new TimestampedBloomFilter<>(new SimpleBloomFilter(shape)))
|
||||
.setCleanup(cleanup)
|
||||
.setExtendCheck(new AdvanceOnTimeQuanta(quanta)
|
||||
.or(LayerManager.ExtendCheck.advanceOnSaturation(shape.estimateMaxN())))
|
||||
|
@ -156,7 +158,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
* @param maxDepth The maximum depth of layers.
|
||||
* @return An empty layered Bloom filter of the specified shape and depth.
|
||||
*/
|
||||
public static LayeredBloomFilter<BloomFilter> fixed(final Shape shape, final int maxDepth) {
|
||||
public static LayeredBloomFilter<SimpleBloomFilter> fixed(final Shape shape, final int maxDepth) {
|
||||
return fixed(shape, maxDepth, () -> new SimpleBloomFilter(shape));
|
||||
}
|
||||
|
||||
|
@ -170,7 +172,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
* @param supplier A supplier of the Bloom filters to create layers with.
|
||||
* @return An empty layered Bloom filter of the specified shape and depth.
|
||||
*/
|
||||
public static <T extends BloomFilter> LayeredBloomFilter<T> fixed(final Shape shape, final int maxDepth, final Supplier<T> supplier) {
|
||||
public static <T extends BloomFilter<T>> LayeredBloomFilter<T> fixed(final Shape shape, final int maxDepth, final Supplier<T> supplier) {
|
||||
final LayerManager.Builder<T> builder = LayerManager.builder();
|
||||
builder.setExtendCheck(LayerManager.ExtendCheck.advanceOnPopulated())
|
||||
.setCleanup(LayerManager.Cleanup.onMaxSize(maxDepth)).setSupplier(supplier);
|
||||
|
@ -188,7 +190,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
// *** end of instrumentation ***
|
||||
|
||||
@Override
|
||||
protected LayeredBloomFilter<BloomFilter> createEmptyFilter(final Shape shape) {
|
||||
protected LayeredBloomFilter<SimpleBloomFilter> createEmptyFilter(final Shape shape) {
|
||||
return LayeredBloomFilterTest.fixed(shape, 10);
|
||||
}
|
||||
|
||||
|
@ -208,8 +210,8 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
return makeFilter(IndexExtractor.fromIndexArray(values));
|
||||
}
|
||||
|
||||
private LayeredBloomFilter<BloomFilter> setupFindTest() {
|
||||
final LayeredBloomFilter<BloomFilter> filter = LayeredBloomFilterTest.fixed(getTestShape(), 10);
|
||||
private LayeredBloomFilter<SimpleBloomFilter> setupFindTest() {
|
||||
final LayeredBloomFilter<SimpleBloomFilter> filter = LayeredBloomFilterTest.fixed(getTestShape(), 10);
|
||||
filter.merge(TestingHashers.FROM1);
|
||||
filter.merge(TestingHashers.FROM11);
|
||||
filter.merge(new IncrementingHasher(11, 2));
|
||||
|
@ -220,7 +222,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
@Override
|
||||
@Test
|
||||
public void testCardinalityAndIsEmpty() {
|
||||
final LayerManager<BloomFilter> layerManager = LayerManager.builder().setExtendCheck(ExtendCheck.neverAdvance())
|
||||
final LayerManager<SimpleBloomFilter> layerManager = LayerManager.<SimpleBloomFilter>builder().setExtendCheck(ExtendCheck.neverAdvance())
|
||||
.setSupplier(() -> new SimpleBloomFilter(getTestShape())).get();
|
||||
testCardinalityAndIsEmpty(new LayeredBloomFilter<>(getTestShape(), layerManager));
|
||||
}
|
||||
|
@ -230,11 +232,11 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
@Test
|
||||
public void testCleanup() {
|
||||
final int[] sequence = {1};
|
||||
final LayerManager layerManager = LayerManager.builder()
|
||||
final LayerManager<NumberedBloomFilter> layerManager = LayerManager.<NumberedBloomFilter>builder()
|
||||
.setSupplier(() -> new NumberedBloomFilter(getTestShape(), 3, sequence[0]++))
|
||||
.setExtendCheck(ExtendCheck.neverAdvance())
|
||||
.setCleanup(ll -> ll.removeIf(f -> (((NumberedBloomFilter) f).value-- == 0))).get();
|
||||
final LayeredBloomFilter underTest = new LayeredBloomFilter(getTestShape(), layerManager);
|
||||
.setCleanup(ll -> ll.removeIf(f -> (f.value-- == 0))).get();
|
||||
final LayeredBloomFilter<NumberedBloomFilter> underTest = new LayeredBloomFilter<>(getTestShape(), layerManager);
|
||||
assertEquals(1, underTest.getDepth());
|
||||
underTest.merge(TestingHashers.randomHasher());
|
||||
underTest.cleanup(); // first count == 2
|
||||
|
@ -243,19 +245,19 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
assertEquals(2, underTest.getDepth());
|
||||
underTest.merge(TestingHashers.randomHasher());
|
||||
underTest.cleanup(); // first count == 0
|
||||
NumberedBloomFilter f = (NumberedBloomFilter) underTest.get(0);
|
||||
NumberedBloomFilter f = underTest.get(0);
|
||||
assertEquals(1, f.sequence);
|
||||
|
||||
assertEquals(2, underTest.getDepth());
|
||||
underTest.cleanup(); // should be removed ; second is now 1st with value 1
|
||||
assertEquals(1, underTest.getDepth());
|
||||
f = (NumberedBloomFilter) underTest.get(0);
|
||||
f = underTest.get(0);
|
||||
assertEquals(2, f.sequence);
|
||||
|
||||
underTest.cleanup(); // first count == 0
|
||||
underTest.cleanup(); // should be removed. But there is always at least one
|
||||
assertEquals(1, underTest.getDepth());
|
||||
f = (NumberedBloomFilter) underTest.get(0);
|
||||
f = underTest.get(0);
|
||||
assertEquals(3, f.sequence); // it is a new one.
|
||||
}
|
||||
/**
|
||||
|
@ -282,7 +284,8 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
|
||||
// create a filter that removes filters that are 4 seconds old
|
||||
// and quantises time to 1 second intervals.
|
||||
final LayeredBloomFilter<TimestampedBloomFilter> underTest = createTimedLayeredFilter(shape, Duration.ofMillis(600), Duration.ofMillis(150));
|
||||
final LayeredBloomFilter<TimestampedBloomFilter<SimpleBloomFilter>> underTest = createTimedLayeredFilter(shape, Duration.ofMillis(600),
|
||||
Duration.ofMillis(150));
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
underTest.merge(TestingHashers.randomHasher());
|
||||
|
@ -314,7 +317,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
|
||||
@Test
|
||||
public void testFindBitMapExtractor() {
|
||||
final LayeredBloomFilter<BloomFilter> filter = setupFindTest();
|
||||
final LayeredBloomFilter<SimpleBloomFilter> filter = setupFindTest();
|
||||
|
||||
IndexExtractor indexExtractor = TestingHashers.FROM1.indices(getTestShape());
|
||||
BitMapExtractor bitMapExtractor = BitMapExtractor.fromIndexExtractor(indexExtractor, getTestShape().getNumberOfBits());
|
||||
|
@ -332,7 +335,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
|
||||
@Test
|
||||
public void testFindBloomFilter() {
|
||||
final LayeredBloomFilter<BloomFilter> filter = setupFindTest();
|
||||
final LayeredBloomFilter<SimpleBloomFilter> filter = setupFindTest();
|
||||
int[] expected = {0, 3};
|
||||
int[] result = filter.find(TestingHashers.FROM1);
|
||||
assertArrayEquals(expected, result);
|
||||
|
@ -344,7 +347,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
@Test
|
||||
public void testFindIndexExtractor() {
|
||||
IndexExtractor indexExtractor = TestingHashers.FROM1.indices(getTestShape());
|
||||
final LayeredBloomFilter<BloomFilter> filter = setupFindTest();
|
||||
final LayeredBloomFilter<SimpleBloomFilter> filter = setupFindTest();
|
||||
|
||||
int[] expected = {0, 3};
|
||||
int[] result = filter.find(indexExtractor);
|
||||
|
@ -360,7 +363,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
public final void testGetLayer() {
|
||||
final BloomFilter bf = new SimpleBloomFilter(getTestShape());
|
||||
bf.merge(TestingHashers.FROM11);
|
||||
final LayeredBloomFilter<BloomFilter> filter = LayeredBloomFilterTest.fixed(getTestShape(), 10);
|
||||
final LayeredBloomFilter<SimpleBloomFilter> filter = LayeredBloomFilterTest.fixed(getTestShape(), 10);
|
||||
filter.merge(TestingHashers.FROM1);
|
||||
filter.merge(TestingHashers.FROM11);
|
||||
filter.merge(new IncrementingHasher(11, 2));
|
||||
|
@ -370,7 +373,7 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
|
||||
@Test
|
||||
public void testMultipleFilters() {
|
||||
final LayeredBloomFilter<BloomFilter> filter = LayeredBloomFilterTest.fixed(getTestShape(), 10);
|
||||
final LayeredBloomFilter<SimpleBloomFilter> filter = LayeredBloomFilterTest.fixed(getTestShape(), 10);
|
||||
filter.merge(TestingHashers.FROM1);
|
||||
filter.merge(TestingHashers.FROM11);
|
||||
assertEquals(2, filter.getDepth());
|
||||
|
@ -384,10 +387,8 @@ public class LayeredBloomFilterTest extends AbstractBloomFilterTest<LayeredBloom
|
|||
|
||||
@Test
|
||||
public final void testNext() {
|
||||
final LayerManager<BloomFilter> layerManager = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(getTestShape()))
|
||||
.get();
|
||||
|
||||
final LayeredBloomFilter<BloomFilter> filter = new LayeredBloomFilter<>(getTestShape(), layerManager);
|
||||
final LayerManager<SimpleBloomFilter> layerManager = LayerManager.<SimpleBloomFilter>builder().setSupplier(() -> new SimpleBloomFilter(getTestShape())).get();
|
||||
final LayeredBloomFilter<SimpleBloomFilter> filter = new LayeredBloomFilter<>(getTestShape(), layerManager);
|
||||
filter.merge(TestingHashers.FROM1);
|
||||
filter.merge(TestingHashers.FROM11);
|
||||
assertEquals(1, filter.getDepth());
|
||||
|
|
Loading…
Reference in New Issue