/**
* Copyright (c) 2002-2007 IBM Corporation and others.
* 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:
* IBM - Initial API and implementation
*/
package org.eclipse.emf.ecore.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.RandomAccess;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.impl.EClassImpl;
public class EContentsEList<E> extends AbstractSequentialInternalEList<E> implements EList<E>, InternalEList<E>
{
public static final EContentsEList<?> EMPTY_CONTENTS_ELIST =
new EContentsEList<Object>(null, (EStructuralFeature [])null)
{
@Override
public List<Object> basicList()
{
return this;
}
};
@SuppressWarnings("unchecked")
public static <T> EContentsEList<T> emptyContentsEList()
{
return (EContentsEList<T>)EMPTY_CONTENTS_ELIST;
}
public static <T> EContentsEList<T> createEContentsEList(EObject eObject)
{
EStructuralFeature [] eStructuralFeatures =
((EClassImpl.FeatureSubsetSupplier)eObject.eClass().getEAllStructuralFeatures()).containments();
return
eStructuralFeatures == null ?
EContentsEList.<T>emptyContentsEList() :
new EContentsEList<T>(eObject, eStructuralFeatures);
}
protected final EObject eObject;
protected final EStructuralFeature [] eStructuralFeatures;
public EContentsEList(EObject eObject)
{
this.eObject = eObject;
this.eStructuralFeatures =
((EClassImpl.FeatureSubsetSupplier)eObject.eClass().getEAllStructuralFeatures()).containments();
}
public EContentsEList(EObject eObject, List<? extends EStructuralFeature> eStructuralFeatures)
{
this.eObject = eObject;
this.eStructuralFeatures = new EStructuralFeature [eStructuralFeatures.size()];
eStructuralFeatures.toArray(this.eStructuralFeatures);
}
public EContentsEList(EObject eObject, EStructuralFeature [] eStructuralFeatures)
{
this.eObject = eObject;
this.eStructuralFeatures = eStructuralFeatures;
}
protected ListIterator<E> newListIterator()
{
return resolve() ? newResolvingListIterator() : newNonResolvingListIterator();
}
protected ListIterator<E> newResolvingListIterator()
{
return new ResolvingFeatureIteratorImpl<E>(eObject, eStructuralFeatures);
}
protected ListIterator<E> newNonResolvingListIterator()
{
return new FeatureIteratorImpl<E>(eObject, eStructuralFeatures);
}
protected Iterator<E> newIterator()
{
return newListIterator();
}
protected boolean useIsSet()
{
return true;
}
protected boolean resolve()
{
return true;
}
protected boolean isIncluded(EStructuralFeature eStructuralFeature)
{
return true;
}
protected boolean isIncludedEntry(EStructuralFeature eStructuralFeature)
{
return eStructuralFeature instanceof EReference && ((EReference)eStructuralFeature).isContainment();
}
@Override
public ListIterator<E> listIterator(int index)
{
if (eStructuralFeatures == null)
{
if (index != 0)
{
throw new IndexOutOfBoundsException("index=" + index + ", size=0");
}
return FeatureIteratorImpl.emptyIterator();
}
ListIterator<E> result = newListIterator();
for (int i = 0; i < index; ++i)
{
result.next();
}
return result;
}
@Override
public Iterator<E> iterator()
{
if (eStructuralFeatures == null)
{
return FeatureIteratorImpl.emptyIterator();
}
Iterator<E> result = newIterator();
return result;
}
@Override
public int size()
{
int result = 0;
if (eStructuralFeatures != null)
{
for (int i = 0; i < eStructuralFeatures.length; ++i)
{
EStructuralFeature feature = eStructuralFeatures[i];
if (isIncluded(feature) && (!useIsSet() || eObject.eIsSet(feature)))
{
Object value = eObject.eGet(feature, false);
if (FeatureMapUtil.isFeatureMap(feature))
{
FeatureMap featureMap = (FeatureMap)value;
for (int j = 0, size = featureMap.size(); j < size; ++j)
{
if (isIncludedEntry(featureMap.getEStructuralFeature(j)) && featureMap.getValue(j) != null)
{
++result;
}
}
}
else if (feature.isMany())
{
result += ((Collection<?>)value).size();
}
else if (value != null)
{
++result;
}
}
}
}
return result;
}
@Override
public boolean isEmpty()
{
if (eStructuralFeatures != null)
{
for (int i = 0; i < eStructuralFeatures.length; ++i)
{
EStructuralFeature feature = eStructuralFeatures[i];
if (isIncluded(feature) && (!useIsSet() || eObject.eIsSet(feature)))
{
Object value = eObject.eGet(feature, false);
if (FeatureMapUtil.isFeatureMap(feature))
{
FeatureMap featureMap = (FeatureMap)value;
for (int j = 0, size = featureMap.size(); j < size; ++j)
{
if (isIncludedEntry(featureMap.getEStructuralFeature(j)) && featureMap.getValue(j) != null)
{
return false;
}
}
}
else if (feature.isMany())
{
if (!((Collection<?>)value).isEmpty())
{
return false;
}
}
else if (value != null)
{
return false;
}
}
}
}
return true;
}
@Override
public void move(int newPosition, Object o)
{
throw new UnsupportedOperationException();
}
@Override
public E move(int newPosition, int oldPosition)
{
throw new UnsupportedOperationException();
}
@Override
public E basicGet(int index)
{
return basicList().get(index);
}
@Override
public List<E> basicList()
{
return
new EContentsEList<E>(eObject, eStructuralFeatures)
{
@Override
protected boolean resolve()
{
return false;
}
};
}
@Override
public Iterator<E> basicIterator()
{
if (eStructuralFeatures == null)
{
return FeatureIteratorImpl.emptyIterator();
}
return newNonResolvingListIterator();
}
@Override
public ListIterator<E> basicListIterator()
{
if (eStructuralFeatures == null)
{
return FeatureIteratorImpl.emptyIterator();
}
return newNonResolvingListIterator();
}
@Override
public ListIterator<E> basicListIterator(int index)
{
if (eStructuralFeatures == null)
{
if (index < 0 || index > 1)
{
throw new IndexOutOfBoundsException("index=" + index + ", size=0");
}
return FeatureIteratorImpl.emptyIterator();
}
ListIterator<E> result = newNonResolvingListIterator();
for (int i = 0; i < index; ++i)
{
result.next();
}
return result;
}
public interface FeatureIterator<E> extends Iterator<E>
{
EStructuralFeature feature();
}
public interface FeatureListIterator<E> extends FeatureIterator<E>, ListIterator<E>
{
// No new methods.
}
public static class FeatureIteratorImpl<E> implements FeatureListIterator<E>
{
protected final EObject eObject;
protected final EStructuralFeature [] eStructuralFeatures;
protected int featureCursor;
protected int cursor;
protected int prepared;
protected E preparedResult;
protected EStructuralFeature preparedFeature;
protected EStructuralFeature feature;
protected boolean isHandlingFeatureMap;
protected ListIterator<E> values;
protected InternalEList<E> valueInternalEList;
protected List<E> valueList;
protected int valueListSize;
protected int valueListIndex;
public FeatureIteratorImpl(EObject eObject, List<? extends EStructuralFeature> eStructuralFeatures)
{
this.eObject = eObject;
this.eStructuralFeatures = new EStructuralFeature [eStructuralFeatures.size()];
eStructuralFeatures.toArray(this.eStructuralFeatures);
}
public FeatureIteratorImpl(EObject eObject, EStructuralFeature [] eStructuralFeatures)
{
this.eObject = eObject;
this.eStructuralFeatures = eStructuralFeatures;
}
protected boolean resolve()
{
return false;
}
protected boolean useIsSet()
{
return true;
}
protected boolean isIncluded(EStructuralFeature eStructuralFeature)
{
return true;
}
protected boolean isIncludedEntry(EStructuralFeature eStructuralFeature)
{
return eStructuralFeature instanceof EReference && ((EReference)eStructuralFeature).isContainment();
}
public EStructuralFeature feature()
{
return feature;
}
public boolean hasNext()
{
switch (prepared)
{
case 3:
case 2:
{
return true;
}
case 1:
{
return false;
}
case -3:
{
// Undo the preparation for previous and continue.
if (values == null)
{
++valueListIndex;
}
else
{
values.next();
}
}
default:
{
if (valueList == null || (values == null ? !scanNext() : !scanNext(values)))
{
while (featureCursor < eStructuralFeatures.length)
{
EStructuralFeature feature = eStructuralFeatures[featureCursor++];
if (isIncluded(feature) && (!useIsSet() || eObject.eIsSet(feature)))
{
Object value = eObject.eGet(feature, resolve());
isHandlingFeatureMap = FeatureMapUtil.isFeatureMap(feature);
if (isHandlingFeatureMap || feature.isMany())
{
if (resolve())
{
@SuppressWarnings("unchecked") List<E> newValueList = (List<E>)value;
valueList = newValueList;
}
else
{
@SuppressWarnings("unchecked") InternalEList<E> newValueList = (InternalEList<E>)value;
valueList = valueInternalEList = newValueList;
}
if (valueList instanceof RandomAccess)
{
values = null;
valueListSize = valueList.size();
valueListIndex = 0;
}
else
{
values =
valueInternalEList == null ?
valueList.listIterator() :
valueInternalEList.basicListIterator();
}
if (values == null ? scanNext() : scanNext(values))
{
Object result =
values == null ?
valueInternalEList == null ?
valueList.get(valueListIndex++) :
valueInternalEList.basicGet(valueListIndex++) :
values.next();
if (isHandlingFeatureMap)
{
FeatureMap.Entry entry = (FeatureMap.Entry)result;
preparedFeature = entry.getEStructuralFeature();
@SuppressWarnings("unchecked") E newPreparedResult = (E)entry.getValue();
preparedResult = newPreparedResult;
}
else
{
@SuppressWarnings("unchecked") E newPreparedResult = (E)result;
preparedResult = newPreparedResult;
preparedFeature = feature;
}
prepared = 3;
return true;
}
}
else if (value != null)
{
valueList = null;
values = null;
@SuppressWarnings("unchecked") E newPreparedResult = (E)value;
preparedResult = newPreparedResult;
preparedFeature = feature;
prepared = 2;
return true;
}
}
}
valueList = null;
values = null;
isHandlingFeatureMap = false;
prepared = 1;
return false;
}
else
{
Object result =
values == null ?
valueInternalEList == null ?
valueList.get(valueListIndex++) :
valueInternalEList.basicGet(valueListIndex++) :
values.next();
if (isHandlingFeatureMap)
{
FeatureMap.Entry entry = (FeatureMap.Entry)result;
preparedFeature = entry.getEStructuralFeature();
@SuppressWarnings("unchecked") E newPreparedResult = (E)entry.getValue();
preparedResult = newPreparedResult;
}
else
{
@SuppressWarnings("unchecked") E newPreparedResult = (E)result;
preparedResult = newPreparedResult;
}
prepared = 3;
return true;
}
}
}
}
protected boolean scanNext(ListIterator<E> values)
{
if (isHandlingFeatureMap)
{
while (values.hasNext())
{
FeatureMap.Entry entry = (FeatureMap.Entry)values.next();
EStructuralFeature entryFeature = entry.getEStructuralFeature();
if (isIncludedEntry(entryFeature) && entry.getValue() != null)
{
values.previous();
return true;
}
}
return false;
}
else
{
return values.hasNext();
}
}
protected boolean scanNext()
{
if (isHandlingFeatureMap)
{
while (valueListIndex < valueListSize)
{
FeatureMap.Entry entry =
(FeatureMap.Entry)
(valueInternalEList == null ?
valueList.get(valueListIndex) :
valueInternalEList.basicGet(valueListIndex));
EStructuralFeature entryFeature = entry.getEStructuralFeature();
if (isIncludedEntry(entryFeature) && entry.getValue() != null)
{
return true;
}
else
{
++valueListIndex;
}
}
return false;
}
else
{
return valueListIndex < valueListSize;
}
}
public E next()
{
if (prepared > 1 || hasNext())
{
++cursor;
prepared = 0;
feature = preparedFeature;
E result = preparedResult;
hasNext();
return result;
}
else
{
throw new NoSuchElementException();
}
}
public int nextIndex()
{
return cursor;
}
public boolean hasPrevious()
{
switch (prepared)
{
case -3:
case -2:
{
return true;
}
case -1:
{
return false;
}
case 3:
{
// Undo the preparation for next and continue.
if (values == null)
{
--valueListIndex;
}
else
{
values.previous();
}
}
default:
{
if (valueList == null || (values == null ? !scanPrevious() : !scanPrevious(values)))
{
while (featureCursor > 0)
{
EStructuralFeature feature = eStructuralFeatures[--featureCursor];
if (isIncluded(feature) && (!useIsSet() || eObject.eIsSet(feature)))
{
Object value = eObject.eGet(feature, resolve());
isHandlingFeatureMap = FeatureMapUtil.isFeatureMap(feature);
if (isHandlingFeatureMap || feature.isMany())
{
if (resolve())
{
@SuppressWarnings("unchecked") List<E> newValueList = (List<E>)value;
valueList = newValueList;
}
else
{
@SuppressWarnings("unchecked") InternalEList<E> newValueList = (InternalEList<E>)value;
valueList = valueInternalEList = newValueList;
}
if (valueList instanceof RandomAccess)
{
valueListSize = valueList.size();
valueListIndex = valueListSize;
}
else
{
values =
valueInternalEList == null ?
valueList.listIterator(valueList.size()) :
valueInternalEList.basicListIterator(valueList.size());
}
if (values == null ? scanPrevious() : scanPrevious(values))
{
Object result =
values == null ?
valueInternalEList == null ?
valueList.get(--valueListIndex) :
valueInternalEList.basicGet(--valueListIndex) :
values.previous();
if (isHandlingFeatureMap)
{
FeatureMap.Entry entry = (FeatureMap.Entry)result;
preparedFeature = entry.getEStructuralFeature();
@SuppressWarnings("unchecked") E newPreparedResult = (E)entry.getValue();
preparedResult = newPreparedResult;
}
else
{
@SuppressWarnings("unchecked") E newPreparedResult = (E)result;
preparedResult = newPreparedResult;
preparedFeature = feature;
}
prepared = -3;
return true;
}
}
else if (value != null)
{
valueList = null;
values = null;
@SuppressWarnings("unchecked") E newPreparedResult = (E)value;
preparedResult = newPreparedResult;
preparedFeature = feature;
prepared = -2;
return true;
}
}
}
valueList = null;
values = null;
prepared = -1;
return false;
}
else
{
Object result =
values == null ?
valueInternalEList == null ?
valueList.get(--valueListIndex) :
valueInternalEList.basicGet(--valueListIndex) :
values.previous();
if (isHandlingFeatureMap)
{
FeatureMap.Entry entry = (FeatureMap.Entry)result;
preparedFeature = entry.getEStructuralFeature();
@SuppressWarnings("unchecked") E newPreparedResult = (E)entry.getValue();
preparedResult = newPreparedResult;
}
else
{
@SuppressWarnings("unchecked") E newPreparedResult = (E)result;
preparedResult = newPreparedResult;
}
prepared = -3;
return true;
}
}
}
}
protected boolean scanPrevious(ListIterator<E> values)
{
if (isHandlingFeatureMap)
{
while (values.hasPrevious())
{
FeatureMap.Entry entry = (FeatureMap.Entry)values.previous();
EStructuralFeature entryFeature = entry.getEStructuralFeature();
if (isIncludedEntry(entryFeature) && entry.getValue() != null)
{
values.next();
return true;
}
}
return false;
}
else
{
return values.hasPrevious();
}
}
protected boolean scanPrevious()
{
if (isHandlingFeatureMap)
{
while (valueListIndex > 0)
{
FeatureMap.Entry entry = (FeatureMap.Entry)valueList.get(valueListIndex - 1);
EStructuralFeature entryFeature = entry.getEStructuralFeature();
if (isIncludedEntry(entryFeature) && entry.getValue() != null)
{
return true;
}
else
{
--valueListIndex;
}
}
return false;
}
else
{
return valueListIndex > 0;
}
}
public E previous()
{
if (prepared < -1 || hasPrevious())
{
--cursor;
prepared = 0;
feature = preparedFeature;
E result = preparedResult;
hasPrevious();
return result;
}
else
{
throw new NoSuchElementException();
}
}
public int previousIndex()
{
return cursor - 1;
}
public void add(Object o)
{
throw new UnsupportedOperationException();
}
public void remove()
{
throw new UnsupportedOperationException();
}
public void set(Object o)
{
throw new UnsupportedOperationException();
}
public static final ListIterator<?> EMPTY_ITERATOR =
new FeatureIteratorImpl<Object>(null, (EStructuralFeature [] )null)
{
@Override
public boolean hasNext()
{
return false;
}
@Override
public boolean hasPrevious()
{
return false;
}
};
@SuppressWarnings("unchecked")
public static <T> ListIterator<T> emptyIterator()
{
return (ListIterator<T>)EMPTY_ITERATOR;
}
}
public static class ResolvingFeatureIteratorImpl<E> extends FeatureIteratorImpl<E>
{
public ResolvingFeatureIteratorImpl(EObject eObject, List<? extends EStructuralFeature> eStructuralFeatures)
{
super(eObject, eStructuralFeatures);
}
public ResolvingFeatureIteratorImpl(EObject eObject, EStructuralFeature [] eStructuralFeatures)
{
super(eObject, eStructuralFeatures);
}
@Override
protected boolean resolve()
{
return true;
}
}
}