1 package org.simantics.graph.store;
3 import java.util.ArrayList;
4 import java.util.regex.Pattern;
6 import org.simantics.graph.query.Path;
7 import org.simantics.graph.query.PathChild;
8 import org.simantics.graph.query.PathRoot;
9 import org.simantics.graph.representation.External;
10 import org.simantics.graph.representation.Identity;
11 import org.simantics.graph.representation.Internal;
12 import org.simantics.graph.representation.Optional;
13 import org.simantics.graph.representation.Root;
15 import gnu.trove.list.array.TIntArrayList;
16 import gnu.trove.map.hash.THashMap;
17 import gnu.trove.map.hash.TIntIntHashMap;
18 import gnu.trove.map.hash.TIntObjectHashMap;
19 import gnu.trove.map.hash.TObjectIntHashMap;
20 import gnu.trove.procedure.TIntProcedure;
21 import gnu.trove.procedure.TObjectIntProcedure;
22 import gnu.trove.procedure.TObjectObjectProcedure;
23 import gnu.trove.procedure.TObjectProcedure;
24 import gnu.trove.set.hash.THashSet;
25 import gnu.trove.set.hash.TIntHashSet;
27 public class IdentityStore implements IStore {
29 private static int[] EMPTY_INT_ARRAY = new int[0];
31 public static class ConsistsOf {
36 public ConsistsOf(int parent, String name, int child) {
37 //System.out.println(parent + "." + name + " = " + child);
44 TObjectIntHashMap<String> roots = new TObjectIntHashMap<String>();
45 TIntObjectHashMap<String> invRoots = new TIntObjectHashMap<String>();
46 TIntObjectHashMap<THashMap<String, ConsistsOf>> parentMap =
47 new TIntObjectHashMap<THashMap<String, ConsistsOf>>();
48 TIntObjectHashMap<ConsistsOf> childMap = new TIntObjectHashMap<ConsistsOf>();
49 TIntHashSet newResources = new TIntHashSet();
50 TIntHashSet optionalResources = new TIntHashSet();
51 int resourceCount = 0;
52 TIntIntHashMap unifications = new TIntIntHashMap();
53 TIntHashSet collisions = new TIntHashSet();
55 public int newResource() {
56 return resourceCount++;
59 public boolean markNew(int resource) {
60 return newResources.add(resource);
63 public boolean markOptional(int resource) {
64 return optionalResources.add(resource);
67 public int[] getNewResources() {
68 return newResources.toArray();
71 public int getResourceCount() {
75 public void setResourceCount(int newCount) {
76 resourceCount = newCount;
79 public void defineRoot(String name, int root) {
80 if(roots.contains(name))
81 unify(root, roots.get(name));
82 roots.put(name, root);
83 invRoots.put(root, name);
86 public void defineChild(int parent, String name, int child) {
87 THashMap<String, ConsistsOf> map = parentMap.get(parent);
89 map = new THashMap<String, ConsistsOf>();
90 parentMap.put(parent, map);
92 ConsistsOf consistsOf = new ConsistsOf(parent, name, child);
93 ConsistsOf oldC = map.put(name, consistsOf);
95 unify(child, oldC.child);
96 childMap.put(child, consistsOf);
99 public boolean hasChild(int parent, String name) {
100 THashMap<String, ConsistsOf> map = parentMap.get(parent);
104 return map.contains(name);
107 public int getChild(int parent, String name) {
108 THashMap<String, ConsistsOf> map = parentMap.get(parent);
110 map = new THashMap<String, ConsistsOf>();
111 parentMap.put(parent, map);
113 else if(map.contains(name))
114 return map.get(name).child;
115 int child = newResource();
116 ConsistsOf consistsOf = new ConsistsOf(parent, name, child);
117 map.put(name, consistsOf);
118 childMap.put(child, consistsOf);
122 public int getChildIfExists(int parent, String name) {
123 THashMap<String, ConsistsOf> map = parentMap.get(parent);
124 if(map != null && map.contains(name))
125 return map.get(name).child;
129 public int getRoot(String uri) {
130 if(roots.contains(uri))
131 return roots.get(uri);
133 int root = newResource();
134 roots.put(uri, root);
135 invRoots.put(root, uri);
140 public int getRootIfExists(String uri) {
141 if(roots.contains(uri))
142 return roots.get(uri);
146 public int[] getChildren(int id) {
147 THashMap<String,ConsistsOf> map = parentMap.get(id);
149 return EMPTY_INT_ARRAY;
150 final int[] result = new int[map.size()];
151 map.forEachValue(new TObjectProcedure<ConsistsOf>() {
154 public boolean execute(ConsistsOf object) {
155 result[i++] = object.child;
162 public THashMap<String, ConsistsOf> getChildMap(int parent) {
163 return parentMap.get(parent);
166 private void collectIdentities(final int parent, final ArrayList<Identity> identities) {
167 THashMap<String, ConsistsOf> map = parentMap.get(parent);
169 map.forEachEntry(new TObjectObjectProcedure<String, ConsistsOf>() {
172 public boolean execute(String a, ConsistsOf b) {
174 if(newResources.contains(child))
175 identities.add(new Identity(child, new Internal(parent, a)));
176 else if(optionalResources.contains(child))
177 identities.add(new Identity(child, new Optional(parent, a)));
179 identities.add(new Identity(child, new External(parent, a)));
180 collectIdentities(b.child, identities);
187 private void collectIdentities(final ArrayList<Identity> identities) {
188 roots.forEachEntry(new TObjectIntProcedure<String>() {
190 public boolean execute(String a, int b) {
191 identities.add(new Identity(b, new Root(a, "")));
192 collectIdentities(b, identities);
199 public void map(final TIntIntHashMap map) {
200 collisions = IndexMappingUtils.map(map, collisions);
201 newResources = IndexMappingUtils.map(map, newResources);
202 IndexMappingUtils.map(map, roots);
203 invRoots = IndexMappingUtils.map(map, invRoots, collisions);
205 final ArrayList<ConsistsOf> consistsOfs = new ArrayList<ConsistsOf>(childMap.size());
206 childMap.forEachValue(new TObjectProcedure<IdentityStore.ConsistsOf>() {
208 public boolean execute(ConsistsOf c) {
209 if(map.contains(c.parent))
210 c.parent = map.get(c.parent);
211 if(map.contains(c.child))
212 c.child = map.get(c.child);
220 assert(unifications.isEmpty());
222 for(ConsistsOf c : consistsOfs) {
223 THashMap<String, ConsistsOf> m = parentMap.get(c.parent);
225 m = new THashMap<String, ConsistsOf>();
226 parentMap.put(c.parent, m);
228 ConsistsOf oldC = m.put(c.name, c);
229 ConsistsOf childC = childMap.put(c.child, c);
230 if(childC != null && (childC.parent != c.parent || !childC.name.equals(c.name)))
231 collisions.add(c.child);
234 unify(oldC.child, c.child);
238 public int pathToId(Path path) {
239 if(path instanceof PathChild) {
240 PathChild child = (PathChild)path;
241 int parent = pathToId(child.parent);
244 return getChildIfExists(parent, child.name);
246 else if(path instanceof PathRoot)
247 return getRootIfExists(((PathRoot)path).name);
249 throw new IllegalArgumentException();
252 public int createPathToId(Path path) {
253 if(path instanceof PathChild) {
254 PathChild child = (PathChild)path;
255 return getChild(createPathToId(child.parent), child.name);
257 else if(path instanceof PathRoot)
258 return getRoot(((PathRoot)path).name);
260 throw new IllegalArgumentException();
263 public Path idToPath(int id) {
264 ConsistsOf consistsOf = childMap.get(id);
265 if(consistsOf == null) {
266 String root = invRoots.get(id);
270 return new PathRoot(root);
272 /*System.out.println("ConsistsOf(" +
273 consistsOf.parent + "." + consistsOf.name +
274 " = " + consistsOf.child + ")");
276 //if(consistsOf.parent == consistsOf.child)
278 Path parentPath = idToPath(consistsOf.parent);
279 if(parentPath == null)
281 return new PathChild(consistsOf.name, parentPath);
284 public boolean contains(Path path) {
285 return pathToId(path) >= 0;
288 public boolean isNewResource(int id) {
289 return newResources.contains(id);
292 public boolean isOptionalResource(int id) {
293 return optionalResources.contains(id);
296 public boolean isRoot(int id) {
297 return invRoots.contains(id);
300 public Identity[] toArray() {
301 final ArrayList<Identity> identities = new ArrayList<Identity>();
302 collectIdentities(identities);
303 return identities.toArray(new Identity[identities.size()]);
306 public void collectReferences(final boolean[] set) {
307 TIntProcedure proc = new TIntProcedure() {
309 public boolean execute(int value) {
315 roots.forEachValue(proc);
316 childMap.forEach(proc);
317 parentMap.forEach(proc);
320 public int removeIdentity(int id) {
321 ConsistsOf c = childMap.remove(id);
323 parentMap.get(c.parent).remove(c.name);
329 public boolean hasIdentity(int id) {
330 return childMap.containsKey(id);
333 public int getParent(int id) {
334 ConsistsOf consistsOf = childMap.get(id);
335 if(consistsOf == null)
337 return consistsOf.parent;
340 public void definePath(Path path, int resource) {
341 if(path instanceof PathChild) {
342 PathChild child = (PathChild)path;
343 int parent = createPathToId(child.parent);
344 defineChild(parent, child.name, resource);
346 else if(path instanceof PathRoot) {
347 defineRoot(((PathRoot)path).name, resource);
350 throw new IllegalArgumentException();
353 public void printChildMap() {
354 System.out.println("ChildMap:");
355 childMap.forEachValue(new TObjectProcedure<ConsistsOf>() {
358 public boolean execute(ConsistsOf c) {
359 System.out.println(" " +
360 c.child + " = " + c.parent + "." + c.name);
367 private int canonical(int a) {
368 if(unifications.contains(a)) {
369 int b = unifications.get(a);
370 if(unifications.contains(b)) {
371 int c = canonical(b);
372 unifications.put(a, c);
373 unifications.put(b, c);
383 public TIntIntHashMap extractUnifications() {
384 // This normalizes the map
385 for(int a : unifications.keys())
388 TIntIntHashMap result = unifications;
389 unifications = new TIntIntHashMap();
394 public void unify(int a, int b) {
399 unifications.put(a, b);
403 public TIntHashSet getCollisions() {
407 public String[] getRoots() {
408 return roots.keys(new String[roots.size()]);
411 void findChildren(int id, final Path path, final String suffix,
412 final Pattern pattern, final THashSet<Path> result) {
413 if(pattern.matcher(suffix).matches())
415 THashMap<String,ConsistsOf> map = parentMap.get(id);
417 map.forEachValue(new TObjectProcedure<ConsistsOf>() {
419 public boolean execute(ConsistsOf consistsOf) {
420 findChildren(consistsOf.child, new PathChild(consistsOf.name, path),
421 suffix + "/" + consistsOf.name, pattern, result);
427 public int[] getUnfoundedIdentities() {
428 TIntArrayList result = new TIntArrayList();
429 for(int resource : parentMap.keys()) {
430 if(!childMap.containsKey(resource) && !invRoots.containsKey(resource)) {
431 result.add(resource);
434 return result.toArray();
437 public void forEachChild(TObjectProcedure<ConsistsOf> proc) {
438 childMap.forEachValue(proc);
441 public void setIdentity(int child, int parent, String name) {
442 THashMap<String, ConsistsOf> map = parentMap.get(parent);
444 map = new THashMap<String, ConsistsOf>();
445 parentMap.put(parent, map);
447 else if(map.contains(name))
448 throw new IllegalStateException();
449 ConsistsOf consistsOf = new ConsistsOf(parent, name, child);
450 map.put(name, consistsOf);
451 childMap.put(child, consistsOf);
454 public void removeOptionalMark(int id) {
455 optionalResources.remove(id);