/**
* Copyright 2014 Sunny Gleason and original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.kazuki.v0.store.index;
import io.kazuki.v0.store.keyvalue.KeyValueIterable;
import io.kazuki.v0.store.keyvalue.KeyValueIterator;
import io.kazuki.v0.store.keyvalue.KeyValuePair;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
public class FilteredKeyValueIterable<U> implements KeyValueIterable<U> {
private final KeyValueIterable<?> inner;
private final Predicate<Object> filter;
private final Function<KeyValuePair<?>, U> transform;
private final Long offset;
private final Long limit;
public FilteredKeyValueIterable(KeyValueIterable<?> keyValueIterable, Predicate<Object> filter,
Function<KeyValuePair<?>, U> transform, @Nullable final Long offset,
@Nullable final Long limit) {
this.inner = keyValueIterable;
this.filter = filter;
this.transform = transform;
this.offset = offset;
this.limit = limit;
}
@Override
public KeyValueIterator<U> iterator() {
return new FilteredKeyValueIterator<U>(inner.iterator(), filter, transform, offset, limit);
}
@Override
public void close() {
this.inner.close();
}
public static class FilteredKeyValueIterator<U> implements KeyValueIterator<U> {
private final KeyValueIterator<?> innerIter;
private final Predicate<Object> innerFilter;
private final Function<KeyValuePair<?>, U> innerTransform;
private final Long offset;
private final AtomicLong toReturn;
private volatile KeyValuePair<?> nextMatch = null;
public FilteredKeyValueIterator(KeyValueIterator<?> innerIter, Predicate<Object> innerFilter,
Function<KeyValuePair<?>, U> innerTransform, @Nullable Long offset, @Nullable Long limit) {
this.innerIter = innerIter;
this.innerFilter = innerFilter;
this.innerTransform = innerTransform;
this.offset = offset == null ? 0L : offset;
this.toReturn = new AtomicLong(limit == null ? -1L : limit);
for (long i = 0; i <= this.offset; i++) {
this.nextMatch = (KeyValuePair<?>) advance();
if (this.nextMatch == null) {
break;
}
}
}
@Override
public synchronized boolean hasNext() {
Long remaining = toReturn.get();
return nextMatch != null && (remaining == -1L || remaining > 0);
}
@Override
public synchronized U next() {
Preconditions.checkNotNull(nextMatch, "next");
KeyValuePair<?> result = nextMatch;
Long remaining = toReturn.get();
if (remaining == 0L) {
nextMatch = null;
return null;
} else if (remaining == -1L) {
nextMatch = advance();
} else if (remaining > 0L) {
toReturn.decrementAndGet();
}
return innerTransform.apply(result);
}
@Override
public synchronized void remove() {
innerIter.remove();
}
@Override
public synchronized void close() {
innerIter.close();
}
private KeyValuePair<?> advance() {
while (innerIter.hasNext()) {
KeyValuePair<?> nextOne = (KeyValuePair<?>) innerIter.next();
if (innerFilter.apply(nextOne.getValue())) {
return nextOne;
}
}
return null;
}
}
}