1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.procore.cluster;
14 import gnu.trove.map.hash.TIntIntHashMap;
15 import gnu.trove.procedure.TIntIntProcedure;
16 import gnu.trove.set.hash.TIntHashSet;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.exception.ValidationException;
20 import org.simantics.db.impl.ClusterBase;
21 import org.simantics.db.impl.ClusterI;
22 import org.simantics.db.impl.ClusterI.CompleteTypeEnum;
23 import org.simantics.db.impl.ClusterI.ObjectProcedure;
24 import org.simantics.db.impl.ClusterI.Procedure;
25 import org.simantics.db.impl.ClusterSupport;
26 import org.simantics.db.impl.ClusterTraitsBase;
27 import org.simantics.db.impl.Modifier;
28 import org.simantics.db.impl.Table;
29 import org.simantics.db.impl.TableFactory;
30 import org.simantics.db.impl.TableIntAllocatorAdapter;
31 import org.simantics.db.impl.TableSizeListener;
32 import org.simantics.db.procore.cluster.TableIntArraySet.Ints;
34 public class CompleteTable extends Table<int[]> {
35 public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase) {
36 super(TableFactory.getIntFactory(), sizeListener, header, headerBase);
38 public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {
39 super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);
41 final int createCompleteArraySet(int o1, int o2)
42 throws DatabaseException {
43 if (0 == o1 || o1 == o2)
44 throw new DatabaseException("Illegal argument to createObejctArray");
45 int[] obs = new int[2];
48 int hashBase = TableIntArraySet.create(obs, new TableIntAllocatorAdapter(this));
49 return convertRealIndexToTableIndex(hashBase);
51 final void deleteCompleteSet(int index)
52 throws DatabaseException {
53 int hashBase = checkIndexAndGetRealIndex(index, 0);
54 if (TableIntArraySet.isArraySet(getTable(), hashBase)) {
55 int capacity = TableIntArraySet.getAllocatedSize(getTable(), hashBase);
56 int elementIndex = index - TableIntArraySet.HeaderSize;
57 deleteOldElement(elementIndex, capacity);
59 int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase);
60 int elementIndex = index - TableIntSet.HeaderSize;
61 deleteOldElement(elementIndex, capacity);
64 final int getCompleteSetSize(int objectIndex) {
65 int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);
66 if (TableIntArraySet.isArraySet(getTable(), hashBase))
67 return TableIntArraySet.getSize(getTable(), hashBase);
69 return TableIntSet.getSize(getTable(), hashBase);
73 * @param oResourceIndex
74 * @return zero if complete already in the set else index of the set
76 final int addComplete(int setIndex, int oResourceIndex)
77 throws DatabaseException {
78 int hashBase = checkIndexAndGetRealIndex(setIndex, 0);
80 if (TableIntArraySet.isArraySet(getTable(), hashBase)) {
81 if (TableIntArraySet.getSize(getTable(), hashBase) < 5)
82 newHashBase = TableIntArraySet.addInt(getTable(), hashBase, oResourceIndex, new TableIntAllocatorAdapter(this));
84 Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex);
86 return 0; // old object, not modified
87 this.deleteCompleteSet(setIndex);
88 newHashBase = TableIntSet.create(ints.ints, new TableIntAllocatorAdapter(this));
89 assert(0 != newHashBase);
92 newHashBase = TableIntSet.addInt(getTable(), hashBase, oResourceIndex, new TableIntAllocatorAdapter(this));
94 return 0; // old object, not modified
95 int ni = convertRealIndexToTableIndex(newHashBase);
98 final int removeLast(int setIndex)
99 throws DatabaseException {
100 int hashBase = checkIndexAndGetRealIndex(setIndex, 0);
101 int[] table = getTable();
103 if (TableIntArraySet.isArraySet(table, hashBase))
104 ref = TableIntArraySet.removeIntLast(table, hashBase);
106 ref = TableIntSet.removeIntLast(table, hashBase);
108 deleteCompleteSet(setIndex);
113 * @param oResourceIndex
114 * @return number of objects after removal.
116 final int removeComplete(int setIndex, int oResourceIndex)
117 throws DatabaseException {
118 int hashBase = checkIndexAndGetRealIndex(setIndex, 0);
119 int[] table = getTable();
120 if (TableIntArraySet.isArraySet(table, hashBase))
121 return TableIntArraySet.removeInt(table, hashBase, oResourceIndex);
123 TableIntSet.removeInt(table, hashBase, oResourceIndex);
124 return TableIntSet.getSize(table, hashBase);
127 final public <Context> boolean foreachComplete(final int setIndex,
128 final ClusterI.ObjectProcedure<Context> procedure, final Context context, final ClusterSupport support,
129 final Modifier modifier) throws DatabaseException {
130 final int hashBase = checkIndexAndGetRealIndex(setIndex, 0);
132 if (TableIntArraySet.isArraySet(getTable(), hashBase))
133 ret = TableIntArraySet.foreachInt(getTable(), hashBase, procedure, context, modifier);
135 ret = TableIntSet.foreachInt(getTable(), hashBase, procedure, context, modifier);
138 public <Context> boolean foreachPredicate(int setIndex,
139 ClusterI.PredicateProcedure<Context> procedure,
140 Context context, ClusterSupport support, Modifier modifier)
141 throws DatabaseException {
142 ForeachPredicate<Context> t = new ForeachPredicate<Context>(procedure, support, modifier);
143 return foreachComplete(setIndex, t, context, null, null);
146 public <Context> boolean foreachObject(int setIndex,
147 ClusterI.ObjectProcedure<Context> procedure,
148 Context context, ClusterSupport support, Modifier modifier,
149 ClusterI.CompleteTypeEnum completeType)
150 throws DatabaseException {
151 ForeachObject<Context> t = new ForeachObject<Context>
152 (procedure, support, modifier, completeType);
153 return foreachComplete(setIndex, t, context, null, null);
156 private void checkEntry(ClusterBase cluster, int[] table, int index)
157 throws DatabaseException {
158 ClusterI.CompleteTypeEnum type = ClusterTraits.completeReferenceGetType(table[index]);
159 if (type == CompleteTypeEnum.NotComplete)
160 throw new ValidationException("Illegal CompleteTable entry type. Entry=" + table[index] + " index=" + index);
161 int fi = ClusterTraits.completeReferenceGetForeignIndex(table[index]);
162 int ri = ClusterTraits.completeReferenceGetResourceIndex(table[index]);
164 cluster.checkForeingIndex(fi);
165 if (ri < 1 || ri > ClusterTraits.getMaxNumberOfResources())
166 throw new ValidationException("Illegal CompleteTable foreign entry. Entry=" + table[index] + " index=" + index);
167 } /*else if (ri < 1 || ri > cluster.getNumberOfResources(-1))
168 throw new ValidationException("Illegal CompleteTable local entry. Entry=" + table[index] + " index=" + index);*/
171 private TIntHashSet checkIndexSet = null;
172 public final void check(ClusterBase cluster)
173 throws DatabaseException {
174 if (null == checkIndexSet)
175 checkIndexSet = new TIntHashSet();
177 checkIndexSet.clear();
179 int[] table = getTable();
180 int ps = getHeader().getOffset() + ZERO_SHIFT;
181 int pe = ps + getTableSize();
182 for (int p = ps; p < pe;) {
184 if (table[cap] >= 0) {
188 assert(table[cap] >= table[use] + table[fre]);
189 assert(table[max] == table[cap] >> 1);
190 assert(table[max]+1 >= table[use]);
191 checkIndexSet.add(p - ps);
192 for (int e = p + table[cap]; p<e; p++) {
193 if (IntHashTrait.isFull(table[p]))
194 checkEntry(cluster, table, p);
197 final int size = -table[cap];
199 checkIndexSet.add(p - ps);
200 boolean free = false;
201 for (int e = p + size; p<e; p++) {
203 assert(table[p] == 0);
204 else if (table[p] == 0)
207 checkEntry(cluster, table, p);
212 assert(getHeader().getCount() <= count); // deleted objects are not recognized
214 public final void checkCompleteSetIndex(ClusterBase cluster, int i)
215 throws DatabaseException {
216 if (null == checkIndexSet)
217 check(cluster); // builds checkIndexSet
218 if (!checkIndexSet.contains(i-ZERO_SHIFT))
219 throw new ValidationException("Illegal object set index=" + i);
221 final void printDebugInfo() {
223 int[] table = getTable();
224 int ps = getHeader().getOffset() + ZERO_SHIFT;
225 int pe = ps + getTableSize();
226 TIntIntHashMap stat = new TIntIntHashMap();
227 TIntIntHashMap stat2 = new TIntIntHashMap();
228 for (int p=ps; p<pe;) {
230 if (table[cap] >= 0) {
234 assert(table[cap] >= table[use] + table[fre]);
235 assert(table[max] == table[cap] >> 1);
237 int val = stat.get(table[use]) + 1;
238 stat.put(table[use], val);
240 final int size = -table[cap];
241 int val = stat2.get(size) + 1;
242 stat2.put(size, val);
247 assert(getHeader().getCount() == count);
248 stat.forEachEntry(new TIntIntProcedure() {
250 public boolean execute(int a, int b) {
251 System.out.println("complete set capacity " + a + " instance count " + b);
255 stat2.forEachEntry(new TIntIntProcedure() {
257 public boolean execute(int a, int b) {
258 System.out.println("complete array set capacity " + a + " instance count " + b);
264 public <Context> boolean foreach(int setIndex, Procedure procedure, Context context, ClusterSupport support, Modifier modifier) throws DatabaseException {
265 return foreachComplete(setIndex, (ObjectProcedure<Context>)procedure, context, support, modifier);
268 class ForeachPredicate<Context>
269 implements ClusterI.ObjectProcedure<Context> {
270 private TIntHashSet completeTypes = new TIntHashSet();
271 private ClusterI.PredicateProcedure<Context> procedure;
272 public ForeachPredicate(ClusterI.PredicateProcedure<Context>
273 procedure, ClusterSupport support, Modifier modifier) {
274 this.procedure = procedure;
277 public boolean execute(Context context, int completeRef) {
278 ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
279 if (!completeTypes.contains(completeType.getValue())) {
280 completeTypes.add(completeType.getValue());
282 int pKey = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);
283 if (procedure.execute(context, pKey, 0))
284 return true; // loop broken by procedure
285 } catch (DatabaseException e) {
294 class ForeachObject<Context>
295 implements ClusterI.ObjectProcedure<Context> {
296 private ClusterI.ObjectProcedure<Context> procedure;
297 private Modifier modifier;
298 private ClusterI.CompleteTypeEnum completeType;
299 public ForeachObject(ClusterI.ObjectProcedure<Context>
300 procedure, ClusterSupport support, Modifier modifier, ClusterI.CompleteTypeEnum completeType) {
301 this.procedure = procedure;
302 this.modifier = modifier;
303 this.completeType = completeType;
306 public boolean execute(Context context, int completeRef) throws DatabaseException {
307 ClusterI.CompleteTypeEnum completeType2 = ClusterTraits.completeReferenceGetType(completeRef);
308 if (completeType == completeType2) {
309 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
310 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
311 if (0 == clusterIndex) {
313 if (null == modifier)
314 externalRef = resourceIndex;
316 externalRef = modifier.execute(resourceIndex);
317 return procedure.execute(context, externalRef);
320 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
321 if (null != modifier)
322 externalRef = modifier.execute(externalRef);
323 return procedure.execute(context, externalRef);
324 } catch (DatabaseException e) {
326 return false; // continue looping
330 return false; // continue looping