X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.graph%2Fsrc%2Forg%2Fsimantics%2Fgraph%2Fquery%2FCompositeGraph.java;fp=bundles%2Forg.simantics.graph%2Fsrc%2Forg%2Fsimantics%2Fgraph%2Fquery%2FCompositeGraph.java;h=bad2777288a8bea52267dac8fbf76ab52a1e0f4c;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.graph/src/org/simantics/graph/query/CompositeGraph.java b/bundles/org.simantics.graph/src/org/simantics/graph/query/CompositeGraph.java new file mode 100644 index 000000000..bad277728 --- /dev/null +++ b/bundles/org.simantics.graph/src/org/simantics/graph/query/CompositeGraph.java @@ -0,0 +1,363 @@ +package org.simantics.graph.query; + +import gnu.trove.list.array.TIntArrayList; +import gnu.trove.map.hash.THashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.databoard.adapter.RuntimeAdaptException; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.mutable.Variant; +import org.simantics.databoard.type.Datatype; +import org.simantics.graph.store.GraphStore; +import org.simantics.graph.store.IdRes; +import org.simantics.graph.store.IdentityStore; +import org.simantics.graph.store.PathPattern; +import org.simantics.graph.store.StatementStore; + +public class CompositeGraph implements IGraph { + + ArrayList fragments = new ArrayList(); + Paths paths; + + public CompositeGraph(Paths paths) { + this.paths = paths; + } + + public void addFragment(GraphStore fragment) { + fragments.add(fragment); + } + + public void undoAddFragment() { + fragments.remove(fragments.size()-1); + } + + public void addFragments(Collection fragments) { + fragments.addAll(fragments); + } + + protected void rawGetObjects(GraphStore fragment, int subject, Res predicate, Collection result) { + int predicateId; + if(predicate instanceof Path) { + predicateId = fragment.identities.pathToId((Path)predicate); + if(predicateId < 0) + return; + } + else { + IdRes idPredicate = (IdRes)predicate; + if(idPredicate.fragment != fragment) + return; + predicateId = idPredicate.id; + } + + TIntArrayList objects = fragment.statements.getObjects(subject, predicateId); + fragment.addIdsToResult(objects, result); + } + + private void rawGetObjects(Res subject, Res predicate, Collection result) { + if(subject instanceof Path) { + Path path = (Path)subject; + for(GraphStore fragment : fragments) { + int id = fragment.identities.pathToId(path); + if(id >= 0) + rawGetObjects(fragment, id, predicate, result); + } + } + else { + IdRes idRes = (IdRes)subject; + rawGetObjects(idRes.fragment, idRes.id, predicate, result); + } + } + + public boolean hasRawObjects(Res subject, Path predicate) { + ArrayList result = new ArrayList(); + rawGetObjects(subject, predicate, result); + return !result.isEmpty(); + } + + @Override + public Collection rawGetObjects(Res subject, Res predicate) { + ArrayList result = new ArrayList(); + rawGetObjects(subject, predicate, result); + return result; + } + + @Override + public Res singleRawObject(Res subject, Res predicate) throws NoUniqueObjectException { + ArrayList result = new ArrayList(1); + rawGetObjects(subject, predicate, result); + if(result.size() != 1) + throw new NoUniqueObjectException("No unique objects (" + result.size()+ ") for " + + subject + " -> " + predicate); + return result.get(0); + } + + @Override + public Collection getTypes(Res subject) { + THashSet result = new THashSet(); + rawGetObjects(subject, paths.InstanceOf, result); + for(Res type : result.toArray(new Res[result.size()])) + collectSupertypes(type, result); + return result; + } + + public Collection getSupertypes(Res subject) { + THashSet result = new THashSet(); + result.add(subject); + collectSupertypes(subject, result); + return result; + } + + private void collectSupertypes(Res type, THashSet result) { + for(Res supertype : rawGetObjects(type, paths.Inherits)) + if(result.add(supertype)) + collectSupertypes(supertype, result); + } + + @Override + public Collection getObjects(Res subject, Res predicate) { + ArrayList result = new ArrayList(); + rawGetObjects(subject, predicate, result); + for(Res type : getTypes(subject)) + for(Res assertion : rawGetObjects(type, paths.Asserts)) { + Res pred = singleRawObject(assertion, paths.HasPredicate); + if(equals(pred, predicate)) + result.add(singleRawObject(assertion, paths.HasObject)); + } + return result; + } + + public Collection getAssertedObjects(Res subject, Path predicate) { + ArrayList result = new ArrayList(); + for(Res type : getSupertypes(subject)) + for(Res assertion : rawGetObjects(type, paths.Asserts)) { + Res pred = singleRawObject(assertion, paths.HasPredicate); + if(equals(pred, predicate)) + result.add(singleRawObject(assertion, paths.HasObject)); + } + return result; + } + + private static boolean equals(Res r1, Res r2) { + return r1.equals(r2); + } + + interface ResourceProcedure { + public void execute(GraphStore fragment, int id); + } + + interface ResourceFunction { + public T execute(GraphStore fragment, int id); + } + + public void forEachFragmentContaining(Res resource, ResourceProcedure proc) { + if(resource instanceof Path) { + Path path = (Path)resource; + for(GraphStore fragment : fragments) { + int id = fragment.identities.pathToId(path); + if(id >= 0) + proc.execute(fragment, id); + } + } + else { + IdRes res = (IdRes)resource; + proc.execute(res.fragment, res.id); + } + } + + public T apply(Res resource, ResourceFunction func) { + if(resource instanceof Path) { + Path path = (Path)resource; + for(GraphStore fragment : fragments) { + int id = fragment.identities.pathToId(path); + if(id >= 0) { + T value = func.execute(fragment, id); + if(value != null) + return value; + } + } + return null; + } + else { + IdRes res = (IdRes)resource; + return func.execute(res.fragment, res.id); + } + } + + private static ResourceFunction getDatatype = + new ResourceFunction() { + @Override + public Datatype execute(GraphStore fragment, int id) { + return fragment.values.getDatatypeValue(id); + } + }; + + private static ResourceFunction getValue = + new ResourceFunction() { + @Override + public Variant execute(GraphStore fragment, int id) { + return fragment.values.getByteValue(id); + } + }; + + THashMap datatypeCache = new THashMap(); + + @Override + public Datatype getDatatype(Res resource) { + for(Res dt : getObjects(resource, paths.HasDatatype)) { + Datatype type = datatypeCache.get(dt); + if(type == null) { + type = apply(dt, getDatatype); + datatypeCache.put(dt, type); + } + return type; + } + return null; + } + + @Override + public Datatype getAssertedDatatype(Res resource) { + for(Res dt : getAssertedObjects(resource, paths.HasDatatype)) { + Datatype type = datatypeCache.get(dt); + if(type == null) { + type = apply(dt, getDatatype); + datatypeCache.put(dt, type); + } + return type; + } + return null; + } + + @Override + public Variant getValue(Res resource) { + return apply(resource, getValue); + } + + @Override + public Object getValue(Res resource, Binding binding) throws NoValueException { + Variant value = getValue(resource); + if(value == null) + throw new NoValueException(); + try { + return value.getValue(binding); + } catch (AdaptException e) { + throw new RuntimeAdaptException(e); + } + } + + @Override + public void setValue(Res resource, Object value, Binding binding) { + final Variant variant = new Variant(binding, value); + apply(resource, new ResourceFunction() { + @Override + public Object execute(GraphStore fragment, int id) { + fragment.values.setValue(id, variant); + return null; + } + }); + } + + /** + * Tells in how many fragments the resource occurs. + */ + public int countOccurences(Res resource) { + if(resource instanceof IdRes) + return 1; + else if(resource instanceof Path) { + Path path = (Path)resource; + int count = 0; + for(GraphStore fragment : fragments) + if(fragment.identities.contains(path)) + ++count; + return count; + } + else + return 0; + } + + private void collectSubtypes(THashSet types, Res type) { + if(types.add(type)) + for(Res subtype : rawGetObjects(type, paths.SupertypeOf)) + collectSubtypes(types, subtype); + } + + @Override + public Collection getInstances(Res supertype) { + THashSet types = new THashSet(); + collectSubtypes(types, supertype); + + ArrayList result = new ArrayList(); + fragmentLoop: + for(GraphStore fragment : fragments) { + IdentityStore identities = fragment.identities; + StatementStore statements = fragment.statements; + + TIntHashSet ids = new TIntHashSet(types.size()); + for(Res type : types) { + if(type instanceof Path) { + int id = identities.pathToId((Path)type); + if(id >= 0) + ids.add(id); + } + else { + IdRes idRes = (IdRes)type; + if(idRes.fragment == fragment) + ids.add(idRes.id); + } + } + if(ids.isEmpty()) + continue; + + int instanceOfId = identities.pathToId(paths.InstanceOf); + if(instanceOfId < 0) + continue; + + int resourceCount = identities.getResourceCount(); + nextResource: + for(int i=0;i getChildren(Res res) { + if(res instanceof Path) { + THashSet result = new THashSet(); + for(GraphStore store : fragments) { + IdentityStore ids = store.identities; + int id = ids.pathToId((Path)res); + if(id >= 0) { + for(int child : ids.getChildren(id)) + result.add(store.idToRes(child)); + } + } + return result; + } + else + return Collections.emptyList(); + } + + public Collection searchByPattern(String pattern) { + THashSet result = new THashSet(); + PathPattern pathPattern = PathPattern.compile(pattern); + for(GraphStore store : fragments) + pathPattern.search(store.identities, result); + return result; + } + + @Override + public Paths getPaths() { + return paths; + } +}