You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2018/04/17 07:25:57 UTC

[isis] 01/11: ISIS-898 applib: introduces initial tree model

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch dev/2.0.0/ISIS-898-treeview
in repository https://gitbox.apache.org/repos/asf/isis.git

commit d337130decc55615a92e7272b5c0100fe6d36bac
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Apr 14 09:13:34 2018 +0200

    ISIS-898 applib: introduces initial tree model
---
 .../org/apache/isis/applib/tree/TreeAdapter.java   | 14 ++++
 .../java/org/apache/isis/applib/tree/TreeNode.java | 80 ++++++++++++++++++++++
 .../org/apache/isis/applib/tree/TreeNode_Lazy.java | 57 +++++++++++++++
 .../applib/tree/TreeNode_iteratorBreadthFirst.java | 42 ++++++++++++
 .../applib/tree/TreeNode_iteratorDepthFirst.java   | 53 ++++++++++++++
 .../applib/tree/TreeNode_iteratorHierarchyUp.java  | 35 ++++++++++
 6 files changed, 281 insertions(+)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreeAdapter.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeAdapter.java
new file mode 100644
index 0000000..5c39b59
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeAdapter.java
@@ -0,0 +1,14 @@
+package org.apache.isis.applib.tree;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public interface TreeAdapter<T> {
+
+	public Optional<T> parentOf(T value);
+	
+	public int childCountOf(T value);
+	
+	public Stream<T> childrenOf(T value);
+	
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode.java
new file mode 100644
index 0000000..f8f6fc4
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode.java
@@ -0,0 +1,80 @@
+package org.apache.isis.applib.tree;
+
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+public interface TreeNode<T> {
+	
+	// -- VALUE
+	
+	public T getValue();
+	
+	// -- PARENT
+	
+	public Optional<TreeNode<T>> getParent();
+	
+	// -- CHILDREN
+	
+	public int getChildCount();
+
+	public Stream<TreeNode<T>> streamChildren();
+	
+	// -- BASIC PREDICATES
+	
+	public default boolean isRoot() {
+		return !getParent().isPresent();
+	}
+	
+	public default boolean isLeaf() {
+		return getChildCount() == 0;
+	}
+
+	// -- CONSTRUCTION
+	
+	public static <T> TreeNode<T> of(T node, TreeAdapter<T> treeAdapter) {
+		return TreeNode_Lazy.of(node, treeAdapter);
+	}
+	
+	// -- PARENT NODE ITERATION
+	
+	public default Iterator<TreeNode<T>> iteratorHierarchyUp(){
+		return new TreeNode_iteratorHierarchyUp<>(this);
+	}
+	
+	// -- PARENT NODE STREAMING
+	
+	public default Stream<TreeNode<T>> streamHierarchyUp(){
+		return StreamSupport.stream(
+				Spliterators.spliteratorUnknownSize(iteratorHierarchyUp(), Spliterator.ORDERED), 
+				false); // not parallel
+	}
+	
+	// -- CHILD NODE ITERATION
+	
+	public default Iterator<TreeNode<T>> iteratorDepthFirst(){
+		return new TreeNode_iteratorDepthFirst<>(this);
+	}
+	
+	public default Iterator<TreeNode<T>> iteratorBreadthFirst(){
+		return new TreeNode_iteratorBreadthFirst<>(this);
+	}
+	
+	// -- CHILD NODE STREAMING
+	
+	public default Stream<TreeNode<T>> streamDepthFirst(){
+		return StreamSupport.stream(
+				Spliterators.spliteratorUnknownSize(iteratorDepthFirst(), Spliterator.ORDERED), 
+				false); // not parallel
+	}
+	
+	public default Stream<TreeNode<T>> streamBreadthFirst(){
+		return StreamSupport.stream(
+				Spliterators.spliteratorUnknownSize(iteratorBreadthFirst(), Spliterator.ORDERED), 
+				false); // not parallel
+	}
+	
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_Lazy.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_Lazy.java
new file mode 100644
index 0000000..83cd503
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_Lazy.java
@@ -0,0 +1,57 @@
+package org.apache.isis.applib.tree;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+class TreeNode_Lazy<T> implements TreeNode<T> {
+	
+	private final T value;
+	private final TreeAdapter<T> treeAdapter;
+	
+	static <T> TreeNode_Lazy<T> of(T value, TreeAdapter<T> treeAdapter) {
+		Objects.requireNonNull(value);
+		Objects.requireNonNull(treeAdapter);
+		return new TreeNode_Lazy<T>(value, treeAdapter);
+	}
+
+	private TreeNode_Lazy(T value, TreeAdapter<T> treeAdapter) {
+		this.value = value;
+		this.treeAdapter = treeAdapter;
+	}
+
+	@Override
+	public T getValue() {
+		return value;
+	}
+
+	@Override
+	public Optional<TreeNode<T>> getParent() {
+		return treeAdapter.parentOf(getValue())
+				.map(this::toTreeNode)
+				;
+	}
+
+	@Override
+	public int getChildCount() {
+		return treeAdapter.childCountOf(value);
+	}
+
+	@Override
+	public Stream<TreeNode<T>> streamChildren() {
+		if(isLeaf()) {
+			return Stream.empty();
+		}
+		return treeAdapter.childrenOf(value)
+				.map(this::toTreeNode)
+				;
+	}
+
+	// -- HELPER
+	
+	private TreeNode<T> toTreeNode(T value){
+		return of(value, treeAdapter);
+	}
+
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorBreadthFirst.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorBreadthFirst.java
new file mode 100644
index 0000000..4f620c2
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorBreadthFirst.java
@@ -0,0 +1,42 @@
+package org.apache.isis.applib.tree;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+class TreeNode_iteratorBreadthFirst<T> implements Iterator<TreeNode<T>> {
+
+	private Deque<TreeNode<T>> deque = new ArrayDeque<>();
+	private TreeNode<T> next;
+
+	TreeNode_iteratorBreadthFirst(TreeNode<T> treeNode) {
+		next = treeNode;
+	}
+
+	@Override
+	public boolean hasNext() {
+		return next!=null;
+	}
+
+	@Override
+	public TreeNode<T> next() {
+		if(next==null) {
+			throw new NoSuchElementException("Iterator has run out of elements.");
+		}
+		final TreeNode<T> result = next; 
+		next = fetchNext(next);		
+		return result;
+	}
+	
+	// -- HELPER
+
+	private TreeNode<T> fetchNext(TreeNode<T> current) {
+		if(!current.isLeaf()) {
+			current.streamChildren()
+			.forEach(deque::offerLast);
+		}
+		return deque.pollFirst();
+	}
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorDepthFirst.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorDepthFirst.java
new file mode 100644
index 0000000..a9f63d3
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorDepthFirst.java
@@ -0,0 +1,53 @@
+package org.apache.isis.applib.tree;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Stack;
+
+class TreeNode_iteratorDepthFirst<T> implements Iterator<TreeNode<T>> {
+
+	private Stack<TreeNode<T>> stack = new Stack<>();
+	private TreeNode<T> next;
+
+	TreeNode_iteratorDepthFirst(TreeNode<T> treeNode) {
+		next = treeNode;
+	}
+
+	@Override
+	public boolean hasNext() {
+		return next!=null;
+	}
+
+	@Override
+	public TreeNode<T> next() {
+		if(next==null) {
+			throw new NoSuchElementException("Iterator has run out of elements.");
+		}
+		final TreeNode<T> result = next; 
+		next = fetchNext(next);		
+		return result;
+	}
+	
+	// -- HELPER
+
+	private TreeNode<T> fetchNext(TreeNode<T> current) {
+		if(!current.isLeaf()) {
+			pushChildrenToStackInReverseOrder(current);
+		}
+		return stack.isEmpty() ? null : stack.pop();
+	}
+
+	private Stack<TreeNode<T>> fifo = new Stack<>(); // declared as field only to reduce heap pollution
+	
+	private void pushChildrenToStackInReverseOrder(TreeNode<T> node) {
+		
+		node.streamChildren()
+		.forEach(fifo::push);
+		
+		while(!fifo.isEmpty()) {
+			stack.push(fifo.pop());
+		}
+	}
+	
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorHierarchyUp.java b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorHierarchyUp.java
new file mode 100644
index 0000000..62813b2
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/tree/TreeNode_iteratorHierarchyUp.java
@@ -0,0 +1,35 @@
+package org.apache.isis.applib.tree;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+class TreeNode_iteratorHierarchyUp<T> implements Iterator<TreeNode<T>> {
+
+	private TreeNode<T> next;
+
+	TreeNode_iteratorHierarchyUp(TreeNode<T> treeNode) {
+		next = treeNode;
+	}
+
+	@Override
+	public boolean hasNext() {
+		return next!=null;
+	}
+
+	@Override
+	public TreeNode<T> next() {
+		if(next==null) {
+			throw new NoSuchElementException("Iterator has run out of elements.");
+		}
+		final TreeNode<T> result = next; 
+		next = fetchNext(next);		
+		return result;
+	}
+	
+	// -- HELPER
+
+	private TreeNode<T> fetchNext(TreeNode<T> current) {
+		return current.getParent().orElse(null);
+	}
+
+}

-- 
To stop receiving notification emails like this one, please contact
ahuber@apache.org.