77import java .util .*;
88
99import org .jetbrains .annotations .NotNull ;
10+ import org .spockframework .util .Assert ;
1011import org .spockframework .util .Nullable ;
1112import spock .config .RunnerConfiguration ;
1213
@@ -431,23 +432,31 @@ private IDataIterator[] createDataProviderIterators() {
431432 nextDataVariableMultiplication = null ;
432433 }
433434
435+ List <DataProviderInfo > dataProviderInfos = context .getCurrentFeature ().getDataProviders ();
434436 List <IDataIterator > dataIterators = new ArrayList <>(dataProviders .length );
435- for (int i = 0 ; i < dataProviders .length ; i ++) {
436- String nextDataVariableName = dataVariableNames .get (i );
437+ for (int dataProviderIndex = 0 , dataVariableNameIndex = 0 ; dataProviderIndex < dataProviders .length ; dataProviderIndex ++, dataVariableNameIndex ++) {
438+ String nextDataVariableName = dataVariableNames .get (dataVariableNameIndex );
437439 if ((nextDataVariableMultiplication != null )
438440 && (nextDataVariableMultiplication .getDataVariables ()[0 ].equals (nextDataVariableName ))) {
439441
440442 // a cross multiplication starts
441- dataIterators .add (createDataProviderMultiplier (nextDataVariableMultiplication , i ));
442- // skip processed variables
443- i += nextDataVariableMultiplication .getDataVariables ().length - 1 ;
443+ dataIterators .add (createDataProviderMultiplier (nextDataVariableMultiplication , dataProviderIndex ));
444+ // skip processed providers and variables
445+ int remainingVariables = nextDataVariableMultiplication .getDataVariables ().length ;
446+ dataVariableNameIndex += remainingVariables - 1 ;
447+ while (remainingVariables > 0 ) {
448+ remainingVariables -= dataProviderInfos .get (dataProviderIndex ).getDataVariables ().size ();
449+ dataProviderIndex ++;
450+ }
451+ dataProviderIndex --;
452+ Assert .that (remainingVariables == 0 );
444453 // wait for next cross multiplication
445454 nextDataVariableMultiplication = dataVariableMultiplications .hasNext () ? dataVariableMultiplications .next () : null ;
446455 } else {
447456 // not a cross multiplication, just use a data provider iterator
448457 dataIterators .add (new DataProviderIterator (
449458 supervisor , context , nextDataVariableName ,
450- context . getCurrentFeature (). getDataProviders (). get (i ), dataProviders [i ]));
459+ dataProviderInfos . get (dataProviderIndex ), dataProviders [dataProviderIndex ]));
451460 }
452461 }
453462 return dataIterators .toArray (new IDataIterator [0 ]);
@@ -457,16 +466,13 @@ private IDataIterator[] createDataProviderIterators() {
457466 * Creates a multiplier that is backed by data providers and on-the-fly multiplies them as they are processed.
458467 *
459468 * @param dataVariableMultiplication the multiplication for which to create the multiplier
460- * @param i the index of the first data variable for the given multiplication
469+ * @param dataProviderOffset the index of the first data provider for the given multiplication
461470 * @return the data provider multiplier
462471 */
463- private DataProviderMultiplier createDataProviderMultiplier (DataVariableMultiplication dataVariableMultiplication , int i ) {
472+ private DataProviderMultiplier createDataProviderMultiplier (DataVariableMultiplication dataVariableMultiplication , int dataProviderOffset ) {
464473 DataVariableMultiplicationFactor multiplier = dataVariableMultiplication .getMultiplier ();
465474 DataVariableMultiplicationFactor multiplicand = dataVariableMultiplication .getMultiplicand ();
466475
467- int multiplierDataVariablesLength = multiplier .getDataVariables ().length ;
468- int multiplicandDataVariablesLength = multiplicand .getDataVariables ().length ;
469-
470476 if (multiplier instanceof DataVariableMultiplication ) {
471477 // recursively dive into the multiplication depth-first
472478 // if you combined a with b with c with d, the multiplication is represented as
@@ -478,49 +484,48 @@ private DataProviderMultiplier createDataProviderMultiplier(DataVariableMultipli
478484 // here we first build the data provider multiplier for the multiplier
479485 // then we collect the data provider infos and data providers for the multiplicand
480486 // and then create the data provider multiplier for them
481- DataProviderMultiplier multiplierProvider = createDataProviderMultiplier ((DataVariableMultiplication ) multiplier , i );
487+ DataProviderMultiplier multiplierProvider = createDataProviderMultiplier ((DataVariableMultiplication ) multiplier , dataProviderOffset );
482488 List <DataProviderInfo > multiplicandProviderInfos = new ArrayList <>();
483- Object [] multiplicandProviders = new Object [multiplicandDataVariablesLength ];
484-
485- List <DataProviderInfo > dataProviderInfos = context .getCurrentFeature ().getDataProviders ();
486- int j = multiplierDataVariablesLength ;
487- int j2 = multiplierDataVariablesLength + multiplicandDataVariablesLength ;
488- int k = 0 ;
489- for (; j < j2 ; j ++, k ++) {
490- multiplicandProviderInfos .add (dataProviderInfos .get (i + j ));
491- multiplicandProviders [k ] = dataProviders [i + j ];
492- }
489+ List <Object > multiplicandProviders = new ArrayList <>();
490+ collectDataProviders (dataProviderOffset + multiplierProvider .getProcessedDataProviders (), multiplicand , multiplicandProviderInfos , multiplicandProviders );
493491
494492 return new DataProviderMultiplier (supervisor , context ,
495493 Arrays .asList (dataVariableMultiplication .getDataVariables ()),
496- multiplicandProviderInfos , multiplierProvider , multiplicandProviders );
494+ multiplicandProviderInfos , multiplierProvider ,
495+ multiplicandProviders .toArray (new Object [0 ]));
497496 } else {
498497 // this path handles the innermost multiplication (a * b)
499498 //
500499 // it collects the data provider infos and data providers for a and b
501500 // and then creates a data provider multiplier for them
502501 List <DataProviderInfo > multiplierProviderInfos = new ArrayList <>();
503502 List <DataProviderInfo > multiplicandProviderInfos = new ArrayList <>();
504- Object [] multiplierProviders = new Object [multiplierDataVariablesLength ];
505- Object [] multiplicandProviders = new Object [multiplicandDataVariablesLength ];
506-
507- List <DataProviderInfo > dataProviderInfos = context .getCurrentFeature ().getDataProviders ();
508- int j = 0 ;
509- int j2 = multiplierDataVariablesLength ;
510- for (; j < j2 ; j ++) {
511- multiplierProviderInfos .add (dataProviderInfos .get (i + j ));
512- multiplierProviders [j ] = dataProviders [i + j ];
513- }
514- int k = 0 ;
515- for (j2 += multiplicandDataVariablesLength ; j < j2 ; j ++, k ++) {
516- multiplicandProviderInfos .add (dataProviderInfos .get (i + j ));
517- multiplicandProviders [k ] = dataProviders [i + j ];
518- }
503+ List <Object > multiplierProviders = new ArrayList <>();
504+ List <Object > multiplicandProviders = new ArrayList <>();
505+ collectDataProviders (dataProviderOffset , multiplier , multiplierProviderInfos , multiplierProviders );
506+ collectDataProviders (dataProviderOffset + multiplierProviderInfos .size (), multiplicand , multiplicandProviderInfos , multiplicandProviders );
519507
520508 return new DataProviderMultiplier (supervisor , context ,
521509 Arrays .asList (dataVariableMultiplication .getDataVariables ()),
522- multiplierProviderInfos , multiplicandProviderInfos , multiplierProviders , multiplicandProviders );
510+ multiplierProviderInfos , multiplicandProviderInfos ,
511+ multiplierProviders .toArray (new Object [0 ]),
512+ multiplicandProviders .toArray (new Object [0 ]));
513+ }
514+ }
515+
516+ private void collectDataProviders (int dataProviderOffset , DataVariableMultiplicationFactor factor ,
517+ List <DataProviderInfo > factorProviderInfos , List <Object > factorProviders ) {
518+ List <DataProviderInfo > dataProviderInfos = context .getCurrentFeature ().getDataProviders ();
519+ int factorDataVariables = factor .getDataVariables ().length ;
520+ int remainingDataVariables = factorDataVariables ;
521+ while (remainingDataVariables > 0 ) {
522+ int dataProviderIndex = dataProviderOffset + factorDataVariables - remainingDataVariables ;
523+ DataProviderInfo dataProviderInfo = dataProviderInfos .get (dataProviderIndex );
524+ factorProviderInfos .add (dataProviderInfo );
525+ factorProviders .add (dataProviders [dataProviderIndex ]);
526+ remainingDataVariables -= dataProviderInfo .getDataVariables ().size ();
523527 }
528+ Assert .that (remainingDataVariables == 0 );
524529 }
525530
526531 @ NotNull
@@ -667,7 +672,7 @@ private static class DataProviderMultiplier extends BaseDataIterator {
667672 /**
668673 * The data providers that are used as multiplicand
669674 * in this multiplication, if it represents in an
670- * {@code ((a * b) * c)} multiplication the {@code (ab * b )}
675+ * {@code ((a * b) * c)} multiplication the {@code (ab * c )}
671676 * or the {@code (a * b)} part or otherwise {@code null}.
672677 * Outside the constructor it is only used for the final cleanup,
673678 */
@@ -929,6 +934,26 @@ public List<String> getDataVariableNames() {
929934 return dataVariableNames ;
930935 }
931936
937+ /**
938+ * Returns how many data providers are processed by this data provider multiplier.
939+ *
940+ * @return how many data providers are processed by this data provider multiplier
941+ */
942+ public int getProcessedDataProviders () {
943+ int result = 0 ;
944+ if (multiplierProvider != null ) {
945+ result += multiplierProvider .getProcessedDataProviders ();
946+ } else if (multiplierProviders != null ) {
947+ result += multiplierProviders .length ;
948+ }
949+ if (multiplicandProvider != null ) {
950+ result += multiplicandProvider .getProcessedDataProviders ();
951+ } else if (multiplicandProviders != null ) {
952+ result += multiplicandProviders .length ;
953+ }
954+ return result ;
955+ }
956+
932957 private Iterator <?>[] createIterators (Object [] dataProviders , List <DataProviderInfo > dataProviderInfos ) {
933958 if (context .getErrorInfoCollector ().hasErrors ()) {
934959 return null ;
0 commit comments