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

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit a3ddd65ea0f8d69b3de1c02b2b99e830b259fad1
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Jan 16 23:03:13 2020 +0100

    Add a copy constructor to PointTree. This constructor share the data 
structures than can safely be shared, in order to reduce memory usage.
---
 .../java/org/apache/sis/index/tree/PointTree.java  | 21 ++++++++++-
 .../org/apache/sis/index/tree/PointTreeNode.java   | 43 +++++++++++++++++++++-
 .../org/apache/sis/index/tree/QuadTreeNode.java    | 16 ++++++++
 3 files changed, 78 insertions(+), 2 deletions(-)

diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTree.java 
b/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTree.java
index b1e0e29..74688e9 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTree.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTree.java
@@ -136,7 +136,8 @@ public class PointTree<E> extends AbstractSet<E> implements 
CheckedContainer<E>,
      * </ul>
      *
      * The length of this array is two times the number of dimensions of 
points in this tree.
-     * This array content should not be modified, until the entire tree is 
rebuilt.
+     * This array content should not be modified, unless the entire tree is 
rebuilt (keep in
+     * mind that this array may be shared by {@link PointTree} copies).
      */
     final double[] treeRegion;
 
@@ -153,6 +154,24 @@ public class PointTree<E> extends AbstractSet<E> 
implements CheckedContainer<E>,
     private final boolean parallel;
 
     /**
+     * Creates a new tree initialized to a copy of the given tree.
+     * This copy constructor shares some data structure from the {@code other} 
tree for reducing memory usage,
+     * but the two trees are nevertheless independent (changes in a tree does 
not affect the other tree).
+     *
+     * @param  other  the other tree to copy.
+     */
+    public PointTree(final PointTree<E> other) {
+        root         = (PointTreeNode) other.root.clone();
+        elementType  = other.elementType;
+        crs          = other.crs;
+        nodeCapacity = other.nodeCapacity;
+        count        = other.count;
+        treeRegion   = other.treeRegion;
+        locator      = other.locator;
+        parallel     = other.parallel;
+    }
+
+    /**
      * Creates an initially empty <var>k</var>-dimensional tree with the given 
capacity for each node.
      * The number of dimensions of the given envelope determines the number of 
dimensions of points in this tree.
      * The positions computed by {@code locator} must have the same number of 
dimensions than the given envelope.
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTreeNode.java 
b/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTreeNode.java
index a424550..87b544b 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTreeNode.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTreeNode.java
@@ -48,7 +48,7 @@ import java.io.Serializable;
  * @since   1.1
  * @module
  */
-abstract class PointTreeNode implements Serializable {
+abstract class PointTreeNode implements Cloneable, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -158,6 +158,22 @@ abstract class PointTreeNode implements Serializable {
     abstract PointTreeNode newInstance();
 
     /**
+     * Returns a clone of this node. This is invoked when creating a copy of 
{@link PointTree}.
+     * The clone is a semi-deep clone: all children that are instances of 
{@link PointTreeNode}
+     * shall be cloned recursively, but instances of {@code Object[]} (the 
leaf nodes) are not
+     * cloned. It is safe to not clone the {@code Object[]} arrays because 
{@link PointTree}
+     * uses a copy-on-write strategy when data need to be modified.
+     */
+    @Override
+    protected Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
      * Default implementation of {@link PointTreeNode} when no specialized 
class is available.
      * This default implementation stores children in an array. The usage of 
arrays allows
      * arbitrary lengths, but implies one more object to be created for each 
node instance.
@@ -187,6 +203,22 @@ abstract class PointTreeNode implements Serializable {
         }
 
         /**
+         * Creates a new node initialized to a copy of the given node.
+         *
+         * @see #clone()
+         */
+        private Default(final Default other) {
+            children = other.children.clone();
+            for (int i=0; i<children.length; i++) {
+                final Object value = children[i];
+                if (value instanceof PointTreeNode) {
+                    children[i] = ((PointTreeNode) value).clone();
+                }
+                // Do not clone arrays because we use them as copy-on-write 
data structures.
+            }
+        }
+
+        /**
          * Creates a new instance of the same class than this node.
          */
         @Override
@@ -223,5 +255,14 @@ abstract class PointTreeNode implements Serializable {
         final void setChild(final int quadrant, final Object child) {
             children[quadrant] = child;
         }
+
+        /**
+         * Returns a clone of this node. This is invoked when creating a copy 
of {@link PointTree}.
+         */
+        @Override
+        @SuppressWarnings("CloneDoesntCallSuperClone")
+        protected Object clone() {
+            return new Default(this);
+        }
     }
 }
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/index/tree/QuadTreeNode.java 
b/core/sis-feature/src/main/java/org/apache/sis/index/tree/QuadTreeNode.java
index 1b4e676..c33af7d 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/index/tree/QuadTreeNode.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/index/tree/QuadTreeNode.java
@@ -112,4 +112,20 @@ final class QuadTreeNode extends PointTreeNode {
             default: throw new IndexOutOfBoundsException(/*quadrant*/);     // 
TODO: uncomment with JDK9.
         }
     }
+
+    /**
+     * Returns a clone of this node. This is invoked when creating a copy of 
{@link PointTree}.
+     */
+    @Override
+    protected Object clone() {
+        final QuadTreeNode c = (QuadTreeNode) super.clone();
+        for (int i=0; i<4; i++) {
+            final Object value = c.getChild(i);
+            if (value instanceof PointTreeNode) {
+                c.setChild(i, ((PointTreeNode) value).clone());
+            }
+            // Do not clone arrays because we use them as copy-on-write data 
structures.
+        }
+        return c;
+    }
 }

Reply via email to