@@ -1796,7 +1796,7 @@ product_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
17961796 lz = (productobject * )type -> tp_alloc (type , 0 );
17971797 if (lz == NULL ) {
17981798 Py_DECREF (pools );
1799- return NULL ;
1799+ goto error ;
18001800 }
18011801
18021802 lz -> pools = pools ;
@@ -1840,18 +1840,22 @@ product_next(productobject *lz)
18401840{
18411841 PyObject * pool ;
18421842 PyObject * elem ;
1843- PyObject * tuple_result ;
1843+ PyObject * oldelem ;
18441844 PyObject * pools = lz -> pools ;
18451845 PyObject * result = lz -> result ;
18461846 Py_ssize_t npools = PyTuple_GET_SIZE (pools );
18471847 Py_ssize_t i ;
18481848
18491849 if (lz -> stopped )
18501850 return NULL ;
1851+
18511852 if (result == NULL ) {
1853+ /* On the first pass, return an initial tuple filled with the
1854+ first element from each pool. If any pool is empty, then
1855+ whole product is empty and we're already done */
18521856 if (npools == 0 )
18531857 goto empty ;
1854- result = PyList_New (npools );
1858+ result = PyTuple_New (npools );
18551859 if (result == NULL )
18561860 goto empty ;
18571861 lz -> result = result ;
@@ -1861,34 +1865,61 @@ product_next(productobject *lz)
18611865 goto empty ;
18621866 elem = PyTuple_GET_ITEM (pool , 0 );
18631867 Py_INCREF (elem );
1864- PyList_SET_ITEM (result , i , elem );
1868+ PyTuple_SET_ITEM (result , i , elem );
18651869 }
18661870 } else {
18671871 Py_ssize_t * indices = lz -> indices ;
18681872 Py_ssize_t * maxvec = lz -> maxvec ;
1873+
1874+ /* Copy the previous result tuple or re-use it if available */
1875+ if (Py_REFCNT (result ) > 1 ) {
1876+ PyObject * old_result = result ;
1877+ result = PyTuple_New (npools );
1878+ if (result == NULL )
1879+ goto empty ;
1880+ lz -> result = result ;
1881+ for (i = 0 ; i < npools ; i ++ ) {
1882+ elem = PyTuple_GET_ITEM (old_result , i );
1883+ Py_INCREF (elem );
1884+ PyTuple_SET_ITEM (result , i , elem );
1885+ }
1886+ Py_DECREF (old_result );
1887+ }
1888+ /* Now, we've got the only copy so we can update it in-place */
1889+ assert (Py_REFCNT (result ) == 1 );
1890+
1891+ /* Update the pool indices right-to-left. Only advance to the
1892+ next pool when the previous one rolls-over */
18691893 for (i = npools - 1 ; i >= 0 ; i -- ) {
18701894 pool = PyTuple_GET_ITEM (pools , i );
18711895 indices [i ]++ ;
18721896 if (indices [i ] == maxvec [i ]) {
1897+ /* Roll-over and advance to next pool */
18731898 indices [i ] = 0 ;
18741899 elem = PyTuple_GET_ITEM (pool , 0 );
18751900 Py_INCREF (elem );
1876- PyList_SetItem (result , i , elem );
1901+ oldelem = PyTuple_GET_ITEM (result , i );
1902+ PyTuple_SET_ITEM (result , i , elem );
1903+ Py_DECREF (oldelem );
18771904 } else {
1905+ /* No rollover. Just increment and stop here. */
18781906 elem = PyTuple_GET_ITEM (pool , indices [i ]);
18791907 Py_INCREF (elem );
1880- PyList_SetItem (result , i , elem );
1908+ oldelem = PyTuple_GET_ITEM (result , i );
1909+ PyTuple_SET_ITEM (result , i , elem );
1910+ Py_DECREF (oldelem );
18811911 break ;
18821912 }
18831913 }
1914+
1915+ /* If i is negative, then the indices have all rolled-over
1916+ and we're done. */
18841917 if (i < 0 )
1885- return NULL ;
1918+ goto empty ;
18861919 }
18871920
1888- tuple_result = PySequence_Tuple (result );
1889- if (tuple_result == NULL )
1890- lz -> stopped = 1 ;
1891- return tuple_result ;
1921+ Py_INCREF (result );
1922+ return result ;
18921923
18931924empty :
18941925 lz -> stopped = 1 ;
@@ -1898,7 +1929,7 @@ product_next(productobject *lz)
18981929PyDoc_STRVAR (product_doc ,
18991930"product(*iterables) --> product object\n\
19001931\n\
1901- Cartesian product of input interables . Equivalent to nested for-loops.\n\n\
1932+ Cartesian product of input iterables . Equivalent to nested for-loops.\n\n\
19021933For example, product(A, B) returns the same as: ((x,y) for x in A for y in B).\n\
19031934The leftmost iterators are in the outermost for-loop, so the output tuples\n\
19041935cycle in a manner similar to an odometer (with the rightmost element changing\n\
0 commit comments