[m-rev.] for review: binary I/O of int8s and uint8s

Julien Fischer jfischer at opturion.com
Thu Sep 21 17:21:55 AEST 2017


For review by anyone.

I will update the NEWS file when I update it for the fixed size types
in general.

-----------------------------------

Add predicates for binary I/O of int8s and uint8s.

Add predicates for reading and writing int8s and uint8s with binary file
streams.

Document the predicates that are used to write fixed size integer types
to text file streams properly.

library/io.m:
      As above.

tests/hard_coded/Mmakefile:
tests/hard_coded/write_binary_uint8.{m,exp}:
tests/hard_coded/write_binary_int8.{m,exp}:
      Test the new predicates.

Julien.

diff --git a/library/io.m b/library/io.m
index b504249..d5cd00e 100644
--- a/library/io.m
+++ b/library/io.m
@@ -498,12 +498,21 @@
  :- pred write_int(int::in, io::di, io::uo) is det.
  :- pred write_int(io.text_output_stream::in, int::in, io::di, io::uo) is det.

+    % Write a signed 8-bit integer to the current output stream
+    % or to the specified output stream.
+    %
  :- pred write_int8(int8::in, io::di, io::uo) is det.
  :- pred write_int8(io.text_output_stream::in, int8::in, io::di, io::uo) is det.

+    % Write a signed 16-bit integer to the current output stream
+    % or to the specified output stream.
+    %
  :- pred write_int16(int16::in, io::di, io::uo) is det.
  :- pred write_int16(io.text_output_stream::in, int16::in, io::di, io::uo) is det.

+    % Write a signed 32-bit integer to the current output stream
+    % or to the specified output stream.
+    %
  :- pred write_int32(int32::in, io::di, io::uo) is det.
  :- pred write_int32(io.text_output_stream::in, int32::in, io::di, io::uo) is det.

@@ -513,12 +522,21 @@
  :- pred write_uint(uint::in, io::di, io::uo) is det.
  :- pred write_uint(io.text_output_stream::in, uint::in, io::di, io::uo) is det.

+    % Write an unsigned 8-bit integer to the current output stream
+    % or to the specified output stream.
+    %
  :- pred write_uint8(uint8::in, io::di, io::uo) is det.
  :- pred write_uint8(io.text_output_stream::in, uint8::in, io::di, io::uo) is det.

+    % Write an unsigned 16-bit integer to the current output stream
+    % or to the specified output stream.
+    %
  :- pred write_uint16(uint16::in, io::di, io::uo) is det.
  :- pred write_uint16(io.text_output_stream::in, uint16::in, io::di, io::uo) is det.

+    % Write an unsigned 32-bit integer to the current output stream
+    % or to the specified output stream.
+    %
  :- pred write_uint32(uint32::in, io::di, io::uo) is det.
  :- pred write_uint32(io.text_output_stream::in, uint32::in, io::di, io::uo) is det.

@@ -814,6 +832,20 @@
  :- pred read_byte(io.binary_input_stream::in, io.result(int)::out,
      io::di, io::uo) is det.

+    % Reads a single signed 8-bit integer from the current binary input
+    % stream or from the specified binary input stream.
+    %
+:- pred read_binary_int8(io.result(int8)::out, io::di, io::uo) is det.
+:- pred read_binary_int8(io.binary_input_stream::in, io.result(int8)::out,
+    io::di, io::uo) is det.
+
+    % Reads a single unsigned 8-bit integer from the current binary input
+    % stream or from the specified binary input stream.
+    %
+:- pred read_binary_uint8(io.result(uint8)::out, io::di, io::uo) is det.
+:- pred read_binary_uint8(io.binary_input_stream::in, io.result(uint8)::out,
+    io::di, io::uo) is det.
+
      % Fill a bitmap from the current binary input stream
      % or from the specified binary input stream.
      % Return the number of bytes read. On end-of-file, the number of
@@ -980,6 +1012,20 @@
  :- pred write_byte(io.binary_output_stream::in, int::in, io::di, io::uo)
      is det.

+    % Writes a signed 8-bit integer to the current binary output stream
+    % or to the specified binary output stream.
+    %
+:- pred write_binary_int8(int8::in, io::di, io::uo) is det.
+:- pred write_binary_int8(io.binary_output_stream::in, int8::in,
+    io::di, io::uo) is det.
+
+    % Writes an unsigned 8-bit integer to the current binary output stream
+    % or to the specified binary output stream.
+    %
+:- pred write_binary_uint8(uint8::in, io::di, io::uo) is det.
+:- pred write_binary_uint8(io.binary_output_stream::in, uint8::in,
+    io::di, io::uo) is det.
+
      % Write a bitmap to the current binary output stream
      % or to the specified binary output stream. The bitmap must not contain
      % a partial final byte.
@@ -1777,6 +1823,7 @@
  :- import_module dir.
  :- import_module exception.
  :- import_module int.
+:- import_module int8.
  :- import_module parser.
  :- import_module require.
  :- import_module stream.string_writer.
@@ -1784,6 +1831,7 @@
  :- import_module term_conversion.
  :- import_module term_io.
  :- import_module type_desc.
+:- import_module uint8.

  :- use_module rtti_implementation.
  :- use_module table_builtin.
@@ -2135,6 +2183,44 @@ read_byte(binary_input_stream(Stream), Result, !IO) :-
          Result = error(io_error(Msg))
      ).

+read_binary_int8(Result, !IO) :-
+    binary_input_stream(Stream, !IO),
+    read_binary_int8(Stream, Result, !IO).
+
+read_binary_int8(binary_input_stream(Stream), Result, !IO) :-
+    read_byte_val(input_stream(Stream), Result0, Int, Error, !IO),
+    (
+        Result0 = ok,
+        Int8 = cast_from_int(Int),
+        Result = ok(Int8)
+    ;
+        Result0 = eof,
+        Result = eof
+    ;
+        Result0 = error,
+        make_err_msg(Error, "read failed: ", Msg),
+        Result = error(io_error(Msg))
+    ).
+
+read_binary_uint8(Result, !IO) :-
+    binary_input_stream(Stream, !IO),
+    read_binary_uint8(Stream, Result, !IO).
+
+read_binary_uint8(binary_input_stream(Stream), Result, !IO) :-
+    read_byte_val(input_stream(Stream), Result0, Int, Error, !IO),
+    (
+        Result0 = ok,
+        UInt8 = cast_from_int(Int),
+        Result = ok(UInt8)
+    ;
+        Result0 = eof,
+        Result = eof
+    ;
+        Result0 = error,
+        make_err_msg(Error, "read failed: ", Msg),
+        Result = error(io_error(Msg))
+    ).
+
  read_bitmap(!Bitmap, BytesRead, Result, !IO) :-
      binary_input_stream(Stream, !IO),
      read_bitmap(Stream, !Bitmap, BytesRead, Result, !IO).
@@ -7819,10 +7905,23 @@ write_float(Val, !IO) :-
      output_stream(Stream, !IO),
      write_float(Stream, Val, !IO).

+%---------------------------------------------------------------------------%
+%
+% Output predicates (with output to mercury_current_binary_output).
+%
+
  write_byte(Byte, !IO) :-
      binary_output_stream(Stream, !IO),
      write_byte(Stream, Byte, !IO).

+write_binary_int8(Int8, !IO) :-
+    binary_output_stream(Stream, !IO),
+    write_binary_int8(Stream, Int8, !IO).
+
+write_binary_uint8(UInt8, !IO) :-
+    binary_output_stream(Stream, !IO),
+    write_binary_uint8(Stream, UInt8, !IO).
+
  write_bitmap(Bitmap, !IO) :-
      binary_output_stream(Stream, !IO),
      write_bitmap(Stream, Bitmap, !IO).
@@ -8141,6 +8240,16 @@ write_byte(binary_output_stream(Stream), Byte, !IO) :-
      do_write_byte(Stream, Byte, Error, !IO),
      throw_on_output_error(Error, !IO).

+write_binary_int8(binary_output_stream(Stream), Int8, !IO) :-
+    Int = int8.to_int(Int8),
+    do_write_byte(Stream, Int, Error, !IO),
+    throw_on_output_error(Error, !IO).
+
+write_binary_uint8(binary_output_stream(Stream), UInt8, !IO) :-
+    Int = uint8.to_int(UInt8),
+    do_write_byte(Stream, Int, Error, !IO),
+    throw_on_output_error(Error, !IO).
+
  :- pred do_write_byte(stream::in, int::in, system_error::out, io::di, io::uo)
      is det.
  :- pragma foreign_proc("C",
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 7a70eaf..d199eea 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -392,6 +392,8 @@ ORDINARY_PROGS =	\
  	words_separator \
  	write \
  	write_array \
+	write_binary_int8 \
+	write_binary_uint8 \
  	write_float_special \
  	write_reg1 \
  	write_reg2 \
diff --git a/tests/hard_coded/write_binary_int8.exp b/tests/hard_coded/write_binary_int8.exp
index e69de29..53cdf1e 100644
--- a/tests/hard_coded/write_binary_int8.exp
+++ b/tests/hard_coded/write_binary_int8.exp
@@ -0,0 +1 @@
+PASSED
diff --git a/tests/hard_coded/write_binary_int8.m b/tests/hard_coded/write_binary_int8.m
index e69de29..de96d37 100644
--- a/tests/hard_coded/write_binary_int8.m
+++ b/tests/hard_coded/write_binary_int8.m
@@ -0,0 +1,99 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test writing and reading int8s with binary streams.
+%
+%---------------------------------------------------------------------------%
+
+:- module write_binary_int8.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module int.
+:- import_module list.
+:- import_module int8.
+
+main(!IO) :-
+    io.make_temp_file(MakeTempResult, !IO),
+    (
+        MakeTempResult = ok(TempFileName),
+        main_2(TempFileName, !IO)
+    ;
+        MakeTempResult = error(Msg),
+        io.print_line(Msg, !IO),
+        io.set_exit_status(1, !IO)
+    ).
+
+:- pred main_2(string::in, io::di, io::uo) is det.
+
+main_2(FileName, !IO) :-
+    io.open_binary_output(FileName, OpenOutputResult, !IO),
+    (
+        OpenOutputResult = ok(OutputFile),
+        list.foldl(write_binary_int8(OutputFile), data, !IO),
+        io.close_binary_output(OutputFile, !IO),
+
+        io.open_binary_input(FileName, OpenInputResult, !IO),
+        (
+            OpenInputResult = ok(InputFile),
+            read_int8s(InputFile, [], ReadResult, !IO),
+            (
+                ReadResult = ok(RevUInt8s),
+                io.close_binary_input(InputFile, !IO),
+                list.reverse(RevUInt8s, UInt8s),
+                ( if UInt8s = data then
+                    io.print_line("PASSED", !IO)
+                else
+                    io.print_line("FAILED", !IO)
+                )
+            ;
+                ReadResult = error(IO_Error),
+                io.error_message(IO_Error, Msg),
+                io.print_line(Msg, !IO)
+            )
+        ;
+            OpenInputResult = error(IO_Error),
+            io.error_message(IO_Error, Msg),
+            io.print_line(Msg, !IO)
+        )
+    ;
+        OpenOutputResult = error(IO_Error),
+        io.error_message(IO_Error, Msg),
+        io.print_line(Msg, !IO)
+    ),
+    io.remove_file(FileName, _, !IO).
+
+:- pred read_int8s(io.binary_input_stream::in,
+    list(int8)::in, io.res(list(int8))::out, io::di, io::uo) is det.
+
+read_int8s(InputFile, !.Us, Result, !IO) :-
+    io.read_binary_int8(InputFile, ReadResult, !IO),
+    (
+        ReadResult = ok(U),
+        !:Us = [U | !.Us],
+        read_int8s(InputFile, !.Us, Result, !IO)
+    ;
+        ReadResult = eof,
+        Result = ok(!.Us)
+    ;
+        ReadResult = error(IO_Error),
+        Result = error(IO_Error)
+    ).
+
+:- func data = list(int8).
+
+data = Uint8s :-
+    int.fold_down(add_int8, -128, 127, [], Uint8s).
+
+:- pred add_int8(int::in,
+    list(int8)::in, list(int8)::out) is det.
+
+add_int8(I, !Us) :-
+    U = int8.cast_from_int(I),
+    !:Us = [U | !.Us].
diff --git a/tests/hard_coded/write_binary_uint8.exp b/tests/hard_coded/write_binary_uint8.exp
index e69de29..53cdf1e 100644
--- a/tests/hard_coded/write_binary_uint8.exp
+++ b/tests/hard_coded/write_binary_uint8.exp
@@ -0,0 +1 @@
+PASSED
diff --git a/tests/hard_coded/write_binary_uint8.m b/tests/hard_coded/write_binary_uint8.m
index e69de29..a3b0847 100644
--- a/tests/hard_coded/write_binary_uint8.m
+++ b/tests/hard_coded/write_binary_uint8.m
@@ -0,0 +1,99 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test writing and reading uint8s with binary streams.
+%
+%---------------------------------------------------------------------------%
+
+:- module write_binary_uint8.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module int.
+:- import_module list.
+:- import_module uint8.
+
+main(!IO) :-
+    io.make_temp_file(MakeTempResult, !IO),
+    (
+        MakeTempResult = ok(TempFileName),
+        main_2(TempFileName, !IO)
+    ;
+        MakeTempResult = error(Msg),
+        io.print_line(Msg, !IO),
+        io.set_exit_status(1, !IO)
+    ).
+
+:- pred main_2(string::in, io::di, io::uo) is det.
+
+main_2(FileName, !IO) :-
+    io.open_binary_output(FileName, OpenOutputResult, !IO),
+    (
+        OpenOutputResult = ok(OutputFile),
+        list.foldl(write_binary_uint8(OutputFile), data, !IO),
+        io.close_binary_output(OutputFile, !IO),
+
+        io.open_binary_input(FileName, OpenInputResult, !IO),
+        (
+            OpenInputResult = ok(InputFile),
+            read_uint8s(InputFile, [], ReadResult, !IO),
+            (
+                ReadResult = ok(RevUInt8s),
+                io.close_binary_input(InputFile, !IO),
+                list.reverse(RevUInt8s, UInt8s),
+                ( if UInt8s = data then
+                    io.print_line("PASSED", !IO)
+                else
+                    io.print_line("FAILED", !IO)
+                )
+            ;
+                ReadResult = error(IO_Error),
+                io.error_message(IO_Error, Msg),
+                io.print_line(Msg, !IO)
+            )
+        ;
+            OpenInputResult = error(IO_Error),
+            io.error_message(IO_Error, Msg),
+            io.print_line(Msg, !IO)
+        )
+    ;
+        OpenOutputResult = error(IO_Error),
+        io.error_message(IO_Error, Msg),
+        io.print_line(Msg, !IO)
+    ),
+    io.remove_file(FileName, _, !IO).
+
+:- pred read_uint8s(io.binary_input_stream::in,
+    list(uint8)::in, io.res(list(uint8))::out, io::di, io::uo) is det.
+
+read_uint8s(InputFile, !.Us, Result, !IO) :-
+    io.read_binary_uint8(InputFile, ReadResult, !IO),
+    (
+        ReadResult = ok(U),
+        !:Us = [U | !.Us],
+        read_uint8s(InputFile, !.Us, Result, !IO)
+    ;
+        ReadResult = eof,
+        Result = ok(!.Us)
+    ;
+        ReadResult = error(IO_Error),
+        Result = error(IO_Error)
+    ).
+
+:- func data = list(uint8).
+
+data = Uint8s :-
+    int.fold_down(add_uint8, 0, 255, [], Uint8s).
+
+:- pred add_uint8(int::in,
+    list(uint8)::in, list(uint8)::out) is det.
+
+add_uint8(I, !Us) :-
+    U = uint8.cast_from_int(I),
+    !:Us = [U | !.Us].


More information about the reviews mailing list