Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify interleave. #181

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cytoolz/itertoolz.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ cdef object c_merge_sorted(object seqs, object key=*)

cdef class interleave:
cdef list iters
cdef list newiters
cdef Py_ssize_t i
cdef Py_ssize_t n
cdef Py_ssize_t active


cdef class _unique_key:
Expand Down
52 changes: 22 additions & 30 deletions cytoolz/itertoolz.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -328,54 +328,46 @@ cdef class interleave:
Returns a lazy iterator
"""
def __cinit__(self, seqs):
self.iters = [iter(seq) for seq in seqs]
self.newiters = []
self.iters = list(map(iter, seqs))
self.i = 0
self.n = PyList_GET_SIZE(self.iters)
self.active = PyList_GET_SIZE(self.iters)

def __iter__(self):
return self

def __next__(self):
# This implementation is similar to what is done in `toolz` in that we
# construct a new list of iterators, `self.newiters`, when a value is
# successfully retrieved from an iterator from `self.iters`.
cdef object itrobj, val
cdef list iters
cdef PyObject *obj
cdef object val
cdef Py_ssize_t _len

if self.i == self.n:
self.n = PyList_GET_SIZE(self.newiters)
self.i = 0
if self.n == 0:
raise StopIteration
self.iters = self.newiters
self.newiters = []
val = <object>PyList_GET_ITEM(self.iters, self.i)
iters = self.iters
_len = PyList_GET_SIZE(iters)

itrobj = <object>PyList_GET_ITEM(iters, self.i)
self.i += 1
obj = PtrIter_Next(val)
if self.i == _len:
self.i = 0
obj = PtrIter_Next(itrobj)

# TODO: optimization opportunity. Previously, it was possible to
# continue on given exceptions, `self.pass_exceptions`, which is
# why this code is structured this way. Time to clean up?
while obj is NULL:
# Check if error occurred
obj = PyErr_Occurred()
if obj is not NULL:
# Iterator raised an exception
val = <object>obj
PyErr_Clear()
raise val

if self.i == self.n:
self.n = PyList_GET_SIZE(self.newiters)
self.i = 0
if self.n == 0:
raise StopIteration
self.iters = self.newiters
self.newiters = []
val = <object>PyList_GET_ITEM(self.iters, self.i)
self.i += 1
obj = PtrIter_Next(val)
self.active = max(self.active - 1, 0)
if self.active == 0:
raise StopIteration

PyList_Append(self.newiters, val)
itrobj = <object>PyList_GET_ITEM(iters, self.i)
self.i += 1
if self.i == _len:
self.i = 0
obj = PtrIter_Next(itrobj)
val = <object>obj
Py_XDECREF(obj)
return val
Expand Down