@@ -1308,6 +1308,7 @@ mod decl {
1308
1308
struct PyItertoolsCombinations {
1309
1309
pool : Vec < PyObjectRef > ,
1310
1310
indices : PyRwLock < Vec < usize > > ,
1311
+ result : PyRwLock < Option < Vec < usize > > > ,
1311
1312
r : AtomicCell < usize > ,
1312
1313
exhausted : AtomicCell < bool > ,
1313
1314
}
@@ -1341,6 +1342,7 @@ mod decl {
1341
1342
PyItertoolsCombinations {
1342
1343
pool,
1343
1344
indices : PyRwLock :: new ( ( 0 ..r) . collect ( ) ) ,
1345
+ result : PyRwLock :: new ( None ) ,
1344
1346
r : AtomicCell :: new ( r) ,
1345
1347
exhausted : AtomicCell :: new ( r > n) ,
1346
1348
}
@@ -1350,7 +1352,39 @@ mod decl {
1350
1352
}
1351
1353
1352
1354
#[ pyclass( with( IterNext , Constructor ) ) ]
1353
- impl PyItertoolsCombinations { }
1355
+ impl PyItertoolsCombinations {
1356
+ #[ pymethod( magic) ]
1357
+ fn reduce ( zelf : PyRef < Self > , vm : & VirtualMachine ) -> PyTupleRef {
1358
+ let result = zelf. result . read ( ) ;
1359
+ if let Some ( result) = & * result {
1360
+ if zelf. exhausted . load ( ) {
1361
+ vm. new_tuple ( (
1362
+ zelf. class ( ) . to_owned ( ) ,
1363
+ vm. new_tuple ( ( vm. new_tuple ( ( ) ) , vm. ctx . new_int ( zelf. r . load ( ) ) ) ) ,
1364
+ ) )
1365
+ } else {
1366
+ vm. new_tuple ( (
1367
+ zelf. class ( ) . to_owned ( ) ,
1368
+ vm. new_tuple ( (
1369
+ vm. new_tuple ( zelf. pool . clone ( ) ) ,
1370
+ vm. ctx . new_int ( zelf. r . load ( ) ) ,
1371
+ ) ) ,
1372
+ vm. ctx
1373
+ . new_tuple ( result. iter ( ) . map ( |& i| zelf. pool [ i] . clone ( ) ) . collect ( ) ) ,
1374
+ ) )
1375
+ }
1376
+ } else {
1377
+ vm. new_tuple ( (
1378
+ zelf. class ( ) . to_owned ( ) ,
1379
+ vm. new_tuple ( (
1380
+ vm. new_tuple ( zelf. pool . clone ( ) ) ,
1381
+ vm. ctx . new_int ( zelf. r . load ( ) ) ,
1382
+ ) ) ,
1383
+ ) )
1384
+ }
1385
+ }
1386
+ }
1387
+
1354
1388
impl IterNextIterable for PyItertoolsCombinations { }
1355
1389
impl IterNext for PyItertoolsCombinations {
1356
1390
fn next ( zelf : & Py < Self > , vm : & VirtualMachine ) -> PyResult < PyIterReturn > {
@@ -1367,38 +1401,51 @@ mod decl {
1367
1401
return Ok ( PyIterReturn :: Return ( vm. new_tuple ( ( ) ) . into ( ) ) ) ;
1368
1402
}
1369
1403
1370
- let res = vm. ctx . new_tuple (
1371
- zelf. indices
1372
- . read ( )
1373
- . iter ( )
1374
- . map ( |& i| zelf. pool [ i] . clone ( ) )
1375
- . collect ( ) ,
1376
- ) ;
1404
+ let mut result = zelf. result . write ( ) ;
1377
1405
1378
- let mut indices = zelf. indices . write ( ) ;
1406
+ if let Some ( ref mut result) = * result {
1407
+ let mut indices = zelf. indices . write ( ) ;
1379
1408
1380
- // Scan indices right-to-left until finding one that is not at its maximum (i + n - r).
1381
- let mut idx = r as isize - 1 ;
1382
- while idx >= 0 && indices[ idx as usize ] == idx as usize + n - r {
1383
- idx -= 1 ;
1384
- }
1409
+ // Scan indices right-to-left until finding one that is not at its maximum (i + n - r).
1410
+ let mut idx = r as isize - 1 ;
1411
+ while idx >= 0 && indices[ idx as usize ] == idx as usize + n - r {
1412
+ idx -= 1 ;
1413
+ }
1385
1414
1386
- // If no suitable index is found, then the indices are all at
1387
- // their maximum value and we're done.
1388
- if idx < 0 {
1389
- zelf. exhausted . store ( true ) ;
1390
- } else {
1391
- // Increment the current index which we know is not at its
1392
- // maximum. Then move back to the right setting each index
1393
- // to its lowest possible value (one higher than the index
1394
- // to its left -- this maintains the sort order invariant).
1395
- indices[ idx as usize ] += 1 ;
1396
- for j in idx as usize + 1 ..r {
1397
- indices[ j] = indices[ j - 1 ] + 1 ;
1415
+ // If no suitable index is found, then the indices are all at
1416
+ // their maximum value and we're done.
1417
+ if idx < 0 {
1418
+ zelf. exhausted . store ( true ) ;
1419
+ return Ok ( PyIterReturn :: StopIteration ( None ) ) ;
1420
+ } else {
1421
+ // Increment the current index which we know is not at its
1422
+ // maximum. Then move back to the right setting each index
1423
+ // to its lowest possible value (one higher than the index
1424
+ // to its left -- this maintains the sort order invariant).
1425
+ indices[ idx as usize ] += 1 ;
1426
+ for j in idx as usize + 1 ..r {
1427
+ indices[ j] = indices[ j - 1 ] + 1 ;
1428
+ }
1429
+ for j in 0 ..r {
1430
+ result[ j] = indices[ j] ;
1431
+ }
1398
1432
}
1433
+ } else {
1434
+ * result = Some ( ( 0 ..r) . collect ( ) ) ;
1399
1435
}
1400
1436
1401
- Ok ( PyIterReturn :: Return ( res. into ( ) ) )
1437
+ Ok ( PyIterReturn :: Return (
1438
+ vm. ctx
1439
+ . new_tuple (
1440
+ result
1441
+ . as_ref ( )
1442
+ . unwrap ( )
1443
+ . iter ( )
1444
+ . map ( |& i| zelf. pool [ i] . clone ( ) )
1445
+ . collect ( ) ,
1446
+ )
1447
+ . into ( ) ,
1448
+ ) )
1402
1449
}
1403
1450
}
1404
1451
0 commit comments