-
-
Notifications
You must be signed in to change notification settings - Fork 357
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(CtBFSIterator): add an iterator that explores a CtElement's chil…
…dren in breadth first order (#2904)
- Loading branch information
Showing
2 changed files
with
143 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/** | ||
* Copyright (C) 2006-2018 INRIA and contributors | ||
* Spoon - http://spoon.gforge.inria.fr/ | ||
* | ||
* This software is governed by the CeCILL-C License under French law and | ||
* abiding by the rules of distribution of free software. You can use, modify | ||
* and/or redistribute the software under the terms of the CeCILL-C license as | ||
* circulated by CEA, CNRS and INRIA at http://www.cecill.info. | ||
* | ||
* This program is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details. | ||
* | ||
* The fact that you are presently reading this means that you have had | ||
* knowledge of the CeCILL-C license and that you accept its terms. | ||
*/ | ||
package spoon.reflect.visitor; | ||
|
||
import spoon.reflect.declaration.CtElement; | ||
|
||
import java.util.ArrayDeque; | ||
import java.util.Iterator; | ||
/** | ||
* A class to be able to iterate over the children elements in the tree of a given node, in breadth-first order. | ||
*/ | ||
public class CtBFSIterator extends CtScanner implements Iterator<CtElement> { | ||
|
||
|
||
/** | ||
* A deque containing the elements the iterator has seen but not expanded | ||
*/ | ||
private ArrayDeque<CtElement> deque = new ArrayDeque<>(); | ||
|
||
/** | ||
* CtIterator constructor, prepares the iterator from the @root node | ||
* | ||
* @param root the initial node to expand | ||
*/ | ||
public CtBFSIterator(CtElement root) { | ||
if (root != null) { | ||
deque.add(root); | ||
} | ||
} | ||
|
||
/** | ||
* prevent scanner from going down the tree, instead save with other CtElement children of the current node | ||
* | ||
* @param element the next direct child of the current node being expanded | ||
*/ | ||
@Override | ||
public void scan(CtElement element) { | ||
if (element != null) { | ||
deque.add(element); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean hasNext() { | ||
return !deque.isEmpty(); | ||
} | ||
|
||
/** | ||
* Dereference the "iterator" | ||
* | ||
* @return CtElement the next element in BFS order without going down the tree | ||
*/ | ||
@Override | ||
public CtElement next() { | ||
CtElement next = deque.poll(); // get the element to expand from the deque | ||
next.accept(this); // call @scan for each direct child of the node | ||
return next; | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
src/test/java/spoon/reflect/visitor/CtBFSIteratorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package spoon.reflect.visitor; | ||
|
||
import org.junit.Test; | ||
import spoon.Launcher; | ||
import spoon.reflect.declaration.CtElement; | ||
|
||
import java.util.ArrayDeque; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Queue; | ||
|
||
import static org.junit.Assert.*; | ||
|
||
public class CtBFSIteratorTest { | ||
|
||
@Test | ||
public void testCtElementIteration() { | ||
// contract: CtIterator must go over all nodes in bfs order | ||
final Launcher launcher = new Launcher(); | ||
launcher.setArgs(new String[]{"--output-type", "nooutput"}); | ||
launcher.getEnvironment().setNoClasspath(true); | ||
// resources to iterate | ||
launcher.addInputResource("./src/main/java/spoon/reflect/visitor/CtScanner.java"); | ||
launcher.buildModel(); | ||
|
||
// get the first Type | ||
CtElement root = launcher.getFactory().getModel().getAllTypes().iterator().next(); | ||
|
||
testCtIterator(root); | ||
} | ||
|
||
public void testCtIterator(CtElement root) { | ||
CtBFSIteratorTest.BFS it = new CtBFSIteratorTest.BFS(root); | ||
|
||
CtBFSIterator iterator = new CtBFSIterator(root); | ||
while (iterator.hasNext()) { | ||
assertTrue(it.hasNext()); | ||
assertEquals(it.next(), iterator.next()); | ||
} | ||
} | ||
|
||
/** | ||
* Class that implement an alternative BFS iterator, | ||
* for the {@link CtBFSIterator} test | ||
*/ | ||
class BFS implements Iterator<CtElement> { | ||
Queue<CtElement> queue = new ArrayDeque<>(); | ||
|
||
public BFS(CtElement root) { | ||
queue.add(root); | ||
} | ||
|
||
@Override | ||
public boolean hasNext() { | ||
return !queue.isEmpty(); | ||
} | ||
|
||
@Override | ||
public CtElement next() { | ||
CtElement cur = queue.poll(); | ||
|
||
//Get all direct children of cur | ||
List<CtElement> toAdd = cur.getElements(el -> (el.getParent() == cur)); | ||
|
||
//Queue them | ||
queue.addAll(toAdd); | ||
return cur; | ||
} | ||
} | ||
} |