|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.github.javaparser.ast; |
|
|
|
import com.github.javaparser.HasParentNode; |
|
import com.github.javaparser.ast.observer.AstObserver; |
|
import com.github.javaparser.ast.observer.Observable; |
|
import com.github.javaparser.ast.visitor.GenericVisitor; |
|
import com.github.javaparser.ast.visitor.Visitable; |
|
import com.github.javaparser.ast.visitor.VoidVisitor; |
|
import com.github.javaparser.metamodel.InternalProperty; |
|
|
|
import java.util.*; |
|
import java.util.function.Consumer; |
|
import java.util.function.Predicate; |
|
import java.util.function.UnaryOperator; |
|
import java.util.stream.Collector; |
|
import java.util.stream.Collectors; |
|
import java.util.stream.Stream; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class NodeList<N extends Node> implements List<N>, Iterable<N>, HasParentNode<NodeList<N>>, Visitable, Observable { |
|
@InternalProperty |
|
private final List<N> innerList = new ArrayList<>(0); |
|
|
|
private Node parentNode; |
|
|
|
private final List<AstObserver> observers = new ArrayList<>(); |
|
|
|
public NodeList() { |
|
parentNode = null; |
|
} |
|
|
|
public NodeList(Collection<N> n) { |
|
this.addAll(n); |
|
} |
|
|
|
@SafeVarargs |
|
public NodeList(N... n) { |
|
this.addAll(Arrays.asList(n)); |
|
} |
|
|
|
@Override |
|
public boolean add(N node) { |
|
notifyElementAdded(innerList.size(), node); |
|
own(node); |
|
return innerList.add(node); |
|
} |
|
|
|
private void own(N node) { |
|
if (node == null) { |
|
return; |
|
} |
|
setAsParentNodeOf(node); |
|
} |
|
|
|
public boolean remove(Node node) { |
|
int index = innerList.indexOf(node); |
|
if (index != -1) { |
|
notifyElementRemoved(index, node); |
|
node.setParentNode(null); |
|
} |
|
return innerList.remove(node); |
|
} |
|
|
|
public N removeFirst() { |
|
return remove(0); |
|
} |
|
|
|
public N removeLast() { |
|
return remove(innerList.size() - 1); |
|
} |
|
|
|
@SafeVarargs |
|
public static <X extends Node> NodeList<X> nodeList(X... nodes) { |
|
final NodeList<X> nodeList = new NodeList<>(); |
|
Collections.addAll(nodeList, nodes); |
|
return nodeList; |
|
} |
|
|
|
public static <X extends Node> NodeList<X> nodeList(Collection<X> nodes) { |
|
final NodeList<X> nodeList = new NodeList<>(); |
|
nodeList.addAll(nodes); |
|
return nodeList; |
|
} |
|
|
|
public static <X extends Node> NodeList<X> nodeList(NodeList<X> nodes) { |
|
final NodeList<X> nodeList = new NodeList<>(); |
|
nodeList.addAll(nodes); |
|
return nodeList; |
|
} |
|
|
|
public boolean contains(N node) { |
|
return innerList.contains(node); |
|
} |
|
|
|
@Override |
|
public int size() { |
|
return innerList.size(); |
|
} |
|
|
|
@Override |
|
public N get(int i) { |
|
return innerList.get(i); |
|
} |
|
|
|
@Override |
|
public Iterator<N> iterator() { |
|
|
|
return new NodeListIterator(innerList); |
|
} |
|
|
|
@Override |
|
public N set(int index, N element) { |
|
if (index < 0 || index >= innerList.size()) { |
|
throw new IllegalArgumentException("Illegal index. The index should be between 0 and " + innerList.size() |
|
+ " excluded. It is instead " + index); |
|
} |
|
if (element == innerList.get(index)) { |
|
return element; |
|
} |
|
notifyElementReplaced(index, element); |
|
innerList.get(index).setParentNode(null); |
|
setAsParentNodeOf(element); |
|
return innerList.set(index, element); |
|
} |
|
|
|
@Override |
|
public N remove(int index) { |
|
notifyElementRemoved(index, innerList.get(index)); |
|
N remove = innerList.remove(index); |
|
if (remove != null) |
|
remove.setParentNode(null); |
|
return remove; |
|
} |
|
|
|
@Override |
|
public boolean isEmpty() { |
|
return innerList.isEmpty(); |
|
} |
|
|
|
@Override |
|
public void sort(Comparator<? super N> comparator) { |
|
innerList.sort(comparator); |
|
} |
|
|
|
public void addAll(NodeList<N> otherList) { |
|
for (N node : otherList) { |
|
add(node); |
|
} |
|
} |
|
|
|
@Override |
|
public void add(int index, N node) { |
|
notifyElementAdded(index, node); |
|
own(node); |
|
innerList.add(index, node); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public NodeList<N> addFirst(N node) { |
|
add(0, node); |
|
return this; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public NodeList<N> addLast(N node) { |
|
add(node); |
|
return this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public NodeList<N> addAfter(N node, N afterThisNode) { |
|
int i = indexOf(afterThisNode); |
|
if (i == -1) { |
|
throw new IllegalArgumentException("Can't find node to insert after."); |
|
} |
|
add(i + 1, node); |
|
return this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public NodeList<N> addBefore(N node, N beforeThisNode) { |
|
int i = indexOf(beforeThisNode); |
|
if (i == -1) { |
|
throw new IllegalArgumentException("Can't find node to insert before."); |
|
} |
|
add(i, node); |
|
return this; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Optional<N> getFirst() { |
|
if (isEmpty()) { |
|
return Optional.empty(); |
|
} |
|
return Optional.of(get(0)); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public Optional<N> getLast() { |
|
if (isEmpty()) { |
|
return Optional.empty(); |
|
} |
|
return Optional.of(get(size() - 1)); |
|
} |
|
|
|
@Override |
|
public Optional<Node> getParentNode() { |
|
return Optional.ofNullable(parentNode); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public NodeList<N> setParentNode(Node parentNode) { |
|
this.parentNode = parentNode; |
|
setAsParentNodeOf(innerList); |
|
return this; |
|
} |
|
|
|
@Override |
|
public Node getParentNodeForChildren() { |
|
return parentNode; |
|
} |
|
|
|
@Override |
|
public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) { |
|
return v.visit(this, arg); |
|
} |
|
|
|
@Override |
|
public <A> void accept(final VoidVisitor<A> v, final A arg) { |
|
v.visit(this, arg); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public void forEach(Consumer<? super N> action) { |
|
innerList.forEach(action); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean contains(Object o) { |
|
return innerList.contains(o); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public Object[] toArray() { |
|
return innerList.toArray(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public <T> T[] toArray(T[] a) { |
|
return innerList.toArray(a); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean remove(Object o) { |
|
if (o instanceof Node) { |
|
return remove((Node) o); |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean containsAll(Collection<?> c) { |
|
return innerList.containsAll(c); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean addAll(Collection<? extends N> c) { |
|
c.forEach(this::add); |
|
return !c.isEmpty(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean addAll(int index, Collection<? extends N> c) { |
|
for (N e : c) { |
|
add(index++, e); |
|
} |
|
return !c.isEmpty(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean removeAll(Collection<?> c) { |
|
boolean changed = false; |
|
for (Object e : c) { |
|
changed = remove(e) || changed; |
|
} |
|
return changed; |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean retainAll(Collection<?> c) { |
|
boolean changed = false; |
|
for (Object e : this.stream().filter(it -> !c.contains(it)).toArray()) { |
|
if (!c.contains(e)) { |
|
changed = remove(e) || changed; |
|
} |
|
} |
|
return changed; |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public void replaceAll(UnaryOperator<N> operator) { |
|
for (int i = 0; i < this.size(); i++) { |
|
set(i, operator.apply(this.get(i))); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean removeIf(Predicate<? super N> filter) { |
|
boolean changed = false; |
|
for (Object e : this.stream().filter(filter).toArray()) { |
|
changed = remove(e) || changed; |
|
} |
|
return changed; |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public void clear() { |
|
while (!isEmpty()) { |
|
remove(0); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean equals(Object o) { |
|
return innerList.equals(o); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public int hashCode() { |
|
return innerList.hashCode(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public int indexOf(Object o) { |
|
return innerList.indexOf(o); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public int lastIndexOf(Object o) { |
|
return innerList.lastIndexOf(o); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public ListIterator<N> listIterator() { |
|
|
|
return new NodeListIterator(innerList); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public ListIterator<N> listIterator(int index) { |
|
|
|
return new NodeListIterator(innerList, index); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public Stream<N> parallelStream() { |
|
return innerList.parallelStream(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public List<N> subList(int fromIndex, int toIndex) { |
|
return innerList.subList(fromIndex, toIndex); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public Spliterator<N> spliterator() { |
|
return innerList.spliterator(); |
|
} |
|
|
|
private void notifyElementAdded(int index, Node nodeAddedOrRemoved) { |
|
this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.ADDITION, index, nodeAddedOrRemoved)); |
|
} |
|
|
|
private void notifyElementRemoved(int index, Node nodeAddedOrRemoved) { |
|
this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.REMOVAL, index, nodeAddedOrRemoved)); |
|
} |
|
|
|
private void notifyElementReplaced(int index, Node nodeAddedOrRemoved) { |
|
this.observers.forEach(o -> o.listReplacement(this, index, this.get(index), nodeAddedOrRemoved)); |
|
} |
|
|
|
@Override |
|
public void unregister(AstObserver observer) { |
|
this.observers.remove(observer); |
|
} |
|
|
|
@Override |
|
public void register(AstObserver observer) { |
|
if (!this.observers.contains(observer)) { |
|
this.observers.add(observer); |
|
} |
|
} |
|
|
|
@Override |
|
public boolean isRegistered(AstObserver observer) { |
|
return this.observers.contains(observer); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean replace(N old, N replacement) { |
|
int i = indexOf(old); |
|
if (i == -1) { |
|
return false; |
|
} |
|
set(i, replacement); |
|
return true; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public boolean isNonEmpty() { |
|
return !isEmpty(); |
|
} |
|
|
|
public void ifNonEmpty(Consumer<? super NodeList<N>> consumer) { |
|
if (isNonEmpty()) |
|
consumer.accept(this); |
|
} |
|
|
|
public static <T extends Node> Collector<T, NodeList<T>, NodeList<T>> toNodeList() { |
|
return Collector.of(NodeList::new, NodeList::add, (left, right) -> { |
|
left.addAll(right); |
|
return left; |
|
}); |
|
} |
|
|
|
private void setAsParentNodeOf(List<? extends Node> childNodes) { |
|
if (childNodes != null) { |
|
for (HasParentNode current : childNodes) { |
|
current.setParentNode(getParentNodeForChildren()); |
|
} |
|
} |
|
} |
|
|
|
private void setAsParentNodeOf(Node childNode) { |
|
if (childNode != null) { |
|
childNode.setParentNode(getParentNodeForChildren()); |
|
} |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
return innerList.stream().map(Node::toString).collect(Collectors.joining(", ", "[", "]")); |
|
} |
|
|
|
protected class NodeListIterator implements ListIterator<N>{ |
|
|
|
ListIterator<N> iterator; |
|
N current = null; |
|
|
|
|
|
public NodeListIterator(List<N> list) { |
|
iterator = list.listIterator(); |
|
} |
|
|
|
public NodeListIterator(List<N> list, int index) { |
|
iterator = list.listIterator(index); |
|
} |
|
|
|
@Override |
|
public boolean hasNext() { |
|
return iterator.hasNext(); |
|
} |
|
|
|
@Override |
|
public N next() { |
|
current = iterator.next(); |
|
return current; |
|
} |
|
|
|
@Override |
|
public boolean hasPrevious() { |
|
return iterator.hasPrevious(); |
|
} |
|
|
|
@Override |
|
public N previous() { |
|
current = iterator.previous(); |
|
return current; |
|
} |
|
|
|
@Override |
|
public int nextIndex() { |
|
return iterator.nextIndex(); |
|
} |
|
|
|
@Override |
|
public int previousIndex() { |
|
return iterator.previousIndex(); |
|
} |
|
|
|
@Override |
|
public void remove() { |
|
int index = innerList.indexOf(current); |
|
if (index != -1) { |
|
notifyElementRemoved(index, current); |
|
current.setParentNode(null); |
|
} |
|
iterator.remove(); |
|
} |
|
|
|
@Override |
|
public void set(N n) { |
|
int index = innerList.indexOf(current); |
|
if (index < 0 || index >= innerList.size()) { |
|
throw new IllegalArgumentException("Illegal index. The index should be between 0 and " + innerList.size() |
|
+ " excluded. It is instead " + index); |
|
} |
|
if (n != innerList.get(index)) { |
|
notifyElementReplaced(index, n); |
|
innerList.get(index).setParentNode(null); |
|
setAsParentNodeOf(n); |
|
|
|
iterator.set(n); |
|
} |
|
} |
|
|
|
@Override |
|
public void add(N n) { |
|
notifyElementAdded(innerList.size(), n); |
|
own(n); |
|
iterator.add(n); |
|
} |
|
|
|
@Override |
|
public void forEachRemaining(Consumer<? super N> action) { |
|
iterator.forEachRemaining(action); |
|
} |
|
} |
|
} |