blob: 58619455122f95089b3d7c373fed5b0942f846ab [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.mem;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.jena.graph.* ;
import org.apache.jena.graph.Triple.Field ;
import org.apache.jena.util.iterator.* ;
/**
A base class for in-memory graphs
*/
public abstract class NodeToTriplesMapBase
{
/**
The map from nodes to Bunch(Triple).
*/
public BunchMap bunchMap = new HashedBunchMap();
/**
The number of triples held in this NTM, maintained incrementally
(because it's a pain to compute from scratch).
*/
protected int size = 0;
protected final Field indexField;
protected final Field f2;
protected final Field f3;
public NodeToTriplesMapBase( Field indexField, Field f2, Field f3 )
{ this.indexField = indexField; this.f2 = f2; this.f3 = f3; }
/**
Add <code>t</code> to this NTM; the node <code>o</code> <i>must</i>
be the index node of the triple. Answer <code>true</code> iff the triple
was not previously in the set, ie, it really truly has been added.
*/
public abstract boolean add( Triple t );
/**
Remove <code>t</code> from this NTM. Answer <code>true</code> iff the
triple was previously in the set, ie, it really truly has been removed.
*/
public abstract boolean remove( Triple t );
public abstract ExtendedIterator<Triple> iterator( Object o, HashCommon.NotifyEmpty container );
/**
Answer true iff this NTM contains the concrete triple <code>t</code>.
*/
public abstract boolean contains( Triple t );
public abstract boolean containsBySameValueAs( Triple t );
/**
The values (usually nodes) which appear in the index position of the stored triples; useful
for eg listSubjects().
*/
public final Iterator<Object> domain()
{ return bunchMap.keyIterator(); }
protected final Object getIndexField( Triple t )
{ return indexField.getField( t ).getIndexingValue(); }
/**
Clear this NTM; it will contain no triples.
*/
public void clear()
{ bunchMap.clear(); size = 0; }
public int size()
{ return size; }
public void removedOneViaIterator()
{ size -= 1; }
public boolean isEmpty()
{ return size == 0; }
public abstract ExtendedIterator<Triple> iterator( Node index, Node n2, Node n3 );
/**
Answer an iterator over all the triples that are indexed by the item <code>y</code>.
Note that <code>y</code> need not be a Node (because of indexing values).
*/
public abstract ExtendedIterator<Triple> iteratorForIndexed( Object y );
/**
Answer an iterator over all the triples in this NTM.
*/
public ExtendedIterator<Triple> iterateAll()
{
return new NiceIterator<Triple>()
{
private final Iterator<TripleBunch> bunchIterator = bunchMap.iterator();
private Iterator<Triple> current = NullIterator.instance();
private NotifyMe emptier = new NotifyMe();
@Override public Triple next()
{
if (!hasNext()) noElements( "NodeToTriples iterator" );
return current.next();
}
class NotifyMe implements HashCommon.NotifyEmpty
{
@Override
public void emptied()
{ bunchIterator.remove(); }
}
@Override public boolean hasNext()
{
while (true)
{
if (current.hasNext()) return true;
if (!bunchIterator.hasNext()) return false;
current = bunchIterator.next().iterator( emptier );
}
}
@Override public void forEachRemaining(Consumer<? super Triple> action)
{
if (current != null) current.forEachRemaining(action);
bunchIterator.forEachRemaining(next ->
{
current = next.iterator();
current.forEachRemaining(action);
});
}
@Override public void remove()
{ current.remove(); }
};
}
public Stream<Triple> streamAll()
{
return StreamSupport.stream(bunchMap.spliterator(), false)
.flatMap(bunch -> StreamSupport.stream(bunch.spliterator(), false));
}
public Stream<Triple> stream( Node index, Node n2, Node n3 )
{
Object indexValue = index.getIndexingValue();
TripleBunch s = bunchMap.get( indexValue );
if (s == null) return Stream.empty();
var filter = FieldFilter.filterOn(f2, n2, f3, n3);
return filter.hasFilter()
? StreamSupport.stream(s.spliterator(), false).filter(filter.getFilter())
: StreamSupport.stream(s.spliterator(), false);
}
public boolean containsMatch( Node index, Node n2, Node n3 )
{
TripleBunch s = bunchMap.get( index.getIndexingValue() );
if (s == null)
return false;
var filter = FieldFilter.filterOn(f2, n2, f3, n3);
if (!filter.hasFilter())
return true;
var spliterator = s.spliterator();
final boolean[] found = {false};
Consumer<Triple> tester = triple -> found[0] = filter.getFilter().test(triple);
while (!found[0] && spliterator.tryAdvance(tester));
return found[0];
}
}