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