88 *
99 * SPDX-License-Identifier: BSD-3-Clause
1010 *******************************************************************************/
11+ // Some portions generated by Codex
1112package org .eclipse .rdf4j .query .algebra .evaluation ;
1213
14+ import java .lang .invoke .MethodHandles ;
15+ import java .lang .invoke .VarHandle ;
1316import java .util .ArrayList ;
1417import java .util .Arrays ;
1518import java .util .Collections ;
@@ -43,9 +46,24 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
4346
4447 private static final long serialVersionUID = -1L ;
4548
49+ @ FunctionalInterface
50+ public interface SortedBindingNamesCache {
51+ List <String > get (long activeBindingMask );
52+ }
53+
4654 private static final Logger logger = LoggerFactory .getLogger (ArrayBindingSet .class );
4755 private static final Value NULL_VALUE = Values
4856 .iri ("urn:null:d57c56f3-41a9-468e-8dce-5706ebdef84c_e88d9e52-27cb-4056-a889-1ea353fa6f0c" );
57+ private static final VarHandle LAST_EQUALS_MISMATCH_INDEX ;
58+ private static int lastEqualsMismatchIndex ;
59+ static {
60+ try {
61+ LAST_EQUALS_MISMATCH_INDEX = MethodHandles .lookup ()
62+ .findStaticVarHandle (ArrayBindingSet .class , "lastEqualsMismatchIndex" , int .class );
63+ } catch (ReflectiveOperationException e ) {
64+ throw new ExceptionInInitializerError (e );
65+ }
66+ }
4967
5068 private final String [] bindingNames ;
5169
@@ -54,6 +72,9 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
5472 private boolean empty ;
5573
5674 private final Value [] values ;
75+ private final SortedBindingNamesCache sharedSortedBindingNamesCache ;
76+ private long activeBindingMask ;
77+ private int cachedSize = -1 ;
5778 private int cachedHashCode ;
5879
5980 /**
@@ -64,16 +85,29 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
6485 * @param names The binding names.
6586 */
6687 public ArrayBindingSet (String ... names ) {
88+ this (names , null );
89+ }
90+
91+ public ArrayBindingSet (String [] names , SortedBindingNamesCache sharedSortedBindingNamesCache ) {
6792 this .bindingNames = names ;
6893 this .values = new Value [names .length ];
94+ this .sharedSortedBindingNamesCache = sharedSortedBindingNamesCache ;
6995 this .empty = true ;
96+ this .cachedSize = 0 ;
7097 }
7198
7299 public ArrayBindingSet (BindingSet toCopy , Set <String > names , String [] namesArray ) {
100+ this (toCopy , names , namesArray , null );
101+ }
102+
103+ public ArrayBindingSet (BindingSet toCopy , Set <String > names , String [] namesArray ,
104+ SortedBindingNamesCache sharedSortedBindingNamesCache ) {
73105 assert !(toCopy instanceof ArrayBindingSet );
74106
75107 this .bindingNames = namesArray ;
76108 this .values = new Value [this .bindingNames .length ];
109+ this .sharedSortedBindingNamesCache = sharedSortedBindingNamesCache ;
110+ int size = 0 ;
77111 for (int i = 0 ; i < this .bindingNames .length ; i ++) {
78112 Binding binding = toCopy .getBinding (this .bindingNames [i ]);
79113
@@ -82,20 +116,36 @@ public ArrayBindingSet(BindingSet toCopy, Set<String> names, String[] namesArray
82116 if (this .values [i ] == null ) {
83117 this .values [i ] = NULL_VALUE ;
84118 }
119+ size ++;
85120 } else if (hasBinding (this .bindingNames [i ])) {
86121 this .values [i ] = NULL_VALUE ;
122+ size ++;
87123 }
88124 }
89125 this .empty = toCopy .isEmpty ();
126+ this .cachedSize = this .empty ? 0 : size ;
127+ if (sharedSortedBindingNamesCache != null ) {
128+ this .activeBindingMask = calculateActiveBindingMask ();
129+ }
90130 assert !this .empty || size () == 0 ;
91131
92132 }
93133
94134 public ArrayBindingSet (ArrayBindingSet toCopy , String ... names ) {
135+ this (toCopy , names , null );
136+ }
137+
138+ public ArrayBindingSet (ArrayBindingSet toCopy , String [] names ,
139+ SortedBindingNamesCache sharedSortedBindingNamesCache ) {
95140 this .bindingNames = names ;
96141
97142 this .values = Arrays .copyOf (toCopy .values , toCopy .values .length );
143+ this .sharedSortedBindingNamesCache = sharedSortedBindingNamesCache ;
98144 this .empty = toCopy .empty ;
145+ this .cachedSize = toCopy .cachedSize ;
146+ if (sharedSortedBindingNamesCache != null ) {
147+ this .activeBindingMask = calculateActiveBindingMask ();
148+ }
99149 assert !this .empty || size () == 0 ;
100150 }
101151
@@ -117,6 +167,7 @@ public BiConsumer<Value, ArrayBindingSet> getDirectSetBinding(String bindingName
117167 return (v , a ) -> {
118168 a .values [index ] = v == null ? NULL_VALUE : v ;
119169 a .empty = false ;
170+ a .updateActiveBindingMask (index , true );
120171 a .clearCache ();
121172 };
122173 }
@@ -132,6 +183,7 @@ public BiConsumer<Value, ArrayBindingSet> getDirectAddBinding(String bindingName
132183 assert a .values [index ] == null ;
133184 a .values [index ] = v == null ? NULL_VALUE : v ;
134185 a .empty = false ;
186+ a .updateActiveBindingMask (index , true );
135187 a .clearCache ();
136188 };
137189
@@ -280,18 +332,23 @@ public Iterator<Binding> iterator() {
280332 @ Override
281333 public int size () {
282334 if (isEmpty ()) {
335+ cachedSize = 0 ;
283336 return 0 ;
284337 }
285338
286- int size = 0 ;
339+ if (cachedSize == -1 ) {
340+ int size = 0 ;
287341
288- for (Value value : values ) {
289- if (value != null ) {
290- size ++;
342+ for (Value value : values ) {
343+ if (value != null ) {
344+ size ++;
345+ }
291346 }
347+
348+ cachedSize = size ;
292349 }
293350
294- return size ;
351+ return cachedSize ;
295352 }
296353
297354 @ Override
@@ -355,23 +412,28 @@ private boolean slowIsCompatible(BindingSet other) {
355412 public List <String > getSortedBindingNames () {
356413
357414 if (sortedBindingNames == null ) {
358- int size = size ();
359-
360- if (size == 1 ) {
361- for (int i = 0 ; i < bindingNames .length ; i ++) {
362- if (values [i ] != null ) {
363- sortedBindingNames = Collections .singletonList (bindingNames [i ]);
364- }
365- }
415+ if (sharedSortedBindingNamesCache != null ) {
416+ sortedBindingNames = sharedSortedBindingNamesCache .get (activeBindingMask );
366417 } else {
367- ArrayList <String > names = new ArrayList <>(size );
368- for (int i = 0 ; i < bindingNames .length ; i ++) {
369- if (values [i ] != null ) {
370- names .add (bindingNames [i ]);
418+ int size = size ();
419+
420+ if (size == 1 ) {
421+ for (int i = 0 ; i < bindingNames .length ; i ++) {
422+ if (values [i ] != null ) {
423+ sortedBindingNames = Collections .singletonList (bindingNames [i ]);
424+ break ;
425+ }
426+ }
427+ } else {
428+ ArrayList <String > names = new ArrayList <>(size );
429+ for (int i = 0 ; i < bindingNames .length ; i ++) {
430+ if (values [i ] != null ) {
431+ names .add (bindingNames [i ]);
432+ }
371433 }
434+ names .sort (String ::compareTo );
435+ sortedBindingNames = names ;
372436 }
373- names .sort (String ::compareTo );
374- sortedBindingNames = names ;
375437 }
376438 }
377439
@@ -393,6 +455,7 @@ public void addBinding(Binding binding) {
393455 assert this .values [index ] == null ;
394456 this .values [index ] = value == null ? NULL_VALUE : value ;
395457 empty = false ;
458+ updateActiveBindingMask (index , true );
396459 clearCache ();
397460 }
398461
@@ -405,6 +468,7 @@ public void setBinding(Binding binding) {
405468 Value value = binding .getValue ();
406469 this .values [index ] = value == null ? NULL_VALUE : value ;
407470 empty = false ;
471+ updateActiveBindingMask (index , true );
408472 clearCache ();
409473 }
410474
@@ -416,6 +480,7 @@ public void setBinding(String name, Value value) {
416480 }
417481
418482 this .values [index ] = value ;
483+ updateActiveBindingMask (index , value != null );
419484 if (value == null ) {
420485 this .empty = true ;
421486 for (Value value1 : this .values ) {
@@ -437,6 +502,8 @@ public boolean isEmpty() {
437502
438503 private void clearCache () {
439504 bindingNamesSetCache = null ;
505+ sortedBindingNames = null ;
506+ cachedSize = -1 ;
440507 cachedHashCode = 0 ;
441508 }
442509
@@ -459,7 +526,33 @@ public void addAll(ArrayBindingSet other) {
459526 }
460527
461528 clearCache ();
529+ if (sharedSortedBindingNamesCache != null ) {
530+ activeBindingMask = calculateActiveBindingMask ();
531+ }
532+
533+ }
534+
535+ private void updateActiveBindingMask (int index , boolean hasValue ) {
536+ if (sharedSortedBindingNamesCache == null ) {
537+ return ;
538+ }
539+
540+ long maskBit = 1L << index ;
541+ if (hasValue ) {
542+ activeBindingMask |= maskBit ;
543+ } else {
544+ activeBindingMask &= ~maskBit ;
545+ }
546+ }
462547
548+ private long calculateActiveBindingMask () {
549+ long mask = 0L ;
550+ for (int i = 0 ; i < values .length ; i ++) {
551+ if (values [i ] != null ) {
552+ mask |= 1L << i ;
553+ }
554+ }
555+ return mask ;
463556 }
464557
465558 @ Override
@@ -495,9 +588,20 @@ public boolean equals(Object other) {
495588 }
496589
497590 if (bindingNames == o .bindingNames ) {
498- for (int i = 0 ; i < values .length ; i ++) {
499- if (values [i ] != o .values [i ]) {
500- if (!Objects .equals (values [i ], o .values [i ])) {
591+ int valuesLength = values .length ;
592+ int startIndex = (int ) LAST_EQUALS_MISMATCH_INDEX .getOpaque ();
593+ if (startIndex >= valuesLength ) {
594+ startIndex = 0 ;
595+ }
596+
597+ for (int i = 0 ; i < valuesLength ; i ++) {
598+ int index = startIndex + i ;
599+ if (index >= valuesLength ) {
600+ index -= valuesLength ;
601+ }
602+ if (values [index ] != o .values [index ]) {
603+ if (!Objects .equals (values [index ], o .values [index ])) {
604+ LAST_EQUALS_MISMATCH_INDEX .setOpaque (index );
501605 return false ;
502606 }
503607 }
0 commit comments