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