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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.db.procore.cluster;
\r
14 import gnu.trove.map.hash.TIntIntHashMap;
\r
15 import gnu.trove.procedure.TIntIntProcedure;
\r
16 import gnu.trove.set.hash.TIntHashSet;
\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
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
38 public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {
\r
39 super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);
\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
48 int hashBase = TableIntArraySet.create(obs, new TableIntAllocatorAdapter(this));
\r
49 return convertRealIndexToTableIndex(hashBase);
\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
59 int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase);
\r
60 int elementIndex = index - TableIntSet.HeaderSize;
\r
61 deleteOldElement(elementIndex, capacity);
\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
69 return TableIntSet.getSize(getTable(), hashBase);
\r
73 * @param oResourceIndex
\r
74 * @return zero if complete already in the set else index of the set
\r
76 final int addComplete(int setIndex, int oResourceIndex)
\r
77 throws DatabaseException {
\r
78 int hashBase = checkIndexAndGetRealIndex(setIndex, 0);
\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
84 Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex);
\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
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
98 final int removeLast(int setIndex)
\r
99 throws DatabaseException {
\r
100 int hashBase = checkIndexAndGetRealIndex(setIndex, 0);
\r
101 int[] table = getTable();
\r
103 if (TableIntArraySet.isArraySet(table, hashBase))
\r
104 ref = TableIntArraySet.removeIntLast(table, hashBase);
\r
106 ref = TableIntSet.removeIntLast(table, hashBase);
\r
108 deleteCompleteSet(setIndex);
\r
113 * @param oResourceIndex
\r
114 * @return number of objects after removal.
\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
123 TableIntSet.removeInt(table, hashBase, oResourceIndex);
\r
124 return TableIntSet.getSize(table, hashBase);
\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
132 if (TableIntArraySet.isArraySet(getTable(), hashBase))
\r
133 ret = TableIntArraySet.foreachInt(getTable(), hashBase, procedure, context, modifier);
\r
135 ret = TableIntSet.foreachInt(getTable(), hashBase, procedure, context, modifier);
\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
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
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
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
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
177 checkIndexSet.clear();
\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
184 if (table[cap] >= 0) {
\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
197 final int size = -table[cap];
\r
199 checkIndexSet.add(p - ps);
\r
200 boolean free = false;
\r
201 for (int e = p + size; p<e; p++) {
\r
203 assert(table[p] == 0);
\r
204 else if (table[p] == 0)
\r
207 checkEntry(cluster, table, p);
\r
212 assert(getHeader().getCount() <= count); // deleted objects are not recognized
\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
221 final void printDebugInfo() {
\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
230 if (table[cap] >= 0) {
\r
234 assert(table[cap] >= table[use] + table[fre]);
\r
235 assert(table[max] == table[cap] >> 1);
\r
237 int val = stat.get(table[use]) + 1;
\r
238 stat.put(table[use], val);
\r
240 final int size = -table[cap];
\r
241 int val = stat2.get(size) + 1;
\r
242 stat2.put(size, val);
\r
247 assert(getHeader().getCount() == count);
\r
248 stat.forEachEntry(new TIntIntProcedure() {
\r
250 public boolean execute(int a, int b) {
\r
251 System.out.println("complete set capacity " + a + " instance count " + b);
\r
255 stat2.forEachEntry(new TIntIntProcedure() {
\r
257 public boolean execute(int a, int b) {
\r
258 System.out.println("complete array set capacity " + a + " instance count " + b);
\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
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
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
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
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
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
313 if (null == modifier)
\r
314 externalRef = resourceIndex;
\r
316 externalRef = modifier.execute(resourceIndex);
\r
317 return procedure.execute(context, externalRef);
\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
330 return false; // continue looping
\r