Skip to content

Commit 25e744c

Browse files
committed
-
1 parent 4624d17 commit 25e744c

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

source_py3/python_toolbox/cute_iter_tools.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,83 @@ def make_false_iterator():
262262
return iterators
263263

264264

265+
def _double_filter_thread_safe(filter_function, iterable, lazy_tuple=False):
266+
'''
267+
(Thread-safe only in the sense that the two iterables may be consumed
268+
simultaneously by two threads; doesn't mean each iterable can be consumed
269+
simultaneously by multiple threads.)
270+
'''
271+
iterator = iter(iterable)
272+
lock_0 = threading.Lock()
273+
274+
deque_0 = collections.deque()
275+
deque_1 = collections.deque()
276+
277+
deque_0_iterator = call_until_exception(deque_0, IndexError)
278+
deque_1_iterator = call_until_exception(deque_1, IndexError)
279+
280+
iterator_exhausted = False
281+
282+
true_deque = collections.deque()
283+
false_deque = collections.deque()
284+
285+
286+
def phase_0():
287+
with lock_0:
288+
item = next(iterator)
289+
pair = [item, None]
290+
deque_0.append(pair)
291+
deque_1.append(pair)
292+
293+
def phase_1():
294+
with lock_1:
295+
try:
296+
pair = deque_1.popleft()
297+
except IndexError:
298+
for item, value in deque_0_iterator:
299+
if value:
300+
true_deque.append(item)
301+
else:
302+
false_deque.append(item)
303+
raise StopIteration
304+
# Reaching here (with released lock) only if we got a pair out of
305+
# `deque_1`:
306+
assert pair[1] is None
307+
pair[1] = filter_function(pair[0])
308+
309+
310+
def make_true_iterator():
311+
try:
312+
while True:
313+
yield from true_deque
314+
phase_0()
315+
phase_1()
316+
except StopIteration: # Original iterator exhausted
317+
318+
yield from true_deque
319+
320+
321+
322+
323+
def make_false_iterator():
324+
while True:
325+
try:
326+
yield false_deque.popleft()
327+
except IndexError:
328+
value = next(iterator) # `StopIteration` exception recycled.
329+
if filter_function(value):
330+
true_deque.append(value)
331+
else:
332+
yield value
333+
334+
iterators = (make_true_iterator(), make_false_iterator())
335+
336+
if lazy_tuple:
337+
from python_toolbox import nifty_collections # Avoiding circular import.
338+
return tuple(map(nifty_collections.LazyTuple, iterators))
339+
else:
340+
return iterators
341+
265342

266343
def get_ratio(filter_function, iterable):
267344
'''Get the ratio of `iterable` items that pass `filter_function`.'''

0 commit comments

Comments
 (0)