]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/CompleteTable.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / CompleteTable.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 gnu.trove.map.hash.TIntIntHashMap;\r
15 import gnu.trove.procedure.TIntIntProcedure;\r
16 import gnu.trove.set.hash.TIntHashSet;\r
17 \r
18 import org.simantics.db.exception.DatabaseException;\r
19 import org.simantics.db.exception.ValidationException;\r
20 import org.simantics.db.impl.ClusterBase;\r
21 import org.simantics.db.impl.ClusterI;\r
22 import org.simantics.db.impl.ClusterI.CompleteTypeEnum;\r
23 import org.simantics.db.impl.ClusterI.ObjectProcedure;\r
24 import org.simantics.db.impl.ClusterI.Procedure;\r
25 import org.simantics.db.impl.ClusterSupport;\r
26 import org.simantics.db.impl.ClusterTraitsBase;\r
27 import org.simantics.db.impl.Modifier;\r
28 import org.simantics.db.impl.Table;\r
29 import org.simantics.db.impl.TableFactory;\r
30 import org.simantics.db.impl.TableIntAllocatorAdapter;\r
31 import org.simantics.db.impl.TableSizeListener;\r
32 import org.simantics.db.procore.cluster.TableIntArraySet.Ints;\r
33 \r
34 public class CompleteTable extends Table<int[]> {\r
35     public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase) {\r
36         super(TableFactory.getIntFactory(), sizeListener, header, headerBase);\r
37     }\r
38     public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {\r
39         super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);\r
40     }\r
41     final int createCompleteArraySet(int o1, int o2)\r
42     throws DatabaseException {\r
43         if (0 == o1 || o1 == o2)\r
44             throw new DatabaseException("Illegal argument to createObejctArray");\r
45         int[] obs = new int[2];\r
46         obs[0] = o1;\r
47         obs[1] = o2;\r
48         int hashBase = TableIntArraySet.create(obs, new TableIntAllocatorAdapter(this));\r
49         return convertRealIndexToTableIndex(hashBase);\r
50     }\r
51     final void deleteCompleteSet(int index)\r
52     throws DatabaseException {\r
53       int hashBase = checkIndexAndGetRealIndex(index, 0);\r
54       if (TableIntArraySet.isArraySet(getTable(), hashBase)) {\r
55           int capacity = TableIntArraySet.getAllocatedSize(getTable(), hashBase);\r
56           int elementIndex = index - TableIntArraySet.HeaderSize;\r
57           deleteOldElement(elementIndex, capacity);\r
58       } else {\r
59           int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase);\r
60           int elementIndex = index - TableIntSet.HeaderSize;\r
61           deleteOldElement(elementIndex, capacity);\r
62       }\r
63     }\r
64     final int getCompleteSetSize(int objectIndex) {\r
65         int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);\r
66         if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
67             return TableIntArraySet.getSize(getTable(), hashBase);\r
68         else\r
69             return TableIntSet.getSize(getTable(), hashBase);\r
70     }\r
71         /**\r
72         * @param setIndex\r
73         * @param oResourceIndex\r
74         * @return zero if complete already in the set else index of the set\r
75         */\r
76     final int addComplete(int setIndex, int oResourceIndex)\r
77     throws DatabaseException {\r
78         int hashBase = checkIndexAndGetRealIndex(setIndex, 0);\r
79         int newHashBase;\r
80         if (TableIntArraySet.isArraySet(getTable(), hashBase)) {\r
81             if (TableIntArraySet.getSize(getTable(), hashBase) < 5)\r
82                 newHashBase = TableIntArraySet.addInt(getTable(), hashBase, oResourceIndex, new TableIntAllocatorAdapter(this));\r
83             else {\r
84                 Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex);\r
85                 if (ints.found)\r
86                     return 0; // old object, not modified \r
87                 this.deleteCompleteSet(setIndex);\r
88                 newHashBase = TableIntSet.create(ints.ints, new TableIntAllocatorAdapter(this));\r
89                 assert(0 != newHashBase);\r
90             }\r
91         } else\r
92             newHashBase = TableIntSet.addInt(getTable(), hashBase, oResourceIndex, new TableIntAllocatorAdapter(this));\r
93         if (0 == newHashBase)\r
94             return 0; // old object, not modified\r
95         int ni = convertRealIndexToTableIndex(newHashBase);\r
96         return ni;\r
97     }\r
98     final int removeLast(int setIndex)\r
99     throws DatabaseException {\r
100         int hashBase = checkIndexAndGetRealIndex(setIndex, 0);\r
101         int[] table = getTable();\r
102         int ref;\r
103         if (TableIntArraySet.isArraySet(table, hashBase))\r
104             ref = TableIntArraySet.removeIntLast(table, hashBase);\r
105         else {\r
106             ref = TableIntSet.removeIntLast(table, hashBase);\r
107         }\r
108         deleteCompleteSet(setIndex);\r
109         return ref;\r
110     }\r
111     /**\r
112      * @param setIndex\r
113      * @param oResourceIndex\r
114      * @return number of objects after removal.\r
115      */\r
116     final int removeComplete(int setIndex, int oResourceIndex)\r
117     throws DatabaseException {\r
118         int hashBase = checkIndexAndGetRealIndex(setIndex, 0);\r
119         int[] table = getTable();\r
120         if (TableIntArraySet.isArraySet(table, hashBase))\r
121             return TableIntArraySet.removeInt(table, hashBase, oResourceIndex);\r
122         else {\r
123             TableIntSet.removeInt(table, hashBase, oResourceIndex);\r
124             return TableIntSet.getSize(table, hashBase);\r
125         }\r
126     }\r
127     final public <Context> boolean foreachComplete(final int setIndex,\r
128         final ClusterI.ObjectProcedure<Context> procedure, final Context context, final ClusterSupport support,\r
129         final Modifier modifier) throws DatabaseException {\r
130         final int hashBase = checkIndexAndGetRealIndex(setIndex, 0);\r
131         boolean ret;\r
132         if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
133             ret = TableIntArraySet.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
134         else\r
135             ret = TableIntSet.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
136         return ret;\r
137     }\r
138     public <Context> boolean foreachPredicate(int setIndex,\r
139             ClusterI.PredicateProcedure<Context> procedure,\r
140             Context context, ClusterSupport support, Modifier modifier)\r
141     throws DatabaseException {\r
142         ForeachPredicate<Context> t = new ForeachPredicate<Context>(procedure, support, modifier);\r
143         return foreachComplete(setIndex, t, context, null, null);\r
144     }\r
145     \r
146     public <Context> boolean foreachObject(int setIndex,\r
147             ClusterI.ObjectProcedure<Context> procedure,\r
148             Context context, ClusterSupport support, Modifier modifier,\r
149             ClusterI.CompleteTypeEnum completeType)\r
150     throws DatabaseException {\r
151         ForeachObject<Context> t = new ForeachObject<Context>\r
152         (procedure, support, modifier, completeType);\r
153         return foreachComplete(setIndex, t, context, null, null);\r
154     }\r
155     \r
156     private void checkEntry(ClusterBase cluster, int[] table, int index)\r
157     throws DatabaseException {\r
158         ClusterI.CompleteTypeEnum type = ClusterTraits.completeReferenceGetType(table[index]);\r
159         if (type == CompleteTypeEnum.NotComplete)\r
160             throw new ValidationException("Illegal CompleteTable entry type. Entry=" + table[index] + " index=" + index);\r
161         int fi = ClusterTraits.completeReferenceGetForeignIndex(table[index]);\r
162         int ri = ClusterTraits.completeReferenceGetResourceIndex(table[index]);\r
163         if (0 != fi) {\r
164             cluster.checkForeingIndex(fi);\r
165             if (ri < 1 || ri > ClusterTraits.getMaxNumberOfResources())\r
166                 throw new ValidationException("Illegal CompleteTable foreign entry. Entry=" + table[index] + " index=" + index);\r
167         } /*else if (ri < 1 || ri > cluster.getNumberOfResources(-1))\r
168                 throw new ValidationException("Illegal CompleteTable local entry. Entry=" + table[index] + " index=" + index);*/\r
169     }\r
170 \r
171     private TIntHashSet checkIndexSet = null;\r
172     public final void check(ClusterBase cluster)\r
173     throws DatabaseException {\r
174         if (null == checkIndexSet)\r
175             checkIndexSet = new TIntHashSet();\r
176         else\r
177             checkIndexSet.clear();\r
178         int count = 0;\r
179         int[] table = getTable();\r
180         int ps = getHeader().getOffset() + ZERO_SHIFT;\r
181         int pe = ps + getTableSize();\r
182         for (int p = ps; p < pe;) {\r
183             int cap = p++;\r
184             if (table[cap] >= 0) {\r
185                 int use = p++;\r
186                 int fre = p++;\r
187                 int max = p++;\r
188                 assert(table[cap] >= table[use] + table[fre]);\r
189                 assert(table[max] == table[cap] >> 1);\r
190                 assert(table[max]+1 >= table[use]);\r
191                 checkIndexSet.add(p - ps);\r
192                 for (int e = p + table[cap]; p<e; p++) {\r
193                     if (IntHashTrait.isFull(table[p])) \r
194                         checkEntry(cluster, table, p);\r
195                 }\r
196             } else {\r
197                 final int size = -table[cap];\r
198                 assert(size > 0);\r
199                 checkIndexSet.add(p - ps);\r
200                 boolean free = false;\r
201                 for (int e = p + size; p<e; p++) {\r
202                     if (free)\r
203                         assert(table[p] == 0);\r
204                     else if (table[p] == 0)\r
205                         free = true;\r
206                     else\r
207                         checkEntry(cluster, table, p);\r
208                 }\r
209             }\r
210             count++;\r
211         }\r
212         assert(getHeader().getCount() <= count);  // deleted objects are not recognized\r
213     }\r
214     public final void checkCompleteSetIndex(ClusterBase cluster, int i)\r
215     throws DatabaseException {\r
216         if (null == checkIndexSet)\r
217                 check(cluster); // builds checkIndexSet\r
218         if (!checkIndexSet.contains(i-ZERO_SHIFT))\r
219                 throw new ValidationException("Illegal object set index=" + i);\r
220     }\r
221     final void printDebugInfo() {\r
222       int count = 0;\r
223       int[] table = getTable();\r
224       int ps = getHeader().getOffset() + ZERO_SHIFT;\r
225       int pe = ps + getTableSize();\r
226       TIntIntHashMap stat = new TIntIntHashMap();\r
227       TIntIntHashMap stat2 = new TIntIntHashMap();\r
228       for (int p=ps; p<pe;) {\r
229           int cap = p++;\r
230           if (table[cap] >= 0) {\r
231               int use = p++;\r
232               int fre = p++;\r
233               int max = p++;\r
234               assert(table[cap] >= table[use] + table[fre]);\r
235               assert(table[max] == table[cap] >> 1);\r
236               p += table[cap];\r
237               int val = stat.get(table[use]) + 1;\r
238               stat.put(table[use], val);\r
239           } else {\r
240               final int size = -table[cap];\r
241               int val = stat2.get(size) + 1;\r
242               stat2.put(size, val);\r
243               p += size;\r
244           }\r
245           count++;\r
246       }\r
247       assert(getHeader().getCount() == count);\r
248       stat.forEachEntry(new TIntIntProcedure() {\r
249           @Override\r
250           public boolean execute(int a, int b) {\r
251               System.out.println("complete set capacity " + a + " instance count " + b);\r
252               return true;\r
253           }\r
254       });\r
255       stat2.forEachEntry(new TIntIntProcedure() {\r
256           @Override\r
257           public boolean execute(int a, int b) {\r
258               System.out.println("complete array set capacity " + a + " instance count " + b);\r
259               return true;\r
260           }\r
261       });\r
262     }\r
263     @Override\r
264     public <Context> boolean foreach(int setIndex, Procedure procedure, Context context, ClusterSupport support, Modifier modifier) throws DatabaseException {\r
265         return foreachComplete(setIndex, (ObjectProcedure<Context>)procedure, context, support, modifier);\r
266     }\r
267 }\r
268 class ForeachPredicate<Context>\r
269 implements ClusterI.ObjectProcedure<Context> {\r
270     private TIntHashSet completeTypes = new TIntHashSet();\r
271     private ClusterI.PredicateProcedure<Context> procedure; \r
272     public ForeachPredicate(ClusterI.PredicateProcedure<Context>\r
273         procedure, ClusterSupport support, Modifier modifier) {\r
274         this.procedure = procedure;\r
275     }\r
276     @Override\r
277     public boolean execute(Context context, int completeRef) {\r
278         ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);\r
279         if (!completeTypes.contains(completeType.getValue())) {\r
280             completeTypes.add(completeType.getValue());\r
281             try {\r
282                 int pKey = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);\r
283                 if (procedure.execute(context, pKey, 0))\r
284                     return true; // loop broken by procedure\r
285             } catch (DatabaseException e) {\r
286                 e.printStackTrace();\r
287                 return false;\r
288             }\r
289         }\r
290         return false;\r
291     }\r
292     \r
293 }\r
294 class ForeachObject<Context>\r
295 implements ClusterI.ObjectProcedure<Context> {\r
296     private ClusterI.ObjectProcedure<Context> procedure; \r
297     private Modifier modifier;\r
298     private ClusterI.CompleteTypeEnum completeType;\r
299     public ForeachObject(ClusterI.ObjectProcedure<Context>\r
300         procedure, ClusterSupport support, Modifier modifier, ClusterI.CompleteTypeEnum completeType) {\r
301         this.procedure = procedure;\r
302         this.modifier = modifier;\r
303         this.completeType = completeType;\r
304     }\r
305     @Override\r
306     public boolean execute(Context context, int completeRef) throws DatabaseException {\r
307         ClusterI.CompleteTypeEnum completeType2 = ClusterTraits.completeReferenceGetType(completeRef);\r
308         if (completeType == completeType2) {\r
309             int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
310             int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
311             if (0 == clusterIndex) {\r
312                 int externalRef;\r
313                 if (null == modifier)\r
314                     externalRef = resourceIndex;\r
315                 else\r
316                     externalRef = modifier.execute(resourceIndex);\r
317                 return procedure.execute(context, externalRef);\r
318             } else {\r
319                 try {\r
320                     int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
321                     if (null != modifier)\r
322                         externalRef = modifier.execute(externalRef);\r
323                     return procedure.execute(context, externalRef);\r
324                 } catch (DatabaseException e) {\r
325                     e.printStackTrace();\r
326                     return false; // continue looping\r
327                 }\r
328             }\r
329         }\r
330         return false; // continue looping\r
331     }\r
332     \r
333 }