]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/PredicateTable.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / PredicateTable.java
index ed63d7fd44631a3fd0916472f28739eff2269392..cfd7bcc55bfb41b44361e1ecfe28f981579aed6c 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.procore.cluster;\r
-\r
-import gnu.trove.map.hash.TIntIntHashMap;\r
-import gnu.trove.procedure.TIntIntProcedure;\r
-import gnu.trove.set.hash.TIntHashSet;\r
-\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ValidationException;\r
-import org.simantics.db.impl.ClusterBase;\r
-import org.simantics.db.impl.ClusterI;\r
-import org.simantics.db.impl.ClusterI.ObjectProcedure;\r
-import org.simantics.db.impl.ClusterI.PredicateProcedure;\r
-import org.simantics.db.impl.ClusterI.Procedure;\r
-import org.simantics.db.impl.ClusterSupport;\r
-import org.simantics.db.impl.Modifier;\r
-import org.simantics.db.impl.Table;\r
-import org.simantics.db.impl.TableFactory;\r
-import org.simantics.db.impl.TableIntAllocatorAdapter;\r
-import org.simantics.db.impl.TableSizeListener;\r
-import org.simantics.db.procore.cluster.TableIntArraySet2.Tables;\r
-\r
-public final class PredicateTable extends Table<int[]> {\r
-       \r
-       final TableIntAllocatorAdapter allocator;\r
-       \r
-    public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase) {\r
-        super(TableFactory.getIntFactory(), sizeListener, header, headerBase);\r
-        allocator = new TableIntAllocatorAdapter(this);\r
-    }\r
-    public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {\r
-        super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);\r
-        allocator = new TableIntAllocatorAdapter(this);\r
-    }\r
-    int createPredicateSet(int[] ps, int[] os)\r
-    throws DatabaseException {\r
-        int hashBase = TableIntArraySet2.create(ps, os, allocator);\r
-        return convertRealIndexToTableIndex(hashBase);\r
-    }\r
-    void deletePredicateSet(int predicateIndex) {\r
-        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
-        if (TableIntArraySet2.isArraySet(getTable(), hashBase)) {\r
-            int capacity = TableIntArraySet2.getAllocatedSize(getTable(), hashBase);\r
-            int elementIndex = predicateIndex - TableIntArraySet2.HeaderSize;\r
-            deleteOldElement(elementIndex, capacity);\r
-        } else {\r
-            int capacity = TableIntSet2.getAllocatedSize(getTable(), hashBase);\r
-            int elementIndex = predicateIndex - TableIntSet2.HeaderSize;\r
-            deleteOldElement(elementIndex, capacity);\r
-        }\r
-    }\r
-    public int getPredicateSetSize(int predicateIndex) {\r
-        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
-        if (TableIntArraySet2.isArraySet(getTable(), hashBase))\r
-            return TableIntArraySet2.getSize(getTable(), hashBase);\r
-        else\r
-            return TableIntSet2.getSize(getTable(), hashBase);\r
-    }\r
-    public int getObjectIndex(int predicateIndex, int pRef) {\r
-        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
-        if (TableIntArraySet2.isArraySet(table, hashBase))\r
-            return TableIntArraySet2.get(table, hashBase, pRef);\r
-        else {\r
-            return TableIntSet2.get(table, hashBase, pRef);\r
-        }\r
-    }\r
-    private int addPredicateArray(int predicateIndex, int hashBase, int pReference, int oReference, ObjectTable ot)\r
-    throws DatabaseException {\r
-        int newHashBase;\r
-        int objectIndex = TableIntArraySet2.get(getTable(), hashBase, pReference);\r
-        if (0 == objectIndex) {\r
-            newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, oReference, allocator);\r
-        } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
-            int oRef = objectIndex;\r
-            if (oRef == oReference) {\r
-                return 0; // old direct object\r
-            }\r
-            objectIndex = ot.createObjectSet(oRef, oReference);\r
-            assert(0 != objectIndex);\r
-            int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);\r
-            newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);\r
-        } else {\r
-            int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);\r
-            if (0 == newObjectIndex)\r
-                return 0; // old indirect object\r
-            newObjectIndex = ClusterTraits.statementIndexMake(newObjectIndex);\r
-            newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);\r
-            if (newHashBase == 0)\r
-                return hashBase;\r
-        }\r
-        int TABLE_SIZE = TableIntArraySet2.getSize(getTable(), newHashBase);\r
-        if (TABLE_SIZE > 5)\r
-            return convertToPredicateSet(predicateIndex, newHashBase);\r
-        return newHashBase;\r
-    }\r
-    private int convertToPredicateSet(int predicateIndex, int hashBase) {\r
-        Tables tables = TableIntArraySet2.getInts(getTable(), hashBase);\r
-        this.deletePredicateSet(predicateIndex);\r
-        int newHashBase = TableIntSet2.create(tables.keys, tables.vals, allocator);\r
-        assert(0 != newHashBase);\r
-        return newHashBase;\r
-    }\r
-    private int addPredicateSet(int hashBase, int pReference, int oReference, ObjectTable ot)\r
-    throws DatabaseException {\r
-        int objectIndex = TableIntSet2.get(getTable(), hashBase, pReference);\r
-        int newHashBase;\r
-        if (0 == objectIndex) {\r
-            newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, oReference, allocator);\r
-        } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
-            int oRef = objectIndex;\r
-            if (oRef == oReference) {\r
-                return 0; // old direct object\r
-            }\r
-            objectIndex = ot.createObjectSet(oRef, oReference);\r
-            assert(0 != objectIndex);\r
-            int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);\r
-            newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);\r
-            assert(0 != newHashBase);\r
-        } else {\r
-            int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);\r
-            if (0 == newObjectIndex)\r
-                return 0; // old indirect object\r
-            int stmIndex = ClusterTraits.statementIndexMake(newObjectIndex);\r
-            newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, stmIndex, allocator);\r
-            if (newHashBase == 0)\r
-                return hashBase; // new object added to old predicate (set)\r
-        }\r
-        return newHashBase;\r
-    }\r
-    /**\r
-     * @param predicateIndex\r
-     * @param pReference\r
-     * @return zero if element was not added or predicate index.\r
-     * Predicate index will change if new space is allocated.\r
-     */\r
-    public int addPredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)\r
-    throws DatabaseException {\r
-        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
-        int newHashBase;\r
-        if (TableIntArraySet2.isArraySet(getTable(), hashBase))\r
-           newHashBase = addPredicateArray(predicateIndex, hashBase, pReference, oReference, ot);\r
-        else\r
-           newHashBase = addPredicateSet(hashBase, pReference, oReference, ot);\r
-        if (0 == newHashBase)\r
-            return 0; // not modified\r
-        return convertRealIndexToTableIndex(newHashBase);\r
-    }\r
-    public enum Status {\r
-        NothingRemoved,\r
-        ObjectRemoved,\r
-        PredicateRemoved;\r
-    }\r
-    /**\r
-     * @param predicateIndex\r
-     * @param oResourceIndex\r
-     * @return null if nothing was removed. Status if either object or both\r
-     * object and predicate were removed. \r
-     */\r
-    public Status removePredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)\r
-    throws DatabaseException {\r
-        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
-        int[] table = getTable();\r
-        if (TableIntArraySet2.isArraySet(table, hashBase)) {\r
-            int objectIndex = TableIntArraySet2.get(table, hashBase, pReference);\r
-            if (0 == objectIndex) {\r
-                return Status.NothingRemoved;\r
-            } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
-                int oRef = objectIndex;\r
-                if (oRef != oReference)\r
-                    return Status.NothingRemoved;\r
-                if (TableIntArraySet2.removeInt(table, hashBase, pReference))\r
-                    return Status.PredicateRemoved;\r
-                else\r
-                    throw new DatabaseException("Internal error during remove.");\r
-            } else {\r
-                int oIndex = ClusterTraits.statementIndexGet(objectIndex);\r
-                int nO = ot.getObjectSetSize(oIndex);\r
-                if (nO < 1)\r
-                    throw new DatabaseException("Illegal object set size="+nO);\r
-                int nObject = ot.removeObject(objectIndex, oReference);\r
-                if (nObject == 0) {\r
-                    ot.deleteObjectSet(oIndex);\r
-                    if (TableIntArraySet2.removeInt(table, hashBase, pReference))\r
-                        return Status.PredicateRemoved;\r
-                    else\r
-                        throw new DatabaseException("Internal error during remove (2).");\r
-                } else if (nO == nObject)\r
-                    return Status.NothingRemoved;\r
-                else\r
-                    return Status.ObjectRemoved;\r
-            }\r
-        } else {\r
-            int objectIndex = TableIntSet2.get(table, hashBase, pReference);\r
-            if (0 == objectIndex) {\r
-                return Status.NothingRemoved;\r
-            } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
-                int oRef = objectIndex;\r
-                if (oRef != oReference)\r
-                    return Status.NothingRemoved;\r
-                if (TableIntSet2.removeInt(table, hashBase, pReference))\r
-                    return Status.PredicateRemoved;\r
-                else\r
-                    throw new DatabaseException("Internal error during remove (3).");\r
-            } else {\r
-                int oIndex = ClusterTraits.statementIndexGet(objectIndex);\r
-                int nO = ot.getObjectSetSize(oIndex);\r
-                if (nO < 1)\r
-                    throw new DatabaseException("Illegal object set size="+nO);\r
-                int nObject = ot.removeObject(objectIndex, oReference);\r
-                if (nObject == 0) {\r
-                    ot.deleteObjectSet(oIndex);\r
-                    if (TableIntSet2.removeInt(table, hashBase, pReference))\r
-                        return Status.PredicateRemoved;\r
-                    else\r
-                        throw new DatabaseException("Internal error during remove (4).");\r
-                } else if (nO == nObject)\r
-                    return Status.NothingRemoved;\r
-                else\r
-                    return Status.ObjectRemoved;\r
-            }\r
-        }\r
-    }\r
-    public <Context> boolean foreachPredicate(int predicateIndex\r
-            , ClusterI.PredicateProcedure<Context> procedure\r
-            , Context context, ClusterSupport support, Modifier modifier)\r
-    throws DatabaseException {\r
-        final int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);\r
-        boolean ret;\r
-        if (TableIntArraySet2.isArraySet(getTable(), hashBase))\r
-            ret = TableIntArraySet2.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
-        else\r
-            ret = TableIntSet2.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
-        return ret;\r
-    }\r
-    private void checkEntry(ClusterBase cluster, int[] table, int index)\r
-    throws DatabaseException {\r
-        assert(ClusterTraits.statementIndexIsDirect(table[index]));\r
-        int dr = table[index];\r
-        cluster.checkDirectReference(dr);\r
-        assert(table[index+1] != 0);\r
-        if (ClusterTraits.statementIndexIsDirect(table[index+1])) {\r
-               cluster.checkDirectReference(table[index+1]);\r
-        } else {\r
-               cluster.checkObjectSetReference(table[index+1]);\r
-        }\r
-    }\r
-    private TIntHashSet checkIndexSet = null;\r
-       public void check(ClusterBase cluster)\r
-       throws DatabaseException {\r
-        if (null == checkIndexSet)\r
-            checkIndexSet = new TIntHashSet();\r
-        else\r
-            checkIndexSet.clear();\r
-        int count = 0;\r
-        int[] table = getTable();\r
-        int ps = getHeader().getOffset() + ZERO_SHIFT;\r
-        int pe = ps + getTableSize();\r
-        for (int p=ps; p<pe;) {\r
-            int cap = p++;\r
-            if (table[cap] >= 0) {\r
-                int use = p++;\r
-                int fre = p++;\r
-                int max = p++;\r
-                assert(table[cap] >= table[use] + table[fre]);\r
-                assert(table[max] == table[cap] >> 1);\r
-                assert(table[max]+1 >= table[use]);\r
-                checkIndexSet.add(p - ps);\r
-                for (int e = p + table[cap]*2; p<e; p+=2) {\r
-                    if (!IntHashTrait.isFull(table[p])) \r
-                        assert(table[p+1]==0);\r
-                    else\r
-                        checkEntry(cluster, table, p);\r
-                }\r
-            } else {\r
-                final int size = -table[cap];\r
-                assert(size > 0);\r
-                boolean free = false;\r
-                checkIndexSet.add(p - ps);\r
-                for (int e = p + size*2; p<e; p+=2) {\r
-                    if (free) {\r
-                        assert(table[p] == 0);\r
-                        assert(table[p+1] == 0);\r
-                    }\r
-                    else if (table[p] == 0) {\r
-                        assert(table[p+1] == 0);\r
-                        free = true;\r
-                    } else\r
-                        checkEntry(cluster, table, p);\r
-                }\r
-            }\r
-            count++;\r
-        }\r
-               assert(getHeader().getCount() <= count);  // deleted objects are not recognized\r
-       }\r
-    public final void checkPredicateSetIndex(ClusterBase cluster, int i)\r
-    throws DatabaseException {\r
-        if (null == checkIndexSet)\r
-            check(cluster); // builds checkIndexSet\r
-        if (!checkIndexSet.contains(i-ZERO_SHIFT))\r
-            throw new ValidationException("Illegal predicate set index=" + i);\r
-    }\r
-    public void printDebugInfo() {\r
-        //int count = 0;\r
-        int[] table = getTable();\r
-        int ps = getHeader().getOffset() + ZERO_SHIFT;\r
-        int pe = ps + getTableSize();\r
-        TIntIntHashMap stat = new TIntIntHashMap();\r
-        TIntIntHashMap stat2 = new TIntIntHashMap();\r
-        for (int p=ps; p<pe;) {\r
-            int cap = p++;\r
-            if (table[cap] >= 0) {\r
-                int use = p++;\r
-                int fre = p++;\r
-                int max = p++;\r
-                assert(table[cap] >= table[use] + table[fre]);\r
-                assert(table[max] == table[cap] >> 1);\r
-                p += table[cap]*2;\r
-                int val = stat.get(table[use]) + 1;\r
-                stat.put(table[use], val);\r
-            } else {\r
-                final int size = -table[cap];\r
-                int val = stat2.get(size) + 1;\r
-                stat2.put(size, val);\r
-                p += size*2;\r
-            }\r
-            //count++;\r
-        }\r
-        //assert(getHeader().getCount() == count);\r
-        stat.forEachEntry(new TIntIntProcedure() {\r
-            @Override\r
-            public boolean execute(int a, int b) {\r
-                System.out.println("predicate set capacity " + a + " instance count " + b);\r
-                return true;\r
-            }\r
-        });\r
-        stat2.forEachEntry(new TIntIntProcedure() {\r
-            @Override\r
-            public boolean execute(int a, int b) {\r
-                System.out.println("predicate array set capacity " + a + " instance count " + b);\r
-                return true;\r
-            }\r
-        });\r
-  }\r
-    @Override\r
-    public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,\r
-            ClusterSupport support, Modifier modifier) throws DatabaseException {\r
-        return foreachPredicate(setIndex, (PredicateProcedure<Context>)procedure, context, support, modifier);\r
-    }\r
-}\r
+/*******************************************************************************
+ * 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.ObjectProcedure;
+import org.simantics.db.impl.ClusterI.PredicateProcedure;
+import org.simantics.db.impl.ClusterI.Procedure;
+import org.simantics.db.impl.ClusterSupport;
+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.TableIntArraySet2.Tables;
+
+public final class PredicateTable extends Table<int[]> {
+       
+       final TableIntAllocatorAdapter allocator;
+       
+    public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase) {
+        super(TableFactory.getIntFactory(), sizeListener, header, headerBase);
+        allocator = new TableIntAllocatorAdapter(this);
+    }
+    public PredicateTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {
+        super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);
+        allocator = new TableIntAllocatorAdapter(this);
+    }
+    int createPredicateSet(int[] ps, int[] os)
+    throws DatabaseException {
+        int hashBase = TableIntArraySet2.create(ps, os, allocator);
+        return convertRealIndexToTableIndex(hashBase);
+    }
+    void deletePredicateSet(int predicateIndex) {
+        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
+        if (TableIntArraySet2.isArraySet(getTable(), hashBase)) {
+            int capacity = TableIntArraySet2.getAllocatedSize(getTable(), hashBase);
+            int elementIndex = predicateIndex - TableIntArraySet2.HeaderSize;
+            deleteOldElement(elementIndex, capacity);
+        } else {
+            int capacity = TableIntSet2.getAllocatedSize(getTable(), hashBase);
+            int elementIndex = predicateIndex - TableIntSet2.HeaderSize;
+            deleteOldElement(elementIndex, capacity);
+        }
+    }
+    public int getPredicateSetSize(int predicateIndex) {
+        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
+        if (TableIntArraySet2.isArraySet(getTable(), hashBase))
+            return TableIntArraySet2.getSize(getTable(), hashBase);
+        else
+            return TableIntSet2.getSize(getTable(), hashBase);
+    }
+    public int getObjectIndex(int predicateIndex, int pRef) {
+        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
+        if (TableIntArraySet2.isArraySet(table, hashBase))
+            return TableIntArraySet2.get(table, hashBase, pRef);
+        else {
+            return TableIntSet2.get(table, hashBase, pRef);
+        }
+    }
+    private int addPredicateArray(int predicateIndex, int hashBase, int pReference, int oReference, ObjectTable ot)
+    throws DatabaseException {
+        int newHashBase;
+        int objectIndex = TableIntArraySet2.get(getTable(), hashBase, pReference);
+        if (0 == objectIndex) {
+            newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, oReference, allocator);
+        } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
+            int oRef = objectIndex;
+            if (oRef == oReference) {
+                return 0; // old direct object
+            }
+            objectIndex = ot.createObjectSet(oRef, oReference);
+            assert(0 != objectIndex);
+            int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);
+            newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
+        } else {
+            int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);
+            if (0 == newObjectIndex)
+                return 0; // old indirect object
+            newObjectIndex = ClusterTraits.statementIndexMake(newObjectIndex);
+            newHashBase = TableIntArraySet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
+            if (newHashBase == 0)
+                return hashBase;
+        }
+        int TABLE_SIZE = TableIntArraySet2.getSize(getTable(), newHashBase);
+        if (TABLE_SIZE > 5)
+            return convertToPredicateSet(predicateIndex, newHashBase);
+        return newHashBase;
+    }
+    private int convertToPredicateSet(int predicateIndex, int hashBase) {
+        Tables tables = TableIntArraySet2.getInts(getTable(), hashBase);
+        this.deletePredicateSet(predicateIndex);
+        int newHashBase = TableIntSet2.create(tables.keys, tables.vals, allocator);
+        assert(0 != newHashBase);
+        return newHashBase;
+    }
+    private int addPredicateSet(int hashBase, int pReference, int oReference, ObjectTable ot)
+    throws DatabaseException {
+        int objectIndex = TableIntSet2.get(getTable(), hashBase, pReference);
+        int newHashBase;
+        if (0 == objectIndex) {
+            newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, oReference, allocator);
+        } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
+            int oRef = objectIndex;
+            if (oRef == oReference) {
+                return 0; // old direct object
+            }
+            objectIndex = ot.createObjectSet(oRef, oReference);
+            assert(0 != objectIndex);
+            int newObjectIndex = ClusterTraits.statementIndexMake(objectIndex);
+            newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, newObjectIndex, allocator);
+            assert(0 != newHashBase);
+        } else {
+            int newObjectIndex = ot.addObject(ClusterTraits.statementIndexGet(objectIndex), oReference);
+            if (0 == newObjectIndex)
+                return 0; // old indirect object
+            int stmIndex = ClusterTraits.statementIndexMake(newObjectIndex);
+            newHashBase = TableIntSet2.addInt(getTable(), hashBase, pReference, stmIndex, allocator);
+            if (newHashBase == 0)
+                return hashBase; // new object added to old predicate (set)
+        }
+        return newHashBase;
+    }
+    /**
+     * @param predicateIndex
+     * @param pReference
+     * @return zero if element was not added or predicate index.
+     * Predicate index will change if new space is allocated.
+     */
+    public int addPredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)
+    throws DatabaseException {
+        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
+        int newHashBase;
+        if (TableIntArraySet2.isArraySet(getTable(), hashBase))
+           newHashBase = addPredicateArray(predicateIndex, hashBase, pReference, oReference, ot);
+        else
+           newHashBase = addPredicateSet(hashBase, pReference, oReference, ot);
+        if (0 == newHashBase)
+            return 0; // not modified
+        return convertRealIndexToTableIndex(newHashBase);
+    }
+    public enum Status {
+        NothingRemoved,
+        ObjectRemoved,
+        PredicateRemoved;
+    }
+    /**
+     * @param predicateIndex
+     * @param oResourceIndex
+     * @return null if nothing was removed. Status if either object or both
+     * object and predicate were removed. 
+     */
+    public Status removePredicate(int predicateIndex, int pReference, int oReference, ObjectTable ot)
+    throws DatabaseException {
+        int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
+        int[] table = getTable();
+        if (TableIntArraySet2.isArraySet(table, hashBase)) {
+            int objectIndex = TableIntArraySet2.get(table, hashBase, pReference);
+            if (0 == objectIndex) {
+                return Status.NothingRemoved;
+            } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
+                int oRef = objectIndex;
+                if (oRef != oReference)
+                    return Status.NothingRemoved;
+                if (TableIntArraySet2.removeInt(table, hashBase, pReference))
+                    return Status.PredicateRemoved;
+                else
+                    throw new DatabaseException("Internal error during remove.");
+            } else {
+                int oIndex = ClusterTraits.statementIndexGet(objectIndex);
+                int nO = ot.getObjectSetSize(oIndex);
+                if (nO < 1)
+                    throw new DatabaseException("Illegal object set size="+nO);
+                int nObject = ot.removeObject(objectIndex, oReference);
+                if (nObject == 0) {
+                    ot.deleteObjectSet(oIndex);
+                    if (TableIntArraySet2.removeInt(table, hashBase, pReference))
+                        return Status.PredicateRemoved;
+                    else
+                        throw new DatabaseException("Internal error during remove (2).");
+                } else if (nO == nObject)
+                    return Status.NothingRemoved;
+                else
+                    return Status.ObjectRemoved;
+            }
+        } else {
+            int objectIndex = TableIntSet2.get(table, hashBase, pReference);
+            if (0 == objectIndex) {
+                return Status.NothingRemoved;
+            } else if (ClusterTraits.statementIndexIsDirect(objectIndex)) {
+                int oRef = objectIndex;
+                if (oRef != oReference)
+                    return Status.NothingRemoved;
+                if (TableIntSet2.removeInt(table, hashBase, pReference))
+                    return Status.PredicateRemoved;
+                else
+                    throw new DatabaseException("Internal error during remove (3).");
+            } else {
+                int oIndex = ClusterTraits.statementIndexGet(objectIndex);
+                int nO = ot.getObjectSetSize(oIndex);
+                if (nO < 1)
+                    throw new DatabaseException("Illegal object set size="+nO);
+                int nObject = ot.removeObject(objectIndex, oReference);
+                if (nObject == 0) {
+                    ot.deleteObjectSet(oIndex);
+                    if (TableIntSet2.removeInt(table, hashBase, pReference))
+                        return Status.PredicateRemoved;
+                    else
+                        throw new DatabaseException("Internal error during remove (4).");
+                } else if (nO == nObject)
+                    return Status.NothingRemoved;
+                else
+                    return Status.ObjectRemoved;
+            }
+        }
+    }
+    public <Context> boolean foreachPredicate(int predicateIndex
+            , ClusterI.PredicateProcedure<Context> procedure
+            , Context context, ClusterSupport support, Modifier modifier)
+    throws DatabaseException {
+        final int hashBase = checkIndexAndGetRealIndex(predicateIndex, 0);
+        boolean ret;
+        if (TableIntArraySet2.isArraySet(getTable(), hashBase))
+            ret = TableIntArraySet2.foreachInt(getTable(), hashBase, procedure, context, modifier);
+        else
+            ret = TableIntSet2.foreachInt(getTable(), hashBase, procedure, context, modifier);
+        return ret;
+    }
+    private void checkEntry(ClusterBase cluster, int[] table, int index)
+    throws DatabaseException {
+        assert(ClusterTraits.statementIndexIsDirect(table[index]));
+        int dr = table[index];
+        cluster.checkDirectReference(dr);
+        assert(table[index+1] != 0);
+        if (ClusterTraits.statementIndexIsDirect(table[index+1])) {
+               cluster.checkDirectReference(table[index+1]);
+        } else {
+               cluster.checkObjectSetReference(table[index+1]);
+        }
+    }
+    private TIntHashSet checkIndexSet = null;
+       public 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]*2; p<e; p+=2) {
+                    if (!IntHashTrait.isFull(table[p])) 
+                        assert(table[p+1]==0);
+                    else
+                        checkEntry(cluster, table, p);
+                }
+            } else {
+                final int size = -table[cap];
+                assert(size > 0);
+                boolean free = false;
+                checkIndexSet.add(p - ps);
+                for (int e = p + size*2; p<e; p+=2) {
+                    if (free) {
+                        assert(table[p] == 0);
+                        assert(table[p+1] == 0);
+                    }
+                    else if (table[p] == 0) {
+                        assert(table[p+1] == 0);
+                        free = true;
+                    } else
+                        checkEntry(cluster, table, p);
+                }
+            }
+            count++;
+        }
+               assert(getHeader().getCount() <= count);  // deleted objects are not recognized
+       }
+    public final void checkPredicateSetIndex(ClusterBase cluster, int i)
+    throws DatabaseException {
+        if (null == checkIndexSet)
+            check(cluster); // builds checkIndexSet
+        if (!checkIndexSet.contains(i-ZERO_SHIFT))
+            throw new ValidationException("Illegal predicate set index=" + i);
+    }
+    public void printDebugInfo() {
+        //int count = 0;
+        int[] table = getTable();
+        int ps = getHeader().getOffset() + ZERO_SHIFT;
+        int pe = ps + getTableSize();
+        TIntIntHashMap stat = new TIntIntHashMap();
+        TIntIntHashMap stat2 = new TIntIntHashMap();
+        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);
+                p += table[cap]*2;
+                int val = stat.get(table[use]) + 1;
+                stat.put(table[use], val);
+            } else {
+                final int size = -table[cap];
+                int val = stat2.get(size) + 1;
+                stat2.put(size, val);
+                p += size*2;
+            }
+            //count++;
+        }
+        //assert(getHeader().getCount() == count);
+        stat.forEachEntry(new TIntIntProcedure() {
+            @Override
+            public boolean execute(int a, int b) {
+                System.out.println("predicate set capacity " + a + " instance count " + b);
+                return true;
+            }
+        });
+        stat2.forEachEntry(new TIntIntProcedure() {
+            @Override
+            public boolean execute(int a, int b) {
+                System.out.println("predicate array set capacity " + a + " instance count " + b);
+                return true;
+            }
+        });
+  }
+    @Override
+    public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,
+            ClusterSupport support, Modifier modifier) throws DatabaseException {
+        return foreachPredicate(setIndex, (PredicateProcedure<Context>)procedure, context, support, modifier);
+    }
+}