[m-rev.] for review: add unboxed_readers to the stream module
Julien Fischer
jfischer at opturion.com
Sat Apr 18 15:34:40 AEST 2020
For review by anyone.
------------------------
Add unboxed_readers to the stream module.
library/stream.m:
Add a new type of reader, unboxed_reader. These provide a 'get'
operation that does not need to box its output in the non-error case.
library/io.m:
Add an unboxed_reader instance for text_input_streams and chars.
NEWS:
Announce the addition.
Julien.
diff --git a/NEWS b/NEWS
index 7032804..bf0d9ef 100644
--- a/NEWS
+++ b/NEWS
@@ -144,6 +144,12 @@ Changes to the Mercury standard library
- func `keys_as_set/1`
- pred `keys_as_set/2`
+### Changes to the `stream` module
+
+* We have added a new `reader/4` subclass, `unboxed_reader/4`. This subclass
+ allows readers to provide a `get` operation that avoids boxing non-error
+ outputs.
+
### Changes to the `thread.channel` module
* The following predicate has been deprecated and will be removed in a future
diff --git a/library/io.m b/library/io.m
index f525daf..91c16ff 100644
--- a/library/io.m
+++ b/library/io.m
@@ -1949,6 +1949,7 @@
:- instance stream.stream(text_input_stream, io).
:- instance stream.input(text_input_stream, io).
:- instance stream.reader(text_input_stream, char, io, io.error).
+:- instance stream.unboxed_reader(text_input_stream, char, io, io.error).
:- instance stream.reader(text_input_stream, line, io, io.error).
:- instance stream.reader(text_input_stream, text_file, io, io.error).
@@ -2294,7 +2295,16 @@
[
( get(Stream, Result, !IO) :-
read_char(Stream, Result0, !IO),
- Result = io.result_to_stream_result(Result0)
+ Result = io.result1_to_stream_result1(Result0)
+ )
+].
+
+:- instance stream.unboxed_reader(input_stream, char, io, io.error)
+ where
+[
+ ( unboxed_get(Stream, Result, Char, !IO) :-
+ read_char_unboxed(Stream, Result0, Char, !IO),
+ Result = io.result0_to_stream_result0(Result0)
)
].
@@ -2336,18 +2346,24 @@
pred(unget/4) is putback_char
].
-:- func result_to_stream_result(io.result(T)) = stream.result(T, io.error).
-
-result_to_stream_result(ok(T)) = ok(T).
-result_to_stream_result(eof) = eof.
-result_to_stream_result(error(Error)) = error(Error).
-
:- instance stream.line_oriented(input_stream, io) where
[
pred(get_line/4) is io.get_line_number,
pred(set_line/4) is io.set_line_number
].
+:- func result1_to_stream_result1(io.result(T)) = stream.result(T, io.error).
+
+result1_to_stream_result1(ok(T)) = ok(T).
+result1_to_stream_result1(eof) = eof.
+result1_to_stream_result1(error(Error)) = error(Error).
+
+:- func result0_to_stream_result0(io.result) = stream.result(io.error).
+
+result0_to_stream_result0(ok) = ok.
+result0_to_stream_result0(eof) = eof.
+result0_to_stream_result0(error(Error)) = error(Error).
+
%---------------------%
%
% Text output streams.
@@ -2458,7 +2474,7 @@ result_to_stream_result(error(Error)) = error(Error).
[
( get(Stream, Result, !IO) :-
read_byte(Stream, Result0, !IO),
- Result = result_to_stream_result(Result0)
+ Result = result1_to_stream_result1(Result0)
)
].
@@ -2467,7 +2483,7 @@ result_to_stream_result(error(Error)) = error(Error).
[
( get(Stream, Result, !IO) :-
read_binary_int8(Stream, Result0, !IO),
- Result = result_to_stream_result(Result0)
+ Result = result1_to_stream_result1(Result0)
)
].
@@ -2476,7 +2492,7 @@ result_to_stream_result(error(Error)) = error(Error).
[
( get(Stream, Result, !IO) :-
read_binary_uint8(Stream, Result0, !IO),
- Result = result_to_stream_result(Result0)
+ Result = result1_to_stream_result1(Result0)
)
].
diff --git a/library/stream.m b/library/stream.m
index 60a599a..6581a2c 100644
--- a/library/stream.m
+++ b/library/stream.m
@@ -110,10 +110,11 @@
% The get operation should block until the next unit is available,
% or the end of the stream or an error is detected.
%
- % If a call to get/4 returns `eof', all further calls to get/4 or
- % bulk_get/9 for that stream return `eof'. If a call to get/4
- % returns `error(...)', all further calls to get/4 or bulk_get/4 for
- % that stream return an error, although not necessarily the same one.
+ % If a call to get/4 returns `eof', all further calls to get/4,
+ % unboxed_get/5 or bulk_get/9 for that stream return `eof'. If a call to
+ % get/4 returns `error(...)', all further calls to get/4, unboxed_get/5 or
+ % bulk_get/4 for that stream return an error, although not necessarily the
+ % same one.
%
% XXX We should provide an interface to allow the user to reset the
% error status to try again if an error is transient.
@@ -122,6 +123,30 @@
State::di, State::uo) is det
].
+ % An unboxed_reader stream is like a reader stream except that it provides
+ % an interface that avoids a memory allocation when there is no error.
+ %
+:- typeclass unboxed_reader(Stream, Unit, State, Error)
+ <= (input(Stream, State), error(Error), (Stream, Unit -> Error)) where
+[
+ % Get the next unit from the given stream.
+ %
+ % The unboxed_get operation should block until the next unit is available,
+ % or the end of the stream or an error is detected.
+ %
+ % If a call to unboxed_get/5 returns `eof', all further calls to get/4,
+ % unboxed_get/5 or bulk_get/9 for that stream return `eof'. If a call to
+ % unboxed_get/5 returns `error(...)', all further calls to get/4,
+ % unboxed_get/5 or bulk_get/4 for that stream return an error, although not
+ % necessarily the same one.
+ %
+ % XXX We should provide an interface to allow the user to reset the
+ % error status to try again if an error is transient.
+ %
+ pred unboxed_get(Stream::in, result(Error)::out, Unit::out,
+ State::di, State::uo) is det
+].
+
% A bulk_reader stream is a subclass of specific input stream that can
% be used to read multiple items of data of a specific type from that
% input stream into a specified container. For example, binary input
@@ -152,10 +177,10 @@
% starting at Index will not fit in !Store.
%
% If a call to bulk_get/4 returns less than NumItems items, all further
- % calls to get/4 or bulk_get/4 for that stream return no items. If a call
- % to bulk_get/9 returns `error(...)', all further calls to get/4 or
- % bulk_get/9 for that stream return an error, although not necessarily
- % the same one.
+ % calls to get/4, unboxed_get/5 or bulk_get/4 for that stream return no
+ % items. If a call to bulk_get/9 returns `error(...)', all further calls to
+ % get/4, unboxed_get/5 or bulk_get/9 for that stream return an error,
+ % although not necessarily the same one.
%
pred bulk_get(Stream::in, Index::in, int::in,
Store::bulk_get_di, Store::bulk_get_uo,
More information about the reviews
mailing list