1 package org.simantics.graph.store;
\r
3 import gnu.trove.list.array.TIntArrayList;
\r
4 import gnu.trove.map.hash.THashMap;
\r
5 import gnu.trove.map.hash.TIntIntHashMap;
\r
6 import gnu.trove.map.hash.TIntObjectHashMap;
\r
7 import gnu.trove.map.hash.TObjectIntHashMap;
\r
8 import gnu.trove.procedure.TIntProcedure;
\r
9 import gnu.trove.procedure.TObjectIntProcedure;
\r
10 import gnu.trove.procedure.TObjectObjectProcedure;
\r
11 import gnu.trove.procedure.TObjectProcedure;
\r
12 import gnu.trove.set.hash.THashSet;
\r
13 import gnu.trove.set.hash.TIntHashSet;
\r
15 import java.util.ArrayList;
\r
16 import java.util.regex.Pattern;
\r
18 import org.simantics.graph.query.Path;
\r
19 import org.simantics.graph.query.PathChild;
\r
20 import org.simantics.graph.query.PathRoot;
\r
21 import org.simantics.graph.representation.External;
\r
22 import org.simantics.graph.representation.Identity;
\r
23 import org.simantics.graph.representation.Internal;
\r
24 import org.simantics.graph.representation.Root;
\r
26 public class IdentityStore implements IStore {
\r
28 private static int[] EMPTY_INT_ARRAY = new int[0];
\r
30 public static class ConsistsOf {
\r
35 public ConsistsOf(int parent, String name, int child) {
\r
36 //System.out.println(parent + "." + name + " = " + child);
\r
37 this.parent = parent;
\r
43 TObjectIntHashMap<String> roots = new TObjectIntHashMap<String>();
\r
44 TIntObjectHashMap<String> invRoots = new TIntObjectHashMap<String>();
\r
45 TIntObjectHashMap<THashMap<String, ConsistsOf>> parentMap =
\r
46 new TIntObjectHashMap<THashMap<String, ConsistsOf>>();
\r
47 TIntObjectHashMap<ConsistsOf> childMap = new TIntObjectHashMap<ConsistsOf>();
\r
48 TIntHashSet newResources = new TIntHashSet();
\r
49 int resourceCount = 0;
\r
50 TIntIntHashMap unifications = new TIntIntHashMap();
\r
51 TIntHashSet collisions = new TIntHashSet();
\r
53 public int newResource() {
\r
54 return resourceCount++;
\r
57 public boolean markNew(int resource) {
\r
58 return newResources.add(resource);
\r
61 public int[] getNewResources() {
\r
62 return newResources.toArray();
\r
65 public int getResourceCount() {
\r
66 return resourceCount;
\r
69 public void setResourceCount(int newCount) {
\r
70 resourceCount = newCount;
\r
73 public void defineRoot(String name, int root) {
\r
74 if(roots.contains(name))
\r
75 unify(root, roots.get(name));
\r
76 roots.put(name, root);
\r
77 invRoots.put(root, name);
\r
80 public void defineChild(int parent, String name, int child) {
\r
81 THashMap<String, ConsistsOf> map = parentMap.get(parent);
\r
83 map = new THashMap<String, ConsistsOf>();
\r
84 parentMap.put(parent, map);
\r
86 ConsistsOf consistsOf = new ConsistsOf(parent, name, child);
\r
87 ConsistsOf oldC = map.put(name, consistsOf);
\r
89 unify(child, oldC.child);
\r
90 childMap.put(child, consistsOf);
\r
93 public boolean hasChild(int parent, String name) {
\r
94 THashMap<String, ConsistsOf> map = parentMap.get(parent);
\r
98 return map.contains(name);
\r
101 public int getChild(int parent, String name) {
\r
102 THashMap<String, ConsistsOf> map = parentMap.get(parent);
\r
104 map = new THashMap<String, ConsistsOf>();
\r
105 parentMap.put(parent, map);
\r
107 else if(map.contains(name))
\r
108 return map.get(name).child;
\r
109 int child = newResource();
\r
110 ConsistsOf consistsOf = new ConsistsOf(parent, name, child);
\r
111 map.put(name, consistsOf);
\r
112 childMap.put(child, consistsOf);
\r
116 public int getChildIfExists(int parent, String name) {
\r
117 THashMap<String, ConsistsOf> map = parentMap.get(parent);
\r
118 if(map != null && map.contains(name))
\r
119 return map.get(name).child;
\r
123 public int getRoot(String uri) {
\r
124 if(roots.contains(uri))
\r
125 return roots.get(uri);
\r
127 int root = newResource();
\r
128 roots.put(uri, root);
\r
129 invRoots.put(root, uri);
\r
134 public int getRootIfExists(String uri) {
\r
135 if(roots.contains(uri))
\r
136 return roots.get(uri);
\r
140 public int[] getChildren(int id) {
\r
141 THashMap<String,ConsistsOf> map = parentMap.get(id);
\r
143 return EMPTY_INT_ARRAY;
\r
144 final int[] result = new int[map.size()];
\r
145 map.forEachValue(new TObjectProcedure<ConsistsOf>() {
\r
148 public boolean execute(ConsistsOf object) {
\r
149 result[i++] = object.child;
\r
156 public THashMap<String, ConsistsOf> getChildMap(int parent) {
\r
157 return parentMap.get(parent);
\r
160 private void collectIdentities(final int parent, final ArrayList<Identity> identities) {
\r
161 THashMap<String, ConsistsOf> map = parentMap.get(parent);
\r
163 map.forEachEntry(new TObjectObjectProcedure<String, ConsistsOf>() {
\r
166 public boolean execute(String a, ConsistsOf b) {
\r
167 if(newResources.contains(b.child))
\r
168 identities.add(new Identity(b.child, new Internal(parent, a)));
\r
170 identities.add(new Identity(b.child, new External(parent, a)));
\r
171 collectIdentities(b.child, identities);
\r
178 private void collectIdentities(final ArrayList<Identity> identities) {
\r
179 roots.forEachEntry(new TObjectIntProcedure<String>() {
\r
181 public boolean execute(String a, int b) {
\r
182 identities.add(new Identity(b, new Root(a, "")));
\r
183 collectIdentities(b, identities);
\r
190 public void map(final TIntIntHashMap map) {
\r
191 collisions = IndexMappingUtils.map(map, collisions);
\r
192 newResources = IndexMappingUtils.map(map, newResources);
\r
193 IndexMappingUtils.map(map, roots);
\r
194 invRoots = IndexMappingUtils.map(map, invRoots, collisions);
\r
196 final ArrayList<ConsistsOf> consistsOfs = new ArrayList<ConsistsOf>(childMap.size());
\r
197 childMap.forEachValue(new TObjectProcedure<IdentityStore.ConsistsOf>() {
\r
199 public boolean execute(ConsistsOf c) {
\r
200 if(map.contains(c.parent))
\r
201 c.parent = map.get(c.parent);
\r
202 if(map.contains(c.child))
\r
203 c.child = map.get(c.child);
\r
204 consistsOfs.add(c);
\r
211 assert(unifications.isEmpty());
\r
213 for(ConsistsOf c : consistsOfs) {
\r
214 THashMap<String, ConsistsOf> m = parentMap.get(c.parent);
\r
216 m = new THashMap<String, ConsistsOf>();
\r
217 parentMap.put(c.parent, m);
\r
219 ConsistsOf oldC = m.put(c.name, c);
\r
220 ConsistsOf childC = childMap.put(c.child, c);
\r
221 if(childC != null && (childC.parent != c.parent || !childC.name.equals(c.name)))
\r
222 collisions.add(c.child);
\r
225 unify(oldC.child, c.child);
\r
229 public int pathToId(Path path) {
\r
230 if(path instanceof PathChild) {
\r
231 PathChild child = (PathChild)path;
\r
232 int parent = pathToId(child.parent);
\r
235 return getChildIfExists(parent, child.name);
\r
237 else if(path instanceof PathRoot)
\r
238 return getRootIfExists(((PathRoot)path).name);
\r
240 throw new IllegalArgumentException();
\r
243 public int createPathToId(Path path) {
\r
244 if(path instanceof PathChild) {
\r
245 PathChild child = (PathChild)path;
\r
246 return getChild(createPathToId(child.parent), child.name);
\r
248 else if(path instanceof PathRoot)
\r
249 return getRoot(((PathRoot)path).name);
\r
251 throw new IllegalArgumentException();
\r
254 public Path idToPath(int id) {
\r
255 ConsistsOf consistsOf = childMap.get(id);
\r
256 if(consistsOf == null) {
\r
257 String root = invRoots.get(id);
\r
261 return new PathRoot(root);
\r
263 /*System.out.println("ConsistsOf(" +
\r
264 consistsOf.parent + "." + consistsOf.name +
\r
265 " = " + consistsOf.child + ")");
\r
267 //if(consistsOf.parent == consistsOf.child)
\r
269 Path parentPath = idToPath(consistsOf.parent);
\r
270 if(parentPath == null)
\r
272 return new PathChild(consistsOf.name, parentPath);
\r
275 public boolean contains(Path path) {
\r
276 return pathToId(path) >= 0;
\r
279 public boolean isNewResource(int id) {
\r
280 return newResources.contains(id);
\r
283 public Identity[] toArray() {
\r
284 final ArrayList<Identity> identities = new ArrayList<Identity>();
\r
285 collectIdentities(identities);
\r
286 return identities.toArray(new Identity[identities.size()]);
\r
289 public void collectReferences(final boolean[] set) {
\r
290 TIntProcedure proc = new TIntProcedure() {
\r
292 public boolean execute(int value) {
\r
298 roots.forEachValue(proc);
\r
299 childMap.forEach(proc);
\r
300 parentMap.forEach(proc);
\r
303 public int removeIdentity(int id) {
\r
304 ConsistsOf c = childMap.remove(id);
\r
306 parentMap.get(c.parent).remove(c.name);
\r
312 public boolean hasIdentity(int id) {
\r
313 return childMap.containsKey(id);
\r
316 public void definePath(Path path, int resource) {
\r
317 if(path instanceof PathChild) {
\r
318 PathChild child = (PathChild)path;
\r
319 int parent = createPathToId(child.parent);
\r
320 defineChild(parent, child.name, resource);
\r
322 else if(path instanceof PathRoot) {
\r
323 defineRoot(((PathRoot)path).name, resource);
\r
326 throw new IllegalArgumentException();
\r
329 public void printChildMap() {
\r
330 System.out.println("ChildMap:");
\r
331 childMap.forEachValue(new TObjectProcedure<ConsistsOf>() {
\r
334 public boolean execute(ConsistsOf c) {
\r
335 System.out.println(" " +
\r
336 c.child + " = " + c.parent + "." + c.name);
\r
343 private int canonical(int a) {
\r
344 if(unifications.contains(a)) {
\r
345 int b = unifications.get(a);
\r
346 if(unifications.contains(b)) {
\r
347 int c = canonical(b);
\r
348 unifications.put(a, c);
\r
349 unifications.put(b, c);
\r
359 public TIntIntHashMap extractUnifications() {
\r
360 // This normalizes the map
\r
361 for(int a : unifications.keys())
\r
364 TIntIntHashMap result = unifications;
\r
365 unifications = new TIntIntHashMap();
\r
370 public void unify(int a, int b) {
\r
375 unifications.put(a, b);
\r
379 public TIntHashSet getCollisions() {
\r
383 public String[] getRoots() {
\r
384 return roots.keys(new String[roots.size()]);
\r
387 void findChildren(int id, final Path path, final String suffix,
\r
388 final Pattern pattern, final THashSet<Path> result) {
\r
389 if(pattern.matcher(suffix).matches())
\r
391 THashMap<String,ConsistsOf> map = parentMap.get(id);
\r
393 map.forEachValue(new TObjectProcedure<ConsistsOf>() {
\r
395 public boolean execute(ConsistsOf consistsOf) {
\r
396 findChildren(consistsOf.child, new PathChild(consistsOf.name, path),
\r
397 suffix + "/" + consistsOf.name, pattern, result);
\r
403 public int[] getUnfoundedIdentities() {
\r
404 TIntArrayList result = new TIntArrayList();
\r
405 for(int resource : parentMap.keys()) {
\r
406 if(!childMap.containsKey(resource) && !invRoots.containsKey(resource)) {
\r
407 result.add(resource);
\r
410 return result.toArray();
\r
413 public void forEachChild(TObjectProcedure<ConsistsOf> proc) {
\r
414 childMap.forEachValue(proc);
\r
417 public void setIdentity(int child, int parent, String name) {
\r
418 THashMap<String, ConsistsOf> map = parentMap.get(parent);
\r
420 map = new THashMap<String, ConsistsOf>();
\r
421 parentMap.put(parent, map);
\r
423 else if(map.contains(name))
\r
424 throw new IllegalStateException();
\r
425 ConsistsOf consistsOf = new ConsistsOf(parent, name, child);
\r
426 map.put(name, consistsOf);
\r
427 childMap.put(child, consistsOf);
\r