]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ObjectTable.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ObjectTable.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.db.procore.cluster;\r
13 \r
14 import org.simantics.db.Resource;\r
15 import org.simantics.db.exception.DatabaseException;\r
16 import org.simantics.db.exception.ValidationException;\r
17 import org.simantics.db.impl.ClusterBase;\r
18 import org.simantics.db.impl.ClusterI;\r
19 import org.simantics.db.impl.ClusterI.ObjectProcedure;\r
20 import org.simantics.db.impl.ClusterI.Procedure;\r
21 import org.simantics.db.impl.ClusterSupport;\r
22 import org.simantics.db.impl.Modifier;\r
23 import org.simantics.db.impl.ResourceImpl;\r
24 import org.simantics.db.impl.Table;\r
25 import org.simantics.db.impl.TableFactory;\r
26 import org.simantics.db.impl.TableIntAllocatorAdapter;\r
27 import org.simantics.db.impl.TableSizeListener;\r
28 import org.simantics.db.impl.graph.ReadGraphImpl;\r
29 import org.simantics.db.procedure.AsyncContextMultiProcedure;\r
30 import org.simantics.db.procedure.AsyncMultiProcedure;\r
31 import org.simantics.db.procore.cluster.TableIntArraySet.Ints;\r
32 \r
33 import gnu.trove.map.hash.TIntIntHashMap;\r
34 import gnu.trove.procedure.TIntIntProcedure;\r
35 import gnu.trove.set.hash.TIntHashSet;\r
36 \r
37 public final class ObjectTable extends Table<int[]> {\r
38 \r
39         final TableIntAllocatorAdapter allocator;\r
40         \r
41     public ObjectTable(TableSizeListener sizeListener, int[] header, int headerBase) {\r
42         super(TableFactory.getIntFactory(), sizeListener, header, headerBase);\r
43         allocator = new TableIntAllocatorAdapter(this);\r
44     }\r
45 \r
46     public ObjectTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {\r
47         super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);\r
48         allocator = new TableIntAllocatorAdapter(this);\r
49     }\r
50 \r
51     final int createObjectSet(int o1, int o2) throws DatabaseException {\r
52         if (0 == o1 || o1 == o2)\r
53             throw new DatabaseException("Illegal argument to createObejctSet");\r
54         int[] obs = new int[2];\r
55         obs[0] = o1;\r
56         obs[1] = o2;\r
57         int hashBase = TableIntArraySet.create(obs, allocator);\r
58         return convertRealIndexToTableIndex(hashBase);\r
59     }\r
60 \r
61     final void deleteObjectSet(int objectIndex) throws DatabaseException {\r
62         int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);\r
63         if (TableIntArraySet.isArraySet(getTable(), hashBase)) {\r
64             int capacity = TableIntArraySet.getAllocatedSize(getTable(), hashBase);\r
65             int elementIndex = objectIndex - TableIntArraySet.HeaderSize;\r
66             deleteOldElement(elementIndex, capacity);\r
67         } else {\r
68             int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase);\r
69             int elementIndex = objectIndex - TableIntSet.HeaderSize;\r
70             deleteOldElement(elementIndex, capacity);\r
71         }\r
72     }\r
73 \r
74     public final int getObjectSetSize(int objectIndex) {\r
75         int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);\r
76         if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
77             return TableIntArraySet.getSize(getTable(), hashBase);\r
78         else\r
79             return TableIntSet.getSize(getTable(), hashBase);\r
80     }\r
81 \r
82     /**\r
83      * @param objectIndex\r
84      * @param oResourceIndex\r
85      * @return zero if object already in the set else object index of the set\r
86      */\r
87     final int addObject(int objectIndex, int oResourceIndex) throws DatabaseException {\r
88         int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);\r
89         int newHashBase;\r
90         if (TableIntArraySet.isArraySet(getTable(), hashBase)) {\r
91             if (TableIntArraySet.getSize(getTable(), hashBase) < 5)\r
92                 newHashBase = TableIntArraySet.addInt(getTable(), hashBase, oResourceIndex, allocator);\r
93             else {\r
94                 Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex);\r
95                 if (ints.found)\r
96                     return 0; // old object, not modified\r
97                 this.deleteObjectSet(objectIndex);\r
98                 newHashBase = TableIntSet.create(ints.ints, allocator);\r
99                 assert(0 != newHashBase);\r
100             }\r
101         } else\r
102             newHashBase = TableIntSet.addInt(getTable(), hashBase, oResourceIndex, allocator);\r
103         if (0 == newHashBase)\r
104             return 0; // old object, not modified\r
105         int ni = convertRealIndexToTableIndex(newHashBase);\r
106         return ni;\r
107     }\r
108 \r
109     /**\r
110      * @param objectIndex\r
111      * @param oResourceIndex\r
112      * @return number of objects after removal.\r
113      */\r
114     final int removeObject(int objectIndex, int oResourceIndex) throws DatabaseException {\r
115         if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
116             int pRef = objectIndex;\r
117             if (oResourceIndex == pRef) {\r
118                 return 0;\r
119             } else\r
120                 return 1;\r
121         } else\r
122             objectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
123         int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);\r
124         int[] table = getTable();\r
125         if (TableIntArraySet.isArraySet(table, hashBase))\r
126             return TableIntArraySet.removeInt(table, hashBase, oResourceIndex);\r
127         else {\r
128             TableIntSet.removeInt(table, hashBase, oResourceIndex);\r
129             return TableIntSet.getSize(table, hashBase);\r
130         }\r
131     }\r
132 \r
133     final public int getSingleObject(final int objectIndex, final ClusterSupport support, Modifier modifier) throws DatabaseException {\r
134 \r
135         if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
136                 return modifier.execute(objectIndex);\r
137         }\r
138         \r
139         int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
140         final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);\r
141         if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
142             return TableIntArraySet.getSingleInt(getTable(), hashBase, modifier);\r
143         else\r
144                 return IntHash.getSingleInt(getTable(), hashBase, modifier);\r
145         \r
146     }\r
147 \r
148     final public void foreachObject( ReadGraphImpl graph, final int objectIndex, \r
149             final AsyncMultiProcedure<Resource> procedure, Modifier modifier) throws DatabaseException {\r
150         if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
151                 int key = modifier.execute(objectIndex);\r
152             procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), key));\r
153                 procedure.finished(graph);\r
154 //              graph.dec();\r
155             return;\r
156         }\r
157         int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
158         final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);\r
159         if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
160             TableIntArraySet.foreachInt(getTable(), hashBase, graph, procedure, modifier);\r
161         else\r
162                 IntHash.foreachInt(graph, table, hashBase, procedure, modifier);\r
163     }\r
164 \r
165     final public <C> void foreachObject( ReadGraphImpl graph, final int objectIndex, C context, \r
166             final AsyncContextMultiProcedure<C, Resource> procedure, Modifier modifier) throws DatabaseException {\r
167         if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
168                 int key = modifier.execute(objectIndex);\r
169             procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), key));\r
170                 procedure.finished(graph);\r
171 //              graph.dec();\r
172             return;\r
173         }\r
174         int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
175         final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);\r
176         if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
177             TableIntArraySet.foreachInt(getTable(), hashBase, graph, context, procedure, modifier);\r
178         else\r
179                 IntHash.foreachInt(graph, table, hashBase, context, procedure, modifier);\r
180     }\r
181 \r
182     final public <Context> boolean foreachObject(final int objectIndex,\r
183             final ClusterI.ObjectProcedure<Context> procedure, final Context context, final ClusterSupport support,\r
184             final Modifier modifier) throws DatabaseException {\r
185         if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
186             int pRef = objectIndex;\r
187             int key;\r
188             if (null == modifier)\r
189                 key = pRef;\r
190             else\r
191                 key = modifier.execute(pRef);\r
192             if (procedure.execute(context, key))\r
193                 return true; // loop broken by procedure\r
194             return false; // loop finished\r
195         }\r
196         int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
197         final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);\r
198         boolean ret;\r
199         if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
200             ret = TableIntArraySet.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
201         else\r
202             ret = TableIntSet.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
203         return ret;\r
204     }\r
205 \r
206     private void checkEntry(ClusterBase cluster, int[] table, int index)\r
207     throws DatabaseException {\r
208         if (!ClusterTraits.statementIndexIsDirect(table[index]))\r
209                 throw new ValidationException("Illegal ObjectTable entry. Entry=" + table[index] + " index=" + index);\r
210         int dr = table[index];\r
211         cluster.checkDirectReference(dr);\r
212     }\r
213     private TIntHashSet checkIndexSet = null;\r
214     public final void check(ClusterBase cluster)\r
215     throws DatabaseException {\r
216         if (null == checkIndexSet)\r
217                 checkIndexSet = new TIntHashSet();\r
218         else\r
219                 checkIndexSet.clear();\r
220         int count = 0;\r
221         int[] table = getTable();\r
222         int ps = getHeader().getOffset() + ZERO_SHIFT;\r
223         int pe = ps + getTableSize();\r
224         for (int p = ps; p < pe;) {\r
225             int cap = p++;\r
226             if (table[cap] >= 0) {\r
227                 int use = p++;\r
228                 int fre = p++;\r
229                 int max = p++;\r
230                 assert(table[cap] >= table[use] + table[fre]);\r
231                 assert(table[max] == table[cap] >> 1);\r
232                 assert(table[max]+1 >= table[use]);\r
233                 checkIndexSet.add(p - ps);\r
234                 for (int e = p + table[cap]; p<e; p++) {\r
235                     if (IntHashTrait.isFull(table[p])) \r
236                         checkEntry(cluster, table, p);\r
237                 }\r
238             } else {\r
239                 final int size = -table[cap];\r
240                 assert(size > 0);\r
241                 checkIndexSet.add(p - ps);\r
242                 boolean free = false;\r
243                 for (int e = p + size; p<e; p++) {\r
244                     if (free)\r
245                         assert(table[p] == 0);\r
246                     else if (table[p] == 0)\r
247                         free = true;\r
248                     else\r
249                         checkEntry(cluster, table, p);\r
250                 }\r
251             }\r
252             count++;\r
253         }\r
254         assert(getHeader().getCount() <= count); // deleted objects are not recognized\r
255     }\r
256 \r
257     public final void checkObjectSetIndex(ClusterBase cluster, int i)\r
258     throws DatabaseException {\r
259         if (null == checkIndexSet)\r
260                 check(cluster); // builds checkIndexSet\r
261         if (!checkIndexSet.contains(i-ZERO_SHIFT))\r
262                 throw new ValidationException("Illegal object set index=" + i);\r
263     }\r
264     public final void printDebugInfo() {\r
265         //int count = 0;\r
266         int[] table = getTable();\r
267         int ps = getHeader().getOffset() + ZERO_SHIFT;\r
268         int pe = ps + getTableSize();\r
269         TIntIntHashMap stat = new TIntIntHashMap();\r
270         TIntIntHashMap stat2 = new TIntIntHashMap();\r
271         for (int p = ps; p < pe;) {\r
272             int cap = p++;\r
273             if (table[cap] >= 0) {\r
274                 int use = p++;\r
275                 int fre = p++;\r
276                 int max = p++;\r
277                 assert(table[cap] >= table[use] + table[fre]);\r
278                 assert(table[max] == table[cap] >> 1);\r
279                 p += table[cap];\r
280                 int val = stat.get(table[use]) + 1;\r
281                 stat.put(table[use], val);\r
282             } else {\r
283                 final int size = -table[cap];\r
284                 int val = stat2.get(size) + 1;\r
285                 stat2.put(size, val);\r
286                 p += size;\r
287             }\r
288             //count++;\r
289         }\r
290         // assert(getHeader().getCount() == count);\r
291         stat.forEachEntry(new TIntIntProcedure() {\r
292             @Override\r
293             public boolean execute(int a, int b) {\r
294                 System.out.println("object set capacity " + a + " instance count " + b);\r
295                 return true;\r
296             }\r
297         });\r
298         stat2.forEachEntry(new TIntIntProcedure() {\r
299             @Override\r
300             public boolean execute(int a, int b) {\r
301                 System.out.println("object array set capacity " + a + " instance count " + b);\r
302                 return true;\r
303             }\r
304         });\r
305     }\r
306 \r
307     @Override\r
308     public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,\r
309             ClusterSupport support, Modifier modifier) throws DatabaseException {\r
310         return foreachObject(setIndex, (ObjectProcedure<Context>)procedure, context, support, modifier);\r
311     }\r
312 }\r