]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceElementSmall.java
Fail safe import fixes made by Antti
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ResourceElementSmall.java
index 71c4c53507f71baff5eae4fc04d66f79d1bdca1c..90519a36c3f6cb5916c7429c5af8e8ca41414deb 100644 (file)
-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.ExternalValueException;\r
-import org.simantics.db.impl.ClusterI;\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.ResourceImpl;\r
-import org.simantics.db.impl.graph.ReadGraphImpl;\r
-import org.simantics.db.procedure.AsyncContextMultiProcedure;\r
-import org.simantics.db.procedure.AsyncMultiProcedure;\r
-\r
-\r
-public final class ResourceElementSmall {\r
-    private static final boolean DEBUG = ClusterImpl.DEBUG;\r
-    // Descriptor = type & complete object reference & value index & predicate index. \r
-    private static final int DESCRIPTOR_OFFSET = 0; // descriptor\r
-    private static final int STM_OFFSET        = 1; // two statements\r
-    private static final int SIZE_OF           = 2;\r
-\r
-    static void construct(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i++] = 0; // descriptor\r
-        table[i++] = 0; // stm1 & 2\r
-    }\r
-\r
-    static void destruct(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i++] = 0; // descriptor\r
-        table[i++] = 0; // stm1 & 2\r
-    }\r
-\r
-    static boolean isUsed(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        if (table[i++] != 0)\r
-            return true;\r
-        if (table[i++] != 0)\r
-            return true;\r
-        return false;\r
-    }\r
-\r
-    static int getSizeOf() {\r
-        return SIZE_OF;\r
-    }\r
-\r
-    static ClusterI.CompleteTypeEnum getCompleteType(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        byte bits = (byte)BitUtility.getMiddle(table[i], 62, 2);\r
-        return ClusterI.CompleteTypeEnum.make(bits);\r
-    }\r
-\r
-    static void setCompleteType(long[] table, int index, byte data) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i] = BitUtility.setMiddle(table[i], 62, 2, data);\r
-    }\r
-\r
-    static short getCompleteObjectRef(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        return (short)BitUtility.getMiddle(table[i], 46, 16);\r
-    }\r
-\r
-    static void setCompleteObjectRef(long[] table, int index, int ref) {\r
-        if (ref > (1<<16)-1)\r
-            throw new IllegalArgumentException();\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i] = BitUtility.setMiddle(table[i], 46, 16, ref);\r
-    }\r
-\r
-    static boolean completeHasMultiple(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        int completeRefAndType= BitUtility.getMiddle(table[i], 46, 18); \r
-        boolean complete = (completeRefAndType >>> 16) != 0;\r
-        return !complete && (completeRefAndType != 0);\r
-    }\r
-\r
-    static boolean completeIsFirstStatement(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        int completeRefAndType = BitUtility.getMiddle(table[i], 46, 18); \r
-        return completeRefAndType == 0;\r
-    }\r
-    \r
-    static boolean completeIsSameStatement(long[] table, int index, int refAndType) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        int completeRefAndType = BitUtility.getMiddle(table[i], 46, 18); \r
-        return completeRefAndType == refAndType;\r
-    }\r
-    \r
-    static int completeGetRefAndType(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        return BitUtility.getMiddle(table[i], 46, 18);\r
-    }\r
-    \r
-    static void completeSetRefAndType(long[] table, int index, int refAndType) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i] = BitUtility.setMiddle(table[i], 46, 18, refAndType); \r
-    }\r
-    \r
-    static int completeMakeObjectRefAndType(short oRef, ClusterI.CompleteTypeEnum completeType) {\r
-        return oRef & (1<<16)-1 | completeType.getValue()<<16;\r
-    }\r
-    \r
-    static short completeGetObjectSetIndex(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        return (short)BitUtility.getMiddle(table[i], 46, 16);\r
-    }\r
-    \r
-    static int completeGetStatementCountApproximation(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        int cType = BitUtility.getMiddle(table[i], 62, 2);\r
-        if (cType != 0)\r
-            return 1;\r
-        int cRef = BitUtility.getMiddle(table[i], 46, 16);\r
-        if (cRef != 0)\r
-            return 2; // Can be bigger, hence the approximation. \r
-        return 0;\r
-    }\r
-    \r
-    static int getValueIndex(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        int valueIndex = BitUtility.getMiddle(table[i], 24, 22);\r
-        return valueIndex;\r
-    }\r
-\r
-    static void setValueIndex(long[] table, int index, int valueIndex) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i] = BitUtility.setMiddle(table[i], 24, 22, valueIndex);\r
-    }\r
-\r
-    static int getPredicateIndex(long[] table, int index) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        int predicateIndex = BitUtility.getMiddle(table[i], 0, 24);\r
-        return predicateIndex;\r
-    }\r
-\r
-    static void setPredicateIndex(long[] table, int index, int predicateIndex) {\r
-        int i = DESCRIPTOR_OFFSET + index;\r
-        table[i] = BitUtility.setMiddle(table[i], 0, 24, predicateIndex);\r
-    }\r
-\r
-    static short getStm1Predicate(long[] table, int index) {\r
-        int i = STM_OFFSET + index;\r
-        short predicateIndex = BitUtility.getLowShort(table[i]);\r
-        return predicateIndex;\r
-    }\r
-\r
-    static void setStm1Predicate(long[] table, int index, short predicateIndex) {\r
-        int i = STM_OFFSET + index;\r
-        table[i] = BitUtility.setLowShort(table[i], predicateIndex);\r
-    }\r
-    \r
-    static short getStm1Object(long[] table, int index) {\r
-        int i = STM_OFFSET + index;\r
-        short objectIndex = (short)BitUtility.getMiddle(table[i], 16, 16);\r
-        return objectIndex;\r
-    }\r
-\r
-    static void setStm1Object(long[] table, int index, short objectIndex) {\r
-        int i = STM_OFFSET + index;\r
-        table[i] = BitUtility.setMiddle(table[i], 16, 16, objectIndex);\r
-    }\r
-    \r
-    static short getStm2Predicate(long[] table, int index) {\r
-        int i = STM_OFFSET + index;\r
-        short predicateIndex = (short)BitUtility.getMiddle(table[i], 32, 16);\r
-        return predicateIndex;\r
-    }\r
-\r
-    static void setStm2Predicate(long[] table, int index, short predicateIndex) {\r
-        int i = STM_OFFSET + index;\r
-        table[i] = BitUtility.setMiddle(table[i], 32, 16, predicateIndex);\r
-    }\r
-\r
-    static short getStm2Object(long[] table, int index) {\r
-        int i = STM_OFFSET + index;\r
-        short objectIndex = (short)BitUtility.getMiddle(table[i], 48, 16);\r
-        return objectIndex;\r
-    }\r
-\r
-    static void setStm2Object(long[] table, int index, short objectIndex) {\r
-        int i = STM_OFFSET + index;\r
-        table[i] = BitUtility.setMiddle(table[i], 48, 16, objectIndex);\r
-    }\r
-\r
-    public static byte[] getValue(ValueTableSmall valueTable, long[] table, int index)\r
-    throws DatabaseException {\r
-        int valueIndex = getValueIndex(table, index);\r
-        if (0 == valueIndex)\r
-            return null; // no value\r
-        else if (ClusterTraitsSmall.VALUE_INDEX_EX == valueIndex)\r
-            throw new ExternalValueException("Value stored externally. index=" + index);\r
-        return valueTable.getValue(valueIndex);\r
-    }\r
-//KRAA:\r
-//    static char[] getString(ValueTableSmall valueTable, long[] table, int index) {\r
-//        int valueIndex = getValueIndex(table, index);\r
-//        if (0 == valueIndex)\r
-//            return null; // no value\r
-////        else if (ClusterTraitsSmall.VALUE_INDEX_MAX == valueIndex)\r
-////            throw new Error("Not implemented! //KRAA:");\r
-//        return valueTable.getString(valueIndex);\r
-//    }\r
-\r
-    static boolean hasValue(long[] table, int index) {\r
-        int valueIndex = getValueIndex(table, index);\r
-        return 0 != valueIndex;\r
-    }\r
-\r
-//    static boolean hasValue(ValueTable valueTable, long[] table, int index, byte[] value) {\r
-//        int valueIndex = getValueIndex(table, index);\r
-//        if (0 == valueIndex)\r
-//            return false;\r
-//        return valueTable.isEqual(valueIndex, value, 0, value.length);\r
-//    }\r
-\r
-    static boolean removeValue(ValueTableSmall valueTable, long[] table, int index) {\r
-        int valueIndex = getValueIndex(table, index);\r
-        if (0 == valueIndex)\r
-            return false; // not removed\r
-        else if (ClusterTraitsSmall.VALUE_INDEX_EX != valueIndex)\r
-            valueTable.removeValue(valueIndex);\r
-        setValueIndex(table, index, 0);\r
-        return true;\r
-    }\r
-\r
-    public static void setValue(ValueTableSmall valueTable, long[] table, int index, byte[] value, int length)\r
-    throws OutOfSpaceException {\r
-        int oldIndex = getValueIndex(table, index);\r
-        if (ClusterTraitsSmall.VALUE_INDEX_EX == oldIndex)\r
-            oldIndex = 0;\r
-        if (length > ClusterTraitsSmall.VALUE_SIZE_MAX)\r
-            throw new OutOfSpaceException("Out of space for value. size=" + length);\r
-        int newIndex = valueTable.setValue(oldIndex, value, 0, length);\r
-        if (newIndex != oldIndex) {\r
-            if (newIndex > ClusterTraitsSmall.VALUE_INDEX_MAX) {\r
-               setValueIndex(table, index, 0);\r
-                throw new OutOfSpaceException("Out of space for values. index=" + newIndex);\r
-            }\r
-            setValueIndex(table, index, newIndex);\r
-        }\r
-        return;\r
-    }\r
-\r
-    public static boolean isValueEx(ValueTableSmall valueTable, long[] table, int index) {\r
-        int vIndex = getValueIndex(table, index);\r
-        if (ClusterTraitsSmall.VALUE_INDEX_EX == vIndex)\r
-            return true;\r
-        else\r
-            return false;\r
-    }\r
-\r
-    public static void setValueEx(ValueTableSmall valueTable, long[] table, int index) {\r
-        setValueIndex(table, index, ClusterTraitsSmall.VALUE_INDEX_EX);\r
-    }\r
-\r
-    public static <Context> boolean foreachPredicate(long[] table, int index,\r
-            ClusterI.PredicateProcedure<Context> procedure,\r
-            Context context, ClusterSupport support, Modifier modifier,\r
-            CompleteTable ct)\r
-    throws DatabaseException {\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.foreachPredicate: 1");\r
-        int completeRef = ResourceElementSmall.getCompleteObjectRef(table, index);\r
-        if (0 != completeRef) {\r
-            if (ResourceElementSmall.completeHasMultiple(table, index)) { // multiple complete objects\r
-                // CompleteRef is a complete object set index.\r
-                boolean broken = ct.foreachPredicate(completeRef, procedure, context, support, modifier);\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.foreachPredicate: multi-complete ci=" + completeRef + " break=" + broken);\r
-                if (broken)\r
-                    return true; // loop broken by procedure\r
-            } else { // We have zero or one complete statement.\r
-                ClusterI.CompleteTypeEnum completeType = ResourceElementSmall.getCompleteType(table, index);\r
-                if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {\r
-                    int key = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);\r
-                    boolean broken = procedure.execute(context, key, 0);\r
-                    if (DEBUG)\r
-                        System.out.println("ResourceElement.foreachPredicate: complete rk=" + key + " break=" + broken);\r
-                    if (broken)\r
-                        return true; // loop broken by procedure\r
-                }\r
-            }\r
-        }\r
-        // If predicate set is in use it will contain also these statements.\r
-        if (0 != ResourceElementSmall.getPredicateIndex(table, index)) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElement.foreachPredicate: more than 2 objects");\r
-            return false;\r
-        }\r
-        int p1 = getStm1Predicate(table, index);\r
-        if (0 == p1) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElement.foreachPredicate: empty cache");\r
-            return false; // loop finished, no statements\r
-        }\r
-        int externalRef;\r
-        if (null == modifier)\r
-            externalRef = p1;\r
-        else\r
-            externalRef = modifier.execute(p1);\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.foreachPredicate: cache1 pk=" + externalRef);\r
-        if (procedure.execute(context, externalRef, 0))\r
-            return true; // loop broken by procedure\r
-        int p2 = getStm2Predicate(table, index);\r
-        if (0 == p2 || p1 == p2) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElement.foreachPredicate: cache2 empty");\r
-            return false; // loop finished, one predicate\r
-        }\r
-        if (null == modifier)\r
-            externalRef = p2;\r
-        else\r
-            externalRef = modifier.execute(p2);\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.foreachPredicate: cache2 pk=" + externalRef);\r
-        return procedure.execute(context, externalRef, 0);\r
-    }\r
-\r
-    public static int getSingleObject(long[] table, int index, ClusterSupport support, final short pRef,\r
-            final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier)\r
-    throws DatabaseException {\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.getSingleObject: index=" + index);\r
-        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {\r
-            int completeRef = getCompleteObjectRef(table, index);\r
-            if (0 == completeRef)\r
-                return 0; // no objects for given complete type\r
-            if (ResourceElementSmall.completeHasMultiple(table, index)) {\r
-                // Multiple complete type statements.\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElement.was complete 2");\r
-                ClusterI.ObjectProcedure<Short> proc = new ClusterI.ObjectProcedure<Short>() {\r
-                    @Override\r
-                    public boolean execute(Short context, int completeRefAndType)\r
-                    throws DatabaseException {\r
-                        ClusterI.CompleteTypeEnum ct = ClusterTraitsSmall.completeRefAndTypeGetType(completeRefAndType);\r
-                        if (ct == pCompleteType) { // we have a match\r
-                            if (context != 0) { // we have an old match\r
-                                context = 0; // multiple objects for given type\r
-                                return true; // break loop\r
-                            }\r
-                            context = ClusterTraitsSmall.completeRefAndTypeGetRef(completeRefAndType);\r
-                        }\r
-                        return true; // continue looping\r
-                    }\r
-                };\r
-                Short objectRef = 0;\r
-                // CompleteRef is complete object set index.\r
-                ct.foreachComplete(completeRef, proc, objectRef, support, modifier);\r
-                return modifier.execute(objectRef);\r
-            } // One complete type statement.\r
-            ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);\r
-            if (pCompleteType != rCompleteType)\r
-                return 0; // no objects for given complete type\r
-            // CompleteRef is object resource reference.\r
-            return modifier.execute(completeRef);\r
-        }\r
-        int p1 = getStm1Predicate(table, index);\r
-        if (0 == p1)\r
-            return 0; // loop finished, no statements\r
-        int result = 0;\r
-        if (pRef == p1) {\r
-            short o1 = getStm1Object(table, index);\r
-            result = modifier.execute(o1);\r
-//            procedure.execute(graph, new ResourceImpl(null, modifier.execute(o1)));\r
-//            int externalRef;\r
-//            if (null == modifier)\r
-//                externalRef = o1;\r
-//            else\r
-//                externalRef = modifier.execute(callerThread, o1);\r
-//            if (procedure.execute(callerThread, context, externalRef))\r
-//                return true; // loop broken by procedure\r
-        }\r
-        int p2 = getStm2Predicate(table, index);\r
-        if (0 == p2 || pRef != p2)\r
-            return result; // loop finished, one statements\r
-\r
-        // Many statements\r
-        if (result != 0) return -1;\r
-        \r
-        short o2 = getStm2Object(table, index);\r
-        return modifier.execute(o2);\r
-//        int externalRef;\r
-//        if (null == modifier)\r
-//            externalRef = o2;\r
-//        else\r
-//            externalRef = modifier.execute(callerThread, o2);\r
-//        if (procedure.execute(callerThread, context, externalRef))\r
-//            return true; // loop broken by procedure\r
-//        return false; // loop finished\r
-//        procedure.execute(graph, new ResourceImpl(null, modifier.execute(o2)));\r
-    }\r
-\r
-    public static void foreachObject(long[] table, int index,\r
-            final ReadGraphImpl graph, final AsyncMultiProcedure<Resource> procedure,\r
-            ClusterSupport support, final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)\r
-    throws DatabaseException {\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.foreachObject1: index=" + index);\r
-        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {\r
-            int completeRef = getCompleteObjectRef(table, index);\r
-            if (0 == completeRef) {\r
-                procedure.finished(graph);\r
-//                graph.state.dec(0);\r
-                return; // no objects for given complete type\r
-            }\r
-            if (ResourceElementSmall.completeHasMultiple(table, index)) {// multiple objects\r
-                ClusterI.ObjectProcedure<Object> proc = new ClusterI.ObjectProcedure<Object>() {\r
-                    @Override\r
-                    public boolean execute(Object _context, int objectRef)\r
-                    throws DatabaseException {\r
-                        procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(objectRef)));\r
-                        return false; // continue looping\r
-                    }\r
-                    \r
-                };\r
-                // CompleteRef is complete object set index.\r
-                ct.foreachComplete(completeRef, proc, null, support, modifier);\r
-            } else { // One complete type element. CompleteRef is resource reference.\r
-                ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);\r
-                if (pCompleteType != rCompleteType) {\r
-                    procedure.finished(graph);\r
-//                    graph.state.dec(0);\r
-                    return; // Complete predicate does not match.\r
-                }\r
-                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(completeRef)));\r
-            }\r
-            procedure.finished(graph);\r
-//            graph.state.dec(0);\r
-            return; // loop finished\r
-        }\r
-        short p1 = getStm1Predicate(table, index);\r
-        if (0 == p1) {\r
-            procedure.finished(graph);\r
-//            graph.state.dec(0);\r
-            return; // loop finished, no statements\r
-        }\r
-        if (pRef == p1) {\r
-            short o1 = getStm1Object(table, index);\r
-            procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));\r
-//            int externalRef;\r
-//            if (null == modifier)\r
-//                externalRef = o1;\r
-//            else\r
-//                externalRef = modifier.execute(callerThread, o1);\r
-//            if (procedure.execute(callerThread, context, externalRef))\r
-//                return true; // loop broken by procedure\r
-        }\r
-        short p2 = getStm2Predicate(table, index);\r
-        if (0 == p2 || pRef != p2) {\r
-            procedure.finished(graph);\r
-//            graph.state.dec(0);\r
-            return; // loop finished, one statements\r
-        }\r
-        int o2 = getStm2Object(table, index);\r
-//        int externalRef;\r
-//        if (null == modifier)\r
-//            externalRef = o2;\r
-//        else\r
-//            externalRef = modifier.execute(callerThread, o2);\r
-//        if (procedure.execute(callerThread, context, externalRef))\r
-//            return true; // loop broken by procedure\r
-//        return false; // loop finished\r
-        procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));\r
-        procedure.finished(graph);\r
-//        graph.state.dec(0);\r
-    }\r
-    \r
-    public static <C> void foreachObject(long[] table, int index,\r
-            final ReadGraphImpl graph, final C context, final AsyncContextMultiProcedure<C, Resource> procedure,\r
-            ClusterSupport support, final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)\r
-    throws DatabaseException {\r
-        if (DEBUG)\r
-            System.out.println("ResourceElement.foreachObject1: index=" + index);\r
-        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {\r
-            int completeRef = getCompleteObjectRef(table, index);\r
-            if (0 == completeRef) {\r
-                procedure.finished(graph);\r
-//                graph.state.dec(0);\r
-                return; // no objects for given complete type\r
-            }\r
-            if (ResourceElementSmall.completeHasMultiple(table, index)) {// multiple objects\r
-                ClusterI.ObjectProcedure<Object> proc = new ClusterI.ObjectProcedure<Object>() {\r
-                    @Override\r
-                    public boolean execute(Object _context, int objectRef)\r
-                    throws DatabaseException {\r
-                        procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(objectRef)));\r
-                        return false; // continue looping\r
-                    }\r
-                    \r
-                };\r
-                // CompleteRef is complete object set index.\r
-                ct.foreachComplete(completeRef, proc, null, support, modifier);\r
-            } else { // One complete type element. CompleteRef is resource reference.\r
-                ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);\r
-                if (pCompleteType != rCompleteType) {\r
-                    procedure.finished(graph);\r
-//                    graph.state.dec(0);\r
-                    return; // Complete predicate does not match.\r
-                }\r
-                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(completeRef)));\r
-            }\r
-            procedure.finished(graph);\r
-//            graph.state.dec(0);\r
-            return; // loop finished\r
-        }\r
-        short p1 = getStm1Predicate(table, index);\r
-        if (0 == p1) {\r
-            procedure.finished(graph);\r
-//            graph.state.dec(0);\r
-            return; // loop finished, no statements\r
-        }\r
-        if (pRef == p1) {\r
-            short o1 = getStm1Object(table, index);\r
-            procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));\r
-//            int externalRef;\r
-//            if (null == modifier)\r
-//                externalRef = o1;\r
-//            else\r
-//                externalRef = modifier.execute(callerThread, o1);\r
-//            if (procedure.execute(callerThread, context, externalRef))\r
-//                return true; // loop broken by procedure\r
-        }\r
-        short p2 = getStm2Predicate(table, index);\r
-        if (0 == p2 || pRef != p2) {\r
-            procedure.finished(graph);\r
-//            graph.state.dec(0);\r
-            return; // loop finished, one statements\r
-        }\r
-        int o2 = getStm2Object(table, index);\r
-//        int externalRef;\r
-//        if (null == modifier)\r
-//            externalRef = o2;\r
-//        else\r
-//            externalRef = modifier.execute(callerThread, o2);\r
-//        if (procedure.execute(callerThread, context, externalRef))\r
-//            return true; // loop broken by procedure\r
-//        return false; // loop finished\r
-        procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));\r
-        procedure.finished(graph);\r
-//        graph.state.dec(0);\r
-    }\r
-\r
-    public static <Context> boolean foreachObject(long[] table, int index\r
-            , ClusterI.ObjectProcedure<Context> procedure\r
-            , Context context, ClusterSupport support, Modifier modifier\r
-            , final short pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)\r
-    throws DatabaseException {\r
-        if (DEBUG)\r
-            System.out.println("ResourceElementSmall.foreachObject2: 1");\r
-        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {\r
-            int completeRef = getCompleteObjectRef(table, index);\r
-            if (0 == completeRef) {\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElementSmall.foreachObject2: no complete");\r
-                return false; // no objects for given complete type\r
-            } if (ResourceElementSmall.completeHasMultiple(table, index)) {\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElementSmall.foreachObject2: multi-complete ci=" + completeRef);\r
-                // CompleteRef is complete object set index.\r
-                return ct.foreachObject(completeRef, procedure, context, support, modifier, pCompleteType);\r
-            }\r
-            // One complete type statement at most.\r
-            ClusterI.CompleteTypeEnum completeType = ResourceElementSmall.getCompleteType(table, index);\r
-            if (pCompleteType != completeType) {\r
-                if (DEBUG)\r
-                    System.out.println("ResourceElementSmall.foreachObject2: complete different predicate");\r
-                return false; // Loop finished. No objects for given complete predicate type.\r
-            }\r
-            int externalRef = completeRef;\r
-            if (null != modifier)\r
-                externalRef = modifier.execute(externalRef);\r
-            if (DEBUG)\r
-                System.out.println("ResourceElementSmall.foreachObject2: complete ok=" + externalRef);\r
-            return procedure.execute(context, externalRef);\r
-        }\r
-        int p1 = getStm1Predicate(table, index);\r
-        if (0 == p1) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElementSmall.foreachObject2: empty cache=");\r
-            return false; // loop finished, no statements\r
-        }\r
-        if (pRef == p1) {\r
-            int o1 = getStm1Object(table, index);\r
-            int externalRef;\r
-            if (null == modifier)\r
-                externalRef = o1;\r
-            else\r
-                externalRef = modifier.execute(o1);\r
-            if (DEBUG)\r
-                System.out.println("ResourceElementSmall.foreachObject2: cache1 ok=" + externalRef);\r
-            if (procedure.execute(context, externalRef))\r
-                return true; // loop broken by procedure\r
-        }\r
-        int p2 = getStm2Predicate(table, index);\r
-        if (0 == p2 || pRef != p2) {\r
-            if (DEBUG)\r
-                System.out.println("ResourceElementSmall.foreachObject2: not in cache1");\r
-            return false; // loop finished, one statements\r
-        }\r
-        int o2 = getStm2Object(table, index);\r
-        int externalRef;\r
-        if (null == modifier)\r
-            externalRef = o2;\r
-        else\r
-            externalRef = modifier.execute(o2);\r
-        if (DEBUG)\r
-            System.out.println("ResourceElementSmall.foreachObject2: cache2 ok=" + externalRef);\r
-        return procedure.execute(context, externalRef);\r
-    }\r
-    static boolean isEmpty(long[] table, int index) {\r
-        return getStatementCountApproximation(table, index) == 0 && !hasValue(table, index);\r
-    }\r
-    static int getStatementCountApproximation(long[] table, int index) {\r
-        int n = ResourceElementSmall.completeGetStatementCountApproximation(table, index);\r
-        short p1 = getStm1Predicate(table, index);\r
-        if (0 == p1)\r
-            return n;\r
-        short p2 = getStm2Predicate(table, index);\r
-        if (0 == p2)\r
-            return n+1;\r
-        int predicateIndex = getPredicateIndex(table, index);\r
-        if (0 == predicateIndex)\r
-            return n + 2;\r
-        return n + 3; // Can be bigger, hence the approximation.\r
-    }\r
-    static int addStatement(long[] table, int index, short pRef, short oRef\r
-            , PredicateTable pt, ObjectTable ot\r
-            , ClusterI.CompleteTypeEnum completeType, CompleteTable ct)\r
-    throws DatabaseException {\r
-        assert (0 != pRef);\r
-        assert (0 != oRef);\r
-        if (ClusterI.CompleteTypeEnum.NotComplete != completeType) { // predicate is complete type\r
-            int coRefAndType = completeMakeObjectRefAndType(oRef, completeType);\r
-            if (completeIsFirstStatement(table, index))\r
-                completeSetRefAndType(table, index, coRefAndType);\r
-            else { // old complete statements exist\r
-                if (completeIsSameStatement(table, index, coRefAndType))\r
-                    return -1; // old complete\r
-                int nRef;\r
-                if (completeHasMultiple(table, index)) { // nth statement\r
-                    int coSetIndex = completeGetObjectSetIndex(table, index) & 0xFFFF;\r
-                    nRef = ct.addComplete(coSetIndex, coRefAndType);\r
-                    if (0 == nRef)\r
-                        return -1; // old complete\r
-                    else if (nRef >= 1<<16) {\r
-                        ct.removeComplete(coSetIndex, coRefAndType);\r
-                        throw new OutOfSpaceException("Out of space for complete objects. index=" + nRef);\r
-                    }\r
-                } else { // second statement\r
-                    int coRefAndTypeOld = ResourceElementSmall.completeGetRefAndType(table, index);\r
-                    nRef = ct.createCompleteArraySet(coRefAndTypeOld, coRefAndType);\r
-                    if (nRef >= 1<<16)\r
-                        throw new OutOfSpaceException("Out of space for complete objects. index=" + nRef);\r
-                    ResourceElementSmall.setCompleteType(table, index, (byte)0);\r
-                }\r
-                setCompleteObjectRef(table, index, nRef);\r
-            }\r
-            return 0; // added to complete\r
-        }\r
-        short p1 = getStm1Predicate(table, index);\r
-        short o1 = getStm1Object(table, index);\r
-        if (0 == p1) {\r
-            setStm1Predicate(table, index, pRef);\r
-            setStm1Object(table, index, oRef);\r
-            return 0; // added to stm cache\r
-        } else if (p1 == pRef && o1 == oRef)\r
-            return -1; // same statement\r
-        short p2 = getStm2Predicate(table, index);\r
-        short o2 = getStm2Object(table, index);\r
-        if (0 == p2) {\r
-            setStm2Predicate(table, index, pRef);\r
-            setStm2Object(table, index, oRef);\r
-            return 0; // added to stm cache\r
-        } else if (p2 == pRef && o2 == oRef)\r
-            return -1; // same statement\r
-        int predicateIndex = getPredicateIndex(table, index);\r
-        if (0 == predicateIndex) {\r
-            if (p1 == p2) {\r
-                int objectIndex = ot.createObjectSet(o1 & 0xFFFF, o2 & 0xFFFF);\r
-                assert (0 != objectIndex);\r
-                int[] os = new int[1];\r
-                os[0] = ClusterTraits.statementIndexMake(objectIndex);\r
-                int[] ps = new int[1];\r
-                ps[0] = p1 & 0xFFFF;\r
-                predicateIndex = pt.createPredicateSet(ps, os);\r
-            } else {\r
-                int[] os = new int[2];\r
-                os[0] = o1 & 0xFFFF; \r
-                os[1] = o2 & 0xFFFF;\r
-                int[] ps = new int[2];\r
-                ps[0] = p1 & 0xFFFF;\r
-                ps[1] = p2 & 0xFFFF;\r
-                predicateIndex = pt.createPredicateSet(ps, os);\r
-            }\r
-            assert (0 != predicateIndex);\r
-            setPredicateIndex(table, index, predicateIndex);\r
-        }\r
-        assert (0 != predicateIndex);\r
-        return predicateIndex;\r
-    }\r
-\r
-    static boolean removeStatement(long[] table, int index, short pRef, short oRef,\r
-            ClusterI.CompleteTypeEnum completeType, CompleteTable ct)\r
-    throws DatabaseException {\r
-        assert (0 != pRef);\r
-        assert (0 != oRef);\r
-        if (completeType != ClusterI.CompleteTypeEnum.NotComplete) {\r
-            int completeRef = ResourceElementSmall.getCompleteObjectRef(table, index);\r
-            if (0 == completeRef)\r
-                return false; // Statement not removed because it doesn't exist.\r
-            int refAndType = ResourceElementSmall.completeMakeObjectRefAndType(oRef, completeType);\r
-            if (ResourceElementSmall.completeIsSameStatement(table, index, refAndType)) {\r
-                ResourceElementSmall.completeSetRefAndType(table, index, 0);\r
-                return true; // statement removed\r
-            } else if (ResourceElementSmall.completeHasMultiple(table, index)) {\r
-                // CompleteRef is index to complete table.\r
-                int oldSize = ct.getCompleteSetSize(completeRef);\r
-                int newSize = ct.removeComplete(completeRef, refAndType);\r
-                if (oldSize == newSize)\r
-                    return false; // not removed\r
-                else if (newSize == 1) {\r
-                    int cRef = ct.removeLast(completeRef);\r
-                    ResourceElementSmall.completeSetRefAndType(table, index, cRef);\r
-                }\r
-                return true; \r
-            }\r
-            return false; // Statement not removed because it doesn't exist.\r
-        }\r
-        short p1 = getStm1Predicate(table, index);\r
-        short o1 = getStm1Object(table, index);\r
-        if (0 == p1)\r
-            return false; // no statements cached\r
-        short p2 = getStm2Predicate(table, index);\r
-        short o2 = getStm2Object(table, index);\r
-        if (p1 == pRef && o1 == oRef) {\r
-            setStm1Predicate(table, index, p2);\r
-            setStm1Object(table, index, o2);\r
-            setStm2Predicate(table, index, (short)0);\r
-            setStm2Object(table, index, (short)0);\r
-            return true; // statement removed\r
-        }\r
-        if (0 == p2)\r
-            return false; // no match\r
-        else if (p2 == pRef && o2 == oRef) {\r
-            setStm2Predicate(table, index, (short)0);\r
-            setStm2Object(table, index, (short)0);\r
-            return true; // statement removed\r
-        }\r
-        return false;\r
-    }\r
-}\r
+package org.simantics.db.procore.cluster;
+
+import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ExternalValueException;
+import org.simantics.db.impl.ClusterI;
+import org.simantics.db.impl.ClusterSupport;
+import org.simantics.db.impl.ClusterTraitsBase;
+import org.simantics.db.impl.Modifier;
+import org.simantics.db.impl.ResourceImpl;
+import org.simantics.db.impl.graph.ReadGraphImpl;
+import org.simantics.db.procedure.AsyncContextMultiProcedure;
+import org.simantics.db.procedure.AsyncMultiProcedure;
+
+
+public final class ResourceElementSmall {
+    private static final boolean DEBUG = ClusterImpl.DEBUG;
+    // Descriptor = type & complete object reference & value index & predicate index. 
+    private static final int DESCRIPTOR_OFFSET = 0; // descriptor
+    private static final int STM_OFFSET        = 1; // two statements
+    private static final int SIZE_OF           = 2;
+
+    static void construct(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i++] = 0; // descriptor
+        table[i++] = 0; // stm1 & 2
+    }
+
+    static void destruct(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i++] = 0; // descriptor
+        table[i++] = 0; // stm1 & 2
+    }
+
+    static boolean isUsed(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        if (table[i++] != 0)
+            return true;
+        if (table[i++] != 0)
+            return true;
+        return false;
+    }
+
+    static int getSizeOf() {
+        return SIZE_OF;
+    }
+
+    static ClusterI.CompleteTypeEnum getCompleteType(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        byte bits = (byte)BitUtility.getMiddle(table[i], 62, 2);
+        return ClusterI.CompleteTypeEnum.make(bits);
+    }
+
+    static void setCompleteType(long[] table, int index, byte data) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i] = BitUtility.setMiddle(table[i], 62, 2, data);
+    }
+
+    static short getCompleteObjectRef(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        return (short)BitUtility.getMiddle(table[i], 46, 16);
+    }
+
+    static void setCompleteObjectRef(long[] table, int index, int ref) {
+        if (ref > (1<<16)-1)
+            throw new IllegalArgumentException();
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i] = BitUtility.setMiddle(table[i], 46, 16, ref);
+    }
+
+    static boolean completeHasMultiple(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        int completeRefAndType= BitUtility.getMiddle(table[i], 46, 18); 
+        boolean complete = (completeRefAndType >>> 16) != 0;
+        return !complete && (completeRefAndType != 0);
+    }
+
+    static boolean completeIsFirstStatement(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        int completeRefAndType = BitUtility.getMiddle(table[i], 46, 18); 
+        return completeRefAndType == 0;
+    }
+    
+    static boolean completeIsSameStatement(long[] table, int index, int refAndType) {
+        int i = DESCRIPTOR_OFFSET + index;
+        int completeRefAndType = BitUtility.getMiddle(table[i], 46, 18); 
+        return completeRefAndType == refAndType;
+    }
+    
+    static int completeGetRefAndType(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        return BitUtility.getMiddle(table[i], 46, 18);
+    }
+    
+    static void completeSetRefAndType(long[] table, int index, int refAndType) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i] = BitUtility.setMiddle(table[i], 46, 18, refAndType); 
+    }
+    
+    static int completeMakeObjectRefAndType(short oRef, ClusterI.CompleteTypeEnum completeType) {
+        return oRef & (1<<16)-1 | completeType.getValue()<<16;
+    }
+    
+    static short completeGetObjectSetIndex(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        return (short)BitUtility.getMiddle(table[i], 46, 16);
+    }
+    
+    static int completeGetStatementCountApproximation(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        int cType = BitUtility.getMiddle(table[i], 62, 2);
+        if (cType != 0)
+            return 1;
+        int cRef = BitUtility.getMiddle(table[i], 46, 16);
+        if (cRef != 0)
+            return 2; // Can be bigger, hence the approximation. 
+        return 0;
+    }
+    
+    static int getValueIndex(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        int valueIndex = BitUtility.getMiddle(table[i], 24, 22);
+        return valueIndex;
+    }
+
+    static void setValueIndex(long[] table, int index, int valueIndex) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i] = BitUtility.setMiddle(table[i], 24, 22, valueIndex);
+    }
+
+    static int getPredicateIndex(long[] table, int index) {
+        int i = DESCRIPTOR_OFFSET + index;
+        int predicateIndex = BitUtility.getMiddle(table[i], 0, 24);
+        return predicateIndex;
+    }
+
+    static void setPredicateIndex(long[] table, int index, int predicateIndex) {
+        int i = DESCRIPTOR_OFFSET + index;
+        table[i] = BitUtility.setMiddle(table[i], 0, 24, predicateIndex);
+    }
+
+    static short getStm1Predicate(long[] table, int index) {
+        int i = STM_OFFSET + index;
+        short predicateIndex = BitUtility.getLowShort(table[i]);
+        return predicateIndex;
+    }
+
+    static void setStm1Predicate(long[] table, int index, short predicateIndex) {
+        int i = STM_OFFSET + index;
+        table[i] = BitUtility.setLowShort(table[i], predicateIndex);
+    }
+    
+    static short getStm1Object(long[] table, int index) {
+        int i = STM_OFFSET + index;
+        short objectIndex = (short)BitUtility.getMiddle(table[i], 16, 16);
+        return objectIndex;
+    }
+
+    static void setStm1Object(long[] table, int index, short objectIndex) {
+        int i = STM_OFFSET + index;
+        table[i] = BitUtility.setMiddle(table[i], 16, 16, objectIndex);
+    }
+    
+    static short getStm2Predicate(long[] table, int index) {
+        int i = STM_OFFSET + index;
+        short predicateIndex = (short)BitUtility.getMiddle(table[i], 32, 16);
+        return predicateIndex;
+    }
+
+    static void setStm2Predicate(long[] table, int index, short predicateIndex) {
+        int i = STM_OFFSET + index;
+        table[i] = BitUtility.setMiddle(table[i], 32, 16, predicateIndex);
+    }
+
+    static short getStm2Object(long[] table, int index) {
+        int i = STM_OFFSET + index;
+        short objectIndex = (short)BitUtility.getMiddle(table[i], 48, 16);
+        return objectIndex;
+    }
+
+    static void setStm2Object(long[] table, int index, short objectIndex) {
+        int i = STM_OFFSET + index;
+        table[i] = BitUtility.setMiddle(table[i], 48, 16, objectIndex);
+    }
+
+    public static byte[] getValue(ValueTableSmall valueTable, long[] table, int index)
+    throws DatabaseException {
+        int valueIndex = getValueIndex(table, index);
+        if (0 == valueIndex)
+            return null; // no value
+        else if (ClusterTraitsSmall.VALUE_INDEX_EX == valueIndex)
+            throw new ExternalValueException("Value stored externally. index=" + index);
+        return valueTable.getValue(valueIndex);
+    }
+//KRAA:
+//    static char[] getString(ValueTableSmall valueTable, long[] table, int index) {
+//        int valueIndex = getValueIndex(table, index);
+//        if (0 == valueIndex)
+//            return null; // no value
+////        else if (ClusterTraitsSmall.VALUE_INDEX_MAX == valueIndex)
+////            throw new Error("Not implemented! //KRAA:");
+//        return valueTable.getString(valueIndex);
+//    }
+
+    static boolean hasValue(long[] table, int index) {
+        int valueIndex = getValueIndex(table, index);
+        return 0 != valueIndex;
+    }
+
+//    static boolean hasValue(ValueTable valueTable, long[] table, int index, byte[] value) {
+//        int valueIndex = getValueIndex(table, index);
+//        if (0 == valueIndex)
+//            return false;
+//        return valueTable.isEqual(valueIndex, value, 0, value.length);
+//    }
+
+    static boolean removeValue(ValueTableSmall valueTable, long[] table, int index) {
+        int valueIndex = getValueIndex(table, index);
+        if (0 == valueIndex)
+            return false; // not removed
+        else if (ClusterTraitsSmall.VALUE_INDEX_EX != valueIndex)
+            valueTable.removeValue(valueIndex);
+        setValueIndex(table, index, 0);
+        return true;
+    }
+
+    public static void setValue(ValueTableSmall valueTable, long[] table, int index, byte[] value, int length)
+    throws OutOfSpaceException {
+        int oldIndex = getValueIndex(table, index);
+        if (ClusterTraitsSmall.VALUE_INDEX_EX == oldIndex)
+            oldIndex = 0;
+        if (length > ClusterTraitsSmall.VALUE_SIZE_MAX)
+            throw new OutOfSpaceException("Out of space for value. size=" + length);
+        int newIndex = valueTable.setValue(oldIndex, value, 0, length);
+        if (newIndex != oldIndex) {
+            if (newIndex > ClusterTraitsSmall.VALUE_INDEX_MAX) {
+               setValueIndex(table, index, 0);
+                throw new OutOfSpaceException("Out of space for values. index=" + newIndex);
+            }
+            setValueIndex(table, index, newIndex);
+        }
+        return;
+    }
+
+    public static boolean isValueEx(ValueTableSmall valueTable, long[] table, int index) {
+        int vIndex = getValueIndex(table, index);
+        if (ClusterTraitsSmall.VALUE_INDEX_EX == vIndex)
+            return true;
+        else
+            return false;
+    }
+
+    public static void setValueEx(ValueTableSmall valueTable, long[] table, int index) {
+        setValueIndex(table, index, ClusterTraitsSmall.VALUE_INDEX_EX);
+    }
+
+    public static <Context> boolean foreachPredicate(long[] table, int index,
+            ClusterI.PredicateProcedure<Context> procedure,
+            Context context, ClusterSupport support, Modifier modifier,
+            CompleteTable ct)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachPredicate: 1");
+        int completeRef = ResourceElementSmall.getCompleteObjectRef(table, index);
+        if (0 != completeRef) {
+            if (ResourceElementSmall.completeHasMultiple(table, index)) { // multiple complete objects
+                // CompleteRef is a complete object set index.
+                boolean broken = ct.foreachPredicate(completeRef, procedure, context, support, modifier);
+                if (DEBUG)
+                    System.out.println("ResourceElement.foreachPredicate: multi-complete ci=" + completeRef + " break=" + broken);
+                if (broken)
+                    return true; // loop broken by procedure
+            } else { // We have zero or one complete statement.
+                ClusterI.CompleteTypeEnum completeType = ResourceElementSmall.getCompleteType(table, index);
+                if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {
+                    int key = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);
+                    boolean broken = procedure.execute(context, key, 0);
+                    if (DEBUG)
+                        System.out.println("ResourceElement.foreachPredicate: complete rk=" + key + " break=" + broken);
+                    if (broken)
+                        return true; // loop broken by procedure
+                }
+            }
+        }
+        // If predicate set is in use it will contain also these statements.
+        if (0 != ResourceElementSmall.getPredicateIndex(table, index)) {
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachPredicate: more than 2 objects");
+            return false;
+        }
+        int p1 = getStm1Predicate(table, index);
+        if (0 == p1) {
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachPredicate: empty cache");
+            return false; // loop finished, no statements
+        }
+        int externalRef;
+        if (null == modifier)
+            externalRef = p1;
+        else
+            externalRef = modifier.execute(p1);
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachPredicate: cache1 pk=" + externalRef);
+        if (procedure.execute(context, externalRef, 0))
+            return true; // loop broken by procedure
+        int p2 = getStm2Predicate(table, index);
+        if (0 == p2 || p1 == p2) {
+            if (DEBUG)
+                System.out.println("ResourceElement.foreachPredicate: cache2 empty");
+            return false; // loop finished, one predicate
+        }
+        if (null == modifier)
+            externalRef = p2;
+        else
+            externalRef = modifier.execute(p2);
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachPredicate: cache2 pk=" + externalRef);
+        return procedure.execute(context, externalRef, 0);
+    }
+
+    public static int getSingleObject(long[] table, int index, ClusterSupport support, final short pRef,
+            final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.getSingleObject: index=" + index);
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+            int completeRef = getCompleteObjectRef(table, index);
+            if (0 == completeRef)
+                return 0; // no objects for given complete type
+            if (ResourceElementSmall.completeHasMultiple(table, index)) {
+                // Multiple complete type statements.
+                if (DEBUG)
+                    System.out.println("ResourceElement.was complete 2");
+                ClusterI.ObjectProcedure<Short> proc = new ClusterI.ObjectProcedure<Short>() {
+                    @Override
+                    public boolean execute(Short context, int completeRefAndType)
+                    throws DatabaseException {
+                        ClusterI.CompleteTypeEnum ct = ClusterTraitsSmall.completeRefAndTypeGetType(completeRefAndType);
+                        if (ct == pCompleteType) { // we have a match
+                            if (context != 0) { // we have an old match
+                                context = 0; // multiple objects for given type
+                                return true; // break loop
+                            }
+                            context = ClusterTraitsSmall.completeRefAndTypeGetRef(completeRefAndType);
+                        }
+                        return true; // continue looping
+                    }
+                };
+                Short objectRef = 0;
+                // CompleteRef is complete object set index.
+                ct.foreachComplete(completeRef, proc, objectRef, support, modifier);
+                return modifier.execute(objectRef);
+            } // One complete type statement.
+            ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);
+            if (pCompleteType != rCompleteType)
+                return 0; // no objects for given complete type
+            // CompleteRef is object resource reference.
+            return modifier.execute(completeRef);
+        }
+        int p1 = getStm1Predicate(table, index);
+        if (0 == p1)
+            return 0; // loop finished, no statements
+        int result = 0;
+        if (pRef == p1) {
+            short o1 = getStm1Object(table, index);
+            result = modifier.execute(o1);
+//            procedure.execute(graph, new ResourceImpl(null, modifier.execute(o1)));
+//            int externalRef;
+//            if (null == modifier)
+//                externalRef = o1;
+//            else
+//                externalRef = modifier.execute(callerThread, o1);
+//            if (procedure.execute(callerThread, context, externalRef))
+//                return true; // loop broken by procedure
+        }
+        int p2 = getStm2Predicate(table, index);
+        if (0 == p2 || pRef != p2)
+            return result; // loop finished, one statements
+
+        // Many statements
+        if (result != 0) return -1;
+        
+        short o2 = getStm2Object(table, index);
+        return modifier.execute(o2);
+//        int externalRef;
+//        if (null == modifier)
+//            externalRef = o2;
+//        else
+//            externalRef = modifier.execute(callerThread, o2);
+//        if (procedure.execute(callerThread, context, externalRef))
+//            return true; // loop broken by procedure
+//        return false; // loop finished
+//        procedure.execute(graph, new ResourceImpl(null, modifier.execute(o2)));
+    }
+
+    public static void foreachObject(long[] table, int index,
+            final ReadGraphImpl graph, final AsyncMultiProcedure<Resource> procedure,
+            ClusterSupport support, final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachObject1: index=" + index);
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+            int completeRef = getCompleteObjectRef(table, index);
+            if (0 == completeRef) {
+                procedure.finished(graph);
+//                graph.state.dec(0);
+                return; // no objects for given complete type
+            }
+            if (ResourceElementSmall.completeHasMultiple(table, index)) {// multiple objects
+                ClusterI.ObjectProcedure<Object> proc = new ClusterI.ObjectProcedure<Object>() {
+                    @Override
+                    public boolean execute(Object _context, int objectRef)
+                    throws DatabaseException {
+                        procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(objectRef)));
+                        return false; // continue looping
+                    }
+                    
+                };
+                // CompleteRef is complete object set index.
+                ct.foreachComplete(completeRef, proc, null, support, modifier);
+            } else { // One complete type element. CompleteRef is resource reference.
+                ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);
+                if (pCompleteType != rCompleteType) {
+                    procedure.finished(graph);
+//                    graph.state.dec(0);
+                    return; // Complete predicate does not match.
+                }
+                procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(completeRef)));
+            }
+            procedure.finished(graph);
+//            graph.state.dec(0);
+            return; // loop finished
+        }
+        short p1 = getStm1Predicate(table, index);
+        if (0 == p1) {
+            procedure.finished(graph);
+//            graph.state.dec(0);
+            return; // loop finished, no statements
+        }
+        if (pRef == p1) {
+            short o1 = getStm1Object(table, index);
+            procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
+//            int externalRef;
+//            if (null == modifier)
+//                externalRef = o1;
+//            else
+//                externalRef = modifier.execute(callerThread, o1);
+//            if (procedure.execute(callerThread, context, externalRef))
+//                return true; // loop broken by procedure
+        }
+        short p2 = getStm2Predicate(table, index);
+        if (0 == p2 || pRef != p2) {
+            procedure.finished(graph);
+//            graph.state.dec(0);
+            return; // loop finished, one statements
+        }
+        int o2 = getStm2Object(table, index);
+//        int externalRef;
+//        if (null == modifier)
+//            externalRef = o2;
+//        else
+//            externalRef = modifier.execute(callerThread, o2);
+//        if (procedure.execute(callerThread, context, externalRef))
+//            return true; // loop broken by procedure
+//        return false; // loop finished
+        procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
+        procedure.finished(graph);
+//        graph.state.dec(0);
+    }
+    
+    public static <C> void foreachObject(long[] table, int index,
+            final ReadGraphImpl graph, final C context, final AsyncContextMultiProcedure<C, Resource> procedure,
+            ClusterSupport support, final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElement.foreachObject1: index=" + index);
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+            int completeRef = getCompleteObjectRef(table, index);
+            if (0 == completeRef) {
+                procedure.finished(graph, context);
+//                graph.state.dec(0);
+                return; // no objects for given complete type
+            }
+            if (ResourceElementSmall.completeHasMultiple(table, index)) {// multiple objects
+                ClusterI.ObjectProcedure<Object> proc = new ClusterI.ObjectProcedure<Object>() {
+                    @Override
+                    public boolean execute(Object _context, int objectRef)
+                    throws DatabaseException {
+                        procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(objectRef)));
+                        return false; // continue looping
+                    }
+                    
+                };
+                // CompleteRef is complete object set index.
+                ct.foreachComplete(completeRef, proc, null, support, modifier);
+            } else { // One complete type element. CompleteRef is resource reference.
+                ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);
+                if (pCompleteType != rCompleteType) {
+                    procedure.finished(graph, context);
+//                    graph.state.dec(0);
+                    return; // Complete predicate does not match.
+                }
+                procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(completeRef)));
+            }
+            procedure.finished(graph, context);
+//            graph.state.dec(0);
+            return; // loop finished
+        }
+        short p1 = getStm1Predicate(table, index);
+        if (0 == p1) {
+            procedure.finished(graph, context);
+//            graph.state.dec(0);
+            return; // loop finished, no statements
+        }
+        if (pRef == p1) {
+            short o1 = getStm1Object(table, index);
+            procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
+//            int externalRef;
+//            if (null == modifier)
+//                externalRef = o1;
+//            else
+//                externalRef = modifier.execute(callerThread, o1);
+//            if (procedure.execute(callerThread, context, externalRef))
+//                return true; // loop broken by procedure
+        }
+        short p2 = getStm2Predicate(table, index);
+        if (0 == p2 || pRef != p2) {
+            procedure.finished(graph, context);
+//            graph.state.dec(0);
+            return; // loop finished, one statements
+        }
+        int o2 = getStm2Object(table, index);
+//        int externalRef;
+//        if (null == modifier)
+//            externalRef = o2;
+//        else
+//            externalRef = modifier.execute(callerThread, o2);
+//        if (procedure.execute(callerThread, context, externalRef))
+//            return true; // loop broken by procedure
+//        return false; // loop finished
+        procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
+        procedure.finished(graph, context);
+//        graph.state.dec(0);
+    }
+
+    public static <Context> boolean foreachObject(long[] table, int index
+            , ClusterI.ObjectProcedure<Context> procedure
+            , Context context, ClusterSupport support, Modifier modifier
+            , final short pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
+    throws DatabaseException {
+        if (DEBUG)
+            System.out.println("ResourceElementSmall.foreachObject2: 1");
+        if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
+            int completeRef = getCompleteObjectRef(table, index);
+            if (0 == completeRef) {
+                if (DEBUG)
+                    System.out.println("ResourceElementSmall.foreachObject2: no complete");
+                return false; // no objects for given complete type
+            } if (ResourceElementSmall.completeHasMultiple(table, index)) {
+                if (DEBUG)
+                    System.out.println("ResourceElementSmall.foreachObject2: multi-complete ci=" + completeRef);
+                // CompleteRef is complete object set index.
+                return ct.foreachObject(completeRef, procedure, context, support, modifier, pCompleteType);
+            }
+            // One complete type statement at most.
+            ClusterI.CompleteTypeEnum completeType = ResourceElementSmall.getCompleteType(table, index);
+            if (pCompleteType != completeType) {
+                if (DEBUG)
+                    System.out.println("ResourceElementSmall.foreachObject2: complete different predicate");
+                return false; // Loop finished. No objects for given complete predicate type.
+            }
+            int externalRef = completeRef;
+            if (null != modifier)
+                externalRef = modifier.execute(externalRef);
+            if (DEBUG)
+                System.out.println("ResourceElementSmall.foreachObject2: complete ok=" + externalRef);
+            return procedure.execute(context, externalRef);
+        }
+        int p1 = getStm1Predicate(table, index);
+        if (0 == p1) {
+            if (DEBUG)
+                System.out.println("ResourceElementSmall.foreachObject2: empty cache=");
+            return false; // loop finished, no statements
+        }
+        if (pRef == p1) {
+            int o1 = getStm1Object(table, index);
+            int externalRef;
+            if (null == modifier)
+                externalRef = o1;
+            else
+                externalRef = modifier.execute(o1);
+            if (DEBUG)
+                System.out.println("ResourceElementSmall.foreachObject2: cache1 ok=" + externalRef);
+            if (procedure.execute(context, externalRef))
+                return true; // loop broken by procedure
+        }
+        int p2 = getStm2Predicate(table, index);
+        if (0 == p2 || pRef != p2) {
+            if (DEBUG)
+                System.out.println("ResourceElementSmall.foreachObject2: not in cache1");
+            return false; // loop finished, one statements
+        }
+        int o2 = getStm2Object(table, index);
+        int externalRef;
+        if (null == modifier)
+            externalRef = o2;
+        else
+            externalRef = modifier.execute(o2);
+        if (DEBUG)
+            System.out.println("ResourceElementSmall.foreachObject2: cache2 ok=" + externalRef);
+        return procedure.execute(context, externalRef);
+    }
+    static boolean isEmpty(long[] table, int index) {
+        return getStatementCountApproximation(table, index) == 0 && !hasValue(table, index);
+    }
+    static int getStatementCountApproximation(long[] table, int index) {
+        int n = ResourceElementSmall.completeGetStatementCountApproximation(table, index);
+        short p1 = getStm1Predicate(table, index);
+        if (0 == p1)
+            return n;
+        short p2 = getStm2Predicate(table, index);
+        if (0 == p2)
+            return n+1;
+        int predicateIndex = getPredicateIndex(table, index);
+        if (0 == predicateIndex)
+            return n + 2;
+        return n + 3; // Can be bigger, hence the approximation.
+    }
+    static int addStatement(long[] table, int index, short pRef, short oRef
+            , PredicateTable pt, ObjectTable ot
+            , ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
+    throws DatabaseException {
+        assert (0 != pRef);
+        assert (0 != oRef);
+        if (ClusterI.CompleteTypeEnum.NotComplete != completeType) { // predicate is complete type
+            int coRefAndType = completeMakeObjectRefAndType(oRef, completeType);
+            if (completeIsFirstStatement(table, index))
+                completeSetRefAndType(table, index, coRefAndType);
+            else { // old complete statements exist
+                if (completeIsSameStatement(table, index, coRefAndType))
+                    return -1; // old complete
+                int nRef;
+                if (completeHasMultiple(table, index)) { // nth statement
+                    int coSetIndex = completeGetObjectSetIndex(table, index) & 0xFFFF;
+                    nRef = ct.addComplete(coSetIndex, coRefAndType);
+                    if (0 == nRef)
+                        return -1; // old complete
+                    else if (nRef >= 1<<16) {
+                        ct.removeComplete(coSetIndex, coRefAndType);
+                        throw new OutOfSpaceException("Out of space for complete objects. index=" + nRef);
+                    }
+                } else { // second statement
+                    int coRefAndTypeOld = ResourceElementSmall.completeGetRefAndType(table, index);
+                    nRef = ct.createCompleteArraySet(coRefAndTypeOld, coRefAndType);
+                    if (nRef >= 1<<16)
+                        throw new OutOfSpaceException("Out of space for complete objects. index=" + nRef);
+                    ResourceElementSmall.setCompleteType(table, index, (byte)0);
+                }
+                setCompleteObjectRef(table, index, nRef);
+            }
+            return 0; // added to complete
+        }
+        short p1 = getStm1Predicate(table, index);
+        short o1 = getStm1Object(table, index);
+        if (0 == p1) {
+            setStm1Predicate(table, index, pRef);
+            setStm1Object(table, index, oRef);
+            return 0; // added to stm cache
+        } else if (p1 == pRef && o1 == oRef)
+            return -1; // same statement
+        short p2 = getStm2Predicate(table, index);
+        short o2 = getStm2Object(table, index);
+        if (0 == p2) {
+            setStm2Predicate(table, index, pRef);
+            setStm2Object(table, index, oRef);
+            return 0; // added to stm cache
+        } else if (p2 == pRef && o2 == oRef)
+            return -1; // same statement
+        int predicateIndex = getPredicateIndex(table, index);
+        if (0 == predicateIndex) {
+            if (p1 == p2) {
+                int objectIndex = ot.createObjectSet(o1 & 0xFFFF, o2 & 0xFFFF);
+                assert (0 != objectIndex);
+                int[] os = new int[1];
+                os[0] = ClusterTraits.statementIndexMake(objectIndex);
+                int[] ps = new int[1];
+                ps[0] = p1 & 0xFFFF;
+                predicateIndex = pt.createPredicateSet(ps, os);
+            } else {
+                int[] os = new int[2];
+                os[0] = o1 & 0xFFFF; 
+                os[1] = o2 & 0xFFFF;
+                int[] ps = new int[2];
+                ps[0] = p1 & 0xFFFF;
+                ps[1] = p2 & 0xFFFF;
+                predicateIndex = pt.createPredicateSet(ps, os);
+            }
+            assert (0 != predicateIndex);
+            setPredicateIndex(table, index, predicateIndex);
+        }
+        assert (0 != predicateIndex);
+        return predicateIndex;
+    }
+
+    static boolean removeStatement(long[] table, int index, short pRef, short oRef,
+            ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
+    throws DatabaseException {
+        assert (0 != pRef);
+        assert (0 != oRef);
+        if (completeType != ClusterI.CompleteTypeEnum.NotComplete) {
+            int completeRef = ResourceElementSmall.getCompleteObjectRef(table, index);
+            if (0 == completeRef)
+                return false; // Statement not removed because it doesn't exist.
+            int refAndType = ResourceElementSmall.completeMakeObjectRefAndType(oRef, completeType);
+            if (ResourceElementSmall.completeIsSameStatement(table, index, refAndType)) {
+                ResourceElementSmall.completeSetRefAndType(table, index, 0);
+                return true; // statement removed
+            } else if (ResourceElementSmall.completeHasMultiple(table, index)) {
+                // CompleteRef is index to complete table.
+                int oldSize = ct.getCompleteSetSize(completeRef);
+                int newSize = ct.removeComplete(completeRef, refAndType);
+                if (oldSize == newSize)
+                    return false; // not removed
+                else if (newSize == 1) {
+                    int cRef = ct.removeLast(completeRef);
+                    ResourceElementSmall.completeSetRefAndType(table, index, cRef);
+                }
+                return true; 
+            }
+            return false; // Statement not removed because it doesn't exist.
+        }
+        short p1 = getStm1Predicate(table, index);
+        short o1 = getStm1Object(table, index);
+        if (0 == p1)
+            return false; // no statements cached
+        short p2 = getStm2Predicate(table, index);
+        short o2 = getStm2Object(table, index);
+        if (p1 == pRef && o1 == oRef) {
+            setStm1Predicate(table, index, p2);
+            setStm1Object(table, index, o2);
+            setStm2Predicate(table, index, (short)0);
+            setStm2Object(table, index, (short)0);
+            return true; // statement removed
+        }
+        if (0 == p2)
+            return false; // no match
+        else if (p2 == pRef && o2 == oRef) {
+            setStm2Predicate(table, index, (short)0);
+            setStm2Object(table, index, (short)0);
+            return true; // statement removed
+        }
+        return false;
+    }
+}