blob: ae2a71b3a6f74b6f114778b935203b675babdfa4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2012 Vrije Universiteit Brussel.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Dennis Wagelaar, Vrije Universiteit Brussel - initial API and
* implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.m2m.atl.emftvm.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import org.eclipse.emf.common.util.EList;
import org.eclipse.m2m.atl.emftvm.CodeBlock;
import org.eclipse.m2m.atl.emftvm.ExecEnv;
/**
* Immutable {@link EList} that supports lazy evaluation.
* @author <a href="mailto:dwagelaar@gmail.com">Dennis Wagelaar</a>
*
* @param <E> the collection element type
*/
public class LazyList<E> extends LazyCollection<E> implements EList<E> {
/**
* Abstract {@link LazyList} that disables caching of the underlying {@link LazyList}.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*
* @param <E> the collection element type
*/
public abstract static class NonCachingList<E> extends LazyList<E> {
/**
* Creates a {@link NonCachingList} around <code>dataSource</code>.
* @param dataSource the underlying {@link LazyList}
*/
public NonCachingList(final LazyList<E> dataSource) {
super(dataSource);
assert dataSource != null;
}
/**
* {@inheritDoc}
*/
@Override
protected void createCache() {
//no caching
}
}
/**
* {@link LazyList} that represents a union of the underlying {@link LazyList}
* and the added {@link LazyList}.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*
* @param <E> The list element type.
*/
public static class UnionList<E> extends NonCachingList<E> {
protected final LazyList<? extends E> s;
/**
* Creates a new {@link UnionList}.
* @param s the collection to union with the underlying collection
* @param dataSource the underlying collection
*/
public UnionList(final LazyList<? extends E> s, final LazyList<E> dataSource) {
super(dataSource);
this.s = s;
assert s != null;
}
/**
* {@inheritDoc}
*/
@Override
public E first() {
return ((LazyList<E>)dataSource).isEmpty() ? s.first() : ((LazyList<E>)dataSource).first();
}
/**
* {@inheritDoc}
*/
@Override
public E get(int index) {
final int size = ((List<E>)dataSource).size();
return index < size ? ((List<E>)dataSource).get(index) : s.get(index - size);
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(Object o) {
final int indexOf = ((List<E>)dataSource).indexOf(o);
if (indexOf > -1) {
return indexOf;
} else {
return ((List<E>)dataSource).size() + s.indexOf(o);
}
}
/**
* {@inheritDoc}
*/
@Override
public E last() {
return s.isEmpty() ? ((LazyList<E>)dataSource).last() : s.last();
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(Object o) {
final int lastIndexOf = s.lastIndexOf(o);
if (lastIndexOf > -1) {
return ((List<E>)dataSource).size() + lastIndexOf;
} else {
return ((List<E>)dataSource).lastIndexOf(o);
}
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator() {
return new UnionListIterator(s);
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator(int index) {
return new UnionListIterator(s, index);
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(Object o) {
return ((Collection<E>)dataSource).contains(o) ||
s.contains(o);
}
/**
* {@inheritDoc}
*/
@Override
public int count(Object object) {
return ((LazyCollection<E>)dataSource).count(object) + s.count(object);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
return ((Collection<E>)dataSource).isEmpty() && s.isEmpty();
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<E> iterator() {
return new UnionIterator(s);
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return ((Collection<E>)dataSource).size() + s.size();
}
}
/**
* {@link LazyList} that appends an element to the underlying {@link LazyList}.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*
* @param <E> The list element type.
*/
public static class AppendList<E> extends NonCachingList<E> {
/**
* {@link ListIterator} that appends an object to the underlying collection.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public class AppendListIterator extends WrappedListIterator {
protected boolean beforeTail = true;
/**
* Creates a new {@link AppendListIterator}.
*/
public AppendListIterator() {
super();
}
/**
* Creates a new {@link AppendListIterator}.
* @param index the iterator starting index.
*/
public AppendListIterator(final int index) {
super(index > 0 ? index - 1 : index);
if (index > 0) {
next();
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
assert beforeTail || !inner.hasNext(); // not beforeTail implies not inner.hasNext()
return beforeTail;
}
/**
* {@inheritDoc}
*/
@Override
public E next() {
if (inner.hasNext()) {
return inner.next();
} else if (beforeTail) {
beforeTail = false;
return object;
}
throw new NoSuchElementException();
}
/**
* {@inheritDoc}
*/
@Override
public int nextIndex() {
return inner.nextIndex() + (beforeTail ? 0 : 1);
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasPrevious() {
return !beforeTail || inner.hasPrevious();
}
/**
* {@inheritDoc}
*/
@Override
public E previous() {
if (!beforeTail) {
beforeTail = true;
return object;
}
return inner.previous();
}
/**
* {@inheritDoc}
*/
@Override
public int previousIndex() {
return inner.previousIndex() + (beforeTail ? 0 : 1);
}
}
/**
* The element to append.
*/
protected final E object;
/**
* Creates a new {@link AppendList}.
* @param object the element to append
* @param dataSource the underlying {@link LazyList}
*/
public AppendList(final E object, final LazyList<E> dataSource) {
super(dataSource);
this.object = object;
}
/**
* {@inheritDoc}
*/
@Override
public E last() {
return object;
}
/**
* {@inheritDoc}
*/
@Override
public E get(final int index) {
final int size = ((List<E>)dataSource).size();
if (index < size) {
return ((List<E>)dataSource).get(index);
} else if (index == size) {
return object;
} else {
throw new IndexOutOfBoundsException(String.valueOf(index));
}
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(final Object o) {
final int index = ((List<E>)dataSource).indexOf(o);
if (index > -1) {
return index;
}
return (object == null ? o == null : object.equals(o)) ? size() - 1 : -1;
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(final Object o) {
if (object == null ? o == null : object.equals(o)) {
return size() - 1;
}
return ((List<E>)dataSource).lastIndexOf(o);
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(final Object o) {
return (object == null ? o == null : object.equals(o)) ||
((Collection<E>)dataSource).contains(o);
}
/**
* {@inheritDoc}
*/
@Override
public int count(final Object o) {
return (object == null ? o == null : object.equals(o)) ? 1 : 0 +
((LazyCollection<E>)dataSource).count(o);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<E> iterator() {
return new AppendIterator(object);
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return ((Collection<E>)dataSource).size() + 1;
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator() {
return new AppendListIterator();
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator(final int index) {
return new AppendListIterator(index);
}
}
/**
* {@link LazyList} that prepends an element to the underlying {@link LazyList}.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*
* @param <E> the collection element type
*/
public static class PrependList<E> extends AppendList<E> {
/**
* {@link Iterator} that prepends an object to the underlying collection.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public class PrependIterator extends WrappedIterator {
protected boolean beforeHead = true;
/**
* Creates a new {@link PrependIterator}.
*/
public PrependIterator() {
super();
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return beforeHead || inner.hasNext();
}
/**
* {@inheritDoc}
*/
@Override
public E next() {
if (beforeHead) {
beforeHead = false;
return object;
}
return inner.next();
}
}
/**
* {@link ListIterator} that appends an object to the underlying collection.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public class PrependListIterator extends WrappedListIterator {
protected boolean beforeHead = true;
/**
* Creates a new {@link PrependListIterator}.
*/
public PrependListIterator() {
super();
}
/**
* Creates a new {@link PrependListIterator}.
* @param index the iterator starting index.
*/
public PrependListIterator(final int index) {
super(index < 1 ? index : index - 1);
this.beforeHead = index < 1;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return beforeHead || inner.hasNext();
}
/**
* {@inheritDoc}
*/
@Override
public E next() {
if (beforeHead) {
beforeHead = false;
return object;
}
return inner.next();
}
/**
* {@inheritDoc}
*/
@Override
public int nextIndex() {
if (beforeHead) {
return 0;
}
return inner.nextIndex() + 1;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasPrevious() {
assert beforeHead || !inner.hasPrevious(); // not beforeHead implies not inner.hasPrevious()
return !beforeHead;
}
/**
* {@inheritDoc}
*/
@Override
public E previous() {
if (inner.hasPrevious()) {
return inner.previous();
} else if (!beforeHead) {
beforeHead = true;
return object;
}
throw new NoSuchElementException();
}
/**
* {@inheritDoc}
*/
@Override
public int previousIndex() {
if (beforeHead) {
return -1;
}
return inner.previousIndex() + 1;
}
}
/**
* Creates a new {@link PrependList}.
* @param object the object to prepend
* @param dataSource the underlying collection
*/
public PrependList(final E object, final LazyList<E> dataSource) {
super(object, dataSource);
}
/**
* {@inheritDoc}
*/
@Override
public E first() {
return object;
}
/**
* {@inheritDoc}
*/
@Override
public E last() {
if (!((LazyList<E>)dataSource).isEmpty()) {
return ((LazyList<E>)dataSource).last();
} else {
return object;
}
}
/**
* {@inheritDoc}
*/
@Override
public E get(final int index) {
if (index == 0) {
return object;
} else {
return ((List<E>)dataSource).get(index - 1);
}
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(final Object o) {
if (object == null ? o == null : object.equals(o)) {
return 0;
}
final int index = ((List<E>)dataSource).indexOf(o);
return index > -1 ? index + 1 : index;
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(Object o) {
final int lastIndex = ((List<E>)dataSource).lastIndexOf(o) + 1;
if (lastIndex > 0) {
return lastIndex;
}
return (object == null ? o == null : object.equals(o)) ? 0 : -1;
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<E> iterator() {
return new PrependIterator();
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator() {
return new PrependListIterator();
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator(int index) {
return new PrependListIterator(index);
}
}
/**
* {@link LazyList} that inserts an element it a given index in the underlying collection.
* List index starts at 0.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*
* @param <E>
*/
public static class InsertAtList<E> extends AppendList<E> {
/**
* Inserts an element into the underlying collection at the given index.
* List index starts at 0.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public class InsertAtIterator extends WrappedIterator {
protected int i = -1;
/**
* Creates a new {@link InsertAtIterator}.
*/
public InsertAtIterator() {
super();
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return i < index || inner.hasNext();
}
/**
* {@inheritDoc}
*/
@Override
public E next() {
if (++i == index) {
return object;
}
return inner.next();
}
}
/**
* Inserts an element into the underlying collection at the given index.
* List index starts at 0.
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public class InsertAtListIterator extends WrappedListIterator {
protected int i = -1;
/**
* Creates a new {@link InsertAtListIterator}.
*/
public InsertAtListIterator() {
super();
}
/**
* Creates a new {@link InsertAtListIterator}.
* @param index the iterator starting index, starting from 0 instead of 1.
*/
public InsertAtListIterator(final int index) {
super(index < InsertAtList.this.index ? index : index - 1);
this.i = index - 1;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
return i < index || inner.hasNext();
}
/**
* {@inheritDoc}
*/
@Override
public E next() {
if (++i == index) {
return object;
}
return inner.next();
}
/**
* {@inheritDoc}
*/
@Override
public int nextIndex() {
return i + 1;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasPrevious() {
return i >= index || inner.hasPrevious();
}
/**
* {@inheritDoc}
*/
@Override
public E previous() {
if (i-- == index) {
return object;
}
return inner.previous();
}
/**
* {@inheritDoc}
*/
@Override
public int previousIndex() {
return i;
}
}
protected final int index;
/**
* Creates a new {@link InsertAtList}.
* @param index the index at which to insert the element, starting from 0
* @param object the element to insert
* @param dataSource the underlying collection
*/
public InsertAtList(final int index, final E object, final LazyList<E> dataSource) {
super(object, dataSource);
this.index = index;
if (index < 0) {
throw new IndexOutOfBoundsException(String.valueOf(index));
}
}
/**
* {@inheritDoc}
*/
@Override
public E first() {
assert index >= 0;
return index == 0 ? object : ((LazyList<E>)dataSource).first();
}
/**
* {@inheritDoc}
*/
@Override
public E last() {
final int size = ((Collection<E>)dataSource).size();
if (index < size) {
return ((LazyList<E>)dataSource).last();
} else if (index == size) {
return object;
}
throw new IndexOutOfBoundsException(String.valueOf(index));
}
/**
* {@inheritDoc}
*/
@Override
public E get(final int index) {
final int size = ((List<E>)dataSource).size();
if (index <= size) {
if (index < this.index) {
return ((List<E>)dataSource).get(index);
} else if (index == this.index) {
return object;
}
assert this.index >= 0;
assert index > this.index;
return ((List<E>)dataSource).get(index - 1);
}
throw new IndexOutOfBoundsException(String.valueOf(index));
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(final Object o) {
final int indexOf = ((List<E>)dataSource).indexOf(o);
if (indexOf > -1) {
assert index >= 0;
if (indexOf > index && (object == null ? o == null : object.equals(o))) {
return index;
}
return indexOf;
}
if (object == null ? o == null : object.equals(o)) {
if (index <= ((Collection<E>)dataSource).size()) {
return index;
}
throw new IndexOutOfBoundsException(String.valueOf(index));
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(final Object o) {
final int lastIndexOf = ((List<E>)dataSource).lastIndexOf(o);
if (lastIndexOf > -1) {
assert index >= 0;
if (lastIndexOf < index && (object == null ? o == null : object.equals(o))) {
return index;
}
return lastIndexOf;
}
if (object == null ? o == null : object.equals(o)) {
if (index <= ((Collection<E>)dataSource).size()) {
return index;
}
throw new IndexOutOfBoundsException(String.valueOf(index));
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<E> iterator() {
return new InsertAtIterator();
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator() {
return new InsertAtListIterator();
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator(final int index) {
return new InsertAtListIterator(index);
}
}
/**
* {@link LazyList} that presents a sub-range of the underlying list.
*/
public static class SubList<E> extends NonCachingList<E> {
protected final int fromIndex;
protected final int toIndex;
/**
* Creates a new {@link SubList}.
* @param fromIndex the starting index, inclusive
* @param toIndex the ending index, exclusive
* @param dataSource the underlying collection
*/
public SubList(final int fromIndex, final int toIndex, final LazyList<E> dataSource) {
super(dataSource);
this.fromIndex = fromIndex;
this.toIndex = toIndex;
if (0 > fromIndex || fromIndex > toIndex) {
throw new IndexOutOfBoundsException(String.valueOf(fromIndex) + " - " +
String.valueOf(toIndex));
}
}
/**
* {@inheritDoc}
*/
@Override
public E first() {
return ((List<E>)dataSource).get(fromIndex);
}
/**
* {@inheritDoc}
*/
@Override
public E last() {
return ((List<E>)dataSource).get(toIndex - 1);
}
/**
* {@inheritDoc}
*/
@Override
public E get(final int index) {
return ((List<E>)dataSource).get(index + fromIndex);
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(final Object o) {
final int index = ((List<E>)dataSource).indexOf(o);
if (index >= fromIndex && index < toIndex) {
return index - fromIndex;
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(final Object o) {
final int index = ((List<E>)dataSource).lastIndexOf(o);
if (index >= fromIndex && index < toIndex) {
return index - fromIndex;
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(final Object o) {
final int index = ((List<E>)dataSource).indexOf(o);
return index >= fromIndex && index < toIndex;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
return fromIndex >= toIndex;
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<E> iterator() {
return new SubListIterator(fromIndex, toIndex);
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return toIndex - fromIndex;
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator() {
return new SubListListIterator(fromIndex, toIndex);
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator(final int index) {
return new SubListListIterator(fromIndex, toIndex, index);
}
}
/**
* {@link LazyList} that reverses the order of the underlying list.
*/
public static class ReverseList<E> extends NonCachingList<E> {
protected final int last;
/**
* Creates a new {@link ReverseList}.
* @param dataSource the underlying collection
*/
public ReverseList(final LazyList<E> dataSource) {
super(dataSource);
this.last = dataSource.size() - 1;
}
/**
* {@inheritDoc}
*/
@Override
public E first() {
return ((List<E>)dataSource).get(last);
}
/**
* {@inheritDoc}
*/
@Override
public E last() {
return ((List<E>)dataSource).get(0);
}
/**
* {@inheritDoc}
*/
@Override
public E get(final int index) {
return ((List<E>)dataSource).get(last - index);
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(final Object o) {
final int index = ((List<E>)dataSource).indexOf(o);
if (index > -1) {
return last - index;
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(final Object o) {
final int index = ((List<E>)dataSource).lastIndexOf(o);
if (index > -1) {
return last - index;
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(final Object o) {
return ((List<E>)dataSource).contains(o);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
return ((List<E>)dataSource).isEmpty();
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<E> iterator() {
return new ReverseIterator(last);
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return last + 1;
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator() {
return new ReverseListIterator(last);
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<E> listIterator(final int index) {
return new ReverseListIterator(last, index);
}
}
/**
* {@link LazyList} that represents a range running from a first to last {@link Integer}.
*
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public static class IntegerRangeList extends LazyList<Integer> {
protected final int first;
protected final int last;
/**
* Creates a new {@link IntegerRangeList}.
*
* @param first
* the first object of the range to include
* @param last
* the last object of the range to include
*/
public IntegerRangeList(final int first, final int last) {
super();
if (first > last) {
throw new IllegalArgumentException(String.format("The first element of a range (%d) cannot be greater than the last (%d)",
first, last));
}
this.first = first;
this.last = last;
}
/**
* {@inheritDoc}
*/
@Override
protected void createCache() {
// no caching
}
/**
* {@inheritDoc}
*/
@Override
public Integer first() {
return first;
}
/**
* {@inheritDoc}
*/
@Override
public Integer get(int index) {
final int element = first + index;
if (element > last) {
throw new IndexOutOfBoundsException(Integer.toString(index));
}
return element;
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(Object o) {
if (contains(o)) {
return (Integer) o - first;
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public Integer last() {
return last;
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(Object o) {
// All elements of a range are unique
return indexOf(o);
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<Integer> listIterator() {
return new IntegerRangeListIterator(first, last);
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<Integer> listIterator(int index) {
return new IntegerRangeListIterator(first, last, index);
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(Object o) {
if (o instanceof Integer) {
final Integer obj = (Integer) o;
return (obj >= first && obj <= last);
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int count(Object object) {
// All elements of a range are unique
return contains(object) ? 1 : 0;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
// Empty ranges are not allowed
return false;
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<Integer> iterator() {
return new IntegerRangeListIterator(first, last);
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return last - first + 1;
}
}
/**
* {@link LazyList} that represents a range running from a first to last {@link Long}.
*
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public static class LongRangeList extends LazyList<Long> {
protected final long first;
protected final long last;
/**
* Creates a new {@link LongRangeList}.
*
* @param first
* the first object of the range to include
* @param last
* the last object of the range to include
*/
public LongRangeList(final long first, final long last) {
super();
if (first > last) {
throw new IllegalArgumentException(String.format("The first element of a range (%d) cannot be greater than the last (%d)",
first, last));
}
this.first = first;
this.last = last;
}
/**
* {@inheritDoc}
*/
@Override
protected void createCache() {
// no caching
}
/**
* {@inheritDoc}
*/
@Override
public Long first() {
return first;
}
/**
* {@inheritDoc}
*/
@Override
public Long get(int index) {
final long element = first + index;
if (element > last) {
throw new IndexOutOfBoundsException(Integer.toString(index));
}
return element;
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(Object o) {
if (contains(o)) {
return (int) ((Long) o - first);
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public Long last() {
return last;
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(Object o) {
// All elements of a range are unique
return indexOf(o);
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<Long> listIterator() {
return new LongRangeListIterator(first, last);
}
/**
* {@inheritDoc}
*/
@Override
public ListIterator<Long> listIterator(int index) {
return new LongRangeListIterator(first, last, index);
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(Object o) {
if (o instanceof Long) {
final Long obj = (Long) o;
return (obj >= first && obj <= last);
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int count(Object object) {
// All elements of a range are unique
return contains(object) ? 1 : 0;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
// Empty ranges are not allowed
return false;
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<Long> iterator() {
return new LongRangeListIterator(first, last);
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return (int) (last - first + 1);
}
}
/**
* {@link ListIterator} that returns first the elements of the underlying collection, then the elements of the other collection.
*
* @author <a href="mailto:dennis.wagelaar@vub.ac.be">Dennis Wagelaar</a>
*/
public class UnionListIterator extends WrappedListIterator {
protected final List<? extends E> s;
protected ListIterator<? extends E> added; // lazily instantiate this iterator
protected boolean innerNext; // cache last inner.hasNext() invocation
protected boolean addedPrev; // cache last added.hasPrevious() invocation
/**
* Creates a new {@link UnionListIterator} for the underlying
* collection and <code>s</code>.
* @param s the collection to union
*/
public UnionListIterator(final List<? extends E> s) {
super();
this.s = s;
}
/**
* Creates a new {@link UnionListIterator} for the underlying
* collection and <code>s</code>.
* @param s the collection to union
* @param index the iterator starting index.
*/
public UnionListIterator(final List<? extends E> s, final int index) {
super(index);
this.s = s;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
if (added == null) {
innerNext = inner.hasNext();
if (innerNext) {
return true;
} else {
added = s.listIterator();
}
}
return added.hasNext();
}
/**
* {@inheritDoc}
*/
@Override
public E next() {
if (added == null) {
if (innerNext || inner.hasNext()) {
innerNext = false;
return inner.next();
} else {
added = s.listIterator();
}
}
return added.next();
}
/**
* {@inheritDoc}
*/
@Override
public int nextIndex() {
if (added == null) {
if (innerNext || inner.hasNext()) {
return inner.nextIndex();
} else {
added = s.listIterator();
}
}
return ((Collection<E>)dataSource).size() + added.nextIndex();
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasPrevious() {
if (added != null) {
addedPrev = added.hasPrevious();
if (addedPrev) {
return true;
} else {
added = null;
}
}
return inner.hasPrevious();
}
/**
* {@inheritDoc}
*/
@Override
public E previous() {
if (added != null) {
if (addedPrev || added.hasPrevious()) {
addedPrev = false;
return added.previous();
} else {
added = null;
}
}
return inner.previous();
}
/**
* {@inheritDoc}
*/
@Override
public int previousIndex() {
if (added != null) {
if (addedPrev || added.hasPrevious()) {
return ((Collection<E>)dataSource).size() + added.previousIndex();
} else {
added = null;
}
}
return inner.previousIndex();
}
}
/**
* {@link LazyList} that implements the {@link LazyList#collect(CodeBlock)} function.
* @author <a href="dwagelaar@gmail.com">Dennis Wagelaar</a>
*
* @param <E> the element type
*/
public static class CollectList<E> extends LazyList<E> {
/**
* Creates a {@link CollectList} around <code>dataSource</code>.
* @param dataSource the underlying {@link LazyList}
*/
public CollectList(final LazyList<E> dataSource) {
super(dataSource);
assert dataSource != null;
}
}
/**
* Creates a {@link LazyList} around <code>dataSource</code>.
* @param dataSource the underlying collection
*/
public LazyList(final Iterable<E> dataSource) {
super(dataSource);
}
/**
* Creates an empty {@link LazyList}.
*/
public LazyList() {
super();
}
/* *********************************************************************
* Non-lazy operations *
* *********************************************************************/
/**
* {@inheritDoc}
*/
@Override
protected void createCache() {
super.createCache();
if (this.cache == null) {
this.cache = new ArrayList<E>();
}
assert this.cache instanceof List<?>;
}
/**
* Unsupported.
* @param index the index at which to add
* @param element the element to add
* @throws UnsupportedOperationException
*/
public void add(final int index, final E element) {
throw new UnsupportedOperationException();
}
/**
* Unsupported.
* @param index the index at which to add
* @param c the collection to add
* @return nothing
* @throws UnsupportedOperationException
*/
public boolean addAll(final int index, final Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public E get(final int index) {
if (index < cache.size()) {
return ((List<E>)cache).get(index);
}
int i = 0;
for (E e : this) {
if (i == index) {
return e;
}
i++;
}
throw new ArrayIndexOutOfBoundsException();
}
/**
* {@inheritDoc}
*/
public int indexOf(final Object o) {
final int index = ((List<E>)cache).indexOf(o);
if (index > -1 || dataSource == null) { // cache complete
return index;
}
int i = 0;
if (o == null) {
for (E e : this) {
if (e == null) return i;
i++;
}
} else {
for (E e : this) {
if (o.equals(e)) return i;
i++;
}
}
return -1;
}
/**
* {@inheritDoc}
*/
public int lastIndexOf(final Object o) {
if (dataSource == null) { // cache complete
return ((List<E>)cache).lastIndexOf(o);
}
int i = 0;
int lastIndex = -1;
if (o == null) {
for (E e : this) {
if (e == null) lastIndex = i;
i++;
}
} else {
for (E e : this) {
if (e.equals(o)) lastIndex = i;
i++;
}
}
return lastIndex;
}
/**
* {@inheritDoc}
*/
public ListIterator<E> listIterator() {
if (dataSource == null) { // cache complete
return Collections.unmodifiableList((List<E>)cache).listIterator();
}
return new IteratorToListIterator();
}
/**
* {@inheritDoc}
*/
public ListIterator<E> listIterator(final int index) {
if (dataSource == null) { // cache complete
return Collections.unmodifiableList((List<E>)cache).listIterator(index);
}
return new IteratorToListIterator(index);
}
/**
* Unsupported.
* @param index the index at which to remove
* @return nothing
* @throws UnsupportedOperationException
*/
public E remove(final int index) {
throw new UnsupportedOperationException();
}
/**
* Unsupported.
* @param index the index at which to set
* @param element the element to set
* @return nothing
* @throws UnsupportedOperationException
*/
public E set(final int index, final E element) {
throw new UnsupportedOperationException();
}
/**
* <p><i>Lazy implementation of {@link List#subList(int, int)}.</i></p>
* {@inheritDoc}
*/
public LazyList<E> subList(final int fromIndex, final int toIndex) {
return new SubList<E>(fromIndex, toIndex, this);
}
/**
* {@inheritDoc}
*
* Unsupported in this implementation.
* @throws UnsupportedOperationException
*/
public void move(int newPosition, E object) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*
* Unsupported in this implementation.
* @throws UnsupportedOperationException
*/
public E move(int newPosition, int oldPosition) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof List<?>)) {
return false;
}
final Iterator<E> e1 = iterator();
final Iterator<?> e2 = ((Collection<?>)o).iterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1 == null ? o2 == null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
int hashCode = 1;
for (E obj : this) {
hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
}
return hashCode;
}
/**
* {@inheritDoc}
*/
public String asString(final ExecEnv env) {
return appendElements(new StringBuffer("Sequence{"), env).append('}').toString();
}
/**
* Returns the <code>i</code>-th element of this list. List index starts at 1.
*
* @param i
* the element index
* @return The <code>i</code>-th element of this list.
*/
public E at(final int i) {
return get(i - 1);
}
/**
* Returns the index of object <code>obj</code> in the sequence.
* List index starts at 1.<br>
* pre : <code>self->includes(obj)</code><br>
* post : <code>self->at(i) = obj</code>
* @param obj the object to look for
* @return The index of object <code>obj</code> in the sequence.
* @throws IndexOutOfBoundsException if <code>obj</code> is not contained in this list.
*/
public int indexOf2(final Object obj) throws IndexOutOfBoundsException {
final int i = indexOf(obj) + 1;
if (i == 0) {
throw new IndexOutOfBoundsException();
}
return i;
}
/**
* Returns the last index of object <code>obj</code> in the sequence.
* List index starts at 1.<br>
* pre : <code>self->includes(obj)</code><br>
* post : <code>self->at(i) = obj</code>
* @param obj the object to look for
* @return The last index of object <code>obj</code> in the sequence.
* @throws IndexOutOfBoundsException if <code>obj</code> is not contained in this list.
*/
public int lastIndexOf2(final Object obj) throws IndexOutOfBoundsException {
final int i = lastIndexOf(obj) + 1;
if (i == 0) {
throw new IndexOutOfBoundsException();
}
return i;
}
/**
* Returns the first element in self.
* @return The first element in self.
*/
public E first() {
if (cache.size() > 0) {
return ((List<E>)cache).get(0);
}
return iterator().next();
}
/**
* Returns the last element in self.
* @return The last element in self.
*/
public E last() {
if (dataSource == null) {
final int size = cache.size();
if (size < 1) {
throw new NoSuchElementException();
}
return ((List<E>)cache).get(size - 1);
}
boolean lastSet = false;
E last = null;
for (final Iterator<E> it = iterator(); it.hasNext();) {
last = it.next();
lastSet = true;
}
if (!lastSet) {
throw new NoSuchElementException();
}
return last;
}
/* *********************************************************************
* Lazy operations *
* *********************************************************************/
/**
* Returns the sequence consisting of all elements in self, followed by all elements in <code>s</code>.
* <p><i>Lazy operation.</i></p>
* @param s the list to union with this
* @return The sequence consisting of all elements in self, followed by all elements in <code>s</code>.
*/
public LazyList<E> union(final LazyList<? extends E> s) {
return new UnionList<E>(s, this);
}
/**
* Returns the sequence consisting of all elements in self, with all elements in <code>s</code> inserted at <code>index</code>.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @param s
* the list to union with this
* @param index
* the insertion index (starting at 1)
* @return The sequence consisting of all elements in self, with all elements in <code>s</code> inserted at <code>index</code>
*/
public LazyList<E> union(final LazyList<? extends E> s, final int index) {
if (index == 1) {
return union(s);
}
return subSequence(1, index - 1).union(s).union(subSequence(index, size()));
}
/**
* If the element type is not a collection type this results in the same self. If the element type is a collection type, the result is
* the sequence containing all the elements of all the elements of self. The order of the elements is partial.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @return <b>if</b> self.type.elementType.oclIsKindOf(CollectionType) <b>then</b><br>
* &nbsp;&nbsp;self-&gt;iterate(c; acc : Sequence() = Sequence{} |<br>
* &nbsp;&nbsp;&nbsp;&nbsp;acc-&gt;union(c-&gt;asSequence() ) )<br>
* <b>else</b><br>
* &nbsp;&nbsp;self<br>
* <b>endif</b>
*/
public LazyList<?> flatten() {
final LazyList<E> inner = this;
return new LazyList<Object>(new Iterable<Object>() {
public Iterator<Object> iterator() {
return new FlattenIterator(inner);
}
});
}
/**
* Returns the sequence of elements, consisting of all elements of self, followed by <code>object</code>.
* <p><i>Lazy operation.</i></p>
* @param object the object to append
* @return The sequence of elements, consisting of all elements of self, followed by <code>object</code>.
*/
public LazyList<E> append(final E object) {
return new AppendList<E>(object, this);
}
/**
* Returns the sequence consisting of <code>object</code>, followed by all elements in self.
* <p><i>Lazy operation.</i></p>
* @param object the object to prepend
* @return The sequence consisting of <code>object</code>, followed by all elements in self.
*/
public LazyList<E> prepend(final E object) {
return new PrependList<E>(object, this);
}
/**
* Returns the sequence consisting of self with <code>object</code> inserted at position <code>index</code>.
* List index starts at 1.
* <p><i>Lazy operation.</i></p>
* @param index the index at which to insert
* @param object the object to insert
* @return The sequence consisting of self with <code>object</code> inserted at position <code>index</code>.
*/
public LazyList<E> insertAt(final int index, final E object) {
return new InsertAtList<E>(index - 1, object, this);
}
/**
* Returns the sub-list of this list starting at number <code>lower</code>,
* up to and including element number <code>upper</code>.
* List index starts at 1.
* <p><i>Lazy operation.</i></p>
* @param lower the sub-list lower bound, inclusive
* @param upper the sub-list upper bound, inclusive
* @return the sub-list of this list.
*/
public LazyList<E> subSequence(final int lower, final int upper) {
return new SubList<E>(lower - 1, upper, this);
}
/**
* Returns the sequence containing all elements of self plus <code>object</code> added as the last element.
* <p><i>Lazy operation.</i></p>
* @param object the object to include
* @return The sequence containing all elements of self plus <code>object</code> added as the last element.
*/
public LazyList<E> including(final E object) {
return append(object);
}
/**
* Returns the collection containing all elements of self plus <code>object</code>.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @param object
* the object to include
* @param index
* the index at which to insert <code>coll</code> (starting at 1)
* @return The collection containing all elements of self plus <code>object</code>.
*/
@Override
public LazyList<E> including(final E object, final int index) {
if (index > 0) {
return insertAt(index, object);
} else {
return append(object);
}
}
/**
* Returns the collection containing all elements of self plus <code>coll</code>.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @param coll
* the collection to include
* @return The collection containing all elements of self plus <code>coll</code>.
*/
@Override
public LazyList<E> includingAll(final Collection<? extends E> coll) {
return union(LazyCollections.asLazyList(coll));
}
/**
* Returns the collection containing all elements of self plus <code>coll</code>.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @param coll
* the collection to include
* @param index
* the index at which to insert <code>coll</code> (starting at 1)
* @return The collection containing all elements of self plus <code>coll</code>.
*/
@Override
public LazyList<E> includingAll(final Collection<? extends E> coll, final int index) {
if (index > 0) {
return union(LazyCollections.asLazyList(coll), index);
} else {
return union(LazyCollections.asLazyList(coll));
}
}
/**
* Returns the sequence containing all elements of self apart from all occurrences of <code>object</code>.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @param object
* the object to exclude
* @return The sequence containing all elements of self apart from all occurrences of <code>object</code>.
*/
public LazyList<E> excluding(final Object object) {
return new LazyList<E>(this) {
@Override
public Iterator<E> iterator() {
if (dataSource == null) {
return Collections.unmodifiableCollection(cache).iterator();
}
return new ExcludingIterator(object);
}
};
}
/**
* Returns the collection containing all elements of self minus <code>coll</code>.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @param coll
* the collection to exclude
* @return The collection containing all elements of self minus <code>coll</code>.
*/
@Override
public LazyList<E> excludingAll(final Collection<?> coll) {
return new LazyList<E>(this) {
@Override
public Iterator<E> iterator() {
if (dataSource == null) {
return Collections.unmodifiableCollection(cache).iterator();
}
return new SubtractionIterator(coll);
}
};
}
/**
* Returns the sequence containing the same elements but with the opposite order.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @return The sequence containing the same elements but with the opposite order.
*/
public LazyList<E> reverse() {
return new ReverseList<E>(this);
}
/**
* Returns the Sequence identical to the object itself. This operation exists for convenience reasons.
* <p><i>Lazy operation.</i></p>
* @return The Sequence identical to the object itself. This operation exists for convenience reasons.
*/
@Override
public LazyList<E> asSequence() {
return this;
}
/**
* Returns the sequence containing all elements of self plus the sequence of <code>first</code> running to <code>last</code> added as
* the last elements.
* <p>
* <i>Lazy operation.</i>
* </p>
*
* @param first
* the first object of the range to include
* @param last
* the last object of the range to include
* @return The sequence containing all elements of self plus the sequence of <code>first</code> running to <code>last</code> added as
* the last elements
*/
@SuppressWarnings("unchecked")
public LazyList<E> includingRange(final E first, final E last) {
if (first instanceof Integer && last instanceof Integer) {
return union((LazyList<E>) new IntegerRangeList((Integer) first, (Integer) last));
}
if (first instanceof Long && last instanceof Long) {
return union((LazyList<E>) new LongRangeList((Long) first, (Long) last));
}
throw new IllegalArgumentException(String.format("includingRange() not supported for arguments of type %s and %s", first.getClass()
.getName(), last.getClass().getName()));
}
/* *********************************************************************
* Lazy, higher-order operations *
* *********************************************************************/
/**
* Selects all elements from this collection for which the
* <code>condition</code> evaluates to <code>true</code>.
* @param condition the condition function
* @return a new lazy list with only the selected elements.
*/
public LazyList<E> select(final CodeBlock condition) {
// Parent frame may change after this method returns!
final StackFrame parentFrame = condition.getParentFrame();
condition.setParentFrame(null);
return new LazyList<E>(this) {
@Override
public Iterator<E> iterator() {
if (dataSource == null) {
return Collections.unmodifiableCollection(cache).iterator();
}
return new SelectIterator(condition, parentFrame);
}
};
}
/**
* Rejects all elements from this collection for which the
* <code>condition</code> evaluates to <code>true</code>.
* @param condition the condition function
* @return a new lazy list without the rejected elements.
*/
public LazyList<E> reject(final CodeBlock condition) {
// Parent frame may change after this method returns!
final StackFrame parentFrame = condition.getParentFrame();
condition.setParentFrame(null);
return new LazyList<E>(this) {
@Override
public Iterator<E> iterator() {
if (dataSource == null) {
return Collections.unmodifiableCollection(cache).iterator();
}
return new RejectIterator(condition, parentFrame);
}
};
}
/**
* Collects the return values of <code>function</code> for
* each of the elements of this collection.
* @param function the return value function
* @return a new lazy list with the <code>function</code> return values.
* @param <T> the element type
*/
public <T> LazyList<T> collect(final CodeBlock function) {
// Parent frame may change after this method returns!
final StackFrame parentFrame = function.getParentFrame();
function.setParentFrame(null);
final LazyList<E> inner = this;
return new LazyList<T>(new Iterable<T>() {
public Iterator<T> iterator() {
return new CollectIterator<T>(inner, function, parentFrame);
}
}) {
@SuppressWarnings("unchecked")
@Override
public T get(final int index) {
if (index < cache.size()) {
return ((List<T>)cache).get(index);
}
return (T) function.execute(parentFrame.getSubFrame(function, inner.get(index)));
}
@SuppressWarnings("unchecked")
@Override
public T last() {
if (dataSource == null) {
final int size = cache.size();
if (size < 1) {
throw new NoSuchElementException();
}
return ((List<T>)cache).get(size - 1);
}
return (T) function.execute(parentFrame.getSubFrame(function, inner.last()));
}
@Override
public int size() {
return inner.size();
}
};
}
/**
* {@inheritDoc}
*/
@Override
public LazyList<E> sortedBy(final CodeBlock body) {
// Parent frame may change after this method returns!
final StackFrame parentFrame = body.getParentFrame();
body.setParentFrame(null);
return new LazyList<E>(this) {
@SuppressWarnings("unchecked")
@Override
public Iterator<E> iterator() {
final Collection<E> inner = (Collection<E>) dataSource;
if (inner != null) {
final Iterator<Comparable<Object>> sortingKeys = new CollectIterator<Comparable<Object>>(inner, body, parentFrame);
final Object[] innerCopy = inner.toArray();
final Map<Object, Comparable<Object>> elementsToKeys = new HashMap<Object, Comparable<Object>>(innerCopy.length);
for (Object o : innerCopy) {
elementsToKeys.put(o, sortingKeys.next());
}
assert !sortingKeys.hasNext();
Arrays.sort(innerCopy, new Comparator<Object>() {
public int compare(Object o1, Object o2) {
return elementsToKeys.get(o1).compareTo(elementsToKeys.get(o2));
}
});
cache = (Collection<E>) Arrays.asList(innerCopy);
dataSource = null;
}
return super.iterator();
}
@Override
public int size() {
if (dataSource == null) {
return cache.size();
}
return ((Collection<E>) dataSource).size();
}
};
}
// TODO provide other iterator operations: collectNested
}