]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/PredicateTable.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / PredicateTable.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.ObjectProcedure;\r
23 import org.simantics.db.impl.ClusterI.PredicateProcedure;\r
24 import org.simantics.db.impl.ClusterI.Procedure;\r
25 import org.simantics.db.impl.ClusterSupport;\r
26 import org.simantics.db.impl.Modifier;\r
27 import org.simantics.db.impl.Table;\r
28 import org.simantics.db.impl.TableFactory;\r
29 import org.simantics.db.impl.TableIntAllocatorAdapter;\r
30 import org.simantics.db.impl.TableSizeListener;\r
31 import org.simantics.db.procore.cluster.TableIntArraySet2.Tables;\r
32 \r
33 public final class PredicateTable extends Table<int[]> {\r
34         \r
35         final TableIntAllocatorAdapter allocator;\r
36         \r
37     public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase) {\r
38         super(TableFactory.getIntFactory(), sizeListener, header, headerBase);\r
39         allocator = new TableIntAllocatorAdapter(this);\r
40     }\r
41     public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {\r
42         super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);\r
43         allocator = new TableIntAllocatorAdapter(this);\r
44     }\r
45     int createPredicateSet(int[] ps, int[] os)\r
46     throws DatabaseException {\r
47         int hashBase = TableIntArraySet2.create(ps, os, allocator);\r
48         return convertRealIndexToTableIndex(hashBase);\r
49     }\r
50     void deletePredicateSet(int predicateIndex) {\r
51         int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
52         if (TableIntArraySet2.isArraySet(getTable(), hashBase)) {\r
53             int capacity = TableIntArraySet2.getAllocatedSize(getTable(), hashBase);\r
54             int elementIndex = predicateIndex - TableIntArraySet2.HeaderSize;\r
55             deleteOldElement(elementIndex, capacity);\r
56         } else {\r
57             int capacity = TableIntSet2.getAllocatedSize(getTable(), hashBase);\r
58             int elementIndex = predicateIndex - TableIntSet2.HeaderSize;\r
59             deleteOldElement(elementIndex, capacity);\r
60         }\r
61     }\r
62     public int getPredicateSetSize(int predicateIndex) {\r
63         int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
64         if (TableIntArraySet2.isArraySet(getTable(), hashBase))\r
65             return TableIntArraySet2.getSize(getTable(), hashBase);\r
66         else\r
67             return TableIntSet2.getSize(getTable(), hashBase);\r
68     }\r
69     public int getObjectIndex(int predicateIndex, int pRef) {\r
70         int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
71         if (TableIntArraySet2.isArraySet(table, hashBase))\r
72             return TableIntArraySet2.get(table, hashBase, pRef);\r
73         else {\r
74             return TableIntSet2.get(table, hashBase, pRef);\r
75         }\r
76     }\r
77     private int addPredicateArray(int predicateIndex, int hashBase, int pReference, int oReference, ObjectTable ot)\r
78     throws DatabaseException {\r
79         int newHashBase;\r
80         int objectIndex = TableIntArraySet2.get(getTable(), hashBase, pReference);\r
81         if (0 == objectIndex) {\r
82             newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, oReference, allocator);\r
83         } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
84             int oRef = objectIndex;\r
85             if (oRef == oReference) {\r
86                 return 0; // old direct object\r
87             }\r
88             objectIndex = ot.createObjectSet(oRef, oReference);\r
89             assert(0 != objectIndex);\r
90             int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);\r
91             newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);\r
92         } else {\r
93             int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);\r
94             if (0 == newObjectIndex)\r
95                 return 0; // old indirect object\r
96             newObjectIndex = ClusterTraits.statementIndexMake(newObjectIndex);\r
97             newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);\r
98             if (newHashBase == 0)\r
99                 return hashBase;\r
100         }\r
101         int TABLE_SIZE = TableIntArraySet2.getSize(getTable(), newHashBase);\r
102         if (TABLE_SIZE > 5)\r
103             return convertToPredicateSet(predicateIndex, newHashBase);\r
104         return newHashBase;\r
105     }\r
106     private int convertToPredicateSet(int predicateIndex, int hashBase) {\r
107         Tables tables = TableIntArraySet2.getInts(getTable(), hashBase);\r
108         this.deletePredicateSet(predicateIndex);\r
109         int newHashBase = TableIntSet2.create(tables.keys, tables.vals, allocator);\r
110         assert(0 != newHashBase);\r
111         return newHashBase;\r
112     }\r
113     private int addPredicateSet(int hashBase, int pReference, int oReference, ObjectTable ot)\r
114     throws DatabaseException {\r
115         int objectIndex = TableIntSet2.get(getTable(), hashBase, pReference);\r
116         int newHashBase;\r
117         if (0 == objectIndex) {\r
118             newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, oReference, allocator);\r
119         } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
120             int oRef = objectIndex;\r
121             if (oRef == oReference) {\r
122                 return 0; // old direct object\r
123             }\r
124             objectIndex = ot.createObjectSet(oRef, oReference);\r
125             assert(0 != objectIndex);\r
126             int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);\r
127             newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);\r
128             assert(0 != newHashBase);\r
129         } else {\r
130             int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);\r
131             if (0 == newObjectIndex)\r
132                 return 0; // old indirect object\r
133             int stmIndex = ClusterTraits.statementIndexMake(newObjectIndex);\r
134             newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, stmIndex, allocator);\r
135             if (newHashBase == 0)\r
136                 return hashBase; // new object added to old predicate (set)\r
137         }\r
138         return newHashBase;\r
139     }\r
140     /**\r
141      * @param predicateIndex\r
142      * @param pReference\r
143      * @return zero if element was not added or predicate index.\r
144      * Predicate index will change if new space is allocated.\r
145      */\r
146     public int addPredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)\r
147     throws DatabaseException {\r
148         int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
149         int newHashBase;\r
150         if (TableIntArraySet2.isArraySet(getTable(), hashBase))\r
151            newHashBase = addPredicateArray(predicateIndex, hashBase, pReference, oReference, ot);\r
152         else\r
153            newHashBase = addPredicateSet(hashBase, pReference, oReference, ot);\r
154         if (0 == newHashBase)\r
155             return 0; // not modified\r
156         return convertRealIndexToTableIndex(newHashBase);\r
157     }\r
158     public enum Status {\r
159         NothingRemoved,\r
160         ObjectRemoved,\r
161         PredicateRemoved;\r
162     }\r
163     /**\r
164      * @param predicateIndex\r
165      * @param oResourceIndex\r
166      * @return null if nothing was removed. Status if either object or both\r
167      * object and predicate were removed. \r
168      */\r
169     public Status removePredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)\r
170     throws DatabaseException {\r
171         int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
172         int[] table = getTable();\r
173         if (TableIntArraySet2.isArraySet(table, hashBase)) {\r
174             int objectIndex = TableIntArraySet2.get(table, hashBase, pReference);\r
175             if (0 == objectIndex) {\r
176                 return Status.NothingRemoved;\r
177             } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
178                 int oRef = objectIndex;\r
179                 if (oRef != oReference)\r
180                     return Status.NothingRemoved;\r
181                 if (TableIntArraySet2.removeInt(table, hashBase, pReference))\r
182                     return Status.PredicateRemoved;\r
183                 else\r
184                     throw new DatabaseException("Internal error during remove.");\r
185             } else {\r
186                 int oIndex = ClusterTraits.statementIndexGet(objectIndex);\r
187                 int nO = ot.getObjectSetSize(oIndex);\r
188                 if (nO < 1)\r
189                     throw new DatabaseException("Illegal object set size="+nO);\r
190                 int nObject = ot.removeObject(objectIndex, oReference);\r
191                 if (nObject == 0) {\r
192                     ot.deleteObjectSet(oIndex);\r
193                     if (TableIntArraySet2.removeInt(table, hashBase, pReference))\r
194                         return Status.PredicateRemoved;\r
195                     else\r
196                         throw new DatabaseException("Internal error during remove (2).");\r
197                 } else if (nO == nObject)\r
198                     return Status.NothingRemoved;\r
199                 else\r
200                     return Status.ObjectRemoved;\r
201             }\r
202         } else {\r
203             int objectIndex = TableIntSet2.get(table, hashBase, pReference);\r
204             if (0 == objectIndex) {\r
205                 return Status.NothingRemoved;\r
206             } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
207                 int oRef = objectIndex;\r
208                 if (oRef != oReference)\r
209                     return Status.NothingRemoved;\r
210                 if (TableIntSet2.removeInt(table, hashBase, pReference))\r
211                     return Status.PredicateRemoved;\r
212                 else\r
213                     throw new DatabaseException("Internal error during remove (3).");\r
214             } else {\r
215                 int oIndex = ClusterTraits.statementIndexGet(objectIndex);\r
216                 int nO = ot.getObjectSetSize(oIndex);\r
217                 if (nO < 1)\r
218                     throw new DatabaseException("Illegal object set size="+nO);\r
219                 int nObject = ot.removeObject(objectIndex, oReference);\r
220                 if (nObject == 0) {\r
221                     ot.deleteObjectSet(oIndex);\r
222                     if (TableIntSet2.removeInt(table, hashBase, pReference))\r
223                         return Status.PredicateRemoved;\r
224                     else\r
225                         throw new DatabaseException("Internal error during remove (4).");\r
226                 } else if (nO == nObject)\r
227                     return Status.NothingRemoved;\r
228                 else\r
229                     return Status.ObjectRemoved;\r
230             }\r
231         }\r
232     }\r
233     public <Context> boolean foreachPredicate(int predicateIndex\r
234             , ClusterI.PredicateProcedure<Context> procedure\r
235             , Context context, ClusterSupport support, Modifier modifier)\r
236     throws DatabaseException {\r
237         final int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
238         boolean ret;\r
239         if (TableIntArraySet2.isArraySet(getTable(), hashBase))\r
240             ret = TableIntArraySet2.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
241         else\r
242             ret = TableIntSet2.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
243         return ret;\r
244     }\r
245     private void checkEntry(ClusterBase cluster, int[] table, int index)\r
246     throws DatabaseException {\r
247         assert(ClusterTraits.statementIndexIsDirect(table[index]));\r
248         int dr = table[index];\r
249         cluster.checkDirectReference(dr);\r
250         assert(table[index+1] != 0);\r
251         if (ClusterTraits.statementIndexIsDirect(table[index+1])) {\r
252                 cluster.checkDirectReference(table[index+1]);\r
253         } else {\r
254                 cluster.checkObjectSetReference(table[index+1]);\r
255         }\r
256     }\r
257     private TIntHashSet checkIndexSet = null;\r
258         public void check(ClusterBase cluster)\r
259         throws DatabaseException {\r
260         if (null == checkIndexSet)\r
261             checkIndexSet = new TIntHashSet();\r
262         else\r
263             checkIndexSet.clear();\r
264         int count = 0;\r
265         int[] table = getTable();\r
266         int ps = getHeader().getOffset() + ZERO_SHIFT;\r
267         int pe = ps + getTableSize();\r
268         for (int p=ps; p<pe;) {\r
269             int cap = p++;\r
270             if (table[cap] >= 0) {\r
271                 int use = p++;\r
272                 int fre = p++;\r
273                 int max = p++;\r
274                 assert(table[cap] >= table[use] + table[fre]);\r
275                 assert(table[max] == table[cap] >> 1);\r
276                 assert(table[max]+1 >= table[use]);\r
277                 checkIndexSet.add(p - ps);\r
278                 for (int e = p + table[cap]*2; p<e; p+=2) {\r
279                     if (!IntHashTrait.isFull(table[p])) \r
280                         assert(table[p+1]==0);\r
281                     else\r
282                         checkEntry(cluster, table, p);\r
283                 }\r
284             } else {\r
285                 final int size = -table[cap];\r
286                 assert(size > 0);\r
287                 boolean free = false;\r
288                 checkIndexSet.add(p - ps);\r
289                 for (int e = p + size*2; p<e; p+=2) {\r
290                     if (free) {\r
291                         assert(table[p] == 0);\r
292                         assert(table[p+1] == 0);\r
293                     }\r
294                     else if (table[p] == 0) {\r
295                         assert(table[p+1] == 0);\r
296                         free = true;\r
297                     } else\r
298                         checkEntry(cluster, table, p);\r
299                 }\r
300             }\r
301             count++;\r
302         }\r
303                 assert(getHeader().getCount() <= count);  // deleted objects are not recognized\r
304         }\r
305     public final void checkPredicateSetIndex(ClusterBase cluster, int i)\r
306     throws DatabaseException {\r
307         if (null == checkIndexSet)\r
308             check(cluster); // builds checkIndexSet\r
309         if (!checkIndexSet.contains(i-ZERO_SHIFT))\r
310             throw new ValidationException("Illegal predicate set index=" + i);\r
311     }\r
312     public void printDebugInfo() {\r
313         //int count = 0;\r
314         int[] table = getTable();\r
315         int ps = getHeader().getOffset() + ZERO_SHIFT;\r
316         int pe = ps + getTableSize();\r
317         TIntIntHashMap stat = new TIntIntHashMap();\r
318         TIntIntHashMap stat2 = new TIntIntHashMap();\r
319         for (int p=ps; p<pe;) {\r
320             int cap = p++;\r
321             if (table[cap] >= 0) {\r
322                 int use = p++;\r
323                 int fre = p++;\r
324                 int max = p++;\r
325                 assert(table[cap] >= table[use] + table[fre]);\r
326                 assert(table[max] == table[cap] >> 1);\r
327                 p += table[cap]*2;\r
328                 int val = stat.get(table[use]) + 1;\r
329                 stat.put(table[use], val);\r
330             } else {\r
331                 final int size = -table[cap];\r
332                 int val = stat2.get(size) + 1;\r
333                 stat2.put(size, val);\r
334                 p += size*2;\r
335             }\r
336             //count++;\r
337         }\r
338         //assert(getHeader().getCount() == count);\r
339         stat.forEachEntry(new TIntIntProcedure() {\r
340             @Override\r
341             public boolean execute(int a, int b) {\r
342                 System.out.println("predicate set capacity " + a + " instance count " + b);\r
343                 return true;\r
344             }\r
345         });\r
346         stat2.forEachEntry(new TIntIntProcedure() {\r
347             @Override\r
348             public boolean execute(int a, int b) {\r
349                 System.out.println("predicate array set capacity " + a + " instance count " + b);\r
350                 return true;\r
351             }\r
352         });\r
353   }\r
354     @Override\r
355     public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,\r
356             ClusterSupport support, Modifier modifier) throws DatabaseException {\r
357         return foreachPredicate(setIndex, (PredicateProcedure<Context>)procedure, context, support, modifier);\r
358     }\r
359 }\r