Skip to content

Commit

Permalink
gh-266 ChainedIterable made public (#267)
Browse files Browse the repository at this point in the history
* gh-266 ChainedIterable made public

* gh-266 ChainedIterable made public - typo

* gh-266: Moved out all Iterable classes into iterable module

* gh-266: Spotless apply

* gh-256: Moved over constructors and tests from Gaffer

* gh-266: Added more iterable tests

* gh-266: Cleanup and add more constructors

* gh-266: Tidy up null check on list

Co-authored-by: GCHQDev404 <[email protected]>
Co-authored-by: t92549 <[email protected]>
  • Loading branch information
3 people authored May 6, 2022
1 parent ec18795 commit 02865ed
Show file tree
Hide file tree
Showing 13 changed files with 1,046 additions and 350 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2022 Crown Copyright
*
* 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 uk.gov.gchq.koryphe.iterable;

import org.apache.commons.lang3.ArrayUtils;

import uk.gov.gchq.koryphe.util.CloseableUtil;

import java.io.Closeable;
import java.util.Arrays;
import java.util.Iterator;

/**
* A {@code ChainedIterable} is a {@link java.io.Closeable}
* {@link java.lang.Iterable} composed of other {@link java.lang.Iterable}s.
*
* As a client iterates through this iterable, the child iterables are consumed
* sequentially.
*
* @param <T> the type of items in the iterable.
*/
public class ChainedIterable<T> implements Closeable, Iterable<T> {
private final Iterable<? extends Iterable<? extends T>> iterables;

public ChainedIterable(final Iterable<? extends T>... iterables) {
this(ArrayUtils.isEmpty(iterables) ? null : Arrays.asList(iterables));
}

public ChainedIterable(final Iterable<? extends Iterable<? extends T>> iterables) {
if (null == iterables) {
throw new IllegalArgumentException("iterables are required");
}
this.iterables = iterables;
}

@Override
public Iterator<T> iterator() {
return new ChainedIterator<>(iterables.iterator());
}

@Override
public void close() {
for (final Iterable<? extends T> iterable : iterables) {
CloseableUtil.close(iterable);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2022 Crown Copyright
*
* 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 uk.gov.gchq.koryphe.iterable;

import uk.gov.gchq.koryphe.util.CloseableUtil;

import java.io.Closeable;
import java.util.Collections;
import java.util.Iterator;

/**
* @param <T> the type of items in the iterator
*/
public class ChainedIterator<T> implements Closeable, Iterator<T> {
private final Iterator<? extends Iterable<? extends T>> iterablesIterator;
private Iterator<? extends T> currentIterator = Collections.emptyIterator();

public ChainedIterator(final Iterator<? extends Iterable<? extends T>> iterablesIterator) {
if (null == iterablesIterator) {
throw new IllegalArgumentException("iterables are required");
}
this.iterablesIterator = iterablesIterator;
}

@Override
public boolean hasNext() {
return getIterator().hasNext();
}

@Override
public T next() {
return getIterator().next();
}

@Override
public void remove() {
currentIterator.remove();
}

@Override
public void close() {
CloseableUtil.close(currentIterator);
while (iterablesIterator.hasNext()) {
CloseableUtil.close(iterablesIterator.next());
}
}

private Iterator<? extends T> getIterator() {
while (!currentIterator.hasNext()) {
CloseableUtil.close(currentIterator);
if (iterablesIterator.hasNext()) {
currentIterator = iterablesIterator.next().iterator();
} else {
break;
}
}

return currentIterator;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2022 Crown Copyright
*
* 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 uk.gov.gchq.koryphe.iterable;

import com.google.common.collect.Lists;

import uk.gov.gchq.koryphe.util.CloseableUtil;

import java.io.Closeable;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;

/**
* A {@code FilteredIterable} is a {@link java.io.Closeable}
* {@link java.lang.Iterable} which can filter out elements
* based on a {@link java.util.List} of {@link java.util.function.Predicate}s.
*
* @param <T> the type of items in the iterable.
*/
public class FilteredIterable<T> implements Closeable, Iterable<T> {
private final Iterable<T> iterable;
private final List<Predicate> predicates;

public FilteredIterable(final Iterable<T> iterable, final Predicate... predicates) {
this(iterable, Lists.newArrayList(predicates));
}

public FilteredIterable(final Iterable<T> iterable, final List<Predicate> predicates) {
if (null == iterable) {
throw new IllegalArgumentException("iterable is required");
}
if (null == predicates) {
throw new IllegalArgumentException("List of predicates cannot be null");
}
if (predicates.stream().anyMatch(Objects::isNull)) {
throw new IllegalArgumentException("Predicates list cannot contain a null predicate");
}

this.iterable = iterable;
this.predicates = predicates;
}

@Override
public Iterator<T> iterator() {
return new FilteredIterator<>(iterable.iterator(), predicates);
}

@Override
public void close() {
CloseableUtil.close(iterable);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2022 Crown Copyright
*
* 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 uk.gov.gchq.koryphe.iterable;

import uk.gov.gchq.koryphe.impl.predicate.And;
import uk.gov.gchq.koryphe.util.CloseableUtil;

import java.io.Closeable;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Predicate;

/**
* @param <T> the type of items in the iterator
*/
public class FilteredIterator<T> implements Closeable, Iterator<T> {
private final Iterator<? extends T> iterator;
private final And<T> andPredicate;

public FilteredIterator(final Iterator<T> iterator, final List<Predicate> predicates) {
if (null == iterator) {
throw new IllegalArgumentException("iterator is required");
}
if (null == predicates) {
throw new IllegalArgumentException("List of predicates cannot be null");
}
if (predicates.stream().anyMatch(Objects::isNull)) {
throw new IllegalArgumentException("Predicates list cannot contain a null predicate");
}

this.iterator = iterator;
this.andPredicate = new And<>(predicates);
}

private T nextElement;
private Boolean hasNext;

@Override
public boolean hasNext() {
if (null == hasNext) {
while (iterator.hasNext()) {
final T possibleNext = iterator.next();
if (andPredicate.test(possibleNext)) {
nextElement = possibleNext;
hasNext = true;
return true;
}
}
hasNext = false;
nextElement = null;
}

final boolean hasNextResult = Boolean.TRUE.equals(hasNext);
if (!hasNextResult) {
close();
}

return hasNextResult;
}

@Override
public T next() {
if ((null == hasNext) && (!hasNext())) {
throw new NoSuchElementException("Reached the end of the iterator");
}

final T elementToReturn = nextElement;
nextElement = null;
hasNext = null;

return elementToReturn;
}

@Override
public void remove() {
throw new UnsupportedOperationException("Cannot call remove on a " + getClass().getSimpleName());
}

@Override
public void close() {
CloseableUtil.close(iterator);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2022 Crown Copyright
*
* 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 uk.gov.gchq.koryphe.iterable;

import com.fasterxml.jackson.annotation.JsonIgnore;

import uk.gov.gchq.koryphe.util.CloseableUtil;

import java.io.Closeable;
import java.util.Collections;
import java.util.Iterator;

import static uk.gov.gchq.koryphe.util.JavaUtils.requireNonNullElse;

/**
* A {@code LimitedIterable} is a {@link java.io.Closeable}
* {@link java.lang.Iterable} which is limited to a maximum size.
*
* @param <T> the type of items in the iterable.
*/
public final class LimitedIterable<T> implements Closeable, Iterable<T> {
private final Iterable<T> iterable;
private final int start;
private final Integer end;
private final Boolean truncate;

public LimitedIterable(final Iterable<T> iterable, final int start, final Integer end) {
this(iterable, start, end, true);
}

public LimitedIterable(final Iterable<T> iterable, final int start, final Integer end, final boolean truncate) {
if (null != end && start > end) {
throw new IllegalArgumentException("The start pointer must be less than the end pointer.");
}

this.iterable = requireNonNullElse(iterable, Collections.emptyList());

this.start = start;
this.end = end;
this.truncate = truncate;
}

@JsonIgnore
public int getStart() {
return start;
}

@JsonIgnore
public Integer getEnd() {
return end;
}

@Override
public void close() {
CloseableUtil.close(iterable);
}

@Override
public Iterator<T> iterator() {
return new LimitedIterator<>(iterable.iterator(), start, end, truncate);
}
}
Loading

0 comments on commit 02865ed

Please sign in to comment.