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; + } }
