blob: 956e0653d60906daf3b80f82c41a31ab56b7476f [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2012 BMW Car IT and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* BMW Car IT - Initial API and implementation
*
* </copyright>
*/
package org.eclipse.sphinx.emf.ecore;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.common.util.DelegatingEList;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.BasicFeatureMap;
/**
* A feature map which maintains an order on its element's feature IDs (ascending).
*/
public class OrderedFeatureMap extends BasicFeatureMap {
private static final long serialVersionUID = 1L;
public static interface ListBehavior<T> {
void add(int index, T t);
T set(int index, T t);
void addAll(int index, Collection<? extends T> collection);
}
public static interface Order<T> {
int order(T t);
}
/**
* Class which encapsulates the behavior that ensures that elements to the list will be inserted into the list
* without violating the order of the list.
*
* @param <T>
*/
public static class OrderedListBehavior<T> implements ListBehavior<T> {
private final List<T> list;
private final Order<T> order;
public OrderedListBehavior(List<T> list, Order<T> order) {
this.list = list;
this.order = order;
}
@Override
public void add(int index, T t) {
// find index where t may be added without violating the order of the list
int ot = order.order(t);
int oi;
if (ot == -1) {
// special case where order does not matter
list.add(index, t);
return;
}
if (index == list.size()) {
oi = Integer.MAX_VALUE;
} else {
oi = order.order(list.get(index));
}
if (ot > oi) {
// t needs to be added further in the back of the list
while (true) {
index++;
if (index == list.size()) {
oi = Integer.MAX_VALUE;
} else {
oi = order.order(list.get(index));
}
if (oi >= ot) {
list.add(index, t);
break;
}
}
} else if (ot < oi) {
// t needs to be added further in front
while (true) {
index--;
if (index < 0) {
oi = Integer.MIN_VALUE;
} else {
oi = order.order(list.get(index));
}
if (oi <= ot) {
list.add(index + 1, t);
break;
}
}
} else {
list.add(index, t);
}
}
@Override
public T set(int index, T t) {
T previous = list.get(index);
if (order.order(previous) != order.order(t)) {
throw new IllegalStateException("Only elements with equal order may be overwritten by a set operation."); //$NON-NLS-1$
}
return list.set(index, t);
}
@Override
public void addAll(int index, Collection<? extends T> c) {
int i = 0;
for (T t : c) {
add(index + i, t);
i++;
}
}
}
ListBehavior<Entry> lb = new OrderedListBehavior<Entry>(new DelegatingEList<Entry>() {
private static final long serialVersionUID = 1L;
@Override
protected List<Entry> delegateList() {
return OrderedFeatureMap.this;
};
@Override
public void add(int index, Entry object) {
OrderedFeatureMap.super.doAdd(index, object);
};
@Override
public Entry set(int index, Entry object) {
return OrderedFeatureMap.super.doSet(index, object);
};
}, new Order<Entry>() {
@Override
public int order(Entry e) {
int order = owner.eClass().getFeatureID(e.getEStructuralFeature());
if (order != -1) {
return order;
} else {
// Return -1 for features that are not part of the EClass, e.g. the XML features (text, comment,
// proccessing instruction or CDATA) to esnure that such elements will not be re-ordered. Explicit else
// branch added for clarity.
return -1;
}
}
});
public OrderedFeatureMap(InternalEObject owner, int featureID) {
super(owner, featureID);
}
public OrderedFeatureMap(InternalEObject owner, int featureID, EStructuralFeature eStructuralFeature) {
super(owner, featureID, eStructuralFeature);
}
@Override
protected boolean doAdd(Entry object) {
doAdd(size(), object);
return true;
}
@Override
public Entry doSet(int index, Entry object) {
return lb.set(index, object);
}
@Override
public void doAdd(int index, Entry object) {
lb.add(index, object);
}
@Override
public boolean doAddAll(Collection<? extends Entry> collection) {
return doAddAll(size(), collection);
}
@Override
public boolean doAddAll(int index, Collection<? extends Entry> collection) {
lb.addAll(index, collection);
return collection.size() > 0;
}
}