blob: b9ef20818a5ed514479c847b9ec09a3270c2ca91 [file] [log] [blame]
/*
* 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.mem2.store.legacy;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.mem2.collection.HashCommonMap;
import org.apache.jena.mem2.collection.JenaSet;
import org.apache.jena.mem2.store.TripleStore;
import org.apache.jena.util.iterator.ExtendedIterator;
import org.apache.jena.util.iterator.NiceIterator;
import org.apache.jena.util.iterator.SingletonIterator;
import java.util.stream.Stream;
/**
* Successor of {@link org.apache.jena.mem.GraphTripleStoreMem} that uses term-equality
* instead of literal value equality.
* This implementation also does not support {@link java.util.Iterator#remove()}.
* <p>
* Inner structure:
* - three {@link NodeToTriplesMapMem} instances for each of the three triple fields (subject, predicate, object)
* - each of these maps is a {@link HashCommonMap} with {@link Node} keys and {@link JenaSet} values.
* - for up to 9 triples with the same subject, predicate or object, the {@link JenaSet} is
* a {@link ArrayBunch}, otherwise it is a {@link HashedTripleBunch}.
* <p>
* Additional optimizations:
* - because we know that if a triple exists in one of the maps, it also exists in the other two, we can use the
* {@link org.apache.jena.mem2.collection.JenaSet#addUnchecked(java.lang.Object)} and
* {@link org.apache.jena.mem2.collection.JenaMapSetCommon#removeUnchecked(java.lang.Object)} methods to avoid
* unnecessary checks.
*/
public class LegacyTripleStore implements TripleStore {
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) {
if (subjects.tryAdd(triple)) {
predicates.addUnchecked(triple);
objects.addUnchecked(triple);
}
}
@Override
public void remove(Triple triple) {
if (subjects.tryRemove(triple)) {
predicates.removeUnchecked(triple);
objects.removeUnchecked(triple);
}
}
@Override
public void clear() {
subjects.clear();
predicates.clear();
objects.clear();
}
@Override
public int countTriples() {
return subjects.size();
}
@Override
public boolean isEmpty() {
return subjects.isEmpty();
}
@Override
public boolean contains(Triple tripleMatch) {
if (tripleMatch.isConcrete()) {
return subjects.containsKey(tripleMatch);
}
final Node pm = tripleMatch.getPredicate();
final Node om = tripleMatch.getObject();
final Node sm = tripleMatch.getSubject();
if (sm.isConcrete())
return subjects.containsMatch(sm, pm, om);
else if (om.isConcrete())
return objects.containsMatch(om, sm, pm);
else if (pm.isConcrete())
return predicates.containsMatch(pm, om, sm);
else
return !this.isEmpty();
}
@Override
public Stream<Triple> stream() {
return subjects.keyStream();
}
@Override
public Stream<Triple> stream(Triple tripleMatch) {
if (tripleMatch.isConcrete()) {
return subjects.containsKey(tripleMatch) ? Stream.of(tripleMatch) : Stream.empty();
}
final Node pm = tripleMatch.getPredicate();
final Node om = tripleMatch.getObject();
final Node sm = tripleMatch.getSubject();
if (sm.isConcrete())
return subjects.streamForMatches(sm, pm, om);
else if (om.isConcrete())
return objects.streamForMatches(om, sm, pm);
else if (pm.isConcrete())
return predicates.streamForMatches(pm, om, sm);
else
return subjects.keyStream();
}
@Override
public ExtendedIterator<Triple> find(Triple tripleMatch) {
if (tripleMatch.isConcrete()) {
return subjects.containsKey(tripleMatch) ? new SingletonIterator<>(tripleMatch) : NiceIterator.emptyIterator();
}
final Node pm = tripleMatch.getPredicate();
final Node om = tripleMatch.getObject();
final Node sm = tripleMatch.getSubject();
if (sm.isConcrete())
return subjects.iteratorForMatches(sm, pm, om);
else if (om.isConcrete())
return objects.iteratorForMatches(om, sm, pm);
else if (pm.isConcrete())
return predicates.iteratorForMatches(pm, om, sm);
else
return subjects.keyIterator();
}
@Override
public LegacyTripleStore copy() {
return new LegacyTripleStore(this);
}
}