summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-08-07 12:11:54 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-08-07 12:11:54 -0700
commitb7d944377a6674e7fd8c6236f2b957a31c2eccde (patch)
tree352a588c225d44b0472875bbb28fd0585d17f04f
parentfbcdc0c91be3700391a3f0294f87c26f2781944d (diff)
downloadtxr-b7d944377a6674e7fd8c6236f2b957a31c2eccde.tar.gz
txr-b7d944377a6674e7fd8c6236f2b957a31c2eccde.tar.bz2
txr-b7d944377a6674e7fd8c6236f2b957a31c2eccde.zip
streams: close-stream only caches non-nil result.
This is motivated by trying to implement a struct delegate stream which performs reference counting in close, in order to close the real stream when the count hits zero. The caching behavior of close-stream is a problem. * stream.c (strm_base_init): Initialize close_result to nil, rather than nao. (strm_base_mark): Don't check close_result for nao. (close_stream): Suppress the call to op->close if close_result has a non-nil value, rather than a value other than nao. * tests/018/close-delegate.tl, * tests/018/close-delegate.expected: New files. * txr.1: Document that only a non-nil return is cached by close-stream.
-rw-r--r--stream.c6
-rw-r--r--tests/018/close-delegate.expected3
-rw-r--r--tests/018/close-delegate.tl20
-rw-r--r--txr.12
4 files changed, 28 insertions, 3 deletions
diff --git a/stream.c b/stream.c
index c088fe58..f25de90c 100644
--- a/stream.c
+++ b/stream.c
@@ -119,7 +119,7 @@ static val shell, shell_arg;
void strm_base_init(struct strm_base *s)
{
- static struct strm_base init = { indent_off, 60, 10, 0, 0, 0, 0, 0, nao, 0 };
+ static struct strm_base init = { indent_off, 60, 10, 0, 0, 0, 0, 0, nil, 0 };
*s = init;
}
@@ -130,7 +130,7 @@ void strm_base_cleanup(struct strm_base *s)
void strm_base_mark(struct strm_base *s)
{
- if (s->close_result != nao)
+ if (s->close_result)
gc_mark(s->close_result);
}
@@ -2989,7 +2989,7 @@ val close_stream(val stream, val throw_on_error)
cobj_handle(self, stream, stream_cls));
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- if (s->close_result == nao)
+ if (!s->close_result)
s->close_result = ops->close(stream, throw_on_error);
return s->close_result;
diff --git a/tests/018/close-delegate.expected b/tests/018/close-delegate.expected
new file mode 100644
index 00000000..227f9f67
--- /dev/null
+++ b/tests/018/close-delegate.expected
@@ -0,0 +1,3 @@
+close called, count 2
+close called, count 1
+20
diff --git a/tests/018/close-delegate.tl b/tests/018/close-delegate.tl
new file mode 100644
index 00000000..4cf1d650
--- /dev/null
+++ b/tests/018/close-delegate.tl
@@ -0,0 +1,20 @@
+(load "../common")
+
+(defstruct refcount-close stream-wrap
+ stream
+ (count 1)
+
+ (:method close (me throw-on-error-p)
+ (put-line `close called, count @{me.count}`)
+ (when (plusp me.count)
+ (if (zerop (dec me.count))
+ (close-stream me.stream throw-on-error-p)))))
+
+(flow
+ (with-stream (s (make-struct-delegate-stream
+ (new refcount-close
+ count 2
+ stream (open-file *load-path*))))
+ (get-lines s))
+ len
+ prinl)
diff --git a/txr.1 b/txr.1
index dfe64a08..fb409b16 100644
--- a/txr.1
+++ b/txr.1
@@ -62097,6 +62097,8 @@ instead of returning
If
.code close-stream
is called in such a way that it returns a value, without throwing an exception,
+and that value isn't
+.codn nil ,
that value is retained. Additional calls to the function with the same
.meta stream
object return that same value without having any effect on the stream.