]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/CompleteTable.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / CompleteTable.java
index 3fe74debf73a4ac7520d318651fa025ffd4e3aec..8fb0a62bcc77a9fa9dff9619072200227b90491d 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.CompleteTypeEnum;\r
-import org.simantics.db.impl.ClusterI.ObjectProcedure;\r
-import org.simantics.db.impl.ClusterI.Procedure;\r
-import org.simantics.db.impl.ClusterSupport;\r
-import org.simantics.db.impl.ClusterTraitsBase;\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.TableIntArraySet.Ints;\r
-\r
-public class CompleteTable extends Table<int[]> {\r
-    public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase) {\r
-        super(TableFactory.getIntFactory(), sizeListener, header, headerBase);\r
-    }\r
-    public CompleteTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {\r
-        super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);\r
-    }\r
-    final int createCompleteArraySet(int o1, int o2)\r
-    throws DatabaseException {\r
-        if (0 == o1 || o1 == o2)\r
-            throw new DatabaseException("Illegal argument to createObejctArray");\r
-        int[] obs = new int[2];\r
-        obs[0] = o1;\r
-        obs[1] = o2;\r
-        int hashBase = TableIntArraySet.create(obs, new TableIntAllocatorAdapter(this));\r
-        return convertRealIndexToTableIndex(hashBase);\r
-    }\r
-    final void deleteCompleteSet(int index)\r
-    throws DatabaseException {\r
-      int hashBase = checkIndexAndGetRealIndex(index, 0);\r
-      if (TableIntArraySet.isArraySet(getTable(), hashBase)) {\r
-          int capacity = TableIntArraySet.getAllocatedSize(getTable(), hashBase);\r
-          int elementIndex = index - TableIntArraySet.HeaderSize;\r
-          deleteOldElement(elementIndex, capacity);\r
-      } else {\r
-          int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase);\r
-          int elementIndex = index - TableIntSet.HeaderSize;\r
-          deleteOldElement(elementIndex, capacity);\r
-      }\r
-    }\r
-    final int getCompleteSetSize(int objectIndex) {\r
-        int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);\r
-        if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
-            return TableIntArraySet.getSize(getTable(), hashBase);\r
-        else\r
-            return TableIntSet.getSize(getTable(), hashBase);\r
-    }\r
-       /**\r
-       * @param setIndex\r
-       * @param oResourceIndex\r
-       * @return zero if complete already in the set else index of the set\r
-       */\r
-    final int addComplete(int setIndex, int oResourceIndex)\r
-    throws DatabaseException {\r
-        int hashBase = checkIndexAndGetRealIndex(setIndex, 0);\r
-        int newHashBase;\r
-        if (TableIntArraySet.isArraySet(getTable(), hashBase)) {\r
-            if (TableIntArraySet.getSize(getTable(), hashBase) < 5)\r
-                newHashBase = TableIntArraySet.addInt(getTable(), hashBase, oResourceIndex, new TableIntAllocatorAdapter(this));\r
-            else {\r
-                Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex);\r
-                if (ints.found)\r
-                    return 0; // old object, not modified \r
-                this.deleteCompleteSet(setIndex);\r
-                newHashBase = TableIntSet.create(ints.ints, new TableIntAllocatorAdapter(this));\r
-                assert(0 != newHashBase);\r
-            }\r
-        } else\r
-            newHashBase = TableIntSet.addInt(getTable(), hashBase, oResourceIndex, new TableIntAllocatorAdapter(this));\r
-        if (0 == newHashBase)\r
-            return 0; // old object, not modified\r
-        int ni = convertRealIndexToTableIndex(newHashBase);\r
-        return ni;\r
-    }\r
-    final int removeLast(int setIndex)\r
-    throws DatabaseException {\r
-        int hashBase = checkIndexAndGetRealIndex(setIndex, 0);\r
-        int[] table = getTable();\r
-        int ref;\r
-        if (TableIntArraySet.isArraySet(table, hashBase))\r
-            ref = TableIntArraySet.removeIntLast(table, hashBase);\r
-        else {\r
-            ref = TableIntSet.removeIntLast(table, hashBase);\r
-        }\r
-        deleteCompleteSet(setIndex);\r
-        return ref;\r
-    }\r
-    /**\r
-     * @param setIndex\r
-     * @param oResourceIndex\r
-     * @return number of objects after removal.\r
-     */\r
-    final int removeComplete(int setIndex, int oResourceIndex)\r
-    throws DatabaseException {\r
-        int hashBase = checkIndexAndGetRealIndex(setIndex, 0);\r
-        int[] table = getTable();\r
-        if (TableIntArraySet.isArraySet(table, hashBase))\r
-            return TableIntArraySet.removeInt(table, hashBase, oResourceIndex);\r
-        else {\r
-            TableIntSet.removeInt(table, hashBase, oResourceIndex);\r
-            return TableIntSet.getSize(table, hashBase);\r
-        }\r
-    }\r
-    final public <Context> boolean foreachComplete(final int setIndex,\r
-        final ClusterI.ObjectProcedure<Context> procedure, final Context context, final ClusterSupport support,\r
-        final Modifier modifier) throws DatabaseException {\r
-        final int hashBase = checkIndexAndGetRealIndex(setIndex, 0);\r
-        boolean ret;\r
-        if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
-            ret = TableIntArraySet.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
-        else\r
-            ret = TableIntSet.foreachInt(getTable(), hashBase, procedure, context, modifier);\r
-        return ret;\r
-    }\r
-    public <Context> boolean foreachPredicate(int setIndex,\r
-            ClusterI.PredicateProcedure<Context> procedure,\r
-            Context context, ClusterSupport support, Modifier modifier)\r
-    throws DatabaseException {\r
-        ForeachPredicate<Context> t = new ForeachPredicate<Context>(procedure, support, modifier);\r
-        return foreachComplete(setIndex, t, context, null, null);\r
-    }\r
-    \r
-    public <Context> boolean foreachObject(int setIndex,\r
-            ClusterI.ObjectProcedure<Context> procedure,\r
-            Context context, ClusterSupport support, Modifier modifier,\r
-            ClusterI.CompleteTypeEnum completeType)\r
-    throws DatabaseException {\r
-        ForeachObject<Context> t = new ForeachObject<Context>\r
-        (procedure, support, modifier, completeType);\r
-        return foreachComplete(setIndex, t, context, null, null);\r
-    }\r
-    \r
-    private void checkEntry(ClusterBase cluster, int[] table, int index)\r
-    throws DatabaseException {\r
-       ClusterI.CompleteTypeEnum type = ClusterTraits.completeReferenceGetType(table[index]);\r
-        if (type == CompleteTypeEnum.NotComplete)\r
-            throw new ValidationException("Illegal CompleteTable entry type. Entry=" + table[index] + " index=" + index);\r
-        int fi = ClusterTraits.completeReferenceGetForeignIndex(table[index]);\r
-        int ri = ClusterTraits.completeReferenceGetResourceIndex(table[index]);\r
-        if (0 != fi) {\r
-            cluster.checkForeingIndex(fi);\r
-            if (ri < 1 || ri > ClusterTraits.getMaxNumberOfResources())\r
-                throw new ValidationException("Illegal CompleteTable foreign entry. Entry=" + table[index] + " index=" + index);\r
-        } /*else if (ri < 1 || ri > cluster.getNumberOfResources(-1))\r
-                throw new ValidationException("Illegal CompleteTable local entry. Entry=" + table[index] + " index=" + index);*/\r
-    }\r
-\r
-    private TIntHashSet checkIndexSet = null;\r
-    public final 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]; p<e; p++) {\r
-                    if (IntHashTrait.isFull(table[p])) \r
-                        checkEntry(cluster, table, p);\r
-                }\r
-            } else {\r
-                final int size = -table[cap];\r
-                assert(size > 0);\r
-                checkIndexSet.add(p - ps);\r
-                boolean free = false;\r
-                for (int e = p + size; p<e; p++) {\r
-                    if (free)\r
-                        assert(table[p] == 0);\r
-                    else if (table[p] == 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 checkCompleteSetIndex(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 object set index=" + i);\r
-    }\r
-    final 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];\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;\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("complete 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("complete 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, ClusterSupport support, Modifier modifier) throws DatabaseException {\r
-        return foreachComplete(setIndex, (ObjectProcedure<Context>)procedure, context, support, modifier);\r
-    }\r
-}\r
-class ForeachPredicate<Context>\r
-implements ClusterI.ObjectProcedure<Context> {\r
-    private TIntHashSet completeTypes = new TIntHashSet();\r
-    private ClusterI.PredicateProcedure<Context> procedure; \r
-    public ForeachPredicate(ClusterI.PredicateProcedure<Context>\r
-        procedure, ClusterSupport support, Modifier modifier) {\r
-        this.procedure = procedure;\r
-    }\r
-    @Override\r
-    public boolean execute(Context context, int completeRef) {\r
-       ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);\r
-        if (!completeTypes.contains(completeType.getValue())) {\r
-            completeTypes.add(completeType.getValue());\r
-            try {\r
-                int pKey = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);\r
-                if (procedure.execute(context, pKey, 0))\r
-                    return true; // loop broken by procedure\r
-            } catch (DatabaseException e) {\r
-                e.printStackTrace();\r
-                return false;\r
-            }\r
-        }\r
-        return false;\r
-    }\r
-    \r
-}\r
-class ForeachObject<Context>\r
-implements ClusterI.ObjectProcedure<Context> {\r
-    private ClusterI.ObjectProcedure<Context> procedure; \r
-    private Modifier modifier;\r
-    private ClusterI.CompleteTypeEnum completeType;\r
-    public ForeachObject(ClusterI.ObjectProcedure<Context>\r
-        procedure, ClusterSupport support, Modifier modifier, ClusterI.CompleteTypeEnum completeType) {\r
-        this.procedure = procedure;\r
-        this.modifier = modifier;\r
-        this.completeType = completeType;\r
-    }\r
-    @Override\r
-    public boolean execute(Context context, int completeRef) throws DatabaseException {\r
-       ClusterI.CompleteTypeEnum completeType2 = ClusterTraits.completeReferenceGetType(completeRef);\r
-        if (completeType == completeType2) {\r
-            int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);\r
-            int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);\r
-            if (0 == clusterIndex) {\r
-                int externalRef;\r
-                if (null == modifier)\r
-                    externalRef = resourceIndex;\r
-                else\r
-                    externalRef = modifier.execute(resourceIndex);\r
-                return procedure.execute(context, externalRef);\r
-            } else {\r
-                try {\r
-                    int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);\r
-                    if (null != modifier)\r
-                        externalRef = modifier.execute(externalRef);\r
-                    return procedure.execute(context, externalRef);\r
-                } catch (DatabaseException e) {\r
-                    e.printStackTrace();\r
-                    return false; // continue looping\r
-                }\r
-            }\r
-        }\r
-        return false; // continue looping\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.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<int[]> {
+    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 <Context> boolean foreachComplete(final int setIndex,
+        final ClusterI.ObjectProcedure<Context> 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 <Context> boolean foreachPredicate(int setIndex,
+            ClusterI.PredicateProcedure<Context> procedure,
+            Context context, ClusterSupport support, Modifier modifier)
+    throws DatabaseException {
+        ForeachPredicate<Context> t = new ForeachPredicate<Context>(procedure, support, modifier);
+        return foreachComplete(setIndex, t, context, null, null);
+    }
+    
+    public <Context> boolean foreachObject(int setIndex,
+            ClusterI.ObjectProcedure<Context> procedure,
+            Context context, ClusterSupport support, Modifier modifier,
+            ClusterI.CompleteTypeEnum completeType)
+    throws DatabaseException {
+        ForeachObject<Context> t = new ForeachObject<Context>
+        (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<e; p++) {
+                    if (IntHashTrait.isFull(table[p])) 
+                        checkEntry(cluster, table, p);
+                }
+            } else {
+                final int size = -table[cap];
+                assert(size > 0);
+                checkIndexSet.add(p - ps);
+                boolean free = false;
+                for (int e = p + size; p<e; p++) {
+                    if (free)
+                        assert(table[p] == 0);
+                    else if (table[p] == 0)
+                        free = true;
+                    else
+                        checkEntry(cluster, table, p);
+                }
+            }
+            count++;
+        }
+        assert(getHeader().getCount() <= count);  // deleted objects are not recognized
+    }
+    public final void checkCompleteSetIndex(ClusterBase cluster, int i)
+    throws DatabaseException {
+       if (null == checkIndexSet)
+               check(cluster); // builds checkIndexSet
+       if (!checkIndexSet.contains(i-ZERO_SHIFT))
+               throw new ValidationException("Illegal object set index=" + i);
+    }
+    final 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];
+              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;
+          }
+          count++;
+      }
+      assert(getHeader().getCount() == count);
+      stat.forEachEntry(new TIntIntProcedure() {
+          @Override
+          public boolean execute(int a, int b) {
+              System.out.println("complete set capacity " + a + " instance count " + b);
+              return true;
+          }
+      });
+      stat2.forEachEntry(new TIntIntProcedure() {
+          @Override
+          public boolean execute(int a, int b) {
+              System.out.println("complete 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 foreachComplete(setIndex, (ObjectProcedure<Context>)procedure, context, support, modifier);
+    }
+}
+class ForeachPredicate<Context>
+implements ClusterI.ObjectProcedure<Context> {
+    private TIntHashSet completeTypes = new TIntHashSet();
+    private ClusterI.PredicateProcedure<Context> procedure; 
+    public ForeachPredicate(ClusterI.PredicateProcedure<Context>
+        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<Context>
+implements ClusterI.ObjectProcedure<Context> {
+    private ClusterI.ObjectProcedure<Context> procedure; 
+    private Modifier modifier;
+    private ClusterI.CompleteTypeEnum completeType;
+    public ForeachObject(ClusterI.ObjectProcedure<Context>
+        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
+    }
+    
 }
\ No newline at end of file