/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.db.procore.cluster; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ValidationException; import org.simantics.db.impl.ClusterBase; import org.simantics.db.impl.ClusterI; import org.simantics.db.impl.ClusterI.ObjectProcedure; import org.simantics.db.impl.ClusterI.Procedure; import org.simantics.db.impl.ClusterSupport; import org.simantics.db.impl.Modifier; import org.simantics.db.impl.ResourceImpl; import org.simantics.db.impl.Table; import org.simantics.db.impl.TableFactory; import org.simantics.db.impl.TableIntAllocatorAdapter; import org.simantics.db.impl.TableSizeListener; import org.simantics.db.impl.graph.ReadGraphImpl; import org.simantics.db.procedure.AsyncContextMultiProcedure; import org.simantics.db.procedure.AsyncMultiProcedure; import org.simantics.db.procore.cluster.TableIntArraySet.Ints; import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.procedure.TIntIntProcedure; import gnu.trove.set.hash.TIntHashSet; public final class ObjectTable extends Table { final TableIntAllocatorAdapter allocator; public ObjectTable(TableSizeListener sizeListener, int[] header, int headerBase) { super(TableFactory.getIntFactory(), sizeListener, header, headerBase); allocator = new TableIntAllocatorAdapter(this); } public ObjectTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) { super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints); allocator = new TableIntAllocatorAdapter(this); } final int createObjectSet(int o1, int o2) throws DatabaseException { if (0 == o1 || o1 == o2) throw new DatabaseException("Illegal argument to createObejctSet"); int[] obs = new int[2]; obs[0] = o1; obs[1] = o2; int hashBase = TableIntArraySet.create(obs, allocator); return convertRealIndexToTableIndex(hashBase); } final void deleteObjectSet(int objectIndex) throws DatabaseException { int hashBase = checkIndexAndGetRealIndex(objectIndex, 0); if (TableIntArraySet.isArraySet(getTable(), hashBase)) { int capacity = TableIntArraySet.getAllocatedSize(getTable(), hashBase); int elementIndex = objectIndex - TableIntArraySet.HeaderSize; deleteOldElement(elementIndex, capacity); } else { int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase); int elementIndex = objectIndex - TableIntSet.HeaderSize; deleteOldElement(elementIndex, capacity); } } public final int getObjectSetSize(int objectIndex) { int hashBase = checkIndexAndGetRealIndex(objectIndex, 0); if (TableIntArraySet.isArraySet(getTable(), hashBase)) return TableIntArraySet.getSize(getTable(), hashBase); else return TableIntSet.getSize(getTable(), hashBase); } /** * @param objectIndex * @param oResourceIndex * @return zero if object already in the set else object index of the set */ final int addObject(int objectIndex, int oResourceIndex) throws DatabaseException { int hashBase = checkIndexAndGetRealIndex(objectIndex, 0); int newHashBase; if (TableIntArraySet.isArraySet(getTable(), hashBase)) { if (TableIntArraySet.getSize(getTable(), hashBase) < 5) newHashBase = TableIntArraySet.addInt(getTable(), hashBase, oResourceIndex, allocator); else { Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex); if (ints.found) return 0; // old object, not modified this.deleteObjectSet(objectIndex); newHashBase = TableIntSet.create(ints.ints, allocator); assert(0 != newHashBase); } } else newHashBase = TableIntSet.addInt(getTable(), hashBase, oResourceIndex, allocator); if (0 == newHashBase) return 0; // old object, not modified int ni = convertRealIndexToTableIndex(newHashBase); return ni; } /** * @param objectIndex * @param oResourceIndex * @return number of objects after removal. */ final int removeObject(int objectIndex, int oResourceIndex) throws DatabaseException { if (ClusterTraits.statementIndexIsDirect(objectIndex)) { int pRef = objectIndex; if (oResourceIndex == pRef) { return 0; } else return 1; } else objectIndex = ClusterTraits.statementIndexGet(objectIndex); int hashBase = checkIndexAndGetRealIndex(objectIndex, 0); int[] table = getTable(); if (TableIntArraySet.isArraySet(table, hashBase)) return TableIntArraySet.removeInt(table, hashBase, oResourceIndex); else { TableIntSet.removeInt(table, hashBase, oResourceIndex); return TableIntSet.getSize(table, hashBase); } } final public int getSingleObject(final int objectIndex, final ClusterSupport support, Modifier modifier) throws DatabaseException { if (ClusterTraits.statementIndexIsDirect(objectIndex)) { return modifier.execute(objectIndex); } int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex); final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0); if (TableIntArraySet.isArraySet(getTable(), hashBase)) return TableIntArraySet.getSingleInt(getTable(), hashBase, modifier); else return IntHash.getSingleInt(getTable(), hashBase, modifier); } final public void foreachObject( ReadGraphImpl graph, final int objectIndex, final AsyncMultiProcedure procedure, Modifier modifier) throws DatabaseException { if (ClusterTraits.statementIndexIsDirect(objectIndex)) { int key = modifier.execute(objectIndex); procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), key)); procedure.finished(graph); // graph.dec(); return; } int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex); final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0); if (TableIntArraySet.isArraySet(getTable(), hashBase)) TableIntArraySet.foreachInt(getTable(), hashBase, graph, procedure, modifier); else IntHash.foreachInt(graph, table, hashBase, procedure, modifier); } final public void foreachObject( ReadGraphImpl graph, final int objectIndex, C context, final AsyncContextMultiProcedure procedure, Modifier modifier) throws DatabaseException { if (ClusterTraits.statementIndexIsDirect(objectIndex)) { int key = modifier.execute(objectIndex); procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), key)); procedure.finished(graph, context); // graph.dec(); return; } int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex); final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0); if (TableIntArraySet.isArraySet(getTable(), hashBase)) TableIntArraySet.foreachInt(getTable(), hashBase, graph, context, procedure, modifier); else IntHash.foreachInt(graph, table, hashBase, context, procedure, modifier); } final public boolean foreachObject(final int objectIndex, final ClusterI.ObjectProcedure procedure, final Context context, final ClusterSupport support, final Modifier modifier) throws DatabaseException { if (ClusterTraits.statementIndexIsDirect(objectIndex)) { int pRef = objectIndex; int key; if (null == modifier) key = pRef; else key = modifier.execute(pRef); if (procedure.execute(context, key)) return true; // loop broken by procedure return false; // loop finished } int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex); final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0); boolean ret; if (TableIntArraySet.isArraySet(getTable(), hashBase)) ret = TableIntArraySet.foreachInt(getTable(), hashBase, procedure, context, modifier); else ret = TableIntSet.foreachInt(getTable(), hashBase, procedure, context, modifier); return ret; } private void checkEntry(ClusterBase cluster, int[] table, int index) throws DatabaseException { if (!ClusterTraits.statementIndexIsDirect(table[index])) throw new ValidationException("Illegal ObjectTable entry. Entry=" + table[index] + " index=" + index); int dr = table[index]; cluster.checkDirectReference(dr); } private TIntHashSet checkIndexSet = null; public final void check(ClusterBase cluster) throws DatabaseException { if (null == checkIndexSet) checkIndexSet = new TIntHashSet(); else checkIndexSet.clear(); int count = 0; int[] table = getTable(); int ps = getHeader().getOffset() + ZERO_SHIFT; int pe = ps + getTableSize(); for (int p = ps; p < pe;) { int cap = p++; if (table[cap] >= 0) { int use = p++; int fre = p++; int max = p++; assert(table[cap] >= table[use] + table[fre]); assert(table[max] == table[cap] >> 1); assert(table[max]+1 >= table[use]); checkIndexSet.add(p - ps); for (int e = p + table[cap]; p 0); checkIndexSet.add(p - ps); boolean free = false; for (int e = p + size; p boolean foreach(int setIndex, Procedure procedure, Context context, ClusterSupport support, Modifier modifier) throws DatabaseException { return foreachObject(setIndex, (ObjectProcedure)procedure, context, support, modifier); } }