@@ -1247,6 +1247,9 @@ align(Py_ssize_t size, char c, const formatdef *e)
12471247 return size ;
12481248}
12491249
1250+ /*
1251+ * Struct object implementation.
1252+ */
12501253
12511254/* calculate the size of a format string */
12521255
@@ -1556,6 +1559,142 @@ s_unpack_from(PyObject *self, PyObject *args, PyObject *kwds)
15561559}
15571560
15581561
1562+ /* Unpack iterator type */
1563+
1564+ typedef struct {
1565+ PyObject_HEAD
1566+ PyStructObject * so ;
1567+ Py_buffer buf ;
1568+ Py_ssize_t index ;
1569+ } unpackiterobject ;
1570+
1571+ static void
1572+ unpackiter_dealloc (unpackiterobject * self )
1573+ {
1574+ Py_XDECREF (self -> so );
1575+ PyBuffer_Release (& self -> buf );
1576+ PyObject_GC_Del (self );
1577+ }
1578+
1579+ static int
1580+ unpackiter_traverse (unpackiterobject * self , visitproc visit , void * arg )
1581+ {
1582+ Py_VISIT (self -> so );
1583+ Py_VISIT (self -> buf .obj );
1584+ return 0 ;
1585+ }
1586+
1587+ static PyObject *
1588+ unpackiter_len (unpackiterobject * self )
1589+ {
1590+ Py_ssize_t len ;
1591+ if (self -> so == NULL )
1592+ len = 0 ;
1593+ else
1594+ len = (self -> buf .len - self -> index ) / self -> so -> s_size ;
1595+ return PyLong_FromSsize_t (len );
1596+ }
1597+
1598+ static PyMethodDef unpackiter_methods [] = {
1599+ {"__length_hint__" , (PyCFunction ) unpackiter_len , METH_NOARGS , NULL },
1600+ {NULL , NULL } /* sentinel */
1601+ };
1602+
1603+ static PyObject *
1604+ unpackiter_iternext (unpackiterobject * self )
1605+ {
1606+ PyObject * result ;
1607+ if (self -> so == NULL )
1608+ return NULL ;
1609+ if (self -> index >= self -> buf .len ) {
1610+ /* Iterator exhausted */
1611+ Py_CLEAR (self -> so );
1612+ PyBuffer_Release (& self -> buf );
1613+ return NULL ;
1614+ }
1615+ assert (self -> index + self -> so -> s_size <= self -> buf .len );
1616+ result = s_unpack_internal (self -> so ,
1617+ (char * ) self -> buf .buf + self -> index );
1618+ self -> index += self -> so -> s_size ;
1619+ return result ;
1620+ }
1621+
1622+ PyTypeObject unpackiter_type = {
1623+ PyVarObject_HEAD_INIT (& PyType_Type , 0 )
1624+ "unpack_iterator" , /* tp_name */
1625+ sizeof (unpackiterobject ), /* tp_basicsize */
1626+ 0 , /* tp_itemsize */
1627+ (destructor )unpackiter_dealloc , /* tp_dealloc */
1628+ 0 , /* tp_print */
1629+ 0 , /* tp_getattr */
1630+ 0 , /* tp_setattr */
1631+ 0 , /* tp_reserved */
1632+ 0 , /* tp_repr */
1633+ 0 , /* tp_as_number */
1634+ 0 , /* tp_as_sequence */
1635+ 0 , /* tp_as_mapping */
1636+ 0 , /* tp_hash */
1637+ 0 , /* tp_call */
1638+ 0 , /* tp_str */
1639+ PyObject_GenericGetAttr , /* tp_getattro */
1640+ 0 , /* tp_setattro */
1641+ 0 , /* tp_as_buffer */
1642+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC , /* tp_flags */
1643+ 0 , /* tp_doc */
1644+ (traverseproc )unpackiter_traverse , /* tp_traverse */
1645+ 0 , /* tp_clear */
1646+ 0 , /* tp_richcompare */
1647+ 0 , /* tp_weaklistoffset */
1648+ PyObject_SelfIter , /* tp_iter */
1649+ (iternextfunc )unpackiter_iternext , /* tp_iternext */
1650+ unpackiter_methods /* tp_methods */
1651+ };
1652+
1653+ PyDoc_STRVAR (s_iter_unpack__doc__ ,
1654+ "S.iter_unpack(buffer) -> iterator(v1, v2, ...)\n\
1655+ \n\
1656+ Return an iterator yielding tuples unpacked from the given bytes\n\
1657+ source, like a repeated invocation of unpack_from(). Requires\n\
1658+ that the bytes length be a multiple of the struct size." );
1659+
1660+ static PyObject *
1661+ s_iter_unpack (PyObject * _so , PyObject * input )
1662+ {
1663+ PyStructObject * so = (PyStructObject * ) _so ;
1664+ unpackiterobject * self ;
1665+
1666+ assert (PyStruct_Check (_so ));
1667+ assert (so -> s_codes != NULL );
1668+
1669+ if (so -> s_size == 0 ) {
1670+ PyErr_Format (StructError ,
1671+ "cannot iteratively unpack with a struct of length 0" );
1672+ return NULL ;
1673+ }
1674+
1675+ self = (unpackiterobject * ) PyType_GenericAlloc (& unpackiter_type , 0 );
1676+ if (self == NULL )
1677+ return NULL ;
1678+
1679+ if (PyObject_GetBuffer (input , & self -> buf , PyBUF_SIMPLE ) < 0 ) {
1680+ Py_DECREF (self );
1681+ return NULL ;
1682+ }
1683+ if (self -> buf .len % so -> s_size != 0 ) {
1684+ PyErr_Format (StructError ,
1685+ "iterative unpacking requires a bytes length "
1686+ "multiple of %zd" ,
1687+ so -> s_size );
1688+ Py_DECREF (self );
1689+ return NULL ;
1690+ }
1691+ Py_INCREF (so );
1692+ self -> so = so ;
1693+ self -> index = 0 ;
1694+ return (PyObject * ) self ;
1695+ }
1696+
1697+
15591698/*
15601699 * Guts of the pack function.
15611700 *
@@ -1776,6 +1915,7 @@ s_sizeof(PyStructObject *self, void *unused)
17761915/* List of functions */
17771916
17781917static struct PyMethodDef s_methods [] = {
1918+ {"iter_unpack" , s_iter_unpack , METH_O , s_iter_unpack__doc__ },
17791919 {"pack" , s_pack , METH_VARARGS , s_pack__doc__ },
17801920 {"pack_into" , s_pack_into , METH_VARARGS , s_pack_into__doc__ },
17811921 {"unpack" , s_unpack , METH_O , s_unpack__doc__ },
@@ -2025,9 +2165,34 @@ unpack_from(PyObject *self, PyObject *args, PyObject *kwds)
20252165 return result ;
20262166}
20272167
2168+ PyDoc_STRVAR (iter_unpack_doc ,
2169+ "iter_unpack(fmt, buffer) -> iterator(v1, v2, ...)\n\
2170+ \n\
2171+ Return an iterator yielding tuples unpacked from the given bytes\n\
2172+ source according to the format string, like a repeated invocation of\n\
2173+ unpack_from(). Requires that the bytes length be a multiple of the\n\
2174+ format struct size." );
2175+
2176+ static PyObject *
2177+ iter_unpack (PyObject * self , PyObject * args )
2178+ {
2179+ PyObject * s_object , * fmt , * input , * result ;
2180+
2181+ if (!PyArg_ParseTuple (args , "OO:iter_unpack" , & fmt , & input ))
2182+ return NULL ;
2183+
2184+ s_object = cache_struct (fmt );
2185+ if (s_object == NULL )
2186+ return NULL ;
2187+ result = s_iter_unpack (s_object , input );
2188+ Py_DECREF (s_object );
2189+ return result ;
2190+ }
2191+
20282192static struct PyMethodDef module_functions [] = {
20292193 {"_clearcache" , (PyCFunction )clearcache , METH_NOARGS , clearcache_doc },
20302194 {"calcsize" , calcsize , METH_O , calcsize_doc },
2195+ {"iter_unpack" , iter_unpack , METH_VARARGS , iter_unpack_doc },
20312196 {"pack" , pack , METH_VARARGS , pack_doc },
20322197 {"pack_into" , pack_into , METH_VARARGS , pack_into_doc },
20332198 {"unpack" , unpack , METH_VARARGS , unpack_doc },
0 commit comments