stream-{ref,tail,take}: avoid retaining stream for potential error
Although retaining the original stream argument to `stream-ref`, `stream-tail`, or `stream-take` can enable a better error message if the stream runs out of elements too soon, it can also interfere with the intended memory use of a stream. Closes #2870
This commit is contained in:
parent
a2d724fff6
commit
f4a9058941
|
@ -194,4 +194,27 @@
|
||||||
(stream-lazy
|
(stream-lazy
|
||||||
(stream-lazy '(1)))))
|
(stream-lazy '(1)))))
|
||||||
|
|
||||||
|
;; Make sure certain operations that could encounter a too-short stream don't
|
||||||
|
;; retain the original stream just in case of the error:
|
||||||
|
(unless (eq? 'cgc (system-type 'gc))
|
||||||
|
(let ([check (lambda (op)
|
||||||
|
(define s (stream-cons
|
||||||
|
1
|
||||||
|
(stream-cons
|
||||||
|
2
|
||||||
|
(begin
|
||||||
|
(collect-garbage)
|
||||||
|
(let ([v (weak-box-value wb)])
|
||||||
|
(stream-cons
|
||||||
|
3
|
||||||
|
(stream-cons
|
||||||
|
v
|
||||||
|
empty)))))))
|
||||||
|
(define wb (make-weak-box s))
|
||||||
|
(test #f 'check-stream-no-retain (op s 3)))])
|
||||||
|
(check stream-ref)
|
||||||
|
(check (lambda (s n) (stream-first (stream-tail s n))))
|
||||||
|
(check (lambda (s n) (stream-ref (stream-take s (add1 n)) n)))))
|
||||||
|
|
||||||
|
|
||||||
(report-errs)
|
(report-errs)
|
||||||
|
|
|
@ -103,7 +103,14 @@
|
||||||
(raise-arguments-error 'stream-ref
|
(raise-arguments-error 'stream-ref
|
||||||
"stream ended before index"
|
"stream ended before index"
|
||||||
"index" i
|
"index" i
|
||||||
"stream" st)]
|
;; Why `"stream" st` is omitted:
|
||||||
|
;; including `st` in the error message
|
||||||
|
;; means that it has to be kept live;
|
||||||
|
;; that's not so great for a stream, where
|
||||||
|
;; lazy construction could otherwise allow
|
||||||
|
;; a element to be reached without consuming
|
||||||
|
;; proportional memory
|
||||||
|
#;"stream" #;st)]
|
||||||
[(zero? n)
|
[(zero? n)
|
||||||
(stream-first s)]
|
(stream-first s)]
|
||||||
[else
|
[else
|
||||||
|
@ -120,12 +127,11 @@
|
||||||
(raise-arguments-error 'stream-tail
|
(raise-arguments-error 'stream-tail
|
||||||
"stream ended before index"
|
"stream ended before index"
|
||||||
"index" i
|
"index" i
|
||||||
"stream" st)]
|
;; See "Why `"stream" st` is omitted" above
|
||||||
|
#;"stream" #;st)]
|
||||||
[else
|
[else
|
||||||
(loop (sub1 n) (stream-rest s))])))
|
(loop (sub1 n) (stream-rest s))])))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define (stream-take st i)
|
(define (stream-take st i)
|
||||||
(unless (stream? st) (raise-argument-error 'stream-take "stream?" st))
|
(unless (stream? st) (raise-argument-error 'stream-take "stream?" st))
|
||||||
(unless (exact-nonnegative-integer? i)
|
(unless (exact-nonnegative-integer? i)
|
||||||
|
@ -137,7 +143,8 @@
|
||||||
(raise-arguments-error 'stream-take
|
(raise-arguments-error 'stream-take
|
||||||
"stream ended before index"
|
"stream ended before index"
|
||||||
"index" i
|
"index" i
|
||||||
"stream" st)]
|
;; See "Why `"stream" st` is omitted" above
|
||||||
|
#;"stream" #;st)]
|
||||||
[else
|
[else
|
||||||
(make-do-stream (lambda () #f)
|
(make-do-stream (lambda () #f)
|
||||||
(lambda () (stream-first s))
|
(lambda () (stream-first s))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user