]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.graph/src/org/simantics/graph/store/StatementStore.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.graph / src / org / simantics / graph / store / StatementStore.java
1 package org.simantics.graph.store;
2
3 import java.util.ArrayList;
4
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;
12
13 /**
14  * Statement store indexes a set of statements. 
15  * @author Hannu Niemist�
16  */
17 public class StatementStore implements IStore {
18         
19         static private final TIntArrayList EMPTY_INT_LIST = new TIntArrayList(0);       
20         
21         TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>> statements =
22                 new TIntObjectHashMap<TIntObjectHashMap<TIntArrayList>>();
23         
24         /**
25          * Adds a statement to the store.
26          * @param subject
27          * @param predicate
28          * @param object
29          */
30         public void add(int subject, int predicate, int object) {
31                 assert(subject >= 0);
32                 assert(predicate >= 0);
33                 assert(object >= 0);
34                 TIntObjectHashMap<TIntArrayList> localStatements = 
35                         statements.get(subject);
36                 if(localStatements == null) {
37                         localStatements = new TIntObjectHashMap<TIntArrayList>(3);
38                         statements.put(subject, localStatements);
39                 }
40                 TIntArrayList objects = localStatements.get(predicate);
41                 if(objects == null) {
42                         objects = new TIntArrayList(2);
43                         localStatements.put(predicate, objects);
44                 }
45                 objects.add(object);
46         }
47         
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>>() {
52                         
53                         TIntObjectHashMap<TIntArrayList> newLocalStatements;
54                         TIntArrayList newObjects;
55                         
56                         TIntProcedure objectProcedure = new TIntProcedure() {                                                           
57                                 @Override
58                                 public boolean execute(int o) {
59                                         if(map.contains(o))
60                                                 o = map.get(o);
61                                         newObjects.add(o);
62                                         return true;
63                                 }
64                         };
65                         
66                         TIntObjectProcedure<TIntArrayList> predicateProcedure = new TIntObjectProcedure<TIntArrayList>() {
67                                 @Override
68                                 public boolean execute(int p, TIntArrayList objects) {
69                                         if(map.contains(p))
70                                                 p = map.get(p);
71                                         TIntArrayList exObjects = newLocalStatements.get(p);
72                                         if(exObjects == null) {
73                                                 IndexMappingUtils.map(map, objects);
74                                                 newLocalStatements.put(p, objects);
75                                         }
76                                         else {
77                                                 newObjects = exObjects;
78                                                 objects.forEach(objectProcedure);
79                                         }
80                                         return true;
81                                 }
82                         };
83                         
84                         @Override
85                         public boolean execute(int s, TIntObjectHashMap<TIntArrayList> localStatements) {
86                                 if(map.contains(s))
87                                         s = map.get(s);
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);
92                                 }
93                                 newLocalStatements = exLocalStatements;
94                                 localStatements.forEachEntry(predicateProcedure);
95                                 return true;
96                         }
97                 });
98                 statements = newStatements;
99         }
100         
101         public void forStatements(final IStatementProcedure proc) {
102                 statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
103                         @Override
104                         public boolean execute(final int s, TIntObjectHashMap<TIntArrayList> localStatements) {
105                                 localStatements.forEachEntry(new TIntObjectProcedure<TIntArrayList>() {
106                                         @Override
107                                         public boolean execute(final int p, TIntArrayList objects) {
108                                                 objects.forEach(new TIntProcedure() {                                                   
109                                                         @Override
110                                                         public boolean execute(int o) {
111                                                                 proc.execute(s, p, o);
112                                                                 return true;
113                                                         }
114                                                 });
115                                                 return true;
116                                         }
117                                 });
118                                 return true;
119                         }
120                 });
121         }
122         
123         private static class ForStatementsWithSubjectProc implements TIntObjectProcedure<TIntArrayList>, TIntProcedure {
124                 int s;
125                 int p;
126                 IStatementProcedure proc;
127                 
128                 public ForStatementsWithSubjectProc(int s, IStatementProcedure proc) {
129                         this.s = s;
130                         this.proc = proc;
131                 }
132
133                 @Override
134                 public boolean execute(int o) {
135                         proc.execute(s, p, o);
136                         return true;
137                 }
138
139                 @Override
140                 public boolean execute(int p, TIntArrayList b) {
141                         this.p = p;
142                         b.forEach(this);
143                         return true;
144                 }               
145         }
146         
147         public void forStatementsWithSubject(int s, IStatementProcedure proc) {
148                 TIntObjectHashMap<TIntArrayList> localStatements = statements.get(s);
149                 if(localStatements == null)
150                         return;
151                 localStatements.forEachEntry(new ForStatementsWithSubjectProc(s, proc));
152         }
153         
154         public void forStatements(final int predicate, final IStatementProcedure proc) {
155                 statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
156                         @Override
157                         public boolean execute(final int s, TIntObjectHashMap<TIntArrayList> localStatements) {
158                                 TIntArrayList objects = localStatements.get(predicate);
159                                 if(objects != null)
160                                         objects.forEach(new TIntProcedure() {                                                   
161                                                         @Override
162                                                         public boolean execute(int o) {
163                                                                 proc.execute(s, predicate, o);
164                                                                 return true;
165                                                         }
166                                                 });                                             
167                                 return true;
168                         }
169                 });
170         }
171         
172         public TIntArrayList getRelation(int predicate) {
173                 final TIntArrayList result = new TIntArrayList();
174                 forStatements(predicate, new IStatementProcedure() {                    
175                         @Override
176                         public void execute(int s, int p, int o) {
177                                 result.add(s);
178                                 result.add(o);
179                         }
180                 });
181                 return result;
182         }
183         
184         public TIntHashSet getRelationDomain(final int predicate) {
185                 final TIntHashSet result = new TIntHashSet();
186                 statements.forEachEntry(new TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {
187                         @Override
188                         public boolean execute(int s, TIntObjectHashMap<TIntArrayList> localStatements) {
189                                 if(localStatements.containsKey(predicate))
190                                         result.add(s);
191                                 return true;
192                         }
193                 });
194                 return result;
195         }
196         
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>>() {
201                         @Override
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()) {
206                                                 result.add(s);
207                                                 result.add(o);
208                                         }
209                                 }
210                                 if(localStatements.isEmpty())
211                                         removals.add(s);
212                                 return true;
213                         }
214                 });
215                 for(int s : removals.toArray())
216                         statements.remove(s);
217                 return result;
218         }
219         
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);
225                 if(objects == null)
226                         return EMPTY_INT_LIST;
227                 return objects;
228         }
229
230         public int[] toArray(final TIntIntHashMap inverseMap) {
231                 final TIntArrayList statements = new TIntArrayList();
232                 forStatements(new IStatementProcedure() {                       
233                         @Override
234                         public void execute(int s, int p, int o) {
235                                 statements.add(s);
236                                 statements.add(p);
237                                 int inverse = -1;
238                                 if(inverseMap.contains(p)) {
239                                         inverse = inverseMap.get(p);
240                                         if(p==inverse && s == o)
241                                                 inverse = -1;
242                                 }
243                                 statements.add(inverse);
244                                 statements.add(o);                              
245                         }
246                 });
247                 return statements.toArray();
248         }
249         
250         public void collectReferences(final boolean[] set) {
251                 forStatements(new IStatementProcedure() {                       
252                         @Override
253                         public void execute(int s, int p, int o) {
254                                 set[s] = true;
255                                 set[p] = true;
256                                 set[o] = true;          
257                         }
258                 });
259         }
260
261         public TIntHashSet getPredicates() {
262                 final TIntHashSet result = new TIntHashSet();
263                 statements.forEachValue(new TObjectProcedure<TIntObjectHashMap<TIntArrayList>>() {                      
264                         TIntProcedure proc = new TIntProcedure() {                              
265                                 @Override
266                                 public boolean execute(int value) {
267                                         result.add(value);
268                                         return true;
269                                 }
270                         };                      
271                         @Override
272                         public boolean execute(TIntObjectHashMap<TIntArrayList> localStatements) {
273                                 localStatements.forEachKey(proc);
274                                 return true;
275                         }
276                 });
277                 return result;
278         }
279
280         public int[] toArray() {
281                 final TIntArrayList statements = new TIntArrayList();
282                 forStatements(new IStatementProcedure() {                       
283                         @Override
284                         public void execute(int s, int p, int o) {
285                                 statements.add(s);
286                                 statements.add(p);
287                                 statements.add(-1);
288                                 statements.add(o);                              
289                         }
290                 });
291                 return statements.toArray();
292         }
293
294         private static class CollisionSubjectProcedure implements TIntObjectProcedure<TIntObjectHashMap<TIntArrayList>> {
295             CollisionPredicateProcedure predicateProcedure;
296
297             public CollisionSubjectProcedure(CollisionPredicateProcedure predicateProcedure) {
298                 this.predicateProcedure = predicateProcedure;
299             }
300
301             @Override
302             public boolean execute(int subject, TIntObjectHashMap<TIntArrayList> predicateObjectMap) {
303                 predicateProcedure.subject = subject;
304                 predicateObjectMap.forEachEntry(predicateProcedure);
305                 return true;
306             }
307
308         }
309
310         private static class CollisionPredicateProcedure implements TIntObjectProcedure<TIntArrayList> {
311         ArrayList<StatementCollision> collisions;
312             int subject;
313             
314             public CollisionPredicateProcedure(ArrayList<StatementCollision> collisions) {
315             this.collisions = collisions;
316         }
317             
318         @Override
319             public boolean execute(int predicate, TIntArrayList objects) {
320                 if(objects.size() > 1) {
321                     objects.sort();
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) {
327                             ++collisionCount;
328                         }
329                         else {
330                             if(collisionCount > 1) {
331                                 collisions.add(new StatementCollision(subject, predicate, oldObject, collisionCount));
332                                 collisionCount = 1;
333                             }
334                             oldObject = curObject;
335                         }
336                     }
337                 if(collisionCount > 1)
338                     collisions.add(new StatementCollision(subject, predicate, oldObject, collisionCount));
339                 }
340                 return true;
341             }
342
343         }
344
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);
350             return collisions;
351         }       
352 }