package jetbrains.mps.internal.collections.runtime.impl;
/*Generated by MPS */
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.internal.collections.runtime.ISequence;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.ArrayList;
public class ComparingSequence<U> extends Sequence<U> implements Iterable<U> {
private final ISequence<? extends U> left;
private final ISequence<? extends U> right;
private final ISequence<?> rightGeneric;
private final ComparingSequence.Kind kind;
public ComparingSequence(ISequence<? extends U> left, ISequence<? extends U> right, ComparingSequence.Kind kind) {
if (left == null || right == null) {
throw new NullPointerException();
}
this.left = left;
this.right = right;
this.rightGeneric = right;
this.kind = kind;
}
public ComparingSequence(ComparingSequence.Kind kind, ISequence<? extends U> left, ISequence<?> right) {
if (left == null || right == null) {
throw new NullPointerException();
}
assert kind == ComparingSequence.Kind.SUBSTRACTION || kind == ComparingSequence.Kind.INTERSECTION;
this.left = left;
this.right = null;
this.rightGeneric = right;
this.kind = kind;
}
@Override
public Iterator<U> iterator() {
return new ComparingSequence.ComparingIterator();
}
public enum Kind {
UNION(),
INTERSECTION(),
SUBSTRACTION(),
DISJUNCTION();
private Kind() {
}
}
private class ComparingIterator implements Iterator<U> {
private CardinalityMap<Object> cardMap = new CardinalityMap<Object>();
private List<U> cache;
private Iterator<? extends U> leftIt;
private Iterator<? extends U> rightIt;
private U next;
private HasNextState hasNext = HasNextState.UNKNOWN;
private ComparingIterator() {
}
@Override
public boolean hasNext() {
if (leftIt == null && rightIt == null) {
init();
}
if (hasNext.unknown()) {
moveToNext();
}
return hasNext.hasNext();
}
@Override
public U next() {
if (leftIt == null && rightIt == null) {
init();
}
if (hasNext.unknown()) {
moveToNext();
}
if (!((hasNext.hasNext()))) {
throw new NoSuchElementException();
}
return clearNext();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private void init() {
switch (kind) {
case SUBSTRACTION:
case INTERSECTION:
for (Object o : rightGeneric.toIterable()) {
cardMap.postInc(o);
}
leftIt = left.toIterable().iterator();
break;
case UNION:
leftIt = left.toIterable().iterator();
rightIt = right.toIterable().iterator();
break;
case DISJUNCTION:
cache = new ArrayList<U>();
for (U o : right.toIterable()) {
cardMap.postInc(o);
cache.add(o);
}
leftIt = left.toIterable().iterator();
rightIt = cache.iterator();
break;
default:
break;
}
}
private void destroy() {
cardMap.clear();
if (cache != null) {
cache.clear();
}
}
private void moveToNext() {
next = null;
hasNext = HasNextState.AT_END;
loop:
do {
switch (kind) {
case SUBSTRACTION:
if (leftIt.hasNext()) {
U tmp = leftIt.next();
if (cardMap.postDec(tmp) == 0) {
setNext(tmp);
break loop;
}
} else {
break loop;
}
break;
case INTERSECTION:
if (leftIt.hasNext()) {
U tmp = leftIt.next();
if (cardMap.postDec(tmp) > 0) {
setNext(tmp);
break loop;
}
} else {
break loop;
}
break;
case UNION:
if (leftIt.hasNext()) {
U tmp = leftIt.next();
cardMap.postInc(tmp);
setNext(tmp);
break loop;
}
if (rightIt.hasNext()) {
U tmp = rightIt.next();
if (cardMap.postDec(tmp) == 0) {
setNext(tmp);
break loop;
}
} else {
break loop;
}
break;
case DISJUNCTION:
if (leftIt.hasNext()) {
U tmp = leftIt.next();
if (cardMap.postDec(tmp) == 0) {
setNext(tmp);
break loop;
}
} else
if (rightIt.hasNext()) {
U tmp = rightIt.next();
if (cardMap.postDec(tmp) > 0) {
setNext(tmp);
break loop;
}
} else {
break loop;
}
break;
default:
break;
}
} while (true);
if (!((hasNext.hasNext()))) {
destroy();
}
}
private U clearNext() {
U tmp = next;
next = null;
hasNext = HasNextState.UNKNOWN;
return tmp;
}
private void setNext(U tmp) {
next = tmp;
hasNext = HasNextState.HAS_NEXT;
}
}
}