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