1 package org.simantics.graph.store;
3 import java.util.ArrayList;
5 import gnu.trove.list.array.TIntArrayList;
6 import gnu.trove.map.hash.TIntIntHashMap;
7 import gnu.trove.map.hash.TIntObjectHashMap;
8 import gnu.trove.procedure.TIntObjectProcedure;
9 import gnu.trove.procedure.TIntProcedure;
10 import gnu.trove.procedure.TObjectProcedure;
11 import gnu.trove.set.hash.TIntHashSet;
14 * Statement store indexes a set of statements.
15 * @author Hannu Niemist�
17 public class StatementStore implements IStore {
19 static private final TIntArrayList EMPTY_INT_LIST = new TIntArrayList(0);
21 TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>> statements =
22 new TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>>();
25 * Adds a statement to the store.
30 public void add(int subject, int predicate, int object) {
32 assert(predicate >= 0);
34 TIntObjectHashMap<TIntArrayList> localStatements =
35 statements.get(subject);
36 if(localStatements == null) {
37 localStatements = new TIntObjectHashMap<TIntArrayList>(3);
38 statements.put(subject, localStatements);
40 TIntArrayList objects = localStatements.get(predicate);
42 objects = new TIntArrayList(2);
43 localStatements.put(predicate, objects);
48 public void map(final TIntIntHashMap map) {
49 final TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>> newStatements =
50 new TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>>(statements.size()*2+1);
51 statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
53 TIntObjectHashMap<TIntArrayList> newLocalStatements;
54 TIntArrayList newObjects;
56 TIntProcedure objectProcedure = new TIntProcedure() {
58 public boolean execute(int o) {
66 TIntObjectProcedure<TIntArrayList> predicateProcedure = new TIntObjectProcedure<TIntArrayList>() {
68 public boolean execute(int p, TIntArrayList objects) {
71 TIntArrayList exObjects = newLocalStatements.get(p);
72 if(exObjects == null) {
73 IndexMappingUtils.map(map, objects);
74 newLocalStatements.put(p, objects);
77 newObjects = exObjects;
78 objects.forEach(objectProcedure);
85 public boolean execute(int s, TIntObjectHashMap<TIntArrayList> localStatements) {
88 TIntObjectHashMap<TIntArrayList> exLocalStatements = newStatements.get(s);
89 if(exLocalStatements == null) {
90 exLocalStatements = new TIntObjectHashMap<TIntArrayList>(localStatements.size()*2 + 1);
91 newStatements.put(s, exLocalStatements);
93 newLocalStatements = exLocalStatements;
94 localStatements.forEachEntry(predicateProcedure);
98 statements = newStatements;
101 public void forStatements(final IStatementProcedure proc) {
102 statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
104 public boolean execute(final int s, TIntObjectHashMap<TIntArrayList> localStatements) {
105 localStatements.forEachEntry(new TIntObjectProcedure<TIntArrayList>() {
107 public boolean execute(final int p, TIntArrayList objects) {
108 objects.forEach(new TIntProcedure() {
110 public boolean execute(int o) {
111 proc.execute(s, p, o);
123 private static class ForStatementsWithSubjectProc implements TIntObjectProcedure<TIntArrayList>, TIntProcedure {
126 IStatementProcedure proc;
128 public ForStatementsWithSubjectProc(int s, IStatementProcedure proc) {
134 public boolean execute(int o) {
135 proc.execute(s, p, o);
140 public boolean execute(int p, TIntArrayList b) {
147 public void forStatementsWithSubject(int s, IStatementProcedure proc) {
148 TIntObjectHashMap<TIntArrayList> localStatements = statements.get(s);
149 if(localStatements == null)
151 localStatements.forEachEntry(new ForStatementsWithSubjectProc(s, proc));
154 public void forStatements(final int predicate, final IStatementProcedure proc) {
155 statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
157 public boolean execute(final int s, TIntObjectHashMap<TIntArrayList> localStatements) {
158 TIntArrayList objects = localStatements.get(predicate);
160 objects.forEach(new TIntProcedure() {
162 public boolean execute(int o) {
163 proc.execute(s, predicate, o);
172 public TIntArrayList getRelation(int predicate) {
173 final TIntArrayList result = new TIntArrayList();
174 forStatements(predicate, new IStatementProcedure() {
176 public void execute(int s, int p, int o) {
184 public TIntHashSet getRelationDomain(final int predicate) {
185 final TIntHashSet result = new TIntHashSet();
186 statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
188 public boolean execute(int s, TIntObjectHashMap<TIntArrayList> localStatements) {
189 if(localStatements.containsKey(predicate))
197 public TIntArrayList extractRelation(final int predicate) {
198 final TIntArrayList result = new TIntArrayList();
199 final TIntArrayList removals = new TIntArrayList();
200 statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
202 public boolean execute(int s, TIntObjectHashMap<TIntArrayList> localStatements) {
203 TIntArrayList objects = localStatements.remove(predicate);
204 if(objects != null) {
205 for(int o : objects.toArray()) {
210 if(localStatements.isEmpty())
215 for(int s : removals.toArray())
216 statements.remove(s);
220 public TIntArrayList getObjects(int subject, int predicate) {
221 TIntObjectHashMap<TIntArrayList> localStatements = statements.get(subject);
222 if(localStatements == null)
223 return EMPTY_INT_LIST;
224 TIntArrayList objects = localStatements.get(predicate);
226 return EMPTY_INT_LIST;
230 public int[] toArray(final TIntIntHashMap inverseMap) {
231 final TIntArrayList statements = new TIntArrayList();
232 forStatements(new IStatementProcedure() {
234 public void execute(int s, int p, int o) {
238 if(inverseMap.contains(p)) {
239 inverse = inverseMap.get(p);
240 if(p==inverse && s == o)
243 statements.add(inverse);
247 return statements.toArray();
250 public void collectReferences(final boolean[] set) {
251 forStatements(new IStatementProcedure() {
253 public void execute(int s, int p, int o) {
261 public TIntHashSet getPredicates() {
262 final TIntHashSet result = new TIntHashSet();
263 statements.forEachValue(new TObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
264 TIntProcedure proc = new TIntProcedure() {
266 public boolean execute(int value) {
272 public boolean execute(TIntObjectHashMap<TIntArrayList> localStatements) {
273 localStatements.forEachKey(proc);
280 public int[] toArray() {
281 final TIntArrayList statements = new TIntArrayList();
282 forStatements(new IStatementProcedure() {
284 public void execute(int s, int p, int o) {
291 return statements.toArray();
294 private static class CollisionSubjectProcedure implements TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>> {
295 CollisionPredicateProcedure predicateProcedure;
297 public CollisionSubjectProcedure(CollisionPredicateProcedure predicateProcedure) {
298 this.predicateProcedure = predicateProcedure;
302 public boolean execute(int subject, TIntObjectHashMap<TIntArrayList> predicateObjectMap) {
303 predicateProcedure.subject = subject;
304 predicateObjectMap.forEachEntry(predicateProcedure);
310 private static class CollisionPredicateProcedure implements TIntObjectProcedure<TIntArrayList> {
311 ArrayList<StatementCollision> collisions;
314 public CollisionPredicateProcedure(ArrayList<StatementCollision> collisions) {
315 this.collisions = collisions;
319 public boolean execute(int predicate, TIntArrayList objects) {
320 if(objects.size() > 1) {
322 int oldObject = objects.get(0);
323 int collisionCount = 1;
324 for(int i=1;i<objects.size();++i) {
325 int curObject = objects.get(i);
326 if(curObject == oldObject) {
330 if(collisionCount > 1) {
331 collisions.add(new StatementCollision(subject, predicate, oldObject, collisionCount));
334 oldObject = curObject;
337 if(collisionCount > 1)
338 collisions.add(new StatementCollision(subject, predicate, oldObject, collisionCount));
345 public ArrayList<StatementCollision> getCollisions() {
346 ArrayList<StatementCollision> collisions = new ArrayList<StatementCollision>();
347 CollisionPredicateProcedure predicateProcedure = new CollisionPredicateProcedure(collisions);
348 CollisionSubjectProcedure subjectProcedure = new CollisionSubjectProcedure(predicateProcedure);
349 statements.forEachEntry(subjectProcedure);