1010 *******************************************************************************/
1111package org .eclipse .rdf4j .query .algebra .evaluation ;
1212
13+ import java .util .AbstractSet ;
1314import java .util .ArrayList ;
1415import java .util .Arrays ;
16+ import java .util .Collection ;
1517import java .util .Collections ;
18+ import java .util .ConcurrentModificationException ;
1619import java .util .Iterator ;
17- import java .util .LinkedHashSet ;
1820import java .util .List ;
1921import java .util .Set ;
2022import java .util .function .BiConsumer ;
@@ -44,9 +46,6 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
4446
4547 private final String [] bindingNames ;
4648
47- // Creating a LinkedHashSet is expensive, so we should cache the binding names set
48- private Set <String > bindingNamesSetCache ;
49-
5049 private final boolean [] whichBindingsHaveBeenSet ;
5150
5251 private final Value [] values ;
@@ -105,7 +104,6 @@ public BiConsumer<Value, ArrayBindingSet> getDirectSetBinding(String bindingName
105104 return (v , a ) -> {
106105 a .values [index ] = v ;
107106 a .whichBindingsHaveBeenSet [index ] = true ;
108- a .clearCache ();
109107 };
110108 }
111109
@@ -120,7 +118,6 @@ public BiConsumer<Value, ArrayBindingSet> getDirectAddBinding(String bindingName
120118 assert !a .whichBindingsHaveBeenSet [index ] : "variable already bound: " + bindingName ;
121119 a .values [index ] = v ;
122120 a .whichBindingsHaveBeenSet [index ] = true ;
123- a .clearCache ();
124121 };
125122
126123 }
@@ -175,30 +172,21 @@ private int getIndex(String bindingName) {
175172
176173 @ Override
177174 public Set <String > getBindingNames () {
178- if (bindingNamesSetCache == null ) {
179- int size = size ();
180- if (size == 0 ) {
181- this .bindingNamesSetCache = Collections .emptySet ();
182- } else if (size == 1 ) {
183- for (int i = 0 ; i < this .bindingNames .length ; i ++) {
184- if (whichBindingsHaveBeenSet [i ]) {
185- this .bindingNamesSetCache = Collections .singleton (bindingNames [i ]);
186- break ;
187- }
175+ final int size = ArrayBindingSet .this .size ();
176+ switch (size ) {
177+ case 0 :
178+ return Collections .emptySet ();
179+ case 1 :
180+ for (int i = 0 ; i < this .bindingNames .length ; i ++) {
181+ if (whichBindingsHaveBeenSet [i ]) {
182+ return Collections .singleton (bindingNames [i ]);
188183 }
189- assert this .bindingNamesSetCache != null ;
190- } else {
191- LinkedHashSet <String > bindingNamesSetCache = new LinkedHashSet <>(size * 2 );
192- for (int i = 0 ; i < this .bindingNames .length ; i ++) {
193- if (whichBindingsHaveBeenSet [i ]) {
194- bindingNamesSetCache .add (bindingNames [i ]);
195- }
196- }
197- this .bindingNamesSetCache = Collections .unmodifiableSet (bindingNamesSetCache );
198184 }
185+ throw new ConcurrentModificationException (
186+ "An bindingset has been modified during the getBindingNames call" );
187+ default :
188+ return new MinimallyAllocatingSet (size );
199189 }
200-
201- return bindingNamesSetCache ;
202190 }
203191
204192 @ Override
@@ -285,6 +273,53 @@ public List<String> getSortedBindingNames() {
285273 /*------------------------------------*
286274 * Inner class ArrayBindingSetIterator *
287275 *------------------------------------*/
276+ private static final class BindingToBindingNameIterator implements Iterator <String > {
277+ private final Iterator <Binding > nested ;
278+
279+ private BindingToBindingNameIterator (Iterator <Binding > nested ) {
280+ this .nested = nested ;
281+ }
282+
283+ @ Override
284+ public boolean hasNext () {
285+ return nested .hasNext ();
286+ }
287+
288+ @ Override
289+ public String next () {
290+ return nested .next ().getName ();
291+ }
292+ }
293+
294+ private final class MinimallyAllocatingSet extends AbstractSet <String > {
295+
296+ private final int size ;
297+
298+ private MinimallyAllocatingSet (int size ) {
299+ this .size = size ;
300+ }
301+
302+ @ Override
303+ public int size () {
304+ return size ;
305+ }
306+
307+ @ Override
308+ public Iterator <String > iterator () {
309+ Iterator <Binding > nested = ArrayBindingSet .this .iterator ();
310+ return new BindingToBindingNameIterator (nested );
311+ }
312+
313+ @ Override
314+ public boolean add (String e ) {
315+ throw new UnsupportedOperationException ();
316+ }
317+
318+ @ Override
319+ public boolean addAll (Collection <? extends String > c ) {
320+ throw new UnsupportedOperationException ();
321+ }
322+ }
288323
289324 private class ArrayBindingSetIterator implements Iterator <Binding > {
290325
@@ -295,8 +330,8 @@ public ArrayBindingSetIterator() {
295330
296331 @ Override
297332 public boolean hasNext () {
298- for (; index < values .length ; index ++) {
299- if (whichBindingsHaveBeenSet [index ] && values [index ] != null ) {
333+ for (int at = index ; at < values .length ; at ++) {
334+ if (whichBindingsHaveBeenSet [at ] && values [at ] != null ) {
300335 return true ;
301336 }
302337 }
@@ -337,11 +372,9 @@ public void addBinding(Binding binding) {
337372 return ;
338373 }
339374
340- assert !this .whichBindingsHaveBeenSet [index ];
375+ assert !this .whichBindingsHaveBeenSet [index ] : "variable already bound: " + binding . getName () ;
341376 this .values [index ] = binding .getValue ();
342377 this .whichBindingsHaveBeenSet [index ] = true ;
343- clearCache ();
344-
345378 }
346379
347380 @ Override
@@ -352,7 +385,6 @@ public void setBinding(Binding binding) {
352385 }
353386 this .values [index ] = binding .getValue ();
354387 this .whichBindingsHaveBeenSet [index ] = true ;
355- clearCache ();
356388 }
357389
358390 @ Override
@@ -364,7 +396,6 @@ public void setBinding(String name, Value value) {
364396
365397 this .values [index ] = value ;
366398 this .whichBindingsHaveBeenSet [index ] = value != null ;
367- clearCache ();
368399 }
369400
370401 @ Override
@@ -376,8 +407,4 @@ public boolean isEmpty() {
376407 }
377408 return true ;
378409 }
379-
380- private void clearCache () {
381- bindingNamesSetCache = null ;
382- }
383410}
0 commit comments