package fr.moresmau.jp.collections; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import fr.moresmau.jp.func.Mapper; /** * an infinite list. You only have to provide the getNext() method. The data is stored in an ArrayList. * @author JP Moresmau * * @param */ public abstract class InfiniteList implements Iterable { /** * the underlying list */ private ArrayList data=new ArrayList(); /** * default constructor */ public InfiniteList(){ // NOOP } /** * constructor precalculating some values * @param precalculate the numbers of values to precalculate */ public InfiniteList(int precalculate){ ensureCalculated(precalculate-1); } /** * @return the underlying array list */ protected ArrayList getData(){ return data; } /** * @return the next element in the list */ protected abstract E getNext(); /** * calculates the next element */ private void calculateNext(){ E next=getNext(); data.add(next); } /** * ensure that the object as the given index has been calculated * @param index the index we want to be able to read */ private void ensureCalculated(int index){ while (index>=data.size()){ calculateNext(); } } /** * @return the number of elements calculated */ public int getCalculatedLength(){ return data.size(); } /** * take the first n elements from the list * @param size * @return an unmodifiable list of size size */ public List take(int size){ if (size<0){ throw new IllegalArgumentException("index<0"); } return take(0,size); } /** * take a sublist * @param start the start index * @param end the end index * @return an unmodifiable sublit of size end-start */ public List take(int start,int end){ if (end iterator() { return new Iterator(){ private int index=0; public boolean hasNext() { return true; } public E next() { return InfiniteList.this.get(index++); } public void remove() { throw new UnsupportedOperationException(); } }; } /** * get another infinite list, obtained by applying a function to every element of the original list * @param the resulting type of the map operation * @param mapper the mapper * @return the infinite list resulting from the mapping */ public InfiniteList map(final Mapper mapper){ return new InfiniteList(){ @Override protected E2 getNext() { return mapper.map(InfiniteList.this.get(getData().size())); } }; } /** * returns another infinite list that is the result of filtering this list * here, you're not event garanteed to have a result from get, since if the filter always returns false we will loop till we find a match... * @param filter the filter to apply * @return the new list */ public InfiniteList filter(final Mapper filter){ return new FilteredInfiniteList(this,filter); } /** * An infinite list built from filtering another list * @author JP Moresmau * * @param the type of the list */ private class FilteredInfiniteList extends InfiniteList { private Iterator innerIterator; private Mapper innerFilter; /** * constructs a filtered list * @param il the original list * @param filter the filter */ private FilteredInfiniteList(InfiniteList il,Mapper filter){ super(); this.innerIterator=il.iterator(); this.innerFilter=filter; } @Override protected Ef getNext() { Ef e=innerIterator.next(); while(!innerFilter.map(e)){ e=innerIterator.next(); } return e; } } }