--- /dev/null
+package org.simantics.graph.store;\r
+\r
+import gnu.trove.list.array.TIntArrayList;\r
+import gnu.trove.map.hash.TIntIntHashMap;\r
+import gnu.trove.map.hash.TIntObjectHashMap;\r
+import gnu.trove.procedure.TIntObjectProcedure;\r
+import gnu.trove.procedure.TIntProcedure;\r
+import gnu.trove.procedure.TObjectProcedure;\r
+import gnu.trove.set.hash.TIntHashSet;\r
+\r
+/**\r
+ * Statement store indexes a set of statements. \r
+ * @author Hannu Niemistö\r
+ */\r
+public class StatementStore implements IStore {\r
+ \r
+ static private final TIntArrayList EMPTY_INT_LIST = new TIntArrayList(0); \r
+ \r
+ TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>> statements =\r
+ new TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>>();\r
+ \r
+ /**\r
+ * Adds a statement to the store.\r
+ * @param subject\r
+ * @param predicate\r
+ * @param object\r
+ */\r
+ public void add(int subject, int predicate, int object) {\r
+ assert(subject >= 0);\r
+ assert(predicate >= 0);\r
+ assert(object >= 0);\r
+ TIntObjectHashMap<TIntArrayList> localStatements = \r
+ statements.get(subject);\r
+ if(localStatements == null) {\r
+ localStatements = new TIntObjectHashMap<TIntArrayList>(3);\r
+ statements.put(subject, localStatements);\r
+ }\r
+ TIntArrayList objects = localStatements.get(predicate);\r
+ if(objects == null) {\r
+ objects = new TIntArrayList(2);\r
+ localStatements.put(predicate, objects);\r
+ }\r
+ objects.add(object);\r
+ }\r
+ \r
+ public void map(final TIntIntHashMap map) {\r
+ final TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>> newStatements = \r
+ new TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>>(statements.size()*2+1);\r
+ statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {\r
+ \r
+ TIntObjectHashMap<TIntArrayList> newLocalStatements;\r
+ TIntArrayList newObjects;\r
+ \r
+ TIntProcedure objectProcedure = new TIntProcedure() { \r
+ @Override\r
+ public boolean execute(int o) {\r
+ if(map.contains(o))\r
+ o = map.get(o);\r
+ newObjects.add(o);\r
+ return true;\r
+ }\r
+ };\r
+ \r
+ TIntObjectProcedure<TIntArrayList> predicateProcedure = new TIntObjectProcedure<TIntArrayList>() {\r
+ @Override\r
+ public boolean execute(int p, TIntArrayList objects) {\r
+ if(map.contains(p))\r
+ p = map.get(p);\r
+ TIntArrayList exObjects = newLocalStatements.get(p);\r
+ if(exObjects == null) {\r
+ IndexMappingUtils.map(map, objects);\r
+ newLocalStatements.put(p, objects);\r
+ }\r
+ else {\r
+ newObjects = exObjects;\r
+ objects.forEach(objectProcedure);\r
+ }\r
+ return true;\r
+ }\r
+ };\r
+ \r
+ @Override\r
+ public boolean execute(int s, TIntObjectHashMap<TIntArrayList> localStatements) {\r
+ if(map.contains(s))\r
+ s = map.get(s);\r
+ TIntObjectHashMap<TIntArrayList> exLocalStatements = newStatements.get(s); \r
+ if(exLocalStatements == null) {\r
+ exLocalStatements = new TIntObjectHashMap<TIntArrayList>(localStatements.size()*2 + 1);\r
+ newStatements.put(s, exLocalStatements);\r
+ }\r
+ newLocalStatements = exLocalStatements;\r
+ localStatements.forEachEntry(predicateProcedure);\r
+ return true;\r
+ }\r
+ });\r
+ statements = newStatements;\r
+ }\r
+ \r
+ public void forStatements(final IStatementProcedure proc) {\r
+ statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {\r
+ @Override\r
+ public boolean execute(final int s, TIntObjectHashMap<TIntArrayList> localStatements) {\r
+ localStatements.forEachEntry(new TIntObjectProcedure<TIntArrayList>() {\r
+ @Override\r
+ public boolean execute(final int p, TIntArrayList objects) {\r
+ objects.forEach(new TIntProcedure() { \r
+ @Override\r
+ public boolean execute(int o) {\r
+ proc.execute(s, p, o);\r
+ return true;\r
+ }\r
+ });\r
+ return true;\r
+ }\r
+ });\r
+ return true;\r
+ }\r
+ });\r
+ }\r
+ \r
+ private static class ForStatementsWithSubjectProc implements TIntObjectProcedure<TIntArrayList>, TIntProcedure {\r
+ int s;\r
+ int p;\r
+ IStatementProcedure proc;\r
+ \r
+ public ForStatementsWithSubjectProc(int s, IStatementProcedure proc) {\r
+ this.s = s;\r
+ this.proc = proc;\r
+ }\r
+\r
+ @Override\r
+ public boolean execute(int o) {\r
+ proc.execute(s, p, o);\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public boolean execute(int p, TIntArrayList b) {\r
+ this.p = p;\r
+ b.forEach(this);\r
+ return true;\r
+ } \r
+ }\r
+ \r
+ public void forStatementsWithSubject(int s, IStatementProcedure proc) {\r
+ TIntObjectHashMap<TIntArrayList> localStatements = statements.get(s);\r
+ if(localStatements == null)\r
+ return;\r
+ localStatements.forEachEntry(new ForStatementsWithSubjectProc(s, proc));\r
+ }\r
+ \r
+ public void forStatements(final int predicate, final IStatementProcedure proc) {\r
+ statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {\r
+ @Override\r
+ public boolean execute(final int s, TIntObjectHashMap<TIntArrayList> localStatements) {\r
+ TIntArrayList objects = localStatements.get(predicate);\r
+ if(objects != null)\r
+ objects.forEach(new TIntProcedure() { \r
+ @Override\r
+ public boolean execute(int o) {\r
+ proc.execute(s, predicate, o);\r
+ return true;\r
+ }\r
+ }); \r
+ return true;\r
+ }\r
+ });\r
+ }\r
+ \r
+ public TIntArrayList getRelation(int predicate) {\r
+ final TIntArrayList result = new TIntArrayList();\r
+ forStatements(predicate, new IStatementProcedure() { \r
+ @Override\r
+ public void execute(int s, int p, int o) {\r
+ result.add(s);\r
+ result.add(o);\r
+ }\r
+ });\r
+ return result;\r
+ }\r
+ \r
+ public TIntHashSet getRelationDomain(final int predicate) {\r
+ final TIntHashSet result = new TIntHashSet();\r
+ statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {\r
+ @Override\r
+ public boolean execute(int s, TIntObjectHashMap<TIntArrayList> localStatements) {\r
+ if(localStatements.containsKey(predicate))\r
+ result.add(s);\r
+ return true;\r
+ }\r
+ });\r
+ return result;\r
+ }\r
+ \r
+ public TIntArrayList extractRelation(final int predicate) {\r
+ final TIntArrayList result = new TIntArrayList();\r
+ final TIntArrayList removals = new TIntArrayList();\r
+ statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {\r
+ @Override\r
+ public boolean execute(int s, TIntObjectHashMap<TIntArrayList> localStatements) {\r
+ TIntArrayList objects = localStatements.remove(predicate);\r
+ if(objects != null) {\r
+ for(int o : objects.toArray()) {\r
+ result.add(s);\r
+ result.add(o);\r
+ }\r
+ }\r
+ if(localStatements.isEmpty())\r
+ removals.add(s);\r
+ return true;\r
+ }\r
+ });\r
+ for(int s : removals.toArray())\r
+ statements.remove(s);\r
+ return result;\r
+ }\r
+ \r
+ public TIntArrayList getObjects(int subject, int predicate) {\r
+ TIntObjectHashMap<TIntArrayList> localStatements = statements.get(subject);\r
+ if(localStatements == null)\r
+ return EMPTY_INT_LIST;\r
+ TIntArrayList objects = localStatements.get(predicate);\r
+ if(objects == null)\r
+ return EMPTY_INT_LIST;\r
+ return objects;\r
+ }\r
+\r
+ public int[] toArray(final TIntIntHashMap inverseMap) {\r
+ final TIntArrayList statements = new TIntArrayList();\r
+ forStatements(new IStatementProcedure() { \r
+ @Override\r
+ public void execute(int s, int p, int o) {\r
+ statements.add(s);\r
+ statements.add(p);\r
+ int inverse = -1;\r
+ if(inverseMap.contains(p)) {\r
+ inverse = inverseMap.get(p);\r
+ if(p==inverse && s == o)\r
+ inverse = -1;\r
+ }\r
+ statements.add(inverse);\r
+ statements.add(o); \r
+ }\r
+ });\r
+ return statements.toArray();\r
+ }\r
+ \r
+ public void collectReferences(final boolean[] set) {\r
+ forStatements(new IStatementProcedure() { \r
+ @Override\r
+ public void execute(int s, int p, int o) {\r
+ set[s] = true;\r
+ set[p] = true;\r
+ set[o] = true; \r
+ }\r
+ });\r
+ }\r
+\r
+ public TIntHashSet getPredicates() {\r
+ final TIntHashSet result = new TIntHashSet();\r
+ statements.forEachValue(new TObjectProcedure<TIntObjectHashMap<TIntArrayList>>() { \r
+ TIntProcedure proc = new TIntProcedure() { \r
+ @Override\r
+ public boolean execute(int value) {\r
+ result.add(value);\r
+ return true;\r
+ }\r
+ }; \r
+ @Override\r
+ public boolean execute(TIntObjectHashMap<TIntArrayList> localStatements) {\r
+ localStatements.forEachKey(proc);\r
+ return true;\r
+ }\r
+ });\r
+ return result;\r
+ }\r
+\r
+ public int[] toArray() {\r
+ final TIntArrayList statements = new TIntArrayList();\r
+ forStatements(new IStatementProcedure() { \r
+ @Override\r
+ public void execute(int s, int p, int o) {\r
+ statements.add(s);\r
+ statements.add(p);\r
+ statements.add(-1);\r
+ statements.add(o); \r
+ }\r
+ });\r
+ return statements.toArray();\r
+ } \r
+}\r