This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new cf0e1f352b GH-2169: Enhanced GraphMem Cloning: - added new interface
Copyable<> - implemented Copyable#copy in GraphMem2 all three descendants
(Legacy, Fast and Roaring) - extended TripleStore to implement Copyable<> and
implemented it in all three descendants (Legacy, Fast and Roaring) - added copy
constructors to mem2/collections/*, mem2/store/*/*Bunch, mem2/store/*/*HashMap
and mem2/store/*/*Set - added unit tests to keep the test coverage for mem2/**
at 100% - added bench [...]
cf0e1f352b is described below
commit cf0e1f352b40708ccfcb4d9228bc8c0e51531acd
Author: arne-bdt <[email protected]>
AuthorDate: Wed Jan 31 22:56:55 2024 +0100
GH-2169: Enhanced GraphMem Cloning:
- added new interface Copyable<>
- implemented Copyable#copy in GraphMem2 all three descendants (Legacy,
Fast and Roaring)
- extended TripleStore to implement Copyable<> and implemented it in all
three descendants (Legacy, Fast and Roaring)
- added copy constructors to mem2/collections/*, mem2/store/*/*Bunch,
mem2/store/*/*HashMap and mem2/store/*/*Set
- added unit tests to keep the test coverage for mem2/** at 100%
- added benchmark for GraphMem2#copy
- implemented new method G#copy which uses Copyable#copy if the graph
implements it, otherwise G#copyGraphSrcToDst is used as fallback.
- added a unit test for G#copy
---
.../src/main/java/org/apache/jena/system/G.java | 32 ++++--
.../test/java/org/apache/jena/system/GTest.java | 81 +++++++++++++++
.../java/org/apache/jena/atlas/lib/Copyable.java | 21 ++--
.../org/apache/jena/mem/graph/TestGraphCopy.java | 111 ++++++++++++++++++++
.../main/java/org/apache/jena/mem2/GraphMem2.java | 17 +++-
.../java/org/apache/jena/mem2/GraphMem2Fast.java | 9 ++
.../java/org/apache/jena/mem2/GraphMem2Legacy.java | 9 ++
.../org/apache/jena/mem2/GraphMem2Roaring.java | 10 +-
.../apache/jena/mem2/collection/FastHashBase.java | 20 ++++
.../apache/jena/mem2/collection/FastHashMap.java | 29 ++++++
.../apache/jena/mem2/collection/FastHashSet.java | 10 ++
.../jena/mem2/collection/HashCommonBase.java | 13 +++
.../apache/jena/mem2/collection/HashCommonMap.java | 29 ++++++
.../apache/jena/mem2/collection/HashCommonSet.java | 10 ++
.../org/apache/jena/mem2/store/TripleStore.java | 11 +-
.../jena/mem2/store/fast/FastArrayBunch.java | 13 +++
.../jena/mem2/store/fast/FastHashedBunchMap.java | 20 +++-
.../mem2/store/fast/FastHashedTripleBunch.java | 15 +++
.../jena/mem2/store/fast/FastTripleBunch.java | 3 +-
.../jena/mem2/store/fast/FastTripleStore.java | 65 +++++++++++-
.../apache/jena/mem2/store/legacy/ArrayBunch.java | 18 ++++
.../jena/mem2/store/legacy/HashedBunchMap.java | 21 ++++
.../jena/mem2/store/legacy/HashedTripleBunch.java | 9 ++
.../jena/mem2/store/legacy/LegacyTripleStore.java | 26 +++--
.../jena/mem2/store/legacy/NodeToTriplesMap.java | 8 ++
.../mem2/store/legacy/NodeToTriplesMapMem.java | 25 ++++-
.../apache/jena/mem2/store/legacy/TripleBunch.java | 3 +-
.../mem2/store/roaring/RoaringTripleStore.java | 109 +++++++++++++++-----
.../apache/jena/mem2/AbstractGraphMem2Test.java | 48 ++++++++-
.../org/apache/jena/mem2/GraphMem2FastTest.java | 4 +-
.../org/apache/jena/mem2/GraphMem2LegacyTest.java | 4 +-
.../org/apache/jena/mem2/GraphMem2RoaringTest.java | 4 +-
.../java/org/apache/jena/mem2/GraphMem2Test.java | 17 +++-
.../jena/mem2/collection/FastHashMapTest2.java | 82 +++++++++++++--
.../jena/mem2/collection/FastHashSetTest2.java | 49 +++++++++
.../jena/mem2/collection/HashCommonMapTest.java | 112 ++++++++++++++++++---
.../jena/mem2/collection/HashCommonSetTest.java | 80 +++++++++++++--
.../jena/mem2/store/AbstractTripleStoreTest.java | 82 +++++++++++++++
.../jena/mem2/store/fast/FastArrayBunchTest.java | 29 ++++--
.../mem2/store/fast/FastHashedTripleBunchTest.java | 37 ++++---
40 files changed, 1165 insertions(+), 130 deletions(-)
diff --git a/jena-arq/src/main/java/org/apache/jena/system/G.java
b/jena-arq/src/main/java/org/apache/jena/system/G.java
index d4a5209c7f..ea6033caa1 100644
--- a/jena-arq/src/main/java/org/apache/jena/system/G.java
+++ b/jena-arq/src/main/java/org/apache/jena/system/G.java
@@ -18,14 +18,8 @@
package org.apache.jena.system;
-import static org.apache.jena.graph.Node.ANY;
-
-import java.util.*;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-
import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.atlas.lib.Copyable;
import org.apache.jena.datatypes.RDFDatatype;
import org.apache.jena.datatypes.xsd.XSDDatatype;
import org.apache.jena.graph.*;
@@ -39,6 +33,13 @@ import org.apache.jena.sparql.util.graph.GraphList;
import org.apache.jena.util.IteratorCollection;
import org.apache.jena.util.iterator.ExtendedIterator;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+import static org.apache.jena.graph.Node.ANY;
+
/**
* A library of functions for working with {@link Graph}. Internally all
* {@link ExtendedIterator ExtendedIterators} used, run to completion or have
@@ -807,6 +808,23 @@ public class G {
apply(src, dst::add);
}
+ /**
+ * Creates a copy of the given graph.
+ * If the graph implements Copyable<Graph> then the copy method is called.
+ * Otherwise, a new system default memory-based graph is created and the
triples are copied
+ * into it.
+ * @param src the graph to copy
+ * @return a copy of the graph
+ */
+ public static Graph copy(Graph src) {
+ if(src instanceof Copyable<?>) {
+ return ((Copyable<Graph>)src).copy();
+ }
+ Graph dst = GraphMemFactory.createDefaultGraph();
+ copyGraphSrcToDst(src, dst);
+ return dst;
+ }
+
/**
* Clear graph.
*/
diff --git a/jena-arq/src/test/java/org/apache/jena/system/GTest.java
b/jena-arq/src/test/java/org/apache/jena/system/GTest.java
new file mode 100644
index 0000000000..e32f851110
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/system/GTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.system;
+
+import org.apache.jena.atlas.lib.Copyable;
+import org.apache.jena.mem.GraphMem;
+import org.apache.jena.mem2.GraphMem2Fast;
+import org.junit.Test;
+
+import static org.apache.jena.testing_framework.GraphHelper.triple;
+import static org.junit.Assert.*;
+
+public class GTest {
+
+ @Test
+ public void copy() {
+ // Test graph which implements Copyable<>
+ {
+ var graphImplementingCopyable = new GraphMem2Fast();
+
+ assertTrue(graphImplementingCopyable instanceof Copyable<?>);
+
+ graphImplementingCopyable.add(triple("s1 p1 o1"));
+ graphImplementingCopyable.add(triple("s1 p2 o1"));
+ graphImplementingCopyable.add(triple("s2 p1 o1"));
+ graphImplementingCopyable.add(triple("s2 p1 o2"));
+ graphImplementingCopyable.add(triple("s2 p1 o2"));
+
+ var copy = G.copy(graphImplementingCopyable);
+
+ assertEquals(graphImplementingCopyable.size(), copy.size());
+
+ copy.delete(triple("s1 p1 o1"));
+ assertEquals(graphImplementingCopyable.size() - 1, copy.size());
+
+ copy.add(triple("s3 p3 o3"));
+ copy.add(triple("s4 p4 o4"));
+ assertEquals(graphImplementingCopyable.size() + 1, copy.size());
+ }
+
+ // Test graph which does not implement Copyable<>
+ {
+ var notCopyableGraph = new GraphMem();
+
+ assertFalse(notCopyableGraph instanceof Copyable<?>);
+
+ notCopyableGraph.add(triple("s1 p1 o1"));
+ notCopyableGraph.add(triple("s1 p2 o1"));
+ notCopyableGraph.add(triple("s2 p1 o1"));
+ notCopyableGraph.add(triple("s2 p1 o2"));
+ notCopyableGraph.add(triple("s2 p1 o2"));
+
+ var copy = G.copy(notCopyableGraph);
+
+ assertEquals(notCopyableGraph.size(), copy.size());
+
+ copy.delete(triple("s1 p1 o1"));
+ assertEquals(notCopyableGraph.size() - 1, copy.size());
+
+ copy.add(triple("s3 p3 o3"));
+ copy.add(triple("s4 p4 o4"));
+ assertEquals(notCopyableGraph.size() + 1, copy.size());
+ }
+ }
+}
\ No newline at end of file
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2LegacyTest.java
b/jena-base/src/main/java/org/apache/jena/atlas/lib/Copyable.java
similarity index 68%
copy from jena-core/src/test/java/org/apache/jena/mem2/GraphMem2LegacyTest.java
copy to jena-base/src/main/java/org/apache/jena/atlas/lib/Copyable.java
index 2f2944a096..6d8ab8a775 100644
--- a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2LegacyTest.java
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/Copyable.java
@@ -15,14 +15,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jena.mem2;
-import org.apache.jena.graph.Graph;
+package org.apache.jena.atlas.lib;
-public class GraphMem2LegacyTest extends AbstractGraphMem2Test {
+/**
+ * Generic interface for objects that can create an independent copy of
themselves.
+ * Any operations on the copy must not affect the original in any way.
+ * @param <T> must be the type of the implementing class
+ */
+public interface Copyable<T> {
- @Override
- protected Graph createGraph() {
- return new GraphMem2Legacy();
- }
-}
\ No newline at end of file
+ /**
+ * Create a copy of this object.
+ * @return
+ */
+ T copy();
+}
diff --git
a/jena-benchmarks/jena-benchmarks-jmh/src/test/java/org/apache/jena/mem/graph/TestGraphCopy.java
b/jena-benchmarks/jena-benchmarks-jmh/src/test/java/org/apache/jena/mem/graph/TestGraphCopy.java
new file mode 100644
index 0000000000..2a44483369
--- /dev/null
+++
b/jena-benchmarks/jena-benchmarks-jmh/src/test/java/org/apache/jena/mem/graph/TestGraphCopy.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.mem.graph;
+
+import org.apache.jena.mem.graph.helper.Context;
+import org.apache.jena.mem.graph.helper.JMHDefaultOptions;
+import org.apache.jena.mem.graph.helper.Releases;
+import org.apache.jena.mem2.GraphMem2;
+import org.junit.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+
+import java.util.function.Supplier;
+
+
+@State(Scope.Benchmark)
+public class TestGraphCopy {
+
+ @Param({
+ "../testing/cheeses-0.1.ttl",
+ "../testing/pizza.owl.rdf",
+ "../testing/BSBM/bsbm-1m.nt.gz",
+ })
+ public String param0_GraphUri;
+
+ @Param({
+ "GraphMem2Fast (current)",
+ "GraphMem2Legacy (current)",
+ "GraphMem2Roaring (current)",
+ })
+ public String param1_GraphImplementation;
+
+ @Param({
+ "copy",
+ "findAndAddAll",
+ })
+ public String param2_CopyOrConstruct;
+
+ Supplier<GraphMem2> copySupplier;
+
+ Supplier<GraphMem2> newGraphSupplier;
+ private GraphMem2 sutCurrent;
+
+ @Benchmark
+ public GraphMem2 copy() {
+ return copySupplier.get();
+ }
+
+ private GraphMem2 nativeCopy() {
+ var copy = sutCurrent.copy();
+ return copy;
+ }
+
+ private GraphMem2 findAndAddAll() {
+ var copy = (GraphMem2) newGraphSupplier.get();
+ sutCurrent.find().forEachRemaining(copy::add);
+ return copy;
+ }
+
+ @Setup(Level.Trial)
+ public void setupTrial() throws Exception {
+ var trialContext = new Context(param1_GraphImplementation);
+ switch (trialContext.getJenaVersion()) {
+ case CURRENT: {
+ this.newGraphSupplier = () -> (GraphMem2)
Releases.current.createGraph(trialContext.getGraphClass());
+ this.sutCurrent = this.newGraphSupplier.get();
+
+ var triples = Releases.current.readTriples(param0_GraphUri);
+ triples.forEach(this.sutCurrent::add);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported Jena version:
" + trialContext.getJenaVersion());
+ }
+ switch (param2_CopyOrConstruct) {
+ case "copy":
+ this.copySupplier = this::nativeCopy;
+ break;
+ case "findAndAddAll":
+ this.copySupplier = this::findAndAddAll;
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported copy or
construct: " + param2_CopyOrConstruct);
+ }
+ }
+
+ @Test
+ public void benchmark() throws Exception {
+ var opt = JMHDefaultOptions.getDefaults(this.getClass())
+ .build();
+ var results = new Runner(opt).run();
+ Assert.assertNotNull(results);
+ }
+}
diff --git a/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2.java
b/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2.java
index 7c115f4b17..cb2be229ce 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2.java
@@ -18,6 +18,7 @@
package org.apache.jena.mem2;
+import org.apache.jena.atlas.lib.Copyable;
import org.apache.jena.graph.Capabilities;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
@@ -36,11 +37,11 @@ import java.util.stream.Stream;
* Implementation must always comply to term-equality semantics. The
characteristics of the
* implementations always have handlesLiteralTyping() == false.
*/
-public class GraphMem2 extends GraphMemBase implements GraphWithPerform {
+public class GraphMem2 extends GraphMemBase implements GraphWithPerform,
Copyable<GraphMem2> {
final TripleStore tripleStore;
- public GraphMem2(TripleStore tripleStore) {
+ protected GraphMem2(TripleStore tripleStore) {
super();
this.tripleStore = tripleStore;
}
@@ -146,4 +147,16 @@ public class GraphMem2 extends GraphMemBase implements
GraphWithPerform {
public Capabilities getCapabilities() {
return AllCapabilities.updateAllowed;
}
+
+ /**
+ * Creates a copy of this graph.
+ * Since the triples and nodes are immutable, the copy contains the same
triples and nodes as this graph.
+ * Modifications to the copy will not affect this graph.
+ *
+ * @return independent copy of the current graph
+ */
+ @Override
+ public GraphMem2 copy() {
+ return new GraphMem2(this.tripleStore.copy());
+ }
}
diff --git a/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Fast.java
b/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Fast.java
index 0e4d2efbab..b32d9495be 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Fast.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Fast.java
@@ -18,6 +18,7 @@
package org.apache.jena.mem2;
+import org.apache.jena.mem2.store.TripleStore;
import org.apache.jena.mem2.store.fast.FastTripleStore;
/**
@@ -42,4 +43,12 @@ public class GraphMem2Fast extends GraphMem2 {
super(new FastTripleStore());
}
+ private GraphMem2Fast(final TripleStore tripleStore) {
+ super(tripleStore);
+ }
+
+ @Override
+ public GraphMem2Fast copy() {
+ return new GraphMem2Fast(this.tripleStore.copy());
+ }
}
diff --git a/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Legacy.java
b/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Legacy.java
index 9a182c894e..bb8e40adf3 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Legacy.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Legacy.java
@@ -18,6 +18,7 @@
package org.apache.jena.mem2;
+import org.apache.jena.mem2.store.TripleStore;
import org.apache.jena.mem2.store.legacy.LegacyTripleStore;
/**
@@ -44,4 +45,12 @@ public class GraphMem2Legacy extends GraphMem2 {
super(new LegacyTripleStore());
}
+ private GraphMem2Legacy(final TripleStore tripleStore) {
+ super(tripleStore);
+ }
+
+ @Override
+ public GraphMem2Legacy copy() {
+ return new GraphMem2Legacy(this.tripleStore.copy());
+ }
}
diff --git a/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Roaring.java
b/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Roaring.java
index c37f5579d5..bee2ab43c1 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Roaring.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/GraphMem2Roaring.java
@@ -18,6 +18,7 @@
package org.apache.jena.mem2;
+import org.apache.jena.mem2.store.TripleStore;
import org.apache.jena.mem2.store.roaring.RoaringTripleStore;
/**
@@ -41,9 +42,16 @@ import org.apache.jena.mem2.store.roaring.RoaringTripleStore;
* - The bitmaps contain the indices of the triples in the central hash set.
*/
public class GraphMem2Roaring extends GraphMem2 {
-
public GraphMem2Roaring() {
super(new RoaringTripleStore());
}
+ private GraphMem2Roaring(final TripleStore tripleStore) {
+ super(tripleStore);
+ }
+
+ @Override
+ public GraphMem2Roaring copy() {
+ return new GraphMem2Roaring(this.tripleStore.copy());
+ }
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashBase.java
b/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashBase.java
index aa2823a1f2..7f895067e7 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashBase.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashBase.java
@@ -86,7 +86,27 @@ public abstract class FastHashBase<K> implements
JenaMapSetCommon<K> {
this.positions = new int[MINIMUM_HASHES_SIZE];
this.keys = newKeysArray(MINIMUM_ELEMENTS_SIZE);
this.hashCodesOrDeletedIndices = new int[MINIMUM_ELEMENTS_SIZE];
+ }
+
+ /**
+ * Copy constructor.
+ * The new map will contain all the same keys of the map to copy.
+ *
+ * @param baseToCopy
+ */
+ protected <T extends FastHashBase> FastHashBase(final T baseToCopy) {
+ this.positions = new int[baseToCopy.positions.length];
+ System.arraycopy(baseToCopy.positions, 0, this.positions, 0,
baseToCopy.positions.length);
+
+ this.hashCodesOrDeletedIndices = new
int[baseToCopy.hashCodesOrDeletedIndices.length];
+ System.arraycopy(baseToCopy.hashCodesOrDeletedIndices, 0,
this.hashCodesOrDeletedIndices, 0, baseToCopy.hashCodesOrDeletedIndices.length);
+
+ this.keys = newKeysArray(baseToCopy.keys.length);
+ System.arraycopy(baseToCopy.keys, 0, this.keys, 0,
baseToCopy.keys.length);
+ this.keysPos = baseToCopy.keysPos;
+ this.lastDeletedIndex = baseToCopy.lastDeletedIndex;
+ this.removedKeysCount = baseToCopy.removedKeysCount;
}
/**
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashMap.java
b/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashMap.java
index b9a162908b..62d4010415 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashMap.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashMap.java
@@ -50,6 +50,35 @@ public abstract class FastHashMap<K, V> extends
FastHashBase<K> implements JenaM
this.values = newValuesArray(keys.length);
}
+ /**
+ * Copy constructor.
+ * The new map will contain all the same keys and values of the map to
copy.
+ *
+ * @param mapToCopy
+ */
+ protected FastHashMap(final FastHashMap<K, V> mapToCopy) {
+ super(mapToCopy);
+ this.values = newValuesArray(keys.length);
+ System.arraycopy(mapToCopy.values, 0, this.values, 0,
mapToCopy.values.length);
+ }
+
+ /**
+ * Copy constructor with value processor.
+ *
+ * @param mapToCopy
+ * @param valueProcessor
+ */
+ protected FastHashMap(final FastHashMap<K, V> mapToCopy, final
UnaryOperator<V> valueProcessor) {
+ super(mapToCopy);
+ this.values = newValuesArray(keys.length);
+ for (int i = 0; i < mapToCopy.values.length; i++) {
+ final var value = mapToCopy.values[i];
+ if (value != null) {
+ this.values[i] = valueProcessor.apply(value);
+ }
+ }
+ }
+
protected abstract V[] newValuesArray(int size);
@Override
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashSet.java
b/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashSet.java
index 1a9d15bc07..78adb1f0d2 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashSet.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/collection/FastHashSet.java
@@ -37,6 +37,16 @@ public abstract class FastHashSet<K> extends FastHashBase<K>
implements JenaSetH
super();
}
+ /**
+ * Copy constructor.
+ * The new set will contain all the same keys of the set to copy.
+ *
+ * @param setToCopy
+ */
+ protected FastHashSet(final FastHashSet<K> setToCopy) {
+ super(setToCopy);
+ }
+
@Override
public boolean tryAdd(K key) {
return tryAdd(key, key.hashCode());
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonBase.java
b/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonBase.java
index 06d98eca0b..87c8932590 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonBase.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonBase.java
@@ -71,6 +71,19 @@ public abstract class HashCommonBase<E> {
threshold = (int) (keys.length * LOAD_FACTOR);
}
+ /**
+ * Copy constructor.
+ * The new table will contain all the same keys of the table to copy.
+ *
+ * @param baseToCopy
+ */
+ protected HashCommonBase(final HashCommonBase<E> baseToCopy) {
+ this.keys = newKeysArray(baseToCopy.keys.length);
+ System.arraycopy(baseToCopy.keys, 0, this.keys, 0,
baseToCopy.keys.length);
+ this.threshold = baseToCopy.threshold;
+ this.size = baseToCopy.size;
+ }
+
protected static int nextSize(int atLeast) {
for (int prime : primes) {
if (prime > atLeast) return prime;
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonMap.java
b/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonMap.java
index 52ac143561..b5acc20727 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonMap.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonMap.java
@@ -43,6 +43,35 @@ public abstract class HashCommonMap<K, V> extends
HashCommonBase<K> implements J
this.values = newValuesArray(keys.length);
}
+ /**
+ * Copy constructor.
+ * The new map will contain all the same keys and values of the map to
copy.
+ *
+ * @param mapToCopy
+ */
+ protected HashCommonMap(final HashCommonMap<K, V> mapToCopy) {
+ super(mapToCopy);
+ this.values = newValuesArray(keys.length);
+ System.arraycopy(mapToCopy.values, 0, this.values, 0,
mapToCopy.values.length);
+ }
+
+ /**
+ * Copy constructor with value processor.
+ *
+ * @param mapToCopy
+ * @param valueProcessor
+ */
+ protected HashCommonMap(final HashCommonMap<K, V> mapToCopy, final
UnaryOperator<V> valueProcessor) {
+ super(mapToCopy);
+ this.values = newValuesArray(keys.length);
+ for (int i = 0; i < mapToCopy.values.length; i++) {
+ final var value = mapToCopy.values[i];
+ if (value != null) {
+ this.values[i] = valueProcessor.apply(value);
+ }
+ }
+ }
+
@Override
public void clear(int initialCapacity) {
super.clear(initialCapacity);
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonSet.java
b/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonSet.java
index 5abbd60dcf..291dce7209 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonSet.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/collection/HashCommonSet.java
@@ -31,6 +31,16 @@ public abstract class HashCommonSet<K> extends
HashCommonBase<K> implements Jena
super(initialCapacity);
}
+ /**
+ * Copy constructor.
+ * The new set will contain all the same keys of the set to copy.
+ *
+ * @param setToCopy
+ */
+ protected HashCommonSet(final HashCommonSet<K> setToCopy) {
+ super(setToCopy);
+ }
+
@Override
public boolean tryAdd(K key) {
final var slot = findSlot(key);
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/TripleStore.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/TripleStore.java
index 2b67813896..8530709b4c 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/store/TripleStore.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/store/TripleStore.java
@@ -18,6 +18,7 @@
package org.apache.jena.mem2.store;
+import org.apache.jena.atlas.lib.Copyable;
import org.apache.jena.graph.Triple;
import org.apache.jena.util.iterator.ExtendedIterator;
@@ -27,7 +28,7 @@ import java.util.stream.Stream;
* A triple store is a collection of triples that supports access to
* triples matching a triple pattern.
*/
-public interface TripleStore {
+public interface TripleStore extends Copyable<TripleStore> {
/**
* Add a triple to the map.
@@ -87,4 +88,12 @@ public interface TripleStore {
* Returns an {@link ExtendedIterator} of all triples in the graph
matching the given triple match.
*/
ExtendedIterator<Triple> find(final Triple tripleMatch);
+
+ /**
+ * Return a new triple store that is a copy of this one.
+ * Since Nodes and Triples are immutable and shared, the copy can share
the same Nodes and Triples.
+ *
+ * @return an independent copy of this store
+ */
+ TripleStore copy();
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastArrayBunch.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastArrayBunch.java
index 57035f4223..f46ffe285c 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastArrayBunch.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastArrayBunch.java
@@ -43,6 +43,19 @@ public abstract class FastArrayBunch implements
FastTripleBunch {
elements = new Triple[INITIAL_SIZE];
}
+ /**
+ * Copy constructor.
+ * The new bunch will contain all the same triples of the bunch to copy.
+ * But it will reserve only the space needed to contain them. Growing is
still possible.
+ *
+ * @param bunchToCopy
+ */
+ protected FastArrayBunch(final FastArrayBunch bunchToCopy) {
+ this.elements = new Triple[bunchToCopy.size];
+ System.arraycopy(bunchToCopy.elements, 0, this.elements, 0,
bunchToCopy.size);
+ this.size = bunchToCopy.size;
+ }
+
public abstract boolean areEqual(final Triple a, final Triple b);
@Override
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastHashedBunchMap.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastHashedBunchMap.java
index a9e598dce6..1f96f85294 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastHashedBunchMap.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastHashedBunchMap.java
@@ -17,18 +17,31 @@
*/
package org.apache.jena.mem2.store.fast;
+import org.apache.jena.atlas.lib.Copyable;
import org.apache.jena.graph.Node;
import org.apache.jena.mem2.collection.FastHashMap;
/**
* Map from nodes to triple bunches.
*/
-public class FastHashedBunchMap extends FastHashMap<Node, FastTripleBunch> {
+public class FastHashedBunchMap
+ extends FastHashMap<Node, FastTripleBunch>
+ implements Copyable<FastHashedBunchMap> {
public FastHashedBunchMap() {
super();
}
+ /**
+ * Copy constructor.
+ * The new map will contain all the same nodes as keys of the map to copy,
but copies of the bunches as values .
+ *
+ * @param mapToCopy
+ */
+ private FastHashedBunchMap(final FastHashedBunchMap mapToCopy) {
+ super(mapToCopy, FastTripleBunch::copy);
+ }
+
@Override
protected Node[] newKeysArray(int size) {
return new Node[size];
@@ -38,4 +51,9 @@ public class FastHashedBunchMap extends FastHashMap<Node,
FastTripleBunch> {
protected FastTripleBunch[] newValuesArray(int size) {
return new FastTripleBunch[size];
}
+
+ @Override
+ public FastHashedBunchMap copy() {
+ return new FastHashedBunchMap(this);
+ }
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastHashedTripleBunch.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastHashedTripleBunch.java
index 752a57971c..7d09fc6ba5 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastHashedTripleBunch.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastHashedTripleBunch.java
@@ -35,6 +35,16 @@ public class FastHashedTripleBunch extends
FastHashSet<Triple> implements FastTr
set.keyIterator().forEachRemaining(this::addUnchecked);
}
+ /**
+ * Copy constructor.
+ * The new bunch will contain all the same triples of the bunch to copy.
+ *
+ * @param bunchToCopy
+ */
+ private FastHashedTripleBunch(final FastHashedTripleBunch bunchToCopy) {
+ super(bunchToCopy);
+ }
+
public FastHashedTripleBunch() {
super();
}
@@ -48,4 +58,9 @@ public class FastHashedTripleBunch extends
FastHashSet<Triple> implements FastTr
public boolean isArray() {
return false;
}
+
+ @Override
+ public FastHashedTripleBunch copy() {
+ return new FastHashedTripleBunch(this);
+ }
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastTripleBunch.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastTripleBunch.java
index 116873f1db..5de934a946 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastTripleBunch.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastTripleBunch.java
@@ -18,6 +18,7 @@
package org.apache.jena.mem2.store.fast;
+import org.apache.jena.atlas.lib.Copyable;
import org.apache.jena.graph.Triple;
import org.apache.jena.mem2.collection.JenaMapSetCommon;
import org.apache.jena.mem2.collection.JenaSetHashOptimized;
@@ -29,7 +30,7 @@ import java.util.function.Predicate;
* bunch is expected to store triples that share some useful property
* (such as having the same subject or predicate).
*/
-public interface FastTripleBunch extends JenaSetHashOptimized<Triple> {
+public interface FastTripleBunch extends JenaSetHashOptimized<Triple>,
Copyable<FastTripleBunch> {
/**
* Answer true iff this bunch is implemented as an array.
* This field is used to optimize some operations by avoiding the need for
instanceOf tests.
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastTripleStore.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastTripleStore.java
index 00e1c48818..e6cb9292c9 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastTripleStore.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/fast/FastTripleStore.java
@@ -68,11 +68,24 @@ public class FastTripleStore implements TripleStore {
protected static final int THRESHOLD_FOR_SECONDARY_LOOKUP = 400;
protected static final int MAX_ARRAY_BUNCH_SIZE_SUBJECT = 16;
protected static final int MAX_ARRAY_BUNCH_SIZE_PREDICATE_OBJECT = 32;
- final FastHashedBunchMap subjects = new FastHashedBunchMap();
- final FastHashedBunchMap predicates = new FastHashedBunchMap();
- final FastHashedBunchMap objects = new FastHashedBunchMap();
+ final FastHashedBunchMap subjects;
+ final FastHashedBunchMap predicates;
+ final FastHashedBunchMap objects;
private int size = 0;
+ public FastTripleStore() {
+ subjects = new FastHashedBunchMap();
+ predicates = new FastHashedBunchMap();
+ objects = new FastHashedBunchMap();
+ }
+
+ private FastTripleStore(final FastTripleStore tripleStoreToCopy) {
+ subjects = tripleStoreToCopy.subjects.copy();
+ predicates = tripleStoreToCopy.predicates.copy();
+ objects = tripleStoreToCopy.objects.copy();
+ size = tripleStoreToCopy.size;
+ }
+
@Override
public void add(Triple triple) {
final int hashCodeOfTriple = triple.hashCode();
@@ -359,8 +372,26 @@ public class FastTripleStore implements TripleStore {
}
}
+ @Override
+ public FastTripleStore copy() {
+ return new FastTripleStore(this);
+ }
+
protected static class ArrayBunchWithSameSubject extends FastArrayBunch {
+ public ArrayBunchWithSameSubject() {
+ super();
+ }
+
+ private ArrayBunchWithSameSubject(ArrayBunchWithSameSubject
bunchToCopy) {
+ super(bunchToCopy);
+ }
+
+ @Override
+ public ArrayBunchWithSameSubject copy() {
+ return new ArrayBunchWithSameSubject(this);
+ }
+
@Override
public boolean areEqual(final Triple a, final Triple b) {
return a.getPredicate().equals(b.getPredicate())
@@ -369,6 +400,20 @@ public class FastTripleStore implements TripleStore {
}
protected static class ArrayBunchWithSamePredicate extends FastArrayBunch {
+
+ public ArrayBunchWithSamePredicate() {
+ super();
+ }
+
+ private ArrayBunchWithSamePredicate(ArrayBunchWithSamePredicate
bunchToCopy) {
+ super(bunchToCopy);
+ }
+
+ @Override
+ public ArrayBunchWithSamePredicate copy() {
+ return new ArrayBunchWithSamePredicate(this);
+ }
+
@Override
public boolean areEqual(final Triple a, final Triple b) {
return a.getSubject().equals(b.getSubject())
@@ -377,6 +422,20 @@ public class FastTripleStore implements TripleStore {
}
protected static class ArrayBunchWithSameObject extends FastArrayBunch {
+
+ public ArrayBunchWithSameObject() {
+ super();
+ }
+
+ private ArrayBunchWithSameObject(ArrayBunchWithSameObject bunchToCopy)
{
+ super(bunchToCopy);
+ }
+
+ @Override
+ public ArrayBunchWithSameObject copy() {
+ return new ArrayBunchWithSameObject(this);
+ }
+
@Override
public boolean areEqual(final Triple a, final Triple b) {
return a.getSubject().equals(b.getSubject())
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/ArrayBunch.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/ArrayBunch.java
index 83ca78aa3f..8387210195 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/ArrayBunch.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/ArrayBunch.java
@@ -46,6 +46,19 @@ public class ArrayBunch implements TripleBunch {
elements = new Triple[INITIAL_SIZE];
}
+ /**
+ * Copy constructor.
+ * The new bunch will contain all the same triples of the bunch to copy.
+ * But it will reserve only the space needed to contain them. Growing is
still possible.
+ *
+ * @param bunchToCopy
+ */
+ private ArrayBunch(final ArrayBunch bunchToCopy) {
+ this.elements = new Triple[bunchToCopy.size];
+ System.arraycopy(bunchToCopy.elements, 0, this.elements, 0,
bunchToCopy.size);
+ this.size = bunchToCopy.size;
+ }
+
@Override
public boolean containsKey(Triple t) {
int i = size;
@@ -163,4 +176,9 @@ public class ArrayBunch implements TripleBunch {
public boolean isArray() {
return true;
}
+
+ @Override
+ public ArrayBunch copy() {
+ return new ArrayBunch(this);
+ }
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/HashedBunchMap.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/HashedBunchMap.java
index d719d74772..426d8d06d3 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/HashedBunchMap.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/HashedBunchMap.java
@@ -29,6 +29,17 @@ public class HashedBunchMap extends HashCommonMap<Node,
TripleBunch> {
super(10);
}
+ /**
+ * Copy constructor.
+ * The new map will contain all the same nodes as keys of the map to copy,
but copies of the bunches as values .
+ *
+ * @param mapToCopy
+ */
+ private HashedBunchMap(final HashedBunchMap mapToCopy) {
+ super(mapToCopy, TripleBunch::copy);
+ }
+
+
@Override
protected Node[] newKeysArray(int size) {
return new Node[size];
@@ -43,4 +54,14 @@ public class HashedBunchMap extends HashCommonMap<Node,
TripleBunch> {
public void clear() {
super.clear(10);
}
+
+ /**
+ * Create a copy of this map.
+ * The new map will contain all the same nodes as keys of this map, but
copies of the bunches as values.
+ *
+ * @return an independent copy of this map
+ */
+ public HashedBunchMap copy() {
+ return new HashedBunchMap(this);
+ }
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/HashedTripleBunch.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/HashedTripleBunch.java
index 9bf8eb3e6a..2e18ffa57f 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/HashedTripleBunch.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/HashedTripleBunch.java
@@ -30,6 +30,10 @@ public class HashedTripleBunch extends HashCommonSet<Triple>
implements TripleBu
b.keyIterator().forEachRemaining(this::addUnchecked);
}
+ private HashedTripleBunch(final HashedTripleBunch bunchToCopy) {
+ super(bunchToCopy);
+ }
+
public HashedTripleBunch() {
super(8);
}
@@ -48,4 +52,9 @@ public class HashedTripleBunch extends HashCommonSet<Triple>
implements TripleBu
public boolean isArray() {
return false;
}
+
+ @Override
+ public HashedTripleBunch copy() {
+ return new HashedTripleBunch(this);
+ }
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/LegacyTripleStore.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/LegacyTripleStore.java
index a8a9e91980..b9ef20818a 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/LegacyTripleStore.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/LegacyTripleStore.java
@@ -47,12 +47,21 @@ import java.util.stream.Stream;
*/
public class LegacyTripleStore implements TripleStore {
- private final NodeToTriplesMap subjects
- = new NodeToTriplesMapMem(Triple.Field.fieldSubject,
Triple.Field.fieldPredicate, Triple.Field.fieldObject);
- private final NodeToTriplesMap predicates
- = new NodeToTriplesMapMem(Triple.Field.fieldPredicate,
Triple.Field.fieldObject, Triple.Field.fieldSubject);
- private final NodeToTriplesMap objects
- = new NodeToTriplesMapMem(Triple.Field.fieldObject,
Triple.Field.fieldSubject, Triple.Field.fieldPredicate);
+ private final NodeToTriplesMap subjects;
+ private final NodeToTriplesMap predicates;
+ private final NodeToTriplesMap objects;
+
+ public LegacyTripleStore() {
+ subjects = new NodeToTriplesMapMem(Triple.Field.fieldSubject,
Triple.Field.fieldPredicate, Triple.Field.fieldObject);
+ predicates = new NodeToTriplesMapMem(Triple.Field.fieldPredicate,
Triple.Field.fieldObject, Triple.Field.fieldSubject);
+ objects = new NodeToTriplesMapMem(Triple.Field.fieldObject,
Triple.Field.fieldSubject, Triple.Field.fieldPredicate);
+ }
+
+ private LegacyTripleStore(final LegacyTripleStore toCopy) {
+ subjects = toCopy.subjects.copy();
+ predicates = toCopy.predicates.copy();
+ objects = toCopy.objects.copy();
+ }
@Override
public void add(Triple triple) {
@@ -149,4 +158,9 @@ public class LegacyTripleStore implements TripleStore {
else
return subjects.keyIterator();
}
+
+ @Override
+ public LegacyTripleStore copy() {
+ return new LegacyTripleStore(this);
+ }
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/NodeToTriplesMap.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/NodeToTriplesMap.java
index d2bd89b966..1b8f6e49c8 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/NodeToTriplesMap.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/NodeToTriplesMap.java
@@ -58,4 +58,12 @@ public interface NodeToTriplesMap extends JenaSet<Triple> {
* @return True iff this map contains a triple that matches the pattern.
*/
boolean containsMatch(Node index, Node n2, Node n3);
+
+ /**
+ * Create a copy of this map.
+ * The new map will contain all the same nodes as keys of this map, but
copies of the bunches as values.
+ *
+ * @return an independent copy of this map
+ */
+ NodeToTriplesMap copy();
}
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/NodeToTriplesMapMem.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/NodeToTriplesMapMem.java
index 9476e70a09..24c2fbfce3 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/NodeToTriplesMapMem.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/NodeToTriplesMapMem.java
@@ -19,7 +19,6 @@ package org.apache.jena.mem2.store.legacy;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
-import org.apache.jena.mem2.collection.JenaMap;
import org.apache.jena.mem2.iterator.IteratorOfJenaSets;
import org.apache.jena.util.iterator.ExtendedIterator;
import org.apache.jena.util.iterator.NullIterator;
@@ -31,7 +30,7 @@ import java.util.stream.StreamSupport;
public class NodeToTriplesMapMem implements NodeToTriplesMap {
- private final JenaMap<Node, TripleBunch> bunchMap = new HashedBunchMap();
+ private final HashedBunchMap bunchMap;
private final Triple.Field indexField;
private final Triple.Field f2;
private final Triple.Field f3;
@@ -42,10 +41,19 @@ public class NodeToTriplesMapMem implements
NodeToTriplesMap {
*/
private int size = 0;
- public NodeToTriplesMapMem(Triple.Field indexField, Triple.Field f2,
Triple.Field f3) {
+ public NodeToTriplesMapMem(final Triple.Field indexField, final
Triple.Field f2, final Triple.Field f3) {
this.indexField = indexField;
this.f2 = f2;
this.f3 = f3;
+ this.bunchMap = new HashedBunchMap();
+ }
+
+ private NodeToTriplesMapMem(final NodeToTriplesMapMem mapToCopy) {
+ this.indexField = mapToCopy.indexField;
+ this.f2 = mapToCopy.f2;
+ this.f3 = mapToCopy.f3;
+ this.size = mapToCopy.size;
+ this.bunchMap = mapToCopy.bunchMap.copy();
}
private Node getIndexNode(Triple t) {
@@ -74,14 +82,16 @@ public class NodeToTriplesMapMem implements
NodeToTriplesMap {
TripleBunch s = bunchMap.get(node);
if (s == null) {
- bunchMap.put(node, s = new ArrayBunch());
+ s = new ArrayBunch();
+ bunchMap.put(node, s);
s.addUnchecked(t);
size++;
return true;
}
if ((s.isArray()) && s.size() == 9) {
- bunchMap.put(node, s = new HashedTripleBunch(s));
+ s = new HashedTripleBunch(s);
+ bunchMap.put(node, s);
}
if (s.tryAdd(t)) {
size++;
@@ -184,6 +194,11 @@ public class NodeToTriplesMapMem implements
NodeToTriplesMap {
return s.anyMatch(filter.getFilter());
}
+ @Override
+ public NodeToTriplesMapMem copy() {
+ return new NodeToTriplesMapMem(this);
+ }
+
@Override
public boolean containsKey(Triple triple) {
final TripleBunch s = bunchMap.get(getIndexNode(triple));
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/TripleBunch.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/TripleBunch.java
index 0c595cf3ac..c981ea0c9c 100644
--- a/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/TripleBunch.java
+++ b/jena-core/src/main/java/org/apache/jena/mem2/store/legacy/TripleBunch.java
@@ -18,6 +18,7 @@
package org.apache.jena.mem2.store.legacy;
+import org.apache.jena.atlas.lib.Copyable;
import org.apache.jena.graph.Triple;
import org.apache.jena.mem2.collection.JenaSet;
@@ -26,7 +27,7 @@ import org.apache.jena.mem2.collection.JenaSet;
* bunch is expected to store triples that share some useful property
* (such as having the same subject or predicate).
*/
-public interface TripleBunch extends JenaSet<Triple> {
+public interface TripleBunch extends JenaSet<Triple>, Copyable<TripleBunch> {
/**
* Answer true iff this bunch is implemented as an array.
* This field is used to optimize some operations by avoiding the need for
instanceOf tests.
diff --git
a/jena-core/src/main/java/org/apache/jena/mem2/store/roaring/RoaringTripleStore.java
b/jena-core/src/main/java/org/apache/jena/mem2/store/roaring/RoaringTripleStore.java
index 547dd0a916..d35d4b5915 100644
---
a/jena-core/src/main/java/org/apache/jena/mem2/store/roaring/RoaringTripleStore.java
+++
b/jena-core/src/main/java/org/apache/jena/mem2/store/roaring/RoaringTripleStore.java
@@ -18,6 +18,7 @@
package org.apache.jena.mem2.store.roaring;
+import org.apache.jena.atlas.lib.Copyable;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.mem2.collection.FastHashMap;
@@ -56,10 +57,24 @@ public class RoaringTripleStore implements TripleStore {
private static final String UNKNOWN_PATTERN_CLASSIFIER = "Unknown pattern
classifier: %s";
private static final RoaringBitmap EMPTY_BITMAP = new RoaringBitmap();
- final NodesToBitmapsMap subjectBitmaps = new NodesToBitmapsMap();
- final NodesToBitmapsMap predicateBitmaps = new NodesToBitmapsMap();
- final NodesToBitmapsMap objectBitmaps = new NodesToBitmapsMap();
- final TripleSet triples = new TripleSet(); // We use a list here to
maintain the order of triples
+ final NodesToBitmapsMap subjectBitmaps;
+ final NodesToBitmapsMap predicateBitmaps;
+ final NodesToBitmapsMap objectBitmaps;
+ final TripleSet triples; // In this special set, each element has an index
+
+ public RoaringTripleStore() {
+ subjectBitmaps = new NodesToBitmapsMap();
+ predicateBitmaps = new NodesToBitmapsMap();
+ objectBitmaps = new NodesToBitmapsMap();
+ triples = new TripleSet();
+ }
+
+ private RoaringTripleStore(final RoaringTripleStore storeToCopy) {
+ subjectBitmaps = storeToCopy.subjectBitmaps.copy();
+ predicateBitmaps = storeToCopy.predicateBitmaps.copy();
+ objectBitmaps = storeToCopy.objectBitmaps.copy();
+ triples = storeToCopy.triples.copy();
+ }
private static void addIndex(final NodesToBitmapsMap map, final Node node,
final int index) {
final var bitmap = map.computeIfAbsent(node, RoaringBitmap::new);
@@ -119,12 +134,12 @@ public class RoaringTripleStore implements TripleStore {
final var matchPattern = PatternClassifier.classify(tripleMatch);
switch (matchPattern) {
- case SUB_ANY_ANY:
- case ANY_PRE_ANY:
- case ANY_ANY_OBJ:
- case SUB_PRE_ANY:
- case ANY_PRE_OBJ:
- case SUB_ANY_OBJ:
+ case SUB_ANY_ANY,
+ ANY_PRE_ANY,
+ ANY_ANY_OBJ,
+ SUB_PRE_ANY,
+ ANY_PRE_OBJ,
+ SUB_ANY_OBJ:
return hasMatchInBitmaps(tripleMatch, matchPattern);
case SUB_PRE_OBJ:
@@ -265,12 +280,12 @@ public class RoaringTripleStore implements TripleStore {
case SUB_PRE_OBJ:
return this.triples.containsKey(tripleMatch) ?
Stream.of(tripleMatch) : Stream.empty();
- case SUB_PRE_ANY:
- case SUB_ANY_OBJ:
- case SUB_ANY_ANY:
- case ANY_PRE_OBJ:
- case ANY_PRE_ANY:
- case ANY_ANY_OBJ:
+ case SUB_PRE_ANY,
+ SUB_ANY_OBJ,
+ SUB_ANY_ANY,
+ ANY_PRE_OBJ,
+ ANY_PRE_ANY,
+ ANY_ANY_OBJ:
return this.getBitmapForMatch(tripleMatch, pattern)
.stream().mapToObj(this.triples::getKeyAt);
@@ -290,12 +305,12 @@ public class RoaringTripleStore implements TripleStore {
case SUB_PRE_OBJ:
return this.triples.containsKey(tripleMatch) ? new
SingletonIterator<>(tripleMatch) : NiceIterator.emptyIterator();
- case SUB_PRE_ANY:
- case SUB_ANY_OBJ:
- case SUB_ANY_ANY:
- case ANY_PRE_OBJ:
- case ANY_PRE_ANY:
- case ANY_ANY_OBJ:
+ case SUB_PRE_ANY,
+ SUB_ANY_OBJ,
+ SUB_ANY_ANY,
+ ANY_PRE_OBJ,
+ ANY_PRE_ANY,
+ ANY_ANY_OBJ:
return new
RoaringBitmapTripleIterator(this.getBitmapForMatch(tripleMatch, pattern),
this.triples);
case ANY_ANY_ANY:
@@ -306,21 +321,56 @@ public class RoaringTripleStore implements TripleStore {
}
}
+ @Override
+ public RoaringTripleStore copy() {
+ return new RoaringTripleStore(this);
+ }
+
/**
* Set of triples that is backed by a {@link TripleSet}.
*/
- private static class TripleSet extends FastHashSet<Triple> {
+ private static class TripleSet
+ extends FastHashSet<Triple>
+ implements Copyable<TripleSet>{
+
+ public TripleSet() {
+ super();
+ }
+
+ private TripleSet(final FastHashSet<Triple> setToCopy) {
+ super(setToCopy);
+ }
@Override
protected Triple[] newKeysArray(int size) {
return new Triple[size];
}
+
+ /**
+ * Create a copy of this set.
+ *
+ * @return
+ */
+ @Override
+ public TripleSet copy() {
+ return new TripleSet(this);
+ }
}
/**
* Map from {@link Node} to {@link RoaringBitmap}.
*/
- private static class NodesToBitmapsMap extends FastHashMap<Node,
RoaringBitmap> {
+ private static class NodesToBitmapsMap
+ extends FastHashMap<Node, RoaringBitmap>
+ implements Copyable<NodesToBitmapsMap> {
+
+ public NodesToBitmapsMap() {
+ super();
+ }
+
+ public NodesToBitmapsMap(final NodesToBitmapsMap mapToCopy) {
+ super(mapToCopy, RoaringBitmap::clone);
+ }
@Override
protected Node[] newKeysArray(int size) {
@@ -331,5 +381,16 @@ public class RoaringTripleStore implements TripleStore {
protected RoaringBitmap[] newValuesArray(int size) {
return new RoaringBitmap[size];
}
+
+ /**
+ * Create a copy of this map.
+ * The new map will contain all the same nodes as keys of this map,
but clones of the bitmaps as values.
+ *
+ * @return a copy of this map
+ */
+ @Override
+ public NodesToBitmapsMap copy() {
+ return new NodesToBitmapsMap(this);
+ }
}
}
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/AbstractGraphMem2Test.java
b/jena-core/src/test/java/org/apache/jena/mem2/AbstractGraphMem2Test.java
index a0ad17d208..2c99e7fbec 100644
--- a/jena-core/src/test/java/org/apache/jena/mem2/AbstractGraphMem2Test.java
+++ b/jena-core/src/test/java/org/apache/jena/mem2/AbstractGraphMem2Test.java
@@ -19,7 +19,6 @@
package org.apache.jena.mem2;
import org.apache.jena.datatypes.xsd.impl.XSDDouble;
-import org.apache.jena.graph.Graph;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Triple;
import org.hamcrest.collection.IsEmptyCollection;
@@ -36,9 +35,9 @@ import static org.junit.Assert.*;
public abstract class AbstractGraphMem2Test {
- protected Graph sut;
+ protected GraphMem2 sut;
- protected abstract Graph createGraph();
+ protected abstract GraphMem2 createGraph();
@Before
public void setUp() throws Exception {
@@ -54,7 +53,6 @@ public abstract class AbstractGraphMem2Test {
assertTrue(sut.isEmpty());
}
-
@Test
public void testDelete() {
sut.add(triple("x R y"));
@@ -1000,4 +998,46 @@ public abstract class AbstractGraphMem2Test {
NodeFactory.createURI("R"))));
}
+ @Test
+ public void testCopy() {
+ sut.add(triple("s p o"));
+ sut.add(triple("s1 p1 o1"));
+ sut.add(triple("s2 p2 o2"));
+ assertEquals(3, sut.size());
+
+ var copy = sut.copy();
+ assertEquals(3, copy.size());
+ assertTrue(copy.contains(triple("s p o")));
+ assertTrue(copy.contains(triple("s1 p1 o1")));
+ assertTrue(copy.contains(triple("s2 p2 o2")));
+ assertFalse(copy.contains(triple("s3 p3 o3")));
+ }
+
+ @Test
+ public void testCopyHasNoSideEffects() {
+ sut.add(triple("s p o"));
+ sut.add(triple("s1 p1 o1"));
+ sut.add(triple("s2 p2 o2"));
+ assertEquals(3, sut.size());
+
+ var copy = sut.copy();
+ copy.delete(triple("s1 p1 o1"));
+ copy.add(triple("s3 p3 o3"));
+ copy.add(triple("s4 p4 o4"));
+
+ assertEquals(4, copy.size());
+ assertTrue(copy.contains(triple("s p o")));
+ assertFalse(copy.contains(triple("s1 p1 o1")));
+ assertTrue(copy.contains(triple("s2 p2 o2")));
+ assertTrue(copy.contains(triple("s3 p3 o3")));
+ assertTrue(copy.contains(triple("s4 p4 o4")));
+
+
+ assertEquals(3, sut.size());
+ assertTrue(sut.contains(triple("s p o")));
+ assertTrue(sut.contains(triple("s1 p1 o1")));
+ assertTrue(sut.contains(triple("s2 p2 o2")));
+ assertFalse(sut.contains(triple("s3 p3 o3")));
+ }
+
}
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2FastTest.java
b/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2FastTest.java
index 2a03057c62..8c7856539e 100644
--- a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2FastTest.java
+++ b/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2FastTest.java
@@ -18,12 +18,10 @@
package org.apache.jena.mem2;
-import org.apache.jena.graph.Graph;
-
public class GraphMem2FastTest extends AbstractGraphMem2Test {
@Override
- protected Graph createGraph() {
+ protected GraphMem2 createGraph() {
return new GraphMem2Fast();
}
}
\ No newline at end of file
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2LegacyTest.java
b/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2LegacyTest.java
index 2f2944a096..59b1db2df1 100644
--- a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2LegacyTest.java
+++ b/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2LegacyTest.java
@@ -17,12 +17,10 @@
*/
package org.apache.jena.mem2;
-import org.apache.jena.graph.Graph;
-
public class GraphMem2LegacyTest extends AbstractGraphMem2Test {
@Override
- protected Graph createGraph() {
+ protected GraphMem2 createGraph() {
return new GraphMem2Legacy();
}
}
\ No newline at end of file
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2RoaringTest.java
b/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2RoaringTest.java
index bc539bab1a..0e1c66f248 100644
--- a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2RoaringTest.java
+++ b/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2RoaringTest.java
@@ -17,12 +17,10 @@
*/
package org.apache.jena.mem2;
-import org.apache.jena.graph.Graph;
-
public class GraphMem2RoaringTest extends AbstractGraphMem2Test {
@Override
- protected Graph createGraph() {
+ protected GraphMem2 createGraph() {
return new GraphMem2Roaring();
}
}
\ No newline at end of file
diff --git a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2Test.java
b/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2Test.java
index aabb0c3c6a..062758176a 100644
--- a/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2Test.java
+++ b/jena-core/src/test/java/org/apache/jena/mem2/GraphMem2Test.java
@@ -26,8 +26,7 @@ import java.util.stream.Stream;
import static org.apache.jena.testing_framework.GraphHelper.node;
import static org.apache.jena.testing_framework.GraphHelper.triple;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class GraphMem2Test {
@@ -170,4 +169,18 @@ public class GraphMem2Test {
assertFalse(capapbilities.handlesLiteralTyping());
}
+
+ @Test
+ public void testCopy() {
+ TripleStore mockStore = mock();
+ TripleStore mockStoreCopy = mock();
+
+ when(mockStore.copy()).thenReturn(mockStoreCopy);
+
+ var sut = new GraphMem2(mockStore);
+ var copy = sut.copy();
+
+ assertTrue(copy instanceof GraphMem2);
+ assertEquals(mockStoreCopy, copy.tripleStore);
+ }
}
\ No newline at end of file
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/collection/FastHashMapTest2.java
b/jena-core/src/test/java/org/apache/jena/mem2/collection/FastHashMapTest2.java
index d9c758d21b..6ea4ec0a60 100644
---
a/jena-core/src/test/java/org/apache/jena/mem2/collection/FastHashMapTest2.java
+++
b/jena-core/src/test/java/org/apache/jena/mem2/collection/FastHashMapTest2.java
@@ -20,17 +20,16 @@ package org.apache.jena.mem2.collection;
import org.apache.jena.graph.Node;
import org.junit.Test;
+import java.util.function.UnaryOperator;
+
import static org.apache.jena.testing_framework.GraphHelper.node;
import static org.junit.Assert.assertEquals;
public class FastHashMapTest2 {
- FastHashMap<Node, Object> sut = new FastNodeHashMap();
-
-
@Test
public void testConstructWithInitialSizeAndAdd() {
- sut = new FastNodeHashMap(3);
+ var sut = new FastNodeHashMap(3);
sut.put(node("s"), null);
sut.put(node("s1"), null);
sut.put(node("s2"), null);
@@ -41,13 +40,74 @@ public class FastHashMapTest2 {
@Test
public void testGetValueAt() {
+ var sut = new FastNodeHashMap();
sut.put(node("s"), 0);
sut.put(node("s1"), 1);
sut.put(node("s2"), 2);
- assertEquals(0, sut.getValueAt(0));
- assertEquals(1, sut.getValueAt(1));
- assertEquals(2, sut.getValueAt(2));
+ assertEquals(0, (int) sut.getValueAt(0));
+ assertEquals(1, (int) sut.getValueAt(1));
+ assertEquals(2, (int) sut.getValueAt(2));
+ }
+
+ @Test
+ public void testCopyConstructor() {
+ var original = new FastNodeHashMap();
+ original.put(node("s"), 0);
+ original.put(node("s1"), 1);
+ original.put(node("s2"), 2);
+ assertEquals(3, original.size());
+
+ var copy = new FastNodeHashMap(original);
+ assertEquals(3, copy.size());
+ assertEquals(0, (int) copy.get(node("s")));
+ assertEquals(1, (int) copy.get(node("s1")));
+ assertEquals(2, (int) copy.get(node("s2")));
+ }
+
+ @Test
+ public void testCopyConstructorWithValueMapping() {
+ var original = new FastNodeHashMap();
+ original.put(node("s"), 0);
+ original.put(node("s1"), 1);
+ original.put(node("s2"), 2);
+ assertEquals(3, original.size());
+
+ var copy = new FastNodeHashMap(original, i -> (int) i + 1);
+ assertEquals(3, copy.size());
+ assertEquals(1, (int) copy.get(node("s")));
+ assertEquals(2, (int) copy.get(node("s1")));
+ assertEquals(3, (int) copy.get(node("s2")));
+
+ assertEquals(0, (int) original.get(node("s")));
+ assertEquals(1, (int) original.get(node("s1")));
+ assertEquals(2, (int) original.get(node("s2")));
+ }
+
+ @Test
+ public void testCopyConstructorAddAndDeleteHasNoSideEffects() {
+ var original = new FastNodeHashMap();
+ original.put(node("s"), 0);
+ original.put(node("s1"), 1);
+ original.put(node("s2"), 2);
+ assertEquals(3, original.size());
+
+ var copy = new FastNodeHashMap(original);
+ copy.removeAndGetIndex(node("s1"));
+ copy.put(node("s3"), 3);
+ copy.put(node("s4"), 4);
+
+ assertEquals(4, copy.size());
+ assertEquals(0, (int) copy.get(node("s")));
+ assertEquals(2, (int) copy.get(node("s2")));
+ assertEquals(3, (int) copy.get(node("s3")));
+ assertEquals(4, (int) copy.get(node("s4")));
+
+
+ assertEquals(3, original.size());
+ assertEquals(0, (int) original.get(node("s")));
+ assertEquals(1, (int) original.get(node("s1")));
+ assertEquals(2, (int) original.get(node("s2")));
}
private static class FastNodeHashMap extends FastHashMap<Node, Object> {
@@ -60,6 +120,14 @@ public class FastHashMapTest2 {
super(initialSize);
}
+ public FastNodeHashMap(FastHashMap<Node, Object> mapToCopy) {
+ super(mapToCopy);
+ }
+
+ public FastNodeHashMap(FastHashMap<Node, Object> mapToCopy,
UnaryOperator<Object> valueProcessor) {
+ super(mapToCopy, valueProcessor);
+ }
+
@Override
protected Object[] newValuesArray(int size) {
return new Object[size];
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/collection/FastHashSetTest2.java
b/jena-core/src/test/java/org/apache/jena/mem2/collection/FastHashSetTest2.java
index 96c8384a91..99cbb73edd 100644
---
a/jena-core/src/test/java/org/apache/jena/mem2/collection/FastHashSetTest2.java
+++
b/jena-core/src/test/java/org/apache/jena/mem2/collection/FastHashSetTest2.java
@@ -20,6 +20,7 @@ package org.apache.jena.mem2.collection;
import org.junit.Before;
import org.junit.Test;
+import static org.apache.jena.testing_framework.GraphHelper.node;
import static org.junit.Assert.*;
/**
@@ -135,6 +136,50 @@ public class FastHashSetTest2 {
assertFalse(sut.anyMatchRandomOrder(k -> k.equals("d")));
}
+ @Test
+ public void testCopyConstructor() {
+ var original = new FastObjectHashSet();
+ original.addAndGetIndex(node("s"));
+ original.addAndGetIndex(node("s1"));
+ original.addAndGetIndex(node("s2"));
+ assertEquals(3, original.size());
+
+ var copy = new FastObjectHashSet(original);
+ assertEquals(3, copy.size());
+ assertTrue(copy.containsKey(node("s")));
+ assertTrue(copy.containsKey(node("s1")));
+ assertTrue(copy.containsKey(node("s2")));
+ assertFalse(copy.containsKey(node("s3")));
+ }
+
+ @Test
+ public void testCopyConstructorAddAndDeleteHasNoSideEffects() {
+ var original = new FastObjectHashSet();
+ original.addAndGetIndex(node("s"));
+ original.addAndGetIndex(node("s1"));
+ original.addAndGetIndex(node("s2"));
+ assertEquals(3, original.size());
+
+ var copy = new FastObjectHashSet(original);
+ copy.removeAndGetIndex(node("s1"));
+ copy.addAndGetIndex(node("s3"));
+ copy.addAndGetIndex(node("s4"));
+
+ assertEquals(4, copy.size());
+ assertTrue(copy.containsKey(node("s")));
+ assertFalse(copy.containsKey(node("s1")));
+ assertTrue(copy.containsKey(node("s2")));
+ assertTrue(copy.containsKey(node("s3")));
+ assertTrue(copy.containsKey(node("s4")));
+
+
+ assertEquals(3, original.size());
+ assertTrue(original.containsKey(node("s")));
+ assertTrue(original.containsKey(node("s1")));
+ assertTrue(original.containsKey(node("s2")));
+ assertFalse(original.containsKey(node("s3")));
+ }
+
private static class FastObjectHashSet extends FastHashSet<Object> {
@@ -142,6 +187,10 @@ public class FastHashSetTest2 {
super();
}
+ public FastObjectHashSet(FastHashSet<Object> setToCopy) {
+ super(setToCopy);
+ }
+
@Override
protected Object[] newKeysArray(int size) {
return new Object[size];
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/collection/HashCommonMapTest.java
b/jena-core/src/test/java/org/apache/jena/mem2/collection/HashCommonMapTest.java
index 7c325cb5d3..75d13c162d 100644
---
a/jena-core/src/test/java/org/apache/jena/mem2/collection/HashCommonMapTest.java
+++
b/jena-core/src/test/java/org/apache/jena/mem2/collection/HashCommonMapTest.java
@@ -18,26 +18,106 @@
package org.apache.jena.mem2.collection;
import org.apache.jena.graph.Node;
+import org.junit.Test;
+
+import java.util.function.UnaryOperator;
+
+import static org.apache.jena.testing_framework.GraphHelper.node;
+import static org.junit.Assert.assertEquals;
public class HashCommonMapTest extends AbstractJenaMapNodeTest {
@Override
protected JenaMap<Node, Object> createNodeMap() {
- return new HashCommonMap<Node, Object>(10) {
- @Override
- public void clear() {
- super.clear(10);
- }
-
- @Override
- protected Object[] newValuesArray(int size) {
- return new Object[size];
- }
-
- @Override
- protected Node[] newKeysArray(int size) {
- return new Node[size];
- }
- };
+ return new HashCommonNodeObjectMap(10);
+ }
+
+ @Test
+ public void testCopyConstructor() {
+ var original = new HashCommonNodeObjectMap(10);
+ original.put(node("s"), 0);
+ original.put(node("s1"), 1);
+ original.put(node("s2"), 2);
+ assertEquals(3, original.size());
+
+ var copy = new HashCommonNodeObjectMap(original);
+ assertEquals(3, copy.size());
+ assertEquals(0, (int) copy.get(node("s")));
+ assertEquals(1, (int) copy.get(node("s1")));
+ assertEquals(2, (int) copy.get(node("s2")));
+ }
+
+ @Test
+ public void testCopyConstructorWithValueMapping() {
+ var original = new HashCommonNodeObjectMap(10);
+ original.put(node("s"), 0);
+ original.put(node("s1"), 1);
+ original.put(node("s2"), 2);
+ assertEquals(3, original.size());
+
+ var copy = new HashCommonNodeObjectMap(original, i -> (int) i + 1);
+ assertEquals(3, copy.size());
+ assertEquals(1, (int) copy.get(node("s")));
+ assertEquals(2, (int) copy.get(node("s1")));
+ assertEquals(3, (int) copy.get(node("s2")));
+
+ assertEquals(0, (int) original.get(node("s")));
+ assertEquals(1, (int) original.get(node("s1")));
+ assertEquals(2, (int) original.get(node("s2")));
+ }
+
+ @Test
+ public void testCopyConstructorAddAndDeleteHasNoSideEffects() {
+ var original = new HashCommonNodeObjectMap(10);
+ original.put(node("s"), 0);
+ original.put(node("s1"), 1);
+ original.put(node("s2"), 2);
+ assertEquals(3, original.size());
+
+ var copy = new HashCommonNodeObjectMap(original);
+ copy.tryRemove(node("s1"));
+ copy.put(node("s3"), 3);
+ copy.put(node("s4"), 4);
+
+ assertEquals(4, copy.size());
+ assertEquals(0, (int) copy.get(node("s")));
+ assertEquals(2, (int) copy.get(node("s2")));
+ assertEquals(3, (int) copy.get(node("s3")));
+ assertEquals(4, (int) copy.get(node("s4")));
+
+
+ assertEquals(3, original.size());
+ assertEquals(0, (int) original.get(node("s")));
+ assertEquals(1, (int) original.get(node("s1")));
+ assertEquals(2, (int) original.get(node("s2")));
+ }
+
+ private static class HashCommonNodeObjectMap extends HashCommonMap<Node,
Object> {
+ protected HashCommonNodeObjectMap(int initialCapacity) {
+ super(initialCapacity);
+ }
+
+ protected HashCommonNodeObjectMap(HashCommonMap<Node, Object>
mapToCopy) {
+ super(mapToCopy);
+ }
+
+ protected HashCommonNodeObjectMap(HashCommonMap<Node, Object>
mapToCopy, UnaryOperator<Object> valueProcessor) {
+ super(mapToCopy, valueProcessor);
+ }
+
+ @Override
+ public void clear() {
+ super.clear(10);
+ }
+
+ @Override
+ protected Object[] newValuesArray(int size) {
+ return new Object[size];
+ }
+
+ @Override
+ protected Node[] newKeysArray(int size) {
+ return new Node[size];
+ }
}
}
\ No newline at end of file
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/collection/HashCommonSetTest.java
b/jena-core/src/test/java/org/apache/jena/mem2/collection/HashCommonSetTest.java
index 5d8cb36d74..83fa2bb073 100644
---
a/jena-core/src/test/java/org/apache/jena/mem2/collection/HashCommonSetTest.java
+++
b/jena-core/src/test/java/org/apache/jena/mem2/collection/HashCommonSetTest.java
@@ -18,22 +18,80 @@
package org.apache.jena.mem2.collection;
import org.apache.jena.graph.Triple;
+import org.junit.Test;
+
+import static org.apache.jena.testing_framework.GraphHelper.triple;
+import static org.junit.Assert.*;
public class HashCommonSetTest extends AbstractJenaSetTripleTest {
@Override
protected JenaSet<Triple> createTripleSet() {
- return new HashCommonSet<Triple>(10) {
- @Override
- protected Triple[] newKeysArray(int size) {
- return new Triple[size];
- }
-
- @Override
- public void clear() {
- super.clear(10);
- }
- };
+ return new HashCommonTripleSet();
+ }
+
+ @Test
+ public void testCopyConstructor() {
+ var original = new HashCommonTripleSet();
+ original.tryAdd(triple("s p o"));
+ original.tryAdd(triple("s1 p1 o1"));
+ original.tryAdd(triple("s2 p2 o2"));
+ assertEquals(3, original.size());
+
+ var copy = new HashCommonTripleSet(original);
+ assertEquals(3, copy.size());
+ assertTrue(copy.containsKey(triple("s p o")));
+ assertTrue(copy.containsKey(triple("s1 p1 o1")));
+ assertTrue(copy.containsKey(triple("s2 p2 o2")));
+ assertFalse(copy.containsKey(triple("s3 p3 o3")));
+ }
+
+ @Test
+ public void testCopyConstructorAddAndDeleteHasNoSideEffects() {
+ var original = new HashCommonTripleSet();
+ original.tryAdd(triple("s p o"));
+ original.tryAdd(triple("s1 p1 o1"));
+ original.tryAdd(triple("s2 p2 o2"));
+ assertEquals(3, original.size());
+
+ var copy = new HashCommonTripleSet(original);
+ copy.tryRemove(triple("s1 p1 o1"));
+ copy.tryAdd(triple("s3 p3 o3"));
+ copy.tryAdd(triple("s4 p4 o4"));
+
+ assertEquals(4, copy.size());
+ assertTrue(copy.containsKey(triple("s p o")));
+ assertFalse(copy.containsKey(triple("s1 p1 o1")));
+ assertTrue(copy.containsKey(triple("s2 p2 o2")));
+ assertTrue(copy.containsKey(triple("s3 p3 o3")));
+ assertTrue(copy.containsKey(triple("s4 p4 o4")));
+
+
+ assertEquals(3, original.size());
+ assertTrue(original.containsKey(triple("s p o")));
+ assertTrue(original.containsKey(triple("s1 p1 o1")));
+ assertTrue(original.containsKey(triple("s2 p2 o2")));
+ assertFalse(original.containsKey(triple("s3 p3 o3")));
+ }
+
+ private static class HashCommonTripleSet extends HashCommonSet<Triple> {
+ public HashCommonTripleSet() {
+ super(10);
+ }
+
+ public HashCommonTripleSet(HashCommonSet<Triple> setToCopy) {
+ super(setToCopy);
+ }
+
+ @Override
+ protected Triple[] newKeysArray(int size) {
+ return new Triple[size];
+ }
+
+ @Override
+ public void clear() {
+ super.clear(10);
+ }
}
}
\ No newline at end of file
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/store/AbstractTripleStoreTest.java
b/jena-core/src/test/java/org/apache/jena/mem2/store/AbstractTripleStoreTest.java
index 56fd3c2e72..56012cd1db 100644
---
a/jena-core/src/test/java/org/apache/jena/mem2/store/AbstractTripleStoreTest.java
+++
b/jena-core/src/test/java/org/apache/jena/mem2/store/AbstractTripleStoreTest.java
@@ -999,4 +999,86 @@ public abstract class AbstractTripleStoreTest {
NodeFactory.createURI("R"))));
}
+ @Test
+ public void testCopy() {
+ sut.add(triple("s p o"));
+ sut.add(triple("s1 p1 o1"));
+ sut.add(triple("s2 p2 o2"));
+ assertEquals(3, sut.countTriples());
+
+ var copy = sut.copy();
+ assertEquals(3, copy.countTriples());
+ assertTrue(copy.contains(triple("s p o")));
+ assertTrue(copy.contains(triple("s1 p1 o1")));
+ assertTrue(copy.contains(triple("s2 p2 o2")));
+ assertFalse(copy.contains(triple("s3 p3 o3")));
+ }
+
+ @Test
+ public void testCopyHasNoSideEffects() {
+ sut.add(triple("s p o"));
+ sut.add(triple("s1 p1 o1"));
+ sut.add(triple("s2 p2 o2"));
+ assertEquals(3, sut.countTriples());
+
+ var copy = sut.copy();
+ copy.remove(triple("s1 p1 o1"));
+ copy.add(triple("s3 p3 o3"));
+ copy.add(triple("s4 p4 o4"));
+
+ assertEquals(4, copy.countTriples());
+ assertTrue(copy.contains(triple("s p o")));
+ assertFalse(copy.contains(triple("s1 p1 o1")));
+ assertTrue(copy.contains(triple("s2 p2 o2")));
+ assertTrue(copy.contains(triple("s3 p3 o3")));
+ assertTrue(copy.contains(triple("s4 p4 o4")));
+
+
+ assertEquals(3, sut.countTriples());
+ assertTrue(sut.contains(triple("s p o")));
+ assertTrue(sut.contains(triple("s1 p1 o1")));
+ assertTrue(sut.contains(triple("s2 p2 o2")));
+ assertFalse(sut.contains(triple("s3 p3 o3")));
+ }
+
+ @Test
+ public void testCopyWithEnoughTriplesToUseHashedBunched() {
+ for (int i = 0; i < 100; i++) {
+ sut.add(triple("s p" + i + " o" + i));
+ }
+ assertEquals(100, sut.countTriples());
+
+ var copy = sut.copy();
+ assertEquals(100, copy.countTriples());
+ assertTrue(copy.contains(triple("s p0 o0")));
+ assertTrue(copy.contains(triple("s p99 o99")));
+ assertFalse(copy.contains(triple("s p100 o100")));
+ }
+
+ @Test
+ public void testCopyHasNoSideEffectsWithEnoughTriplesToUseHashedBunched() {
+ for (int i = 0; i < 100; i++) {
+ sut.add(triple("s p" + i + " o" + i));
+ }
+ assertEquals(100, sut.countTriples());
+
+
+ var copy = sut.copy();
+ copy.remove(triple("s p50 o50"));
+ copy.add(triple("s p100 o100"));
+ copy.add(triple("s p101 o101"));
+
+ assertEquals(101, copy.countTriples());
+ assertTrue(copy.contains(triple("s p0 o0")));
+ assertFalse(copy.contains(triple("s p50 o50")));
+ assertTrue(copy.contains(triple("s p100 o100")));
+ assertTrue(copy.contains(triple("s p101 o101")));
+
+
+ assertEquals(100, sut.countTriples());
+ assertTrue(sut.contains(triple("s p0 o0")));
+ assertTrue(sut.contains(triple("s p99 o99")));
+ assertFalse(sut.contains(triple("s p100 o100")));
+ }
+
}
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/store/fast/FastArrayBunchTest.java
b/jena-core/src/test/java/org/apache/jena/mem2/store/fast/FastArrayBunchTest.java
index 83fd8aef27..29ccd7bd6f 100644
---
a/jena-core/src/test/java/org/apache/jena/mem2/store/fast/FastArrayBunchTest.java
+++
b/jena-core/src/test/java/org/apache/jena/mem2/store/fast/FastArrayBunchTest.java
@@ -23,14 +23,29 @@ import org.apache.jena.mem2.collection.JenaSet;
public class FastArrayBunchTest extends AbstractJenaSetTripleTest {
-
@Override
protected JenaSet<Triple> createTripleSet() {
- return new FastArrayBunch() {
- @Override
- public boolean areEqual(Triple a, Triple b) {
- return a.equals(b);
- }
- };
+ return new FastTripleArrayBunch();
+ }
+
+ private static class FastTripleArrayBunch extends FastArrayBunch {
+
+ public FastTripleArrayBunch() {
+ super();
+ }
+
+ private FastTripleArrayBunch(FastTripleArrayBunch bunchToCopy) {
+ super(bunchToCopy);
+ }
+
+ @Override
+ public FastTripleArrayBunch copy() {
+ return new FastTripleArrayBunch(this);
+ }
+
+ @Override
+ public boolean areEqual(final Triple a, final Triple b) {
+ return a.equals(b);
+ }
}
}
\ No newline at end of file
diff --git
a/jena-core/src/test/java/org/apache/jena/mem2/store/fast/FastHashedTripleBunchTest.java
b/jena-core/src/test/java/org/apache/jena/mem2/store/fast/FastHashedTripleBunchTest.java
index 7efa52a250..81b68b54b7 100644
---
a/jena-core/src/test/java/org/apache/jena/mem2/store/fast/FastHashedTripleBunchTest.java
+++
b/jena-core/src/test/java/org/apache/jena/mem2/store/fast/FastHashedTripleBunchTest.java
@@ -34,30 +34,39 @@ public class FastHashedTripleBunchTest extends
AbstractJenaSetTripleTest {
@Test
public void testConstructorWithArrayBunchEmpty() {
- final var arrayBunch = new FastArrayBunch() {
-
- @Override
- public boolean areEqual(Triple a, Triple b) {
- return a.equals(b);
- }
- };
+ final var arrayBunch = new FastTripleArrayBunch();
final var sut = new FastHashedTripleBunch(arrayBunch);
assertEquals(0, sut.size());
}
@Test
public void testConstructorWithArrayBunch() {
- final var arrayBunch = new FastArrayBunch() {
-
- @Override
- public boolean areEqual(Triple a, Triple b) {
- return a.equals(b);
- }
- };
+ final var arrayBunch = new FastTripleArrayBunch();
arrayBunch.tryAdd(triple("s P o"));
arrayBunch.tryAdd(triple("s P o1"));
arrayBunch.tryAdd(triple("s P o2"));
final var sut = new FastHashedTripleBunch(arrayBunch);
assertEquals(3, sut.size());
}
+
+ private static class FastTripleArrayBunch extends FastArrayBunch {
+
+ public FastTripleArrayBunch() {
+ super();
+ }
+
+ private FastTripleArrayBunch(FastTripleArrayBunch bunchToCopy) {
+ super(bunchToCopy);
+ }
+
+ @Override
+ public FastTripleArrayBunch copy() {
+ return new FastTripleArrayBunch(this);
+ }
+
+ @Override
+ public boolean areEqual(final Triple a, final Triple b) {
+ return a.equals(b);
+ }
+ }
}
\ No newline at end of file