/*******************************************************************************
* Copyright (c) 2009 Centrum Wiskunde en Informatica (CWI)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Arnold Lankamp - interfaces and implementation
* Michael Steindorfer - performance improvements
*******************************************************************************/
package org.rascalmpl.value.impl.fast;
import java.util.HashSet;
import org.rascalmpl.value.IList;
import org.rascalmpl.value.IListWriter;
import org.rascalmpl.value.ITuple;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.exceptions.IllegalOperationException;
import org.rascalmpl.value.impl.util.collections.ShareableValuesHashSet;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.value.type.TypeFactory;
public class RelationalFunctionsOnList {
protected final static TypeFactory typeFactory = TypeFactory.getInstance();
protected final static Type voidType = typeFactory.voidType();
public static int arity(IList rel) {
return rel.getElementType().getArity();
}
public static IList carrier(IList rel1) {
Type newType = rel1.getType().carrier();
IListWriter w = List.createListWriter(newType.getElementType());
HashSet<IValue> cache = new HashSet<>();
for (IValue v : rel1) {
ITuple t = (ITuple) v;
for(IValue e : t){
if(!cache.contains(e)){
cache.add(e);
w.append(e);
}
}
}
return w.done();
}
public static IList domain(IList rel1) {
Type lrelType = rel1.getType();
IListWriter w = List.createListWriter(lrelType.getFieldType(0));
HashSet<IValue> cache = new HashSet<>();
for (IValue elem : rel1) {
ITuple tuple = (ITuple) elem;
IValue e = tuple.get(0);
if(!cache.contains(e)){
cache.add(e);
w.append(e);
}
}
return w.done();
}
public static IList range(IList rel1) {
Type lrelType = rel1.getType();
int last = lrelType.getArity() - 1;
IListWriter w = List.createListWriter(lrelType.getFieldType(last));
HashSet<IValue> cache = new HashSet<>();
for (IValue elem : rel1) {
ITuple tuple = (ITuple) elem;
IValue e = tuple.get(last);
if(!cache.contains(e)){
cache.add(e);
w.append(e);
}
}
return w.done();
}
public static IList compose(IList rel1, IList rel2) {
Type otherTupleType = rel2.getType().getFieldTypes();
if(rel1.getElementType() == voidType) return rel1;
if(otherTupleType == voidType) return rel2;
if(rel1.getElementType().getArity() != 2 || otherTupleType.getArity() != 2) throw new IllegalOperationException("compose", rel1.getElementType(), otherTupleType);
// Relaxed type constraint:
if(!rel1.getElementType().getFieldType(1).comparable(otherTupleType.getFieldType(0))) throw new IllegalOperationException("compose", rel1.getElementType(), otherTupleType);
Type[] newTupleFieldTypes = new Type[]{rel1.getElementType().getFieldType(0), otherTupleType.getFieldType(1)};
Type tupleType = typeFactory.tupleType(newTupleFieldTypes);
IListWriter w = new ListWriter(tupleType);
for (IValue v1 : rel1) {
ITuple tuple1 = (ITuple) v1;
for (IValue t2 : rel2) {
ITuple tuple2 = (ITuple) t2;
if (tuple1.get(1).isEqual(tuple2.get(0))) {
w.append(Tuple.newTuple(tuple1.get(0), tuple2.get(1)));
}
}
}
return w.done();
}
public static IList closure(IList rel1) {
Type resultType = rel1.getType().closure(); // will throw exception if not binary and reflexive
IList tmp = rel1;
int prevCount = 0;
ShareableValuesHashSet addedTuples = new ShareableValuesHashSet();
while (prevCount != tmp.length()) {
prevCount = tmp.length();
IList tcomp = compose(tmp, tmp);
IListWriter w = List.createListWriter(resultType.getElementType());
for(IValue t1 : tcomp){
if(!tmp.contains(t1)){
if(!addedTuples.contains(t1)){
addedTuples.add(t1);
w.append(t1);
}
}
}
tmp = tmp.concat(w.done());
addedTuples.clear();
}
return tmp;
}
public static IList closureStar(IList rel1) {
Type resultType = rel1.getType().closure();
// an exception will have been thrown if the type is not acceptable
IListWriter reflex = List.createListWriter(resultType.getElementType());
for (IValue e: carrier(rel1)) {
reflex.insert(Tuple.newTuple(new IValue[] {e, e}));
}
return closure(rel1).concat(reflex.done());
}
public static IList project(IList rel1, int... fields) {
IListWriter w = ValueFactory.getInstance().listWriter();
for (IValue v : rel1) {
w.append(((ITuple) v).select(fields));
}
return w.done();
}
public static IList projectByFieldNames(IList rel1, String... fields) {
int[] indexes = new int[fields.length];
int i = 0;
if (rel1.getType().getFieldTypes().hasFieldNames()) {
for (String field : fields) {
indexes[i++] = rel1.getType().getFieldTypes().getFieldIndex(field);
}
return project(rel1, indexes);
}
throw new IllegalOperationException("select with field names", rel1.getType());
}
}