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 org.simantics.db.Resource;
15 import org.simantics.db.exception.DatabaseException;
16 import org.simantics.db.exception.ValidationException;
17 import org.simantics.db.impl.ClusterBase;
18 import org.simantics.db.impl.ClusterI;
19 import org.simantics.db.impl.ClusterI.ObjectProcedure;
20 import org.simantics.db.impl.ClusterI.Procedure;
21 import org.simantics.db.impl.ClusterSupport;
22 import org.simantics.db.impl.Modifier;
23 import org.simantics.db.impl.ResourceImpl;
24 import org.simantics.db.impl.Table;
25 import org.simantics.db.impl.TableFactory;
26 import org.simantics.db.impl.TableIntAllocatorAdapter;
27 import org.simantics.db.impl.TableSizeListener;
28 import org.simantics.db.impl.graph.ReadGraphImpl;
29 import org.simantics.db.procedure.SyncContextMultiProcedure;
30 import org.simantics.db.procedure.SyncMultiProcedure;
31 import org.simantics.db.procore.cluster.TableIntArraySet.Ints;
33 import gnu.trove.map.hash.TIntIntHashMap;
34 import gnu.trove.procedure.TIntIntProcedure;
35 import gnu.trove.set.hash.TIntHashSet;
37 public final class ObjectTable extends Table<int[]> {
39 final TableIntAllocatorAdapter allocator;
41 public ObjectTable(TableSizeListener sizeListener, int[] header, int headerBase) {
42 super(TableFactory.getIntFactory(), sizeListener, header, headerBase);
43 allocator = new TableIntAllocatorAdapter(this);
46 public ObjectTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {
47 super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);
48 allocator = new TableIntAllocatorAdapter(this);
51 final int createObjectSet(int o1, int o2) throws DatabaseException {
52 if (0 == o1 || o1 == o2)
53 throw new DatabaseException("Illegal argument to createObejctSet");
54 int[] obs = new int[2];
57 int hashBase = TableIntArraySet.create(obs, allocator);
58 return convertRealIndexToTableIndex(hashBase);
61 final void deleteObjectSet(int objectIndex) throws DatabaseException {
62 int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);
63 if (TableIntArraySet.isArraySet(getTable(), hashBase)) {
64 int capacity = TableIntArraySet.getAllocatedSize(getTable(), hashBase);
65 int elementIndex = objectIndex - TableIntArraySet.HeaderSize;
66 deleteOldElement(elementIndex, capacity);
68 int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase);
69 int elementIndex = objectIndex - TableIntSet.HeaderSize;
70 deleteOldElement(elementIndex, capacity);
74 public final int getObjectSetSize(int objectIndex) {
75 int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);
76 if (TableIntArraySet.isArraySet(getTable(), hashBase))
77 return TableIntArraySet.getSize(getTable(), hashBase);
79 return TableIntSet.getSize(getTable(), hashBase);
84 * @param oResourceIndex
85 * @return zero if object already in the set else object index of the set
87 final int addObject(int objectIndex, int oResourceIndex) throws DatabaseException {
88 int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);
90 if (TableIntArraySet.isArraySet(getTable(), hashBase)) {
91 if (TableIntArraySet.getSize(getTable(), hashBase) < 5)
92 newHashBase = TableIntArraySet.addInt(getTable(), hashBase, oResourceIndex, allocator);
94 Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex);
96 return 0; // old object, not modified
97 this.deleteObjectSet(objectIndex);
98 newHashBase = TableIntSet.create(ints.ints, allocator);
99 assert(0 != newHashBase);
102 newHashBase = TableIntSet.addInt(getTable(), hashBase, oResourceIndex, allocator);
103 if (0 == newHashBase)
104 return 0; // old object, not modified
105 int ni = convertRealIndexToTableIndex(newHashBase);
111 * @param oResourceIndex
112 * @return number of objects after removal.
114 final int removeObject(int objectIndex, int oResourceIndex) throws DatabaseException {
115 if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
116 int pRef = objectIndex;
117 if (oResourceIndex == pRef) {
122 objectIndex = ClusterTraits.statementIndexGet(objectIndex);
123 int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);
124 int[] table = getTable();
125 if (TableIntArraySet.isArraySet(table, hashBase))
126 return TableIntArraySet.removeInt(table, hashBase, oResourceIndex);
128 TableIntSet.removeInt(table, hashBase, oResourceIndex);
129 return TableIntSet.getSize(table, hashBase);
133 final public int getSingleObject(final int objectIndex, final ClusterSupport support, Modifier modifier) throws DatabaseException {
135 if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
136 return modifier.execute(objectIndex);
139 int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);
140 final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);
141 if (TableIntArraySet.isArraySet(getTable(), hashBase))
142 return TableIntArraySet.getSingleInt(getTable(), hashBase, modifier);
144 return IntHash.getSingleInt(getTable(), hashBase, modifier);
148 final public void foreachObject( ReadGraphImpl graph, final int objectIndex,
149 final SyncMultiProcedure<Resource> procedure, Modifier modifier) throws DatabaseException {
150 if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
151 int key = modifier.execute(objectIndex);
152 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), key));
153 procedure.finished(graph);
157 int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);
158 final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);
159 if (TableIntArraySet.isArraySet(getTable(), hashBase))
160 TableIntArraySet.foreachInt(getTable(), hashBase, graph, procedure, modifier);
162 IntHash.foreachInt(graph, table, hashBase, procedure, modifier);
165 final public <C> void foreachObject( ReadGraphImpl graph, final int objectIndex, C context,
166 final SyncContextMultiProcedure<C, Resource> procedure, Modifier modifier) throws DatabaseException {
167 if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
168 int key = modifier.execute(objectIndex);
169 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), key));
170 procedure.finished(graph, context);
174 int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);
175 final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);
176 if (TableIntArraySet.isArraySet(getTable(), hashBase))
177 TableIntArraySet.foreachInt(getTable(), hashBase, graph, context, procedure, modifier);
179 IntHash.foreachInt(graph, table, hashBase, context, procedure, modifier);
182 final public <Context> boolean foreachObject(final int objectIndex,
183 final ClusterI.ObjectProcedure<Context> procedure, final Context context, final ClusterSupport support,
184 final Modifier modifier) throws DatabaseException {
185 if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
186 int pRef = objectIndex;
188 if (null == modifier)
191 key = modifier.execute(pRef);
192 if (procedure.execute(context, key))
193 return true; // loop broken by procedure
194 return false; // loop finished
196 int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);
197 final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);
199 if (TableIntArraySet.isArraySet(getTable(), hashBase))
200 ret = TableIntArraySet.foreachInt(getTable(), hashBase, procedure, context, modifier);
202 ret = TableIntSet.foreachInt(getTable(), hashBase, procedure, context, modifier);
206 private void checkEntry(ClusterBase cluster, int[] table, int index)
207 throws DatabaseException {
208 if (!ClusterTraits.statementIndexIsDirect(table[index]))
209 throw new ValidationException("Illegal ObjectTable entry. Entry=" + table[index] + " index=" + index);
210 int dr = table[index];
211 cluster.checkDirectReference(dr);
213 private TIntHashSet checkIndexSet = null;
214 public final void check(ClusterBase cluster)
215 throws DatabaseException {
216 if (null == checkIndexSet)
217 checkIndexSet = new TIntHashSet();
219 checkIndexSet.clear();
221 int[] table = getTable();
222 int ps = getHeader().getOffset() + ZERO_SHIFT;
223 int pe = ps + getTableSize();
224 for (int p = ps; p < pe;) {
226 if (table[cap] >= 0) {
230 assert(table[cap] >= table[use] + table[fre]);
231 assert(table[max] == table[cap] >> 1);
232 assert(table[max]+1 >= table[use]);
233 checkIndexSet.add(p - ps);
234 for (int e = p + table[cap]; p<e; p++) {
235 if (IntHashTrait.isFull(table[p]))
236 checkEntry(cluster, table, p);
239 final int size = -table[cap];
241 checkIndexSet.add(p - ps);
242 boolean free = false;
243 for (int e = p + size; p<e; p++) {
245 assert(table[p] == 0);
246 else if (table[p] == 0)
249 checkEntry(cluster, table, p);
254 assert(getHeader().getCount() <= count); // deleted objects are not recognized
257 public final void checkObjectSetIndex(ClusterBase cluster, int i)
258 throws DatabaseException {
259 if (null == checkIndexSet)
260 check(cluster); // builds checkIndexSet
261 if (!checkIndexSet.contains(i-ZERO_SHIFT))
262 throw new ValidationException("Illegal object set index=" + i);
264 public final void printDebugInfo() {
266 int[] table = getTable();
267 int ps = getHeader().getOffset() + ZERO_SHIFT;
268 int pe = ps + getTableSize();
269 TIntIntHashMap stat = new TIntIntHashMap();
270 TIntIntHashMap stat2 = new TIntIntHashMap();
271 for (int p = ps; p < pe;) {
273 if (table[cap] >= 0) {
277 assert(table[cap] >= table[use] + table[fre]);
278 assert(table[max] == table[cap] >> 1);
280 int val = stat.get(table[use]) + 1;
281 stat.put(table[use], val);
283 final int size = -table[cap];
284 int val = stat2.get(size) + 1;
285 stat2.put(size, val);
290 // assert(getHeader().getCount() == count);
291 stat.forEachEntry(new TIntIntProcedure() {
293 public boolean execute(int a, int b) {
294 System.out.println("object set capacity " + a + " instance count " + b);
298 stat2.forEachEntry(new TIntIntProcedure() {
300 public boolean execute(int a, int b) {
301 System.out.println("object array set capacity " + a + " instance count " + b);
308 public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,
309 ClusterSupport support, Modifier modifier) throws DatabaseException {
310 return foreachObject(setIndex, (ObjectProcedure<Context>)procedure, context, support, modifier);