/******************************************************************************* * 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 gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.procedure.TIntIntProcedure; import gnu.trove.set.hash.TIntHashSet; 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.CompleteTypeEnum; 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.ClusterTraitsBase; import org.simantics.db.impl.Modifier; 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.procore.cluster.TableIntArraySet.Ints; public class CompleteTable extends Table { public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase) { super(TableFactory.getIntFactory(), sizeListener, header, headerBase); } public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) { super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints); } final int createCompleteArraySet(int o1, int o2) throws DatabaseException { if (0 == o1 || o1 == o2) throw new DatabaseException("Illegal argument to createObejctArray"); int[] obs = new int[2]; obs[0] = o1; obs[1] = o2; int hashBase = TableIntArraySet.create(obs, new TableIntAllocatorAdapter(this)); return convertRealIndexToTableIndex(hashBase); } final void deleteCompleteSet(int index) throws DatabaseException { int hashBase = checkIndexAndGetRealIndex(index, 0); if (TableIntArraySet.isArraySet(getTable(), hashBase)) { int capacity = TableIntArraySet.getAllocatedSize(getTable(), hashBase); int elementIndex = index - TableIntArraySet.HeaderSize; deleteOldElement(elementIndex, capacity); } else { int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase); int elementIndex = index - TableIntSet.HeaderSize; deleteOldElement(elementIndex, capacity); } } final int getCompleteSetSize(int objectIndex) { int hashBase = checkIndexAndGetRealIndex(objectIndex, 0); if (TableIntArraySet.isArraySet(getTable(), hashBase)) return TableIntArraySet.getSize(getTable(), hashBase); else return TableIntSet.getSize(getTable(), hashBase); } /** * @param setIndex * @param oResourceIndex * @return zero if complete already in the set else index of the set */ final int addComplete(int setIndex, int oResourceIndex) throws DatabaseException { int hashBase = checkIndexAndGetRealIndex(setIndex, 0); int newHashBase; if (TableIntArraySet.isArraySet(getTable(), hashBase)) { if (TableIntArraySet.getSize(getTable(), hashBase) < 5) newHashBase = TableIntArraySet.addInt(getTable(), hashBase, oResourceIndex, new TableIntAllocatorAdapter(this)); else { Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex); if (ints.found) return 0; // old object, not modified this.deleteCompleteSet(setIndex); newHashBase = TableIntSet.create(ints.ints, new TableIntAllocatorAdapter(this)); assert(0 != newHashBase); } } else newHashBase = TableIntSet.addInt(getTable(), hashBase, oResourceIndex, new TableIntAllocatorAdapter(this)); if (0 == newHashBase) return 0; // old object, not modified int ni = convertRealIndexToTableIndex(newHashBase); return ni; } final int removeLast(int setIndex) throws DatabaseException { int hashBase = checkIndexAndGetRealIndex(setIndex, 0); int[] table = getTable(); int ref; if (TableIntArraySet.isArraySet(table, hashBase)) ref = TableIntArraySet.removeIntLast(table, hashBase); else { ref = TableIntSet.removeIntLast(table, hashBase); } deleteCompleteSet(setIndex); return ref; } /** * @param setIndex * @param oResourceIndex * @return number of objects after removal. */ final int removeComplete(int setIndex, int oResourceIndex) throws DatabaseException { int hashBase = checkIndexAndGetRealIndex(setIndex, 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 boolean foreachComplete(final int setIndex, final ClusterI.ObjectProcedure procedure, final Context context, final ClusterSupport support, final Modifier modifier) throws DatabaseException { final int hashBase = checkIndexAndGetRealIndex(setIndex, 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; } public boolean foreachPredicate(int setIndex, ClusterI.PredicateProcedure procedure, Context context, ClusterSupport support, Modifier modifier) throws DatabaseException { ForeachPredicate t = new ForeachPredicate(procedure, support, modifier); return foreachComplete(setIndex, t, context, null, null); } public boolean foreachObject(int setIndex, ClusterI.ObjectProcedure procedure, Context context, ClusterSupport support, Modifier modifier, ClusterI.CompleteTypeEnum completeType) throws DatabaseException { ForeachObject t = new ForeachObject (procedure, support, modifier, completeType); return foreachComplete(setIndex, t, context, null, null); } private void checkEntry(ClusterBase cluster, int[] table, int index) throws DatabaseException { ClusterI.CompleteTypeEnum type = ClusterTraits.completeReferenceGetType(table[index]); if (type == CompleteTypeEnum.NotComplete) throw new ValidationException("Illegal CompleteTable entry type. Entry=" + table[index] + " index=" + index); int fi = ClusterTraits.completeReferenceGetForeignIndex(table[index]); int ri = ClusterTraits.completeReferenceGetResourceIndex(table[index]); if (0 != fi) { cluster.checkForeingIndex(fi); if (ri < 1 || ri > ClusterTraits.getMaxNumberOfResources()) throw new ValidationException("Illegal CompleteTable foreign entry. Entry=" + table[index] + " index=" + index); } /*else if (ri < 1 || ri > cluster.getNumberOfResources(-1)) throw new ValidationException("Illegal CompleteTable local entry. Entry=" + table[index] + " index=" + index);*/ } 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 foreachComplete(setIndex, (ObjectProcedure)procedure, context, support, modifier); } } class ForeachPredicate implements ClusterI.ObjectProcedure { private TIntHashSet completeTypes = new TIntHashSet(); private ClusterI.PredicateProcedure procedure; public ForeachPredicate(ClusterI.PredicateProcedure procedure, ClusterSupport support, Modifier modifier) { this.procedure = procedure; } @Override public boolean execute(Context context, int completeRef) { ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef); if (!completeTypes.contains(completeType.getValue())) { completeTypes.add(completeType.getValue()); try { int pKey = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType); if (procedure.execute(context, pKey, 0)) return true; // loop broken by procedure } catch (DatabaseException e) { e.printStackTrace(); return false; } } return false; } } class ForeachObject implements ClusterI.ObjectProcedure { private ClusterI.ObjectProcedure procedure; private Modifier modifier; private ClusterI.CompleteTypeEnum completeType; public ForeachObject(ClusterI.ObjectProcedure procedure, ClusterSupport support, Modifier modifier, ClusterI.CompleteTypeEnum completeType) { this.procedure = procedure; this.modifier = modifier; this.completeType = completeType; } @Override public boolean execute(Context context, int completeRef) throws DatabaseException { ClusterI.CompleteTypeEnum completeType2 = ClusterTraits.completeReferenceGetType(completeRef); if (completeType == completeType2) { int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef); int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef); if (0 == clusterIndex) { int externalRef; if (null == modifier) externalRef = resourceIndex; else externalRef = modifier.execute(resourceIndex); return procedure.execute(context, externalRef); } else { try { int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex); if (null != modifier) externalRef = modifier.execute(externalRef); return procedure.execute(context, externalRef); } catch (DatabaseException e) { e.printStackTrace(); return false; // continue looping } } } return false; // continue looping } }