TreeNode.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-5.2.0).
003  * Copyright (c) 2007-2020 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.ext.util;
021 
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024 
025 import java.io.IOException;
026 import java.io.InvalidObjectException;
027 import java.io.ObjectInput;
028 import java.io.ObjectInputStream;
029 import java.io.ObjectOutput;
030 import java.io.Serializable;
031 import java.util.ArrayList;
032 import java.util.List;
033 import java.util.Optional;
034 import java.util.function.Function;
035 
036 import io.jenetics.util.Copyable;
037 import io.jenetics.util.ISeq;
038 
039 /**
040  * A general purpose node in a tree data-structure. The {@code TreeNode} is a
041  * mutable implementation of the {@link Tree} interface.
042  *
043  @param <T> the value type of the tree node
044  *
045  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
046  @version 5.2
047  @since 3.9
048  */
049 public final class TreeNode<T>
050     implements
051         Tree<T, TreeNode<T>>,
052         Iterable<TreeNode<T>>,
053         Copyable<TreeNode<T>>,
054         Serializable
055 {
056     private static final long serialVersionUID = 2L;
057 
058     private T _value;
059     private TreeNode<T> _parent;
060     private List<TreeNode<T>> _children;
061 
062     /**
063      * Create a new tree node with no parent and children, but with the given
064      * user {@code value}.
065      *
066      @param value the user value of the new tree node
067      */
068     private TreeNode(final T value) {
069         _value = value;
070     }
071 
072 
073     /* *************************************************************************
074      * Basic operations
075      **************************************************************************/
076 
077     /**
078      * Sets the user object for this node.
079      *
080      @param value the node {@code value}
081      */
082     public void value(final T value) {
083         _value = value;
084     }
085 
086     /**
087      * Sets the user object for this node.
088      *
089      @param value the node {@code value}
090      @deprecated Use {@link #value(Object)} instead
091      */
092     @Deprecated
093     public void setValue(final T value) {
094         _value = value;
095     }
096 
097     /**
098      * Return the node value
099      *
100      @return the node value
101      */
102     @Override
103     @Deprecated
104     public T getValue() {
105         return _value;
106     }
107 
108     /**
109      * Returns this node's parent if available.
110      *
111      @return the tree-node, or an empty value if this node has no parent
112      */
113     @Deprecated
114     @Override
115     public Optional<TreeNode<T>> getParent() {
116         return Optional.ofNullable(_parent);
117     }
118 
119     /**
120      * Sets this node's parent, but does not change the parent's child array.
121      * This method is called from {@code insert()} and {@code remove()} to
122      * reassign a child's parent, and it should not be messaged from anywhere
123      * else.
124      *
125      @param parent this node's new parent
126      */
127     void setParent(final TreeNode<T> parent) {
128         _parent = parent;
129     }
130 
131     /**
132      * Returns the child at the specified index in this node's child array.
133      *
134      @param index   an index into this node's child array
135      @return the tree-node in this node's child array at the specified index
136      @throws ArrayIndexOutOfBoundsException  if the {@code index} is out of
137      *         bounds
138      */
139     @Override
140     public TreeNode<T> childAt(final int index) {
141         if (_children == null) {
142             throw new ArrayIndexOutOfBoundsException(format(
143                 "Child index is out of bounds: %s", index
144             ));
145         }
146 
147         return _children.get(index);
148     }
149 
150     @Override
151     public int childCount() {
152         return _children != null ? _children.size() 0;
153     }
154 
155     /**
156      * Removes the {@code child} from its present parent (if it has one), sets
157      * the child's parent to this node, and then adds the child to this node's
158      * child array at index {@code index}. The new {@code child} must not be
159      * {@code null} and must not be an ancestor of {@code this} node.
160      *
161      @param index the index in the child array where this node is to be
162      *        inserted
163      @param child the sub-node to be inserted
164      @return {@code this} tree-node, for method chaining
165      @throws ArrayIndexOutOfBoundsException if {@code index} is out of bounds
166      @throws IllegalArgumentException if {@code child} is an ancestor of
167      *         {@code this} node
168      @throws NullPointerException if the given {@code child} is {@code null}
169      */
170     public TreeNode<T> insert(final int index, final TreeNode<T> child) {
171         requireNonNull(child);
172         if (isAncestor(child)) {
173             throw new IllegalArgumentException("The new child is an ancestor.");
174         }
175 
176         if (child._parent != null) {
177             child._parent.remove(child);
178         }
179 
180         child.setParent(this);
181         createChildrenIfMissing();
182         _children.add(index, child);
183 
184         return this;
185     }
186 
187     // Only entry point for checking and creating non-existing children list.
188     private void createChildrenIfMissing() {
189         if (_children == null) {
190             _children = new ArrayList<>(2);
191         }
192     }
193 
194     /**
195      * Replaces the child at the give index with the given {@code child}
196      *
197      @param index the index of the child which will be replaced
198      @param child the new child
199      @return {@code this} tree-node, for method chaining
200      @throws ArrayIndexOutOfBoundsException  if the {@code index} is out of
201      *         bounds
202      @throws IllegalArgumentException if {@code child} is an ancestor of
203      *         {@code this} node
204      @throws NullPointerException if the given {@code child} is {@code null}
205      */
206     public TreeNode<T> replace(final int index, final TreeNode<T> child) {
207         requireNonNull(child);
208         if (_children == null) {
209             throw new ArrayIndexOutOfBoundsException(format(
210                 "Child index is out of bounds: %s", index
211             ));
212         }
213         if (isAncestor(child)) {
214             throw new IllegalArgumentException("The new child is an ancestor.");
215         }
216 
217         final TreeNode<T> oldChild = _children.set(index, child);
218         assert oldChild != null;
219         assert oldChild._parent == this;
220 
221         oldChild.setParent(null);
222         child.setParent(this);
223 
224         return this;
225     }
226 
227     /**
228      * Removes the child at the specified index from this node's children and
229      * sets that node's parent to {@code null}.
230      *
231      @param index the index in this node's child array of the child to remove
232      @return {@code this} tree-node, for method chaining
233      @throws ArrayIndexOutOfBoundsException  if the {@code index} is out of
234      *         bounds
235      */
236     public TreeNode<T> remove(final int index) {
237         if (_children == null) {
238             throw new ArrayIndexOutOfBoundsException(format(
239                 "Child index is out of bounds: %s", index
240             ));
241         }
242 
243         final TreeNode<T> child = _children.remove(index);
244         assert child._parent == this;
245         child.setParent(null);
246 
247         if (_children.isEmpty()) {
248             _children = null;
249         }
250 
251         return this;
252     }
253 
254     /**
255      * Removes the child at the given {@code path}. If no child exists at the
256      * given path, nothing is removed.
257      *
258      @since 4.4
259      *
260      @param path the path of the child to replace
261      @return {@code true} if a child at the given {@code path} existed and
262      *         has been removed
263      @throws NullPointerException if one of the given argument is {@code null}
264      */
265     public boolean removeAtPath(final Path path) {
266         final Optional<TreeNode<T>> parent = childAtPath(path)
267             .flatMap(Tree::parent);
268 
269         parent.ifPresent(p -> p.remove(path.get(path.length() 1)));
270         return parent.isPresent();
271     }
272 
273     /**
274      * Replaces the child at the given {@code path} with the given new
275      * {@code child}. If no child exists at the given path, nothing is replaced.
276      *
277      @since 4.4
278      *
279      @param path the path of the child to replace
280      @param child the new child
281      @return {@code true} if a child at the given {@code path} existed and
282      *         has been replaced
283      @throws NullPointerException if one of the given argument is {@code null}
284      */
285     public boolean replaceAtPath(final Path path, final TreeNode<T> child) {
286         requireNonNull(path);
287         requireNonNull(child);
288 
289         final Optional<TreeNode<T>> old = childAtPath(path);
290         final Optional<TreeNode<T>> parent = old.flatMap(TreeNode::parent);
291 
292         if (parent.isPresent()) {
293             parent.orElseThrow(AssertionError::new)
294                 .replace(path.get(path.length() 1), child);
295         else {
296             removeAllChildren();
297             value(child.value());
298 
299             final ISeq<TreeNode<T>> nodes = child.childStream()
300                 .collect(ISeq.toISeq());
301 
302             for (TreeNode<T> node : nodes) {
303                 attach(node);
304             }
305         }
306 
307         return old.isPresent();
308     }
309 
310     /* *************************************************************************
311      * Derived operations
312      **************************************************************************/
313 
314     /**
315      * Detaches the subtree rooted at {@code this} node from the tree, giving
316      * {@code this} node a {@code null} parent. Does nothing if {@code this}
317      * node is the root of its tree.
318      *
319      @return {@code this}
320      */
321     public TreeNode<T> detach() {
322         if (_parent != null) {
323             _parent.remove(this);
324         }
325 
326         return this;
327     }
328 
329     /**
330      * Remove the {@code child} from {@code this} node's child array, giving it
331      * a {@code null} parent.
332      *
333      @param child the child of this node to remove
334      @throws NullPointerException if the given {@code child} is {@code null}
335      @throws IllegalArgumentException if the given {@code child} is not a
336      *         child of this node
337      */
338     public void remove(final Tree<?, ?> child) {
339         requireNonNull(child);
340 
341         if (!isChild(child)) {
342             throw new IllegalArgumentException("The given child is not a child.");
343         }
344         remove(indexOf(child));
345     }
346 
347     /**
348      * Removes all children fo {@code this} node and setting their parents to
349      * {@code null}. If {@code this} node has no children, this method does
350      * nothing.
351      */
352     public void removeAllChildren() {
353         if (_children != null) {
354             for (TreeNode<T> child : _children) {
355                 child.setParent(null);
356             }
357 
358             _children = null;
359         }
360     }
361 
362     /**
363      * Remove the given {@code child} from its parent and makes it a child of
364      * this node by adding it to the end of this node's child array.
365      *
366      @param child the new child added to this node
367      @return {@code this} tree-node, for method chaining
368      @throws NullPointerException if the given {@code child} is {@code null}
369      */
370     public TreeNode<T> attach(final TreeNode<T> child) {
371         requireNonNull(child);
372 
373         if (child._parent == this) {
374             insert(childCount() 1, child);
375         else {
376             insert(childCount(), child);
377         }
378 
379         return this;
380     }
381 
382     /**
383      * Attaches the given {@code children} to {@code this} node.
384      *
385      @param children the children to attach to {@code this} node
386      @return {@code this} tree-node, for method chaining
387      @throws NullPointerException if the given {@code children} array is
388      *         {@code null}
389      */
390     @SafeVarargs
391     public final TreeNode<T> attach(final T... children) {
392         for (T child : children) {
393             attach(TreeNode.of(child));
394         }
395 
396         return this;
397     }
398 
399     /**
400      * Attaches the given {@code child} to {@code this} node.
401      *
402      @param child the child to attach to {@code this} node
403      @return {@code this} tree-node, for method chaining
404      */
405     public TreeNode<T> attach(final T child) {
406         return attach(TreeNode.of(child));
407     }
408 
409     @Override
410     public TreeNode<T> copy() {
411         return ofTree(this);
412     }
413 
414     /**
415      * Returns a new {@code TreeNode} consisting of all nodes of {@code this}
416      * tree, but with a different value type, created by applying the given
417      * function to the node values of {@code this} tree.
418      *
419      @param mapper the node value mapper
420      @param <B> the new node type
421      @return a new tree consisting of all nodes of {@code this} tree
422      @throws NullPointerException if the given {@code mapper} function is
423      *         {@code null}
424      */
425     public <B> TreeNode<B> map(final Function<? super T, ? extends B> mapper) {
426         final TreeNode<B> target = TreeNode.of(mapper.apply(value()));
427         fill(this, target, mapper);
428         return target;
429     }
430 
431 
432     @Override
433     public int hashCode() {
434         return Tree.hashCode(this);
435     }
436 
437     @Override
438     public boolean equals(final Object obj) {
439         return obj == this ||
440             obj instanceof TreeNode &&
441             Tree.equals(this, (TreeNode)obj);
442     }
443 
444     @Override
445     public String toString() {
446         return toParenthesesString();
447     }
448 
449 
450 
451     /* *************************************************************************
452      * Static factory methods.
453      **************************************************************************/
454 
455     /**
456      * Return a new {@code TreeNode} with a {@code null} tree value.
457      *
458      @param <T> the tree-node type
459      @return a new tree-node
460      */
461     public static <T> TreeNode<T> of() {
462         return TreeNode.of(null);
463     }
464 
465     /**
466      * Return a new {@code TreeNode} with the given node {@code value}.
467      *
468      @param value the node value
469      @param <T> the tree-node type
470      @return a new tree-node
471      */
472     public static <T> TreeNode<T> of(final T value) {
473         return new TreeNode<>(value);
474     }
475 
476     /**
477      * Return a new {@code TreeNode} from the given source {@code tree}. The
478      * whole tree is copied.
479      *
480      @param tree the source tree the new tree-node is created from
481      @param mapper the tree value mapper function
482      @param <T> the current tree value type
483      @param <B> the mapped tree value type
484      @return a new {@code TreeNode} from the given source {@code tree}
485      @throws NullPointerException if one of the arguments is {@code null}
486      */
487     public static <T, B> TreeNode<B> ofTree(
488         final Tree<? extends T, ?> tree,
489         final Function<? super T, ? extends B> mapper
490     ) {
491         final TreeNode<B> target = of(mapper.apply(tree.value()));
492         fill(tree, target, mapper);
493         return target;
494     }
495 
496     private static <T, B> void fill(
497         final Tree<? extends T, ?> source,
498         final TreeNode<B> target,
499         final Function<? super T, ? extends B> mapper
500     ) {
501         source.childStream().forEachOrdered(child -> {
502             final TreeNode<B> targetChild = of(mapper.apply(child.value()));
503             target.attach(targetChild);
504             fill(child, targetChild, mapper);
505         });
506     }
507 
508     /**
509      * Return a new {@code TreeNode} from the given source {@code tree}. The
510      * whole tree is copied.
511      *
512      @param tree the source tree the new tree-node is created from
513      @param <T> the current tree value type
514      @return a new {@code TreeNode} from the given source {@code tree}
515      @throws NullPointerException if the source {@code tree} is {@code null}
516      */
517     public static <T> TreeNode<T> ofTree(final Tree<? extends T, ?> tree) {
518         return ofTree(tree, Function.identity());
519     }
520 
521     /**
522      * Parses a (parentheses) tree string, created with
523      {@link Tree#toParenthesesString()}. The tree string might look like this:
524      <pre>
525      *  mul(div(cos(1.0),cos(π)),sin(mul(1.0,z)))
526      </pre>
527      *
528      * The parse method doesn't strip the whitespace between the parentheses and
529      * the commas. If you want to remove this <em>formatting</em> whitespaces,
530      * you should do the parsing with an addition <em>mapper</em> function.
531      <pre>{@code
532      * final TreeNode<String> tree = TreeNode.parse(
533      *     "mul(  div(cos( 1.0) , cos(π )), sin(mul(1.0, z) ) )",
534      *     String::trim
535      * );
536      * }</pre>
537      * The code above will trim all tree nodes during the parsing process.
538      *
539      @see Tree#toParenthesesString(Function)
540      @see Tree#toParenthesesString()
541      @see TreeNode#parse(String, Function)
542      *
543      @since 4.3
544      *
545      @param tree the parentheses tree string
546      @return the parsed tree
547      @throws NullPointerException if the given {@code tree} string is
548      *         {@code null}
549      @throws IllegalArgumentException if the given tree string could not be
550      *         parsed
551      */
552     public static TreeNode<String> parse(final String tree) {
553         return TreeParser.parse(tree, Function.identity());
554     }
555 
556     /**
557      * Parses a (parentheses) tree string, created with
558      {@link Tree#toParenthesesString()}. The tree string might look like this
559      <pre>
560      *  0(1(4,5),2(6),3(7(10,11),8,9))
561      </pre>
562      * and can be parsed to an integer tree with the following code:
563      <pre>{@code
564      * final Tree<Integer, ?> tree = TreeNode.parse(
565      *     "0(1(4,5),2(6),3(7(10,11),8,9))",
566      *     Integer::parseInt
567      * );
568      * }</pre>
569      *
570      @see Tree#toParenthesesString(Function)
571      @see Tree#toParenthesesString()
572      @see TreeNode#parse(String)
573      *
574      @since 4.3
575      *
576      @param <B> the tree node value type
577      @param tree the parentheses tree string
578      @param mapper the mapper which converts the serialized string value to
579      *        the desired type
580      @return the parsed tree object
581      @throws NullPointerException if one of the arguments is {@code null}
582      @throws IllegalArgumentException if the given parentheses tree string
583      *         doesn't represent a valid tree
584      */
585     public static <B> TreeNode<B> parse(
586         final String tree,
587         final Function<? super String, ? extends B> mapper
588     ) {
589         return TreeParser.parse(tree, mapper);
590     }
591 
592 
593     /* *************************************************************************
594      *  Java object serialization
595      * ************************************************************************/
596 
597     private Object writeReplace() {
598         return new Serial(Serial.TREE_NODE, this);
599     }
600 
601     private void readObject(final ObjectInputStream stream)
602         throws InvalidObjectException
603     {
604         throw new InvalidObjectException("Serialization proxy required.");
605     }
606 
607 
608     void write(final ObjectOutput outthrows IOException {
609         FlatTreeNode.of(this).write(out);
610     }
611 
612     @SuppressWarnings({"rawtypes""unchecked"})
613     static TreeNode read(final ObjectInput in)
614         throws IOException, ClassNotFoundException
615     {
616         return TreeNode.ofTree(FlatTreeNode.read(in));
617     }
618 
619 }