@@ -1353,8 +1353,8 @@ save_tuple(PicklerObject *self, PyObject *obj)
13531353static int
13541354batch_list (PicklerObject * self , PyObject * iter )
13551355{
1356- PyObject * obj ;
1357- PyObject * slice [ BATCHSIZE ] ;
1356+ PyObject * obj = NULL ;
1357+ PyObject * firstitem = NULL ;
13581358 int i , n ;
13591359
13601360 const char mark_op = MARK ;
@@ -1389,44 +1389,69 @@ batch_list(PicklerObject *self, PyObject *iter)
13891389
13901390 /* proto > 0: write in batches of BATCHSIZE. */
13911391 do {
1392- /* Get next group of (no more than) BATCHSIZE elements. */
1393- for (n = 0 ; n < BATCHSIZE ; n ++ ) {
1392+ /* Get first item */
1393+ firstitem = PyIter_Next (iter );
1394+ if (firstitem == NULL ) {
1395+ if (PyErr_Occurred ())
1396+ goto error ;
1397+
1398+ /* nothing more to add */
1399+ break ;
1400+ }
1401+
1402+ /* Try to get a second item */
1403+ obj = PyIter_Next (iter );
1404+ if (obj == NULL ) {
1405+ if (PyErr_Occurred ())
1406+ goto error ;
1407+
1408+ /* Only one item to write */
1409+ if (save (self , firstitem , 0 ) < 0 )
1410+ goto error ;
1411+ if (pickler_write (self , & append_op , 1 ) < 0 )
1412+ goto error ;
1413+ Py_CLEAR (firstitem );
1414+ break ;
1415+ }
1416+
1417+ /* More than one item to write */
1418+
1419+ /* Pump out MARK, items, APPENDS. */
1420+ if (pickler_write (self , & mark_op , 1 ) < 0 )
1421+ goto error ;
1422+
1423+ if (save (self , firstitem , 0 ) < 0 )
1424+ goto error ;
1425+ Py_CLEAR (firstitem );
1426+ n = 1 ;
1427+
1428+ /* Fetch and save up to BATCHSIZE items */
1429+ while (obj ) {
1430+ if (save (self , obj , 0 ) < 0 )
1431+ goto error ;
1432+ Py_CLEAR (obj );
1433+ n += 1 ;
1434+
1435+ if (n == BATCHSIZE )
1436+ break ;
1437+
13941438 obj = PyIter_Next (iter );
13951439 if (obj == NULL ) {
13961440 if (PyErr_Occurred ())
13971441 goto error ;
13981442 break ;
13991443 }
1400- slice [n ] = obj ;
14011444 }
14021445
1403- if (n > 1 ) {
1404- /* Pump out MARK, slice[0:n], APPENDS. */
1405- if (pickler_write (self , & mark_op , 1 ) < 0 )
1406- goto error ;
1407- for (i = 0 ; i < n ; i ++ ) {
1408- if (save (self , slice [i ], 0 ) < 0 )
1409- goto error ;
1410- }
1411- if (pickler_write (self , & appends_op , 1 ) < 0 )
1412- goto error ;
1413- }
1414- else if (n == 1 ) {
1415- if (save (self , slice [0 ], 0 ) < 0 ||
1416- pickler_write (self , & append_op , 1 ) < 0 )
1417- goto error ;
1418- }
1446+ if (pickler_write (self , & appends_op , 1 ) < 0 )
1447+ goto error ;
14191448
1420- for (i = 0 ; i < n ; i ++ ) {
1421- Py_DECREF (slice [i ]);
1422- }
14231449 } while (n == BATCHSIZE );
14241450 return 0 ;
14251451
14261452 error :
1427- while (-- n >= 0 ) {
1428- Py_DECREF (slice [n ]);
1429- }
1453+ Py_XDECREF (firstitem );
1454+ Py_XDECREF (obj );
14301455 return -1 ;
14311456}
14321457
@@ -1496,8 +1521,8 @@ save_list(PicklerObject *self, PyObject *obj)
14961521static int
14971522batch_dict (PicklerObject * self , PyObject * iter )
14981523{
1499- PyObject * obj ;
1500- PyObject * slice [ BATCHSIZE ] ;
1524+ PyObject * obj = NULL ;
1525+ PyObject * firstitem = NULL ;
15011526 int i , n ;
15021527
15031528 const char mark_op = MARK ;
@@ -1534,53 +1559,84 @@ batch_dict(PicklerObject *self, PyObject *iter)
15341559
15351560 /* proto > 0: write in batches of BATCHSIZE. */
15361561 do {
1537- /* Get next group of (no more than) BATCHSIZE elements. */
1538- for (n = 0 ; n < BATCHSIZE ; n ++ ) {
1539- obj = PyIter_Next (iter );
1540- if (obj == NULL ) {
1541- if (PyErr_Occurred ())
1542- goto error ;
1543- break ;
1544- }
1545- if (!PyTuple_Check (obj ) || PyTuple_Size (obj ) != 2 ) {
1546- PyErr_SetString (PyExc_TypeError , "dict items "
1547- "iterator must return 2-tuples" );
1562+ /* Get first item */
1563+ firstitem = PyIter_Next (iter );
1564+ if (firstitem == NULL ) {
1565+ if (PyErr_Occurred ())
15481566 goto error ;
1549- }
1550- slice [n ] = obj ;
1567+
1568+ /* nothing more to add */
1569+ break ;
1570+ }
1571+ if (!PyTuple_Check (firstitem ) || PyTuple_Size (firstitem ) != 2 ) {
1572+ PyErr_SetString (PyExc_TypeError , "dict items "
1573+ "iterator must return 2-tuples" );
1574+ goto error ;
15511575 }
15521576
1553- if (n > 1 ) {
1554- /* Pump out MARK, slice[0:n], SETITEMS. */
1555- if (pickler_write (self , & mark_op , 1 ) < 0 )
1577+ /* Try to get a second item */
1578+ obj = PyIter_Next (iter );
1579+ if (obj == NULL ) {
1580+ if (PyErr_Occurred ())
15561581 goto error ;
1557- for ( i = 0 ; i < n ; i ++ ) {
1558- obj = slice [ i ];
1559- if (save (self , PyTuple_GET_ITEM (obj , 0 ), 0 ) < 0 ||
1560- save ( self , PyTuple_GET_ITEM ( obj , 1 ), 0 ) < 0 )
1561- goto error ;
1562- }
1563- if (pickler_write (self , & setitems_op , 1 ) < 0 )
1582+
1583+ /* Only one item to write */
1584+ if (save (self , PyTuple_GET_ITEM (firstitem , 0 ), 0 ) < 0 )
1585+ goto error ;
1586+ if ( save ( self , PyTuple_GET_ITEM ( firstitem , 1 ), 0 ) < 0 )
1587+ goto error ;
1588+ if (pickler_write (self , & setitem_op , 1 ) < 0 )
15641589 goto error ;
1590+ Py_CLEAR (firstitem );
1591+ break ;
15651592 }
1566- else if (n == 1 ) {
1567- obj = slice [0 ];
1593+
1594+ /* More than one item to write */
1595+
1596+ /* Pump out MARK, items, SETITEMS. */
1597+ if (pickler_write (self , & mark_op , 1 ) < 0 )
1598+ goto error ;
1599+
1600+ if (save (self , PyTuple_GET_ITEM (firstitem , 0 ), 0 ) < 0 )
1601+ goto error ;
1602+ if (save (self , PyTuple_GET_ITEM (firstitem , 1 ), 0 ) < 0 )
1603+ goto error ;
1604+ Py_CLEAR (firstitem );
1605+ n = 1 ;
1606+
1607+ /* Fetch and save up to BATCHSIZE items */
1608+ while (obj ) {
1609+ if (!PyTuple_Check (obj ) || PyTuple_Size (obj ) != 2 ) {
1610+ PyErr_SetString (PyExc_TypeError , "dict items "
1611+ "iterator must return 2-tuples" );
1612+ goto error ;
1613+ }
15681614 if (save (self , PyTuple_GET_ITEM (obj , 0 ), 0 ) < 0 ||
1569- save (self , PyTuple_GET_ITEM (obj , 1 ), 0 ) < 0 ||
1570- pickler_write (self , & setitem_op , 1 ) < 0 )
1615+ save (self , PyTuple_GET_ITEM (obj , 1 ), 0 ) < 0 )
15711616 goto error ;
1572- }
1617+ Py_CLEAR (obj );
1618+ n += 1 ;
1619+
1620+ if (n == BATCHSIZE )
1621+ break ;
15731622
1574- for (i = 0 ; i < n ; i ++ ) {
1575- Py_DECREF (slice [i ]);
1623+ obj = PyIter_Next (iter );
1624+ if (obj == NULL ) {
1625+ if (PyErr_Occurred ())
1626+ goto error ;
1627+ break ;
1628+ }
15761629 }
1630+
1631+ if (pickler_write (self , & setitems_op , 1 ) < 0 )
1632+ goto error ;
1633+
15771634 } while (n == BATCHSIZE );
15781635 return 0 ;
15791636
15801637 error :
1581- while (-- n >= 0 ) {
1582- Py_DECREF (slice [n ]);
1583- }
1638+ Py_XDECREF (firstitem );
1639+ Py_XDECREF (obj );
15841640 return -1 ;
15851641}
15861642
0 commit comments