1
1
import functools
2
+ import threading
2
3
from typing import Callable , Iterable , Iterator , Optional , TypeVar , overload
3
4
4
5
from basilisp .lang .interfaces import (
@@ -152,7 +153,7 @@ class LazySeq(IWithMeta, ISequential, ISeq[T]):
152
153
Callers should never provide the `obj` or `seq` arguments -- these are provided
153
154
only to support `with_meta` returning a new LazySeq instance."""
154
155
155
- __slots__ = ("_gen" , "_obj" , "_seq" , "_meta" )
156
+ __slots__ = ("_gen" , "_obj" , "_seq" , "_lock" , " _meta" )
156
157
157
158
def __init__ (
158
159
self ,
@@ -165,6 +166,7 @@ def __init__(
165
166
self ._gen : Optional [LazySeqGenerator ] = gen
166
167
self ._obj : Optional [ISeq [T ]] = obj
167
168
self ._seq : Optional [ISeq [T ]] = seq
169
+ self ._lock = threading .RLock ()
168
170
self ._meta = meta
169
171
170
172
@property
@@ -206,22 +208,23 @@ def _compute_seq(self) -> Optional[ISeq[T]]:
206
208
return self ._obj if self ._obj is not None else self ._seq
207
209
208
210
def seq (self ) -> Optional [ISeq [T ]]:
209
- self ._compute_seq ()
210
- if self ._obj is not None :
211
- o = self ._obj
212
- self ._obj = None
213
- # Consume any additional lazy sequences returned immediately so we have a
214
- # "real" concrete sequence to proxy to.
215
- #
216
- # The common idiom with LazySeqs is to return (cons value (lazy-seq ...))
217
- # from the generator function, so this will only result in evaluating away
218
- # instances where _another_ LazySeq is returned rather than a cons cell
219
- # with a concrete first value. This loop will not consume the LazySeq in
220
- # the rest position of the cons.
221
- while isinstance (o , LazySeq ):
222
- o = o ._compute_seq () # type: ignore
223
- self ._seq = to_seq (o )
224
- return self ._seq
211
+ with self ._lock :
212
+ self ._compute_seq ()
213
+ if self ._obj is not None :
214
+ o = self ._obj
215
+ self ._obj = None
216
+ # Consume any additional lazy sequences returned immediately, so we
217
+ # have a "real" concrete sequence to proxy to.
218
+ #
219
+ # The common idiom with LazySeqs is to return
220
+ # (cons value (lazy-seq ...)) from the generator function, so this will
221
+ # only result in evaluating away instances where _another_ LazySeq is
222
+ # returned rather than a cons cell with a concrete first value. This
223
+ # loop will not consume the LazySeq in the rest position of the cons.
224
+ while isinstance (o , LazySeq ):
225
+ o = o ._compute_seq () # type: ignore
226
+ self ._seq = to_seq (o )
227
+ return self ._seq
225
228
226
229
@property
227
230
def is_empty (self ) -> bool :
@@ -246,7 +249,8 @@ def cons(self, elem):
246
249
247
250
@property
248
251
def is_realized (self ):
249
- return self ._gen is None
252
+ with self ._lock :
253
+ return self ._gen is None
250
254
251
255
252
256
def sequence (s : Iterable [T ]) -> ISeq [T ]:
0 commit comments