/*
* 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.sparql.core.mem;
import java.util.function.Consumer;
import org.apache.jena.atlas.lib.tuple.TConsumer3;
import org.apache.jena.atlas.lib.tuple.TConsumer4;
import org.apache.jena.atlas.lib.tuple.TFunction3;
import org.apache.jena.atlas.lib.tuple.TFunction4;
import org.apache.jena.atlas.lib.tuple.TupleMap;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.sparql.core.Quad;
/**
* A table of {@code TupleType} tuples that uses an internal order recorded via {@link TupleMap}. In this code, names
* {@code g}, {@code s}, {@code p} and {@code o} are used for the components of a tuple in canonical order, and
* {@code x1} through {@code x4} are used for the components of a tuple in internal order.
*
* @param <TupleType> the tuple type in which an instance of this class works, typically {@link Triple} or {@link Quad}
* @param <ConsumerType> a consumer type that can accept the elements of a {@code TupleType}, typically
* {@link TConsumer3} or {@link TConsumer4}
*/
public abstract class OrderedTupleTable<TupleType, ConsumerType> implements TupleTable<TupleType> {
/**
* The order in which elements are held in this table, e.g. SPO or OSGP.
*/
protected final TupleMap order;
/**
* The reverse of {@link #order}.
*/
protected final TupleMap reverse;
/**
* @param order the order of elements in this table
*/
public OrderedTupleTable(final TupleMap order) {
this.order = order;
this.reverse = order.reverse();
}
/**
* @return a consumer that adds a tuple in the form of the elements in a {@code TupleType} to this table
*/
protected abstract ConsumerType add();
/**
* @return a consumer that removes a tuple in the form of the elements in a {@code TupleType} from this table
*/
protected abstract ConsumerType delete();
protected Consumer<Quad> map(final TConsumer4<Node> consumer) {
return q -> {
final Node g = q.getGraph();
final Node s = q.getSubject();
final Node p = q.getPredicate();
final Node o = q.getObject();
final Node x1 = get(order.mapIdx(0), g, s, p, o);
final Node x2 = get(order.mapIdx(1), g, s, p, o);
final Node x3 = get(order.mapIdx(2), g, s, p, o);
final Node x4 = get(order.mapIdx(3), g, s, p, o);
consumer.accept(x1, x2, x3, x4);
};
}
protected <X> TFunction4<Node, X> map(final TFunction4<Node, X> f) {
return (g, s, p, o) -> apply(order, g, s, p, o, f);
}
protected Quad unmap(final Node x1, final Node x2, final Node x3, final Node x4) {
return apply(reverse, x1, x2, x3, x4, Quad::new);
}
protected Consumer<Triple> map(final TConsumer3<Node> consumer) {
return t -> {
final Node s = t.getSubject();
final Node p = t.getPredicate();
final Node o = t.getObject();
final Node x1 = get(order.mapIdx(0), s, p, o);
final Node x2 = get(order.mapIdx(1), s, p, o);
final Node x3 = get(order.mapIdx(2), s, p, o);
consumer.accept(x1, x2, x3);
};
}
protected <T, X> TFunction3<T, X> map(final TFunction3<T, X> f) {
return (s, p, o) -> OrderedTupleTable.apply(order, s, p, o, f);
}
protected Triple unmap(final Node x1, final Node x2, final Node x3) {
return apply(reverse, x1, x2, x3, Triple::new);
}
private static <X> X get(final int i, final X x1, final X x2, final X x3) {
switch (i) {
case 0:
return x1;
case 1:
return x2;
case 2:
return x3;
default:
throw new IndexOutOfBoundsException("Triples have components 0, 1, 2 but index = " + i + "!");
}
}
private static <X> X get(final int i, final X x1, final X x2, final X x3, final X x4) {
switch (i) {
case 0:
return x1;
case 1:
return x2;
case 2:
return x3;
case 3:
return x4;
default:
throw new IndexOutOfBoundsException("Quads have components 0, 1, 2, 3 but index = " + i + "!");
}
}
private static <X, Z> Z apply(final TupleMap tupleMap, final X x1, final X x2, final X x3, final X x4,
final TFunction4<X, Z> f) {
final X x1a = get(tupleMap.mapIdx(0), x1, x2, x3, x4);
final X x2a = get(tupleMap.mapIdx(1), x1, x2, x3, x4);
final X x3a = get(tupleMap.mapIdx(2), x1, x2, x3, x4);
final X x4a = get(tupleMap.mapIdx(3), x1, x2, x3, x4);
return f.apply(x1a, x2a, x3a, x4a);
}
private static <X, Z> Z apply(final TupleMap ordering, final X x1, final X x2, final X x3,
final TFunction3<X, Z> f) {
final X x1a = get(ordering.mapIdx(0), x1, x2, x3);
final X x2a = get(ordering.mapIdx(1), x1, x2, x3);
final X x3a = get(ordering.mapIdx(2), x1, x2, x3);
return f.apply(x1a, x2a, x3a);
}
}