hashindex: fix iterator implementation

NSKeyIterator and ChunkKeyIterator raised StopIteration once only when they reached their end.

But they did not raise StopIteration if one called next() again after they were exhausted,
so they did not comply to the standard iterator protocol.

AFAIK, this did not cause actual problems due to the way these iterators are used,
but when I tried to use itertools.islice() to get n-long sequences from these iterators,
it failed / went into an endless loop.
This commit is contained in:
Thomas Waldmann 2016-09-29 04:41:59 +02:00
parent 4838b9e110
commit 8fd0e07a1c
2 changed files with 14 additions and 1 deletions

View File

@ -168,17 +168,22 @@ cdef class NSKeyIterator:
cdef HashIndex *index
cdef const void *key
cdef int key_size
cdef int exhausted
def __cinit__(self, key_size):
self.key = NULL
self.key_size = key_size
self.exhausted = 0
def __iter__(self):
return self
def __next__(self):
if self.exhausted:
raise StopIteration
self.key = hashindex_next_key(self.index, <char *>self.key)
if not self.key:
self.exhausted = 1
raise StopIteration
cdef uint32_t *value = <uint32_t *>(self.key + self.key_size)
cdef uint32_t segment = _le32toh(value[0])
@ -330,17 +335,22 @@ cdef class ChunkKeyIterator:
cdef HashIndex *index
cdef const void *key
cdef int key_size
cdef int exhausted
def __cinit__(self, key_size):
self.key = NULL
self.key_size = key_size
self.exhausted = 0
def __iter__(self):
return self
def __next__(self):
if self.exhausted:
raise StopIteration
self.key = hashindex_next_key(self.index, <char *>self.key)
if not self.key:
self.exhausted = 1
raise StopIteration
cdef uint32_t *value = <uint32_t *>(self.key + self.key_size)
cdef uint32_t refcount = _le32toh(value[0])

View File

@ -83,8 +83,11 @@ class HashIndexTestCase(BaseTestCase):
idx = NSIndex()
for x in range(100):
idx[H(x)] = x, x
all = list(idx.iteritems())
iterator = idx.iteritems()
all = list(iterator)
self.assert_equal(len(all), 100)
# iterator is already exhausted by list():
self.assert_raises(StopIteration, next, iterator)
second_half = list(idx.iteritems(marker=all[49][0]))
self.assert_equal(len(second_half), 50)
self.assert_equal(second_half, all[50:])