Fail safe import fixes made by Antti
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ResourceElementSmall.java
1 package org.simantics.db.procore.cluster;
2
3 import org.simantics.db.Resource;
4 import org.simantics.db.exception.DatabaseException;
5 import org.simantics.db.exception.ExternalValueException;
6 import org.simantics.db.impl.ClusterI;
7 import org.simantics.db.impl.ClusterSupport;
8 import org.simantics.db.impl.ClusterTraitsBase;
9 import org.simantics.db.impl.Modifier;
10 import org.simantics.db.impl.ResourceImpl;
11 import org.simantics.db.impl.graph.ReadGraphImpl;
12 import org.simantics.db.procedure.AsyncContextMultiProcedure;
13 import org.simantics.db.procedure.AsyncMultiProcedure;
14
15
16 public final class ResourceElementSmall {
17     private static final boolean DEBUG = ClusterImpl.DEBUG;
18     // Descriptor = type & complete object reference & value index & predicate index. 
19     private static final int DESCRIPTOR_OFFSET = 0; // descriptor
20     private static final int STM_OFFSET        = 1; // two statements
21     private static final int SIZE_OF           = 2;
22
23     static void construct(long[] table, int index) {
24         int i = DESCRIPTOR_OFFSET + index;
25         table[i++] = 0; // descriptor
26         table[i++] = 0; // stm1 & 2
27     }
28
29     static void destruct(long[] table, int index) {
30         int i = DESCRIPTOR_OFFSET + index;
31         table[i++] = 0; // descriptor
32         table[i++] = 0; // stm1 & 2
33     }
34
35     static boolean isUsed(long[] table, int index) {
36         int i = DESCRIPTOR_OFFSET + index;
37         if (table[i++] != 0)
38             return true;
39         if (table[i++] != 0)
40             return true;
41         return false;
42     }
43
44     static int getSizeOf() {
45         return SIZE_OF;
46     }
47
48     static ClusterI.CompleteTypeEnum getCompleteType(long[] table, int index) {
49         int i = DESCRIPTOR_OFFSET + index;
50         byte bits = (byte)BitUtility.getMiddle(table[i], 62, 2);
51         return ClusterI.CompleteTypeEnum.make(bits);
52     }
53
54     static void setCompleteType(long[] table, int index, byte data) {
55         int i = DESCRIPTOR_OFFSET + index;
56         table[i] = BitUtility.setMiddle(table[i], 62, 2, data);
57     }
58
59     static short getCompleteObjectRef(long[] table, int index) {
60         int i = DESCRIPTOR_OFFSET + index;
61         return (short)BitUtility.getMiddle(table[i], 46, 16);
62     }
63
64     static void setCompleteObjectRef(long[] table, int index, int ref) {
65         if (ref > (1<<16)-1)
66             throw new IllegalArgumentException();
67         int i = DESCRIPTOR_OFFSET + index;
68         table[i] = BitUtility.setMiddle(table[i], 46, 16, ref);
69     }
70
71     static boolean completeHasMultiple(long[] table, int index) {
72         int i = DESCRIPTOR_OFFSET + index;
73         int completeRefAndType= BitUtility.getMiddle(table[i], 46, 18); 
74         boolean complete = (completeRefAndType >>> 16) != 0;
75         return !complete && (completeRefAndType != 0);
76     }
77
78     static boolean completeIsFirstStatement(long[] table, int index) {
79         int i = DESCRIPTOR_OFFSET + index;
80         int completeRefAndType = BitUtility.getMiddle(table[i], 46, 18); 
81         return completeRefAndType == 0;
82     }
83     
84     static boolean completeIsSameStatement(long[] table, int index, int refAndType) {
85         int i = DESCRIPTOR_OFFSET + index;
86         int completeRefAndType = BitUtility.getMiddle(table[i], 46, 18); 
87         return completeRefAndType == refAndType;
88     }
89     
90     static int completeGetRefAndType(long[] table, int index) {
91         int i = DESCRIPTOR_OFFSET + index;
92         return BitUtility.getMiddle(table[i], 46, 18);
93     }
94     
95     static void completeSetRefAndType(long[] table, int index, int refAndType) {
96         int i = DESCRIPTOR_OFFSET + index;
97         table[i] = BitUtility.setMiddle(table[i], 46, 18, refAndType); 
98     }
99     
100     static int completeMakeObjectRefAndType(short oRef, ClusterI.CompleteTypeEnum completeType) {
101         return oRef & (1<<16)-1 | completeType.getValue()<<16;
102     }
103     
104     static short completeGetObjectSetIndex(long[] table, int index) {
105         int i = DESCRIPTOR_OFFSET + index;
106         return (short)BitUtility.getMiddle(table[i], 46, 16);
107     }
108     
109     static int completeGetStatementCountApproximation(long[] table, int index) {
110         int i = DESCRIPTOR_OFFSET + index;
111         int cType = BitUtility.getMiddle(table[i], 62, 2);
112         if (cType != 0)
113             return 1;
114         int cRef = BitUtility.getMiddle(table[i], 46, 16);
115         if (cRef != 0)
116             return 2; // Can be bigger, hence the approximation. 
117         return 0;
118     }
119     
120     static int getValueIndex(long[] table, int index) {
121         int i = DESCRIPTOR_OFFSET + index;
122         int valueIndex = BitUtility.getMiddle(table[i], 24, 22);
123         return valueIndex;
124     }
125
126     static void setValueIndex(long[] table, int index, int valueIndex) {
127         int i = DESCRIPTOR_OFFSET + index;
128         table[i] = BitUtility.setMiddle(table[i], 24, 22, valueIndex);
129     }
130
131     static int getPredicateIndex(long[] table, int index) {
132         int i = DESCRIPTOR_OFFSET + index;
133         int predicateIndex = BitUtility.getMiddle(table[i], 0, 24);
134         return predicateIndex;
135     }
136
137     static void setPredicateIndex(long[] table, int index, int predicateIndex) {
138         int i = DESCRIPTOR_OFFSET + index;
139         table[i] = BitUtility.setMiddle(table[i], 0, 24, predicateIndex);
140     }
141
142     static short getStm1Predicate(long[] table, int index) {
143         int i = STM_OFFSET + index;
144         short predicateIndex = BitUtility.getLowShort(table[i]);
145         return predicateIndex;
146     }
147
148     static void setStm1Predicate(long[] table, int index, short predicateIndex) {
149         int i = STM_OFFSET + index;
150         table[i] = BitUtility.setLowShort(table[i], predicateIndex);
151     }
152     
153     static short getStm1Object(long[] table, int index) {
154         int i = STM_OFFSET + index;
155         short objectIndex = (short)BitUtility.getMiddle(table[i], 16, 16);
156         return objectIndex;
157     }
158
159     static void setStm1Object(long[] table, int index, short objectIndex) {
160         int i = STM_OFFSET + index;
161         table[i] = BitUtility.setMiddle(table[i], 16, 16, objectIndex);
162     }
163     
164     static short getStm2Predicate(long[] table, int index) {
165         int i = STM_OFFSET + index;
166         short predicateIndex = (short)BitUtility.getMiddle(table[i], 32, 16);
167         return predicateIndex;
168     }
169
170     static void setStm2Predicate(long[] table, int index, short predicateIndex) {
171         int i = STM_OFFSET + index;
172         table[i] = BitUtility.setMiddle(table[i], 32, 16, predicateIndex);
173     }
174
175     static short getStm2Object(long[] table, int index) {
176         int i = STM_OFFSET + index;
177         short objectIndex = (short)BitUtility.getMiddle(table[i], 48, 16);
178         return objectIndex;
179     }
180
181     static void setStm2Object(long[] table, int index, short objectIndex) {
182         int i = STM_OFFSET + index;
183         table[i] = BitUtility.setMiddle(table[i], 48, 16, objectIndex);
184     }
185
186     public static byte[] getValue(ValueTableSmall valueTable, long[] table, int index)
187     throws DatabaseException {
188         int valueIndex = getValueIndex(table, index);
189         if (0 == valueIndex)
190             return null; // no value
191         else if (ClusterTraitsSmall.VALUE_INDEX_EX == valueIndex)
192             throw new ExternalValueException("Value stored externally. index=" + index);
193         return valueTable.getValue(valueIndex);
194     }
195 //KRAA:
196 //    static char[] getString(ValueTableSmall valueTable, long[] table, int index) {
197 //        int valueIndex = getValueIndex(table, index);
198 //        if (0 == valueIndex)
199 //            return null; // no value
200 ////        else if (ClusterTraitsSmall.VALUE_INDEX_MAX == valueIndex)
201 ////            throw new Error("Not implemented! //KRAA:");
202 //        return valueTable.getString(valueIndex);
203 //    }
204
205     static boolean hasValue(long[] table, int index) {
206         int valueIndex = getValueIndex(table, index);
207         return 0 != valueIndex;
208     }
209
210 //    static boolean hasValue(ValueTable valueTable, long[] table, int index, byte[] value) {
211 //        int valueIndex = getValueIndex(table, index);
212 //        if (0 == valueIndex)
213 //            return false;
214 //        return valueTable.isEqual(valueIndex, value, 0, value.length);
215 //    }
216
217     static boolean removeValue(ValueTableSmall valueTable, long[] table, int index) {
218         int valueIndex = getValueIndex(table, index);
219         if (0 == valueIndex)
220             return false; // not removed
221         else if (ClusterTraitsSmall.VALUE_INDEX_EX != valueIndex)
222             valueTable.removeValue(valueIndex);
223         setValueIndex(table, index, 0);
224         return true;
225     }
226
227     public static void setValue(ValueTableSmall valueTable, long[] table, int index, byte[] value, int length)
228     throws OutOfSpaceException {
229         int oldIndex = getValueIndex(table, index);
230         if (ClusterTraitsSmall.VALUE_INDEX_EX == oldIndex)
231             oldIndex = 0;
232         if (length > ClusterTraitsSmall.VALUE_SIZE_MAX)
233             throw new OutOfSpaceException("Out of space for value. size=" + length);
234         int newIndex = valueTable.setValue(oldIndex, value, 0, length);
235         if (newIndex != oldIndex) {
236             if (newIndex > ClusterTraitsSmall.VALUE_INDEX_MAX) {
237                 setValueIndex(table, index, 0);
238                 throw new OutOfSpaceException("Out of space for values. index=" + newIndex);
239             }
240             setValueIndex(table, index, newIndex);
241         }
242         return;
243     }
244
245     public static boolean isValueEx(ValueTableSmall valueTable, long[] table, int index) {
246         int vIndex = getValueIndex(table, index);
247         if (ClusterTraitsSmall.VALUE_INDEX_EX == vIndex)
248             return true;
249         else
250             return false;
251     }
252
253     public static void setValueEx(ValueTableSmall valueTable, long[] table, int index) {
254         setValueIndex(table, index, ClusterTraitsSmall.VALUE_INDEX_EX);
255     }
256
257     public static <Context> boolean foreachPredicate(long[] table, int index,
258             ClusterI.PredicateProcedure<Context> procedure,
259             Context context, ClusterSupport support, Modifier modifier,
260             CompleteTable ct)
261     throws DatabaseException {
262         if (DEBUG)
263             System.out.println("ResourceElement.foreachPredicate: 1");
264         int completeRef = ResourceElementSmall.getCompleteObjectRef(table, index);
265         if (0 != completeRef) {
266             if (ResourceElementSmall.completeHasMultiple(table, index)) { // multiple complete objects
267                 // CompleteRef is a complete object set index.
268                 boolean broken = ct.foreachPredicate(completeRef, procedure, context, support, modifier);
269                 if (DEBUG)
270                     System.out.println("ResourceElement.foreachPredicate: multi-complete ci=" + completeRef + " break=" + broken);
271                 if (broken)
272                     return true; // loop broken by procedure
273             } else { // We have zero or one complete statement.
274                 ClusterI.CompleteTypeEnum completeType = ResourceElementSmall.getCompleteType(table, index);
275                 if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {
276                     int key = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);
277                     boolean broken = procedure.execute(context, key, 0);
278                     if (DEBUG)
279                         System.out.println("ResourceElement.foreachPredicate: complete rk=" + key + " break=" + broken);
280                     if (broken)
281                         return true; // loop broken by procedure
282                 }
283             }
284         }
285         // If predicate set is in use it will contain also these statements.
286         if (0 != ResourceElementSmall.getPredicateIndex(table, index)) {
287             if (DEBUG)
288                 System.out.println("ResourceElement.foreachPredicate: more than 2 objects");
289             return false;
290         }
291         int p1 = getStm1Predicate(table, index);
292         if (0 == p1) {
293             if (DEBUG)
294                 System.out.println("ResourceElement.foreachPredicate: empty cache");
295             return false; // loop finished, no statements
296         }
297         int externalRef;
298         if (null == modifier)
299             externalRef = p1;
300         else
301             externalRef = modifier.execute(p1);
302         if (DEBUG)
303             System.out.println("ResourceElement.foreachPredicate: cache1 pk=" + externalRef);
304         if (procedure.execute(context, externalRef, 0))
305             return true; // loop broken by procedure
306         int p2 = getStm2Predicate(table, index);
307         if (0 == p2 || p1 == p2) {
308             if (DEBUG)
309                 System.out.println("ResourceElement.foreachPredicate: cache2 empty");
310             return false; // loop finished, one predicate
311         }
312         if (null == modifier)
313             externalRef = p2;
314         else
315             externalRef = modifier.execute(p2);
316         if (DEBUG)
317             System.out.println("ResourceElement.foreachPredicate: cache2 pk=" + externalRef);
318         return procedure.execute(context, externalRef, 0);
319     }
320
321     public static int getSingleObject(long[] table, int index, ClusterSupport support, final short pRef,
322             final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier)
323     throws DatabaseException {
324         if (DEBUG)
325             System.out.println("ResourceElement.getSingleObject: index=" + index);
326         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
327             int completeRef = getCompleteObjectRef(table, index);
328             if (0 == completeRef)
329                 return 0; // no objects for given complete type
330             if (ResourceElementSmall.completeHasMultiple(table, index)) {
331                 // Multiple complete type statements.
332                 if (DEBUG)
333                     System.out.println("ResourceElement.was complete 2");
334                 ClusterI.ObjectProcedure<Short> proc = new ClusterI.ObjectProcedure<Short>() {
335                     @Override
336                     public boolean execute(Short context, int completeRefAndType)
337                     throws DatabaseException {
338                         ClusterI.CompleteTypeEnum ct = ClusterTraitsSmall.completeRefAndTypeGetType(completeRefAndType);
339                         if (ct == pCompleteType) { // we have a match
340                             if (context != 0) { // we have an old match
341                                 context = 0; // multiple objects for given type
342                                 return true; // break loop
343                             }
344                             context = ClusterTraitsSmall.completeRefAndTypeGetRef(completeRefAndType);
345                         }
346                         return true; // continue looping
347                     }
348                 };
349                 Short objectRef = 0;
350                 // CompleteRef is complete object set index.
351                 ct.foreachComplete(completeRef, proc, objectRef, support, modifier);
352                 return modifier.execute(objectRef);
353             } // One complete type statement.
354             ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);
355             if (pCompleteType != rCompleteType)
356                 return 0; // no objects for given complete type
357             // CompleteRef is object resource reference.
358             return modifier.execute(completeRef);
359         }
360         int p1 = getStm1Predicate(table, index);
361         if (0 == p1)
362             return 0; // loop finished, no statements
363         int result = 0;
364         if (pRef == p1) {
365             short o1 = getStm1Object(table, index);
366             result = modifier.execute(o1);
367 //            procedure.execute(graph, new ResourceImpl(null, modifier.execute(o1)));
368 //            int externalRef;
369 //            if (null == modifier)
370 //                externalRef = o1;
371 //            else
372 //                externalRef = modifier.execute(callerThread, o1);
373 //            if (procedure.execute(callerThread, context, externalRef))
374 //                return true; // loop broken by procedure
375         }
376         int p2 = getStm2Predicate(table, index);
377         if (0 == p2 || pRef != p2)
378             return result; // loop finished, one statements
379
380         // Many statements
381         if (result != 0) return -1;
382         
383         short o2 = getStm2Object(table, index);
384         return modifier.execute(o2);
385 //        int externalRef;
386 //        if (null == modifier)
387 //            externalRef = o2;
388 //        else
389 //            externalRef = modifier.execute(callerThread, o2);
390 //        if (procedure.execute(callerThread, context, externalRef))
391 //            return true; // loop broken by procedure
392 //        return false; // loop finished
393 //        procedure.execute(graph, new ResourceImpl(null, modifier.execute(o2)));
394     }
395
396     public static void foreachObject(long[] table, int index,
397             final ReadGraphImpl graph, final AsyncMultiProcedure<Resource> procedure,
398             ClusterSupport support, final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
399     throws DatabaseException {
400         if (DEBUG)
401             System.out.println("ResourceElement.foreachObject1: index=" + index);
402         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
403             int completeRef = getCompleteObjectRef(table, index);
404             if (0 == completeRef) {
405                 procedure.finished(graph);
406 //                graph.state.dec(0);
407                 return; // no objects for given complete type
408             }
409             if (ResourceElementSmall.completeHasMultiple(table, index)) {// multiple objects
410                 ClusterI.ObjectProcedure<Object> proc = new ClusterI.ObjectProcedure<Object>() {
411                     @Override
412                     public boolean execute(Object _context, int objectRef)
413                     throws DatabaseException {
414                         procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(objectRef)));
415                         return false; // continue looping
416                     }
417                     
418                 };
419                 // CompleteRef is complete object set index.
420                 ct.foreachComplete(completeRef, proc, null, support, modifier);
421             } else { // One complete type element. CompleteRef is resource reference.
422                 ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);
423                 if (pCompleteType != rCompleteType) {
424                     procedure.finished(graph);
425 //                    graph.state.dec(0);
426                     return; // Complete predicate does not match.
427                 }
428                 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(completeRef)));
429             }
430             procedure.finished(graph);
431 //            graph.state.dec(0);
432             return; // loop finished
433         }
434         short p1 = getStm1Predicate(table, index);
435         if (0 == p1) {
436             procedure.finished(graph);
437 //            graph.state.dec(0);
438             return; // loop finished, no statements
439         }
440         if (pRef == p1) {
441             short o1 = getStm1Object(table, index);
442             procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
443 //            int externalRef;
444 //            if (null == modifier)
445 //                externalRef = o1;
446 //            else
447 //                externalRef = modifier.execute(callerThread, o1);
448 //            if (procedure.execute(callerThread, context, externalRef))
449 //                return true; // loop broken by procedure
450         }
451         short p2 = getStm2Predicate(table, index);
452         if (0 == p2 || pRef != p2) {
453             procedure.finished(graph);
454 //            graph.state.dec(0);
455             return; // loop finished, one statements
456         }
457         int o2 = getStm2Object(table, index);
458 //        int externalRef;
459 //        if (null == modifier)
460 //            externalRef = o2;
461 //        else
462 //            externalRef = modifier.execute(callerThread, o2);
463 //        if (procedure.execute(callerThread, context, externalRef))
464 //            return true; // loop broken by procedure
465 //        return false; // loop finished
466         procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
467         procedure.finished(graph);
468 //        graph.state.dec(0);
469     }
470     
471     public static <C> void foreachObject(long[] table, int index,
472             final ReadGraphImpl graph, final C context, final AsyncContextMultiProcedure<C, Resource> procedure,
473             ClusterSupport support, final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
474     throws DatabaseException {
475         if (DEBUG)
476             System.out.println("ResourceElement.foreachObject1: index=" + index);
477         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
478             int completeRef = getCompleteObjectRef(table, index);
479             if (0 == completeRef) {
480                 procedure.finished(graph, context);
481 //                graph.state.dec(0);
482                 return; // no objects for given complete type
483             }
484             if (ResourceElementSmall.completeHasMultiple(table, index)) {// multiple objects
485                 ClusterI.ObjectProcedure<Object> proc = new ClusterI.ObjectProcedure<Object>() {
486                     @Override
487                     public boolean execute(Object _context, int objectRef)
488                     throws DatabaseException {
489                         procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(objectRef)));
490                         return false; // continue looping
491                     }
492                     
493                 };
494                 // CompleteRef is complete object set index.
495                 ct.foreachComplete(completeRef, proc, null, support, modifier);
496             } else { // One complete type element. CompleteRef is resource reference.
497                 ClusterI.CompleteTypeEnum rCompleteType = ResourceElementSmall.getCompleteType(table, index);
498                 if (pCompleteType != rCompleteType) {
499                     procedure.finished(graph, context);
500 //                    graph.state.dec(0);
501                     return; // Complete predicate does not match.
502                 }
503                 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(completeRef)));
504             }
505             procedure.finished(graph, context);
506 //            graph.state.dec(0);
507             return; // loop finished
508         }
509         short p1 = getStm1Predicate(table, index);
510         if (0 == p1) {
511             procedure.finished(graph, context);
512 //            graph.state.dec(0);
513             return; // loop finished, no statements
514         }
515         if (pRef == p1) {
516             short o1 = getStm1Object(table, index);
517             procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
518 //            int externalRef;
519 //            if (null == modifier)
520 //                externalRef = o1;
521 //            else
522 //                externalRef = modifier.execute(callerThread, o1);
523 //            if (procedure.execute(callerThread, context, externalRef))
524 //                return true; // loop broken by procedure
525         }
526         short p2 = getStm2Predicate(table, index);
527         if (0 == p2 || pRef != p2) {
528             procedure.finished(graph, context);
529 //            graph.state.dec(0);
530             return; // loop finished, one statements
531         }
532         int o2 = getStm2Object(table, index);
533 //        int externalRef;
534 //        if (null == modifier)
535 //            externalRef = o2;
536 //        else
537 //            externalRef = modifier.execute(callerThread, o2);
538 //        if (procedure.execute(callerThread, context, externalRef))
539 //            return true; // loop broken by procedure
540 //        return false; // loop finished
541         procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
542         procedure.finished(graph, context);
543 //        graph.state.dec(0);
544     }
545
546     public static <Context> boolean foreachObject(long[] table, int index
547             , ClusterI.ObjectProcedure<Context> procedure
548             , Context context, ClusterSupport support, Modifier modifier
549             , final short pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
550     throws DatabaseException {
551         if (DEBUG)
552             System.out.println("ResourceElementSmall.foreachObject2: 1");
553         if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
554             int completeRef = getCompleteObjectRef(table, index);
555             if (0 == completeRef) {
556                 if (DEBUG)
557                     System.out.println("ResourceElementSmall.foreachObject2: no complete");
558                 return false; // no objects for given complete type
559             } if (ResourceElementSmall.completeHasMultiple(table, index)) {
560                 if (DEBUG)
561                     System.out.println("ResourceElementSmall.foreachObject2: multi-complete ci=" + completeRef);
562                 // CompleteRef is complete object set index.
563                 return ct.foreachObject(completeRef, procedure, context, support, modifier, pCompleteType);
564             }
565             // One complete type statement at most.
566             ClusterI.CompleteTypeEnum completeType = ResourceElementSmall.getCompleteType(table, index);
567             if (pCompleteType != completeType) {
568                 if (DEBUG)
569                     System.out.println("ResourceElementSmall.foreachObject2: complete different predicate");
570                 return false; // Loop finished. No objects for given complete predicate type.
571             }
572             int externalRef = completeRef;
573             if (null != modifier)
574                 externalRef = modifier.execute(externalRef);
575             if (DEBUG)
576                 System.out.println("ResourceElementSmall.foreachObject2: complete ok=" + externalRef);
577             return procedure.execute(context, externalRef);
578         }
579         int p1 = getStm1Predicate(table, index);
580         if (0 == p1) {
581             if (DEBUG)
582                 System.out.println("ResourceElementSmall.foreachObject2: empty cache=");
583             return false; // loop finished, no statements
584         }
585         if (pRef == p1) {
586             int o1 = getStm1Object(table, index);
587             int externalRef;
588             if (null == modifier)
589                 externalRef = o1;
590             else
591                 externalRef = modifier.execute(o1);
592             if (DEBUG)
593                 System.out.println("ResourceElementSmall.foreachObject2: cache1 ok=" + externalRef);
594             if (procedure.execute(context, externalRef))
595                 return true; // loop broken by procedure
596         }
597         int p2 = getStm2Predicate(table, index);
598         if (0 == p2 || pRef != p2) {
599             if (DEBUG)
600                 System.out.println("ResourceElementSmall.foreachObject2: not in cache1");
601             return false; // loop finished, one statements
602         }
603         int o2 = getStm2Object(table, index);
604         int externalRef;
605         if (null == modifier)
606             externalRef = o2;
607         else
608             externalRef = modifier.execute(o2);
609         if (DEBUG)
610             System.out.println("ResourceElementSmall.foreachObject2: cache2 ok=" + externalRef);
611         return procedure.execute(context, externalRef);
612     }
613     static boolean isEmpty(long[] table, int index) {
614         return getStatementCountApproximation(table, index) == 0 && !hasValue(table, index);
615     }
616     static int getStatementCountApproximation(long[] table, int index) {
617         int n = ResourceElementSmall.completeGetStatementCountApproximation(table, index);
618         short p1 = getStm1Predicate(table, index);
619         if (0 == p1)
620             return n;
621         short p2 = getStm2Predicate(table, index);
622         if (0 == p2)
623             return n+1;
624         int predicateIndex = getPredicateIndex(table, index);
625         if (0 == predicateIndex)
626             return n + 2;
627         return n + 3; // Can be bigger, hence the approximation.
628     }
629     static int addStatement(long[] table, int index, short pRef, short oRef
630             , PredicateTable pt, ObjectTable ot
631             , ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
632     throws DatabaseException {
633         assert (0 != pRef);
634         assert (0 != oRef);
635         if (ClusterI.CompleteTypeEnum.NotComplete != completeType) { // predicate is complete type
636             int coRefAndType = completeMakeObjectRefAndType(oRef, completeType);
637             if (completeIsFirstStatement(table, index))
638                 completeSetRefAndType(table, index, coRefAndType);
639             else { // old complete statements exist
640                 if (completeIsSameStatement(table, index, coRefAndType))
641                     return -1; // old complete
642                 int nRef;
643                 if (completeHasMultiple(table, index)) { // nth statement
644                     int coSetIndex = completeGetObjectSetIndex(table, index) & 0xFFFF;
645                     nRef = ct.addComplete(coSetIndex, coRefAndType);
646                     if (0 == nRef)
647                         return -1; // old complete
648                     else if (nRef >= 1<<16) {
649                         ct.removeComplete(coSetIndex, coRefAndType);
650                         throw new OutOfSpaceException("Out of space for complete objects. index=" + nRef);
651                     }
652                 } else { // second statement
653                     int coRefAndTypeOld = ResourceElementSmall.completeGetRefAndType(table, index);
654                     nRef = ct.createCompleteArraySet(coRefAndTypeOld, coRefAndType);
655                     if (nRef >= 1<<16)
656                         throw new OutOfSpaceException("Out of space for complete objects. index=" + nRef);
657                     ResourceElementSmall.setCompleteType(table, index, (byte)0);
658                 }
659                 setCompleteObjectRef(table, index, nRef);
660             }
661             return 0; // added to complete
662         }
663         short p1 = getStm1Predicate(table, index);
664         short o1 = getStm1Object(table, index);
665         if (0 == p1) {
666             setStm1Predicate(table, index, pRef);
667             setStm1Object(table, index, oRef);
668             return 0; // added to stm cache
669         } else if (p1 == pRef && o1 == oRef)
670             return -1; // same statement
671         short p2 = getStm2Predicate(table, index);
672         short o2 = getStm2Object(table, index);
673         if (0 == p2) {
674             setStm2Predicate(table, index, pRef);
675             setStm2Object(table, index, oRef);
676             return 0; // added to stm cache
677         } else if (p2 == pRef && o2 == oRef)
678             return -1; // same statement
679         int predicateIndex = getPredicateIndex(table, index);
680         if (0 == predicateIndex) {
681             if (p1 == p2) {
682                 int objectIndex = ot.createObjectSet(o1 & 0xFFFF, o2 & 0xFFFF);
683                 assert (0 != objectIndex);
684                 int[] os = new int[1];
685                 os[0] = ClusterTraits.statementIndexMake(objectIndex);
686                 int[] ps = new int[1];
687                 ps[0] = p1 & 0xFFFF;
688                 predicateIndex = pt.createPredicateSet(ps, os);
689             } else {
690                 int[] os = new int[2];
691                 os[0] = o1 & 0xFFFF; 
692                 os[1] = o2 & 0xFFFF;
693                 int[] ps = new int[2];
694                 ps[0] = p1 & 0xFFFF;
695                 ps[1] = p2 & 0xFFFF;
696                 predicateIndex = pt.createPredicateSet(ps, os);
697             }
698             assert (0 != predicateIndex);
699             setPredicateIndex(table, index, predicateIndex);
700         }
701         assert (0 != predicateIndex);
702         return predicateIndex;
703     }
704
705     static boolean removeStatement(long[] table, int index, short pRef, short oRef,
706             ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
707     throws DatabaseException {
708         assert (0 != pRef);
709         assert (0 != oRef);
710         if (completeType != ClusterI.CompleteTypeEnum.NotComplete) {
711             int completeRef = ResourceElementSmall.getCompleteObjectRef(table, index);
712             if (0 == completeRef)
713                 return false; // Statement not removed because it doesn't exist.
714             int refAndType = ResourceElementSmall.completeMakeObjectRefAndType(oRef, completeType);
715             if (ResourceElementSmall.completeIsSameStatement(table, index, refAndType)) {
716                 ResourceElementSmall.completeSetRefAndType(table, index, 0);
717                 return true; // statement removed
718             } else if (ResourceElementSmall.completeHasMultiple(table, index)) {
719                 // CompleteRef is index to complete table.
720                 int oldSize = ct.getCompleteSetSize(completeRef);
721                 int newSize = ct.removeComplete(completeRef, refAndType);
722                 if (oldSize == newSize)
723                     return false; // not removed
724                 else if (newSize == 1) {
725                     int cRef = ct.removeLast(completeRef);
726                     ResourceElementSmall.completeSetRefAndType(table, index, cRef);
727                 }
728                 return true; 
729             }
730             return false; // Statement not removed because it doesn't exist.
731         }
732         short p1 = getStm1Predicate(table, index);
733         short o1 = getStm1Object(table, index);
734         if (0 == p1)
735             return false; // no statements cached
736         short p2 = getStm2Predicate(table, index);
737         short o2 = getStm2Object(table, index);
738         if (p1 == pRef && o1 == oRef) {
739             setStm1Predicate(table, index, p2);
740             setStm1Object(table, index, o2);
741             setStm2Predicate(table, index, (short)0);
742             setStm2Object(table, index, (short)0);
743             return true; // statement removed
744         }
745         if (0 == p2)
746             return false; // no match
747         else if (p2 == pRef && o2 == oRef) {
748             setStm2Predicate(table, index, (short)0);
749             setStm2Object(table, index, (short)0);
750             return true; // statement removed
751         }
752         return false;
753     }
754 }