1010 *******************************************************************************/
1111package org .eclipse .rdf4j .query .algebra .evaluation ;
1212
13- import java .util .AbstractSet ;
1413import java .util .ArrayList ;
1514import java .util .Arrays ;
16- import java .util .Collection ;
1715import java .util .Collections ;
18- import java .util .ConcurrentModificationException ;
1916import java .util .Iterator ;
17+ import java .util .LinkedHashSet ;
2018import java .util .List ;
2119import java .util .NoSuchElementException ;
2220import java .util .Set ;
@@ -83,6 +81,7 @@ public ArrayBindingSet(BindingSet toCopy, Set<String> names, String[] namesArray
8381 }
8482 }
8583 this .empty = toCopy .isEmpty ();
84+ assert !this .empty || size () == 0 ;
8685
8786 }
8887
@@ -93,6 +92,7 @@ public ArrayBindingSet(ArrayBindingSet toCopy, String... names) {
9392 this .whichBindingsHaveBeenSet = Arrays .copyOf (toCopy .whichBindingsHaveBeenSet ,
9493 toCopy .whichBindingsHaveBeenSet .length );
9594 this .empty = toCopy .empty ;
95+ assert !this .empty || size () == 0 ;
9696 }
9797
9898 /**
@@ -185,21 +185,30 @@ private int getIndex(String bindingName) {
185185
186186 @ Override
187187 public Set <String > getBindingNames () {
188- final int size = ArrayBindingSet .this .size ();
189- switch (size ) {
190- case 0 :
191- return Collections .emptySet ();
192- case 1 :
193- for (int i = 0 ; i < this .bindingNames .length ; i ++) {
194- if (whichBindingsHaveBeenSet [i ]) {
195- return Collections .singleton (bindingNames [i ]);
188+ if (bindingNamesSetCache == null ) {
189+ int size = size ();
190+ if (size == 0 ) {
191+ this .bindingNamesSetCache = Collections .emptySet ();
192+ } else if (size == 1 ) {
193+ for (int i = 0 ; i < this .bindingNames .length ; i ++) {
194+ if (whichBindingsHaveBeenSet [i ]) {
195+ this .bindingNamesSetCache = Collections .singleton (bindingNames [i ]);
196+ break ;
197+ }
198+ }
199+ assert this .bindingNamesSetCache != null ;
200+ } else {
201+ LinkedHashSet <String > bindingNamesSetCache = new LinkedHashSet <>(size * 2 );
202+ for (int i = 0 ; i < this .bindingNames .length ; i ++) {
203+ if (whichBindingsHaveBeenSet [i ]) {
204+ bindingNamesSetCache .add (bindingNames [i ]);
205+ }
196206 }
207+ this .bindingNamesSetCache = Collections .unmodifiableSet (bindingNamesSetCache );
197208 }
198- throw new ConcurrentModificationException (
199- "An bindingset has been modified during the getBindingNames call" );
200- default :
201- return new MinimallyAllocatingSet (size );
202209 }
210+
211+ return bindingNamesSetCache ;
203212 }
204213
205214 @ Override
@@ -245,7 +254,7 @@ public Iterator<Binding> iterator() {
245254
246255 @ Override
247256 public int size () {
248- if (empty ) {
257+ if (isEmpty () ) {
249258 return 0 ;
250259 }
251260 int size = 0 ;
@@ -286,102 +295,6 @@ public List<String> getSortedBindingNames() {
286295 return sortedBindingNames ;
287296 }
288297
289- /*------------------------------------*
290- * Inner class ArrayBindingSetIterator *
291- *------------------------------------*/
292- private static final class BindingToBindingNameIterator implements Iterator <String > {
293- private final Iterator <Binding > nested ;
294-
295- private BindingToBindingNameIterator (Iterator <Binding > nested ) {
296- this .nested = nested ;
297- }
298-
299- @ Override
300- public boolean hasNext () {
301- return nested .hasNext ();
302- }
303-
304- @ Override
305- public String next () {
306- return nested .next ().getName ();
307- }
308- }
309-
310- private final class MinimallyAllocatingSet extends AbstractSet <String > {
311-
312- private final int size ;
313-
314- private MinimallyAllocatingSet (int size ) {
315- this .size = size ;
316- }
317-
318- @ Override
319- public int size () {
320- return size ;
321- }
322-
323- @ Override
324- public Iterator <String > iterator () {
325- Iterator <Binding > nested = ArrayBindingSet .this .iterator ();
326- return new BindingToBindingNameIterator (nested );
327- }
328-
329- @ Override
330- public boolean add (String e ) {
331- throw new UnsupportedOperationException ();
332- }
333-
334- @ Override
335- public boolean addAll (Collection <? extends String > c ) {
336- throw new UnsupportedOperationException ();
337- }
338- }
339-
340- private class ArrayBindingSetIterator implements Iterator <Binding > {
341-
342- private int index = 0 ;
343-
344- public ArrayBindingSetIterator () {
345- }
346-
347- @ Override
348- public boolean hasNext () {
349- // If the current index is at at a set value then this wont advance again.
350- for (; index < values .length ; index ++) {
351- if (whichBindingsHaveBeenSet [index ] && values [index ] != null ) {
352- return true ;
353- }
354- }
355- return false ;
356- }
357-
358- @ Override
359- public Binding next () {
360- for (; index < values .length ; index ++) {
361- if (whichBindingsHaveBeenSet [index ] && values [index ] != null ) {
362- break ;
363- }
364- }
365-
366- try {
367- String name = bindingNames [index ];
368- Value value = values [index ++];
369- if (value != null ) {
370- return new SimpleBinding (name , value );
371- } else {
372- return null ;
373- }
374- } catch (ArrayIndexOutOfBoundsException e ) {
375- throw new NoSuchElementException ();
376- }
377- }
378-
379- @ Override
380- public void remove () {
381- throw new UnsupportedOperationException ();
382- }
383- }
384-
385298 @ Override
386299 public void addBinding (Binding binding ) {
387300 int index = getIndex (binding .getName ());
@@ -393,9 +306,11 @@ public void addBinding(Binding binding) {
393306 return ;
394307 }
395308
396- assert !this .whichBindingsHaveBeenSet [index ] : "variable already bound: " + binding . getName () ;
309+ assert !this .whichBindingsHaveBeenSet [index ];
397310 this .values [index ] = binding .getValue ();
398311 this .whichBindingsHaveBeenSet [index ] = true ;
312+ empty = false ;
313+ clearCache ();
399314 }
400315
401316 @ Override
@@ -406,6 +321,8 @@ public void setBinding(Binding binding) {
406321 }
407322 this .values [index ] = binding .getValue ();
408323 this .whichBindingsHaveBeenSet [index ] = true ;
324+ empty = false ;
325+ clearCache ();
409326 }
410327
411328 @ Override
@@ -425,12 +342,29 @@ public void setBinding(String name, Value value) {
425342 break ;
426343 }
427344 }
345+ } else {
346+ this .empty = false ;
428347 }
429348 clearCache ();
430349 }
431350
432351 @ Override
433352 public boolean isEmpty () {
353+ if (empty ) {
354+ for (boolean b : whichBindingsHaveBeenSet ) {
355+ if (b ) {
356+ assert false : "empty should be false" ;
357+ }
358+ }
359+ } else {
360+ var tempEmpty = true ;
361+ for (boolean b : whichBindingsHaveBeenSet ) {
362+ if (b ) {
363+ tempEmpty = false ;
364+ }
365+ }
366+ assert tempEmpty == empty ;
367+ }
434368 return empty ;
435369 }
436370
@@ -461,4 +395,46 @@ public void addAll(ArrayBindingSet other) {
461395
462396 }
463397
398+ private class ArrayBindingSetIterator implements Iterator <Binding > {
399+
400+ private int index = 0 ;
401+
402+ public ArrayBindingSetIterator () {
403+ }
404+
405+ @ Override
406+ public boolean hasNext () {
407+ while (index < values .length ) {
408+ if (whichBindingsHaveBeenSet [index ]) {
409+ return true ;
410+ }
411+ index ++;
412+ }
413+ return false ;
414+ }
415+
416+ @ Override
417+ public Binding next () {
418+ while (index < values .length ) {
419+ if (whichBindingsHaveBeenSet [index ]) {
420+ String name = bindingNames [index ];
421+ Value value = values [index ++];
422+ if (value != null ) {
423+ return new SimpleBinding (name , value );
424+ } else {
425+ return null ;
426+ }
427+ }
428+ index ++;
429+ }
430+
431+ throw new NoSuchElementException ();
432+ }
433+
434+ @ Override
435+ public void remove () {
436+ throw new UnsupportedOperationException ();
437+ }
438+ }
439+
464440}
0 commit comments