]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ObjectTable.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ObjectTable.java
diff --git a/bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ObjectTable.java b/bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ObjectTable.java
new file mode 100644 (file)
index 0000000..61d2eda
--- /dev/null
@@ -0,0 +1,312 @@
+/*******************************************************************************\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 org.simantics.db.Resource;\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.Procedure;\r
+import org.simantics.db.impl.ClusterSupport;\r
+import org.simantics.db.impl.Modifier;\r
+import org.simantics.db.impl.ResourceImpl;\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.impl.graph.ReadGraphImpl;\r
+import org.simantics.db.procedure.AsyncContextMultiProcedure;\r
+import org.simantics.db.procedure.AsyncMultiProcedure;\r
+import org.simantics.db.procore.cluster.TableIntArraySet.Ints;\r
+\r
+import gnu.trove.map.hash.TIntIntHashMap;\r
+import gnu.trove.procedure.TIntIntProcedure;\r
+import gnu.trove.set.hash.TIntHashSet;\r
+\r
+public final class ObjectTable extends Table<int[]> {\r
+\r
+       final TableIntAllocatorAdapter allocator;\r
+       \r
+    public ObjectTable(TableSizeListener sizeListener, int[] header, int headerBase) {\r
+        super(TableFactory.getIntFactory(), sizeListener, header, headerBase);\r
+        allocator = new TableIntAllocatorAdapter(this);\r
+    }\r
+\r
+    public ObjectTable(TableSizeListener sizeListener, int[] header, int headerBase, int[] ints) {\r
+        super(TableFactory.getIntFactory(), sizeListener, header, headerBase, ints);\r
+        allocator = new TableIntAllocatorAdapter(this);\r
+    }\r
+\r
+    final int createObjectSet(int o1, int o2) throws DatabaseException {\r
+        if (0 == o1 || o1 == o2)\r
+            throw new DatabaseException("Illegal argument to createObejctSet");\r
+        int[] obs = new int[2];\r
+        obs[0] = o1;\r
+        obs[1] = o2;\r
+        int hashBase = TableIntArraySet.create(obs, allocator);\r
+        return convertRealIndexToTableIndex(hashBase);\r
+    }\r
+\r
+    final void deleteObjectSet(int objectIndex) throws DatabaseException {\r
+        int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);\r
+        if (TableIntArraySet.isArraySet(getTable(), hashBase)) {\r
+            int capacity = TableIntArraySet.getAllocatedSize(getTable(), hashBase);\r
+            int elementIndex = objectIndex - TableIntArraySet.HeaderSize;\r
+            deleteOldElement(elementIndex, capacity);\r
+        } else {\r
+            int capacity = TableIntSet.getAllocatedSize(getTable(), hashBase);\r
+            int elementIndex = objectIndex - TableIntSet.HeaderSize;\r
+            deleteOldElement(elementIndex, capacity);\r
+        }\r
+    }\r
+\r
+    public final int getObjectSetSize(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
+    /**\r
+     * @param objectIndex\r
+     * @param oResourceIndex\r
+     * @return zero if object already in the set else object index of the set\r
+     */\r
+    final int addObject(int objectIndex, int oResourceIndex) throws DatabaseException {\r
+        int hashBase = checkIndexAndGetRealIndex(objectIndex, 0);\r
+        int newHashBase;\r
+        if (TableIntArraySet.isArraySet(getTable(), hashBase)) {\r
+            if (TableIntArraySet.getSize(getTable(), hashBase) < 5)\r
+                newHashBase = TableIntArraySet.addInt(getTable(), hashBase, oResourceIndex, allocator);\r
+            else {\r
+                Ints ints = TableIntArraySet.getIntsIfValueNotFound(getTable(), hashBase, oResourceIndex);\r
+                if (ints.found)\r
+                    return 0; // old object, not modified\r
+                this.deleteObjectSet(objectIndex);\r
+                newHashBase = TableIntSet.create(ints.ints, allocator);\r
+                assert(0 != newHashBase);\r
+            }\r
+        } else\r
+            newHashBase = TableIntSet.addInt(getTable(), hashBase, oResourceIndex, allocator);\r
+        if (0 == newHashBase)\r
+            return 0; // old object, not modified\r
+        int ni = convertRealIndexToTableIndex(newHashBase);\r
+        return ni;\r
+    }\r
+\r
+    /**\r
+     * @param objectIndex\r
+     * @param oResourceIndex\r
+     * @return number of objects after removal.\r
+     */\r
+    final int removeObject(int objectIndex, int oResourceIndex) throws DatabaseException {\r
+        if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
+            int pRef = objectIndex;\r
+            if (oResourceIndex == pRef) {\r
+                return 0;\r
+            } else\r
+                return 1;\r
+        } else\r
+            objectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
+        int hashBase = checkIndexAndGetRealIndex(objectIndex, 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
+\r
+    final public int getSingleObject(final int objectIndex, final ClusterSupport support, Modifier modifier) throws DatabaseException {\r
+\r
+       if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
+               return modifier.execute(objectIndex);\r
+        }\r
+       \r
+        int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
+        final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);\r
+        if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
+            return TableIntArraySet.getSingleInt(getTable(), hashBase, modifier);\r
+        else\r
+               return IntHash.getSingleInt(getTable(), hashBase, modifier);\r
+        \r
+    }\r
+\r
+    final public void foreachObject( ReadGraphImpl graph, final int objectIndex, \r
+            final AsyncMultiProcedure<Resource> procedure, Modifier modifier) throws DatabaseException {\r
+       if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
+               int key = modifier.execute(objectIndex);\r
+            procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), key));\r
+               procedure.finished(graph);\r
+//             graph.dec();\r
+            return;\r
+        }\r
+        int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
+        final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);\r
+        if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
+            TableIntArraySet.foreachInt(getTable(), hashBase, graph, procedure, modifier);\r
+        else\r
+               IntHash.foreachInt(graph, table, hashBase, procedure, modifier);\r
+    }\r
+\r
+    final public <C> void foreachObject( ReadGraphImpl graph, final int objectIndex, C context, \r
+            final AsyncContextMultiProcedure<C, Resource> procedure, Modifier modifier) throws DatabaseException {\r
+       if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
+               int key = modifier.execute(objectIndex);\r
+            procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), key));\r
+               procedure.finished(graph);\r
+//             graph.dec();\r
+            return;\r
+        }\r
+        int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
+        final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 0);\r
+        if (TableIntArraySet.isArraySet(getTable(), hashBase))\r
+            TableIntArraySet.foreachInt(getTable(), hashBase, graph, context, procedure, modifier);\r
+        else\r
+               IntHash.foreachInt(graph, table, hashBase, context, procedure, modifier);\r
+    }\r
+\r
+    final public <Context> boolean foreachObject(final int objectIndex,\r
+            final ClusterI.ObjectProcedure<Context> procedure, final Context context, final ClusterSupport support,\r
+            final Modifier modifier) throws DatabaseException {\r
+        if (ClusterTraits.statementIndexIsDirect(objectIndex)) {\r
+            int pRef = objectIndex;\r
+            int key;\r
+            if (null == modifier)\r
+                key = pRef;\r
+            else\r
+                key = modifier.execute(pRef);\r
+            if (procedure.execute(context, key))\r
+                return true; // loop broken by procedure\r
+            return false; // loop finished\r
+        }\r
+        int realObjectIndex = ClusterTraits.statementIndexGet(objectIndex);\r
+        final int hashBase = checkIndexAndGetRealIndex(realObjectIndex, 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
+\r
+    private void checkEntry(ClusterBase cluster, int[] table, int index)\r
+    throws DatabaseException {\r
+       if (!ClusterTraits.statementIndexIsDirect(table[index]))\r
+               throw new ValidationException("Illegal ObjectTable entry. Entry=" + table[index] + " index=" + index);\r
+        int dr = table[index];\r
+        cluster.checkDirectReference(dr);\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
+\r
+    public final void checkObjectSetIndex(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
+    public 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("object 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("object array set capacity " + a + " instance count " + b);\r
+                return true;\r
+            }\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 foreachObject(setIndex, (ObjectProcedure<Context>)procedure, context, support, modifier);\r
+    }\r
+}\r