[m-rev.] for review: writing 16- and 32-bit integers to binary file streams

Julien Fischer jfischer at opturion.com
Mon Sep 25 15:04:15 AEST 2017


For review by anyone.

Also, does anyone have any better suggestion as to the name of the new 
runtime header file?

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


Writing 16- and 32-bit integers to binary file streams.

Add predicates for writing 16- and 32-bit integers to binary file streams in
native, little and big endian byte order to the standard library.

library/io.m:
     Add the new predicates.

library/uint16.m:
library/uint32.m:
     Add a functions for casting from the signed to unsigned versions
     of these types.

runtime/mercury_int.h:
     New header intended to hold things related to the implementation
     of the integer types in C grades.  Currently it contains the
     macros defining the byte reverse operations for 16- and 32-bit
     types.   (It will eventually containing macros for boxing 64-bit
     integer types on 32-bit platforms as well.)

runtime/mercury_imp.h:
runtime/Mmakefile:
      Add the new header.

tests/hard_coded/Mmakefile:
tests/write_binary_multibyte_int.{m,exp}:
      Add a test for the new predicates.

Julien.

diff --git a/library/io.m b/library/io.m
index a3320d4..aecd8d2 100644
--- a/library/io.m
+++ b/library/io.m
@@ -1026,6 +1026,94 @@
  :- pred write_binary_uint8(io.binary_output_stream::in, uint8::in,
      io::di, io::uo) is det.

+    % Writes a signed 16-bit integer to the current binary output stream or
+    % to the specified binary output stream in the native byte order of the
+    % underlying platform.
+    %
+:- pred write_binary_int16(int16::in, io::di, io::uo) is det.
+:- pred write_binary_int16(io.binary_output_stream::in, int16::in,
+    io::di, io::uo) is det.
+
+    % Writes a signed 16-bit integer to the current binary output stream or
+    % to the specified binary output stream in little endian byte order.
+    %
+:- pred write_binary_int16_le(int16::in, io::di, io::uo) is det.
+:- pred write_binary_int16_le(io.binary_output_stream::in, int16::in,
+    io::di, io::uo) is det.
+
+    % Writes a signed 16-bit integer to the current binary output stream or
+    % to the specified binary output stream in big endian byte order.
+    %
+:- pred write_binary_int16_be(int16::in, io::di, io::uo) is det.
+:- pred write_binary_int16_be(io.binary_output_stream::in, int16::in,
+    io::di, io::uo) is det.
+
+    % Writes an unsigned 16-bit integer to the current binary output stream or
+    % to the specified binary output stream in native byte order of the
+    % underlying platform.
+    %
+:- pred write_binary_uint16(uint16::in, io::di, io::uo) is det.
+:- pred write_binary_uint16(io.binary_output_stream::in, uint16::in,
+    io::di, io::uo) is det.
+
+    % Writes an unsigned 16-bit integer to the current binary output stream or
+    % to the specified binary output stream in little endian byte order.
+    %
+:- pred write_binary_uint16_le(uint16::in, io::di, io::uo) is det.
+:- pred write_binary_uint16_le(io.binary_output_stream::in, uint16::in,
+    io::di, io::uo) is det.
+
+    % Writes an unsigned 16-bit integer to the current binary output stream or
+    % to the specified binary output stream in big endian byte order.
+    %
+:- pred write_binary_uint16_be(uint16::in, io::di, io::uo) is det.
+:- pred write_binary_uint16_be(io.binary_output_stream::in, uint16::in,
+    io::di, io::uo) is det.
+
+    % Writes a signed 32-bit integer to the current binary output stream or
+    % to the specified binary output stream in native byte order of the
+    % underlying platform.
+    %
+:- pred write_binary_int32(int32::in, io::di, io::uo) is det.
+:- pred write_binary_int32(io.binary_output_stream::in, int32::in,
+    io::di, io::uo) is det.
+
+    % Writes a signed 32-bit integer to the current binary output stream or
+    % to the specified binary output stream in little endian byte order.
+    %
+:- pred write_binary_int32_le(int32::in, io::di, io::uo) is det.
+:- pred write_binary_int32_le(io.binary_output_stream::in, int32::in,
+    io::di, io::uo) is det.
+
+    % Writes a signed 32-bit integer to the current binary output stream or
+    % to the specified binary output stream in big endian byte order.
+    %
+:- pred write_binary_int32_be(int32::in, io::di, io::uo) is det.
+:- pred write_binary_int32_be(io.binary_output_stream::in, int32::in,
+    io::di, io::uo) is det.
+
+    % Writes an unsigned 32-bit integer to the current binary output stream or
+    % to the specified binary output stream in native byte order of the
+    % underlying platform.
+    %
+:- pred write_binary_uint32(uint32::in, io::di, io::uo) is det.
+:- pred write_binary_uint32(io.binary_output_stream::in, uint32::in,
+    io::di, io::uo) is det.
+
+    % Writes an unsigned 32-bit integer to the current binary output stream or
+    % to the specified binary output stream in little endian byte order.
+    %
+:- pred write_binary_uint32_le(uint32::in, io::di, io::uo) is det.
+:- pred write_binary_uint32_le(io.binary_output_stream::in, uint32::in,
+    io::di, io::uo) is det.
+
+    % Writes an unsigned 32-bit integer to the current binary output stream or
+    % to the specified binary output stream in big endian byte order.
+    %
+:- pred write_binary_uint32_be(uint32::in, io::di, io::uo) is det.
+:- pred write_binary_uint32_be(io.binary_output_stream::in, uint32::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.
@@ -1834,6 +1922,8 @@
  :- import_module term_io.
  :- import_module type_desc.
  :- import_module uint8.
+:- import_module uint16.
+:- import_module uint32.

  :- use_module rtti_implementation.
  :- use_module table_builtin.
@@ -7924,6 +8014,54 @@ write_binary_uint8(UInt8, !IO) :-
      binary_output_stream(Stream, !IO),
      write_binary_uint8(Stream, UInt8, !IO).

+write_binary_int16(Int16, !IO) :-
+    UInt16 = uint16.cast_from_int16(Int16),
+    write_binary_uint16(UInt16, !IO).
+
+write_binary_int16_le(Int16, !IO) :-
+    UInt16 = uint16.cast_from_int16(Int16),
+    write_binary_uint16_le(UInt16, !IO).
+
+write_binary_int16_be(Int16, !IO) :-
+    UInt16 = uint16.cast_from_int16(Int16),
+    write_binary_uint16_be(UInt16, !IO).
+
+write_binary_uint16(UInt16, !IO) :-
+    binary_output_stream(Stream, !IO),
+    write_binary_uint16(Stream, UInt16, !IO).
+
+write_binary_uint16_le(UInt16, !IO) :-
+    binary_output_stream(Stream, !IO),
+    write_binary_uint16_le(Stream, UInt16, !IO).
+
+write_binary_uint16_be(UInt16, !IO) :-
+    binary_output_stream(Stream, !IO),
+    write_binary_uint16_be(Stream, UInt16, !IO).
+
+write_binary_int32(Int32, !IO) :-
+    UInt32 = uint32.cast_from_int32(Int32),
+    write_binary_uint32(UInt32, !IO).
+
+write_binary_int32_le(Int32, !IO) :-
+    UInt32 = uint32.cast_from_int32(Int32),
+    write_binary_uint32_le(UInt32, !IO).
+
+write_binary_int32_be(Int32, !IO) :-
+    UInt32 = uint32.cast_from_int32(Int32),
+    write_binary_uint32_be(UInt32, !IO).
+
+write_binary_uint32(UInt32, !IO) :-
+    binary_output_stream(Stream, !IO),
+    write_binary_uint32(Stream, UInt32, !IO).
+
+write_binary_uint32_le(UInt32, !IO) :-
+    binary_output_stream(Stream, !IO),
+    write_binary_uint32_le(Stream, UInt32, !IO).
+
+write_binary_uint32_be(UInt32, !IO) :-
+    binary_output_stream(Stream, !IO),
+    write_binary_uint32_be(Stream, UInt32, !IO).
+
  write_bitmap(Bitmap, !IO) :-
      binary_output_stream(Stream, !IO),
      write_bitmap(Stream, Bitmap, !IO).
@@ -8186,8 +8324,8 @@ write_uint16(output_stream(Stream), Val, !IO) :-
      do_write_uint16(Stream, Val, Error, !IO),
      throw_on_output_error(Error, !IO).

-:- pred do_write_uint16(stream::in, uint16::in, system_error::out, io::di, io::uo)
-    is det.
+:- pred do_write_uint16(stream::in, uint16::in, system_error::out,
+    io::di, io::uo) is det.
  :- pragma foreign_proc("C",
      do_write_uint16(Stream::in, Val::in, Error::out, _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
@@ -8204,8 +8342,8 @@ write_uint32(output_stream(Stream), Val, !IO) :-
      do_write_uint32(Stream, Val, Error, !IO),
      throw_on_output_error(Error, !IO).

-:- pred do_write_uint32(stream::in, uint32::in, system_error::out, io::di, io::uo)
-    is det.
+:- pred do_write_uint32(stream::in, uint32::in, system_error::out,
+    io::di, io::uo) is det.
  :- pragma foreign_proc("C",
      do_write_uint32(Stream::in, Val::in, Error::out, _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
@@ -8267,6 +8405,348 @@ write_binary_uint8(binary_output_stream(Stream), UInt8, !IO) :-
      }
  ").

+write_binary_int16(Stream, Int16, !IO) :-
+    UInt16 = uint16.cast_from_int16(Int16),
+    write_binary_uint16(Stream, UInt16, !IO).
+
+write_binary_uint16(binary_output_stream(Stream), UInt16, !IO) :-
+    do_write_binary_uint16(Stream, UInt16, Error, !IO),
+    throw_on_output_error(Error, !IO).
+
+:- pred do_write_binary_uint16(stream::in, uint16::in, system_error::out,
+    io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_write_binary_uint16(Stream::in, U16::in, Error::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    if (MR_WRITE(*Stream, (unsigned char *)(&U16), 2) != 2) {
+        Error = errno;
+    } else {
+        Error = 0;
+    }
+").
+
+:- pragma foreign_proc("Java",
+    do_write_binary_uint16(Stream::in, U16::in, Error::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    try {
+        java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(2);
+        buffer.order(java.nio.ByteOrder.nativeOrder());
+        buffer.putShort(U16);
+        ((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 2);
+        Error = null;
+    } catch (java.io.IOException e) {
+        Error = e;
+    }
+").
+
+:- pragma foreign_proc("C#",
+    do_write_binary_uint16(Stream::in, U16::in, Error::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    byte[] bytes = BitConverter.GetBytes(U16);
+    try {
+        Stream.stream.Write(bytes, 0, 2);
+        Error = null;
+    } catch (System.Exception e) {
+        Error = e;
+    }
+").
+
+write_binary_int16_le(Stream, Int16, !IO) :-
+    UInt16 = uint16.cast_from_int16(Int16),
+    write_binary_uint16_le(Stream, UInt16, !IO).
+
+write_binary_uint16_le(binary_output_stream(Stream), UInt16, !IO) :-
+    do_write_binary_uint16_le(Stream, UInt16, Error, !IO),
+    throw_on_output_error(Error, !IO).
+
+:- pred do_write_binary_uint16_le(stream::in, uint16::in, system_error::out,
+    io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_write_binary_uint16_le(Stream::in, U16::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    #if defined(MR_BIG_ENDIAN)
+        U16 = MR_uint16_reverse_bytes(U16);
+    #endif
+
+    if (MR_WRITE(*Stream, (unsigned char *)(&U16), 2) != 2) {
+        Error = errno;
+    } else {
+        Error = 0;
+    }
+").
+
+:- pragma foreign_proc("Java",
+    do_write_binary_uint16_le(Stream::in, U16::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    try {
+        java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(2);
+        buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
+        buffer.putShort(U16);
+        ((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 2);
+        Error = null;
+    } catch (java.io.IOException e) {
+        Error = e;
+    }
+").
+
+:- pragma foreign_proc("C#",
+    do_write_binary_uint16_le(Stream::in, U16::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    byte[] bytes = BitConverter.GetBytes(U16);
+    if (!BitConverter.IsLittleEndian) {
+        Array.Reverse(bytes);
+    }
+    try {
+        Stream.stream.Write(bytes, 0, 2);
+        Error = null;
+    } catch (System.Exception e) {
+        Error = e;
+    }
+").
+
+write_binary_int16_be(Stream, Int16, !IO) :-
+    UInt16 = uint16.cast_from_int16(Int16),
+    write_binary_uint16_be(Stream, UInt16, !IO).
+
+write_binary_uint16_be(binary_output_stream(Stream), UInt16, !IO) :-
+    do_write_binary_uint16_be(Stream, UInt16, Error, !IO),
+    throw_on_output_error(Error, !IO).
+
+:- pred do_write_binary_uint16_be(stream::in, uint16::in, system_error::out,
+    io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_write_binary_uint16_be(Stream::in, U16::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    #if defined(MR_LITTLE_ENDIAN)
+        U16 = MR_uint16_reverse_bytes(U16);
+    #endif
+
+    if (MR_WRITE(*Stream, (unsigned char *)(&U16), 2) != 2) {
+        Error = errno;
+    } else {
+        Error = 0;
+    }
+").
+
+:- pragma foreign_proc("Java",
+    do_write_binary_uint16_be(Stream::in, U16::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    try {
+        java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(2);
+        // Order in a byte buffer is big endian by default.
+        buffer.putShort(U16);
+        ((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 2);
+        Error = null;
+    } catch (java.io.IOException e) {
+        Error = e;
+    }
+").
+
+:- pragma foreign_proc("C#",
+    do_write_binary_uint16_be(Stream::in, U16::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    byte[] bytes = BitConverter.GetBytes(U16);
+    if (BitConverter.IsLittleEndian) {
+        Array.Reverse(bytes);
+    }
+    try {
+        Stream.stream.Write(bytes, 0, 2);
+        Error = null;
+    } catch (System.Exception e) {
+        Error = e;
+    }
+").
+
+write_binary_int32(Stream, Int32, !IO) :-
+    UInt32 = uint32.cast_from_int32(Int32),
+    write_binary_uint32(Stream, UInt32, !IO).
+
+write_binary_uint32(binary_output_stream(Stream), UInt32, !IO) :-
+    do_write_binary_uint32(Stream, UInt32, Error, !IO),
+    throw_on_output_error(Error, !IO).
+
+:- pred do_write_binary_uint32(stream::in, uint32::in, system_error::out,
+    io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_write_binary_uint32(Stream::in, U32::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    if (MR_WRITE(*Stream, (unsigned char *)(&U32), 4) != 4) {
+        Error = errno;
+    } else {
+        Error = 0;
+    }
+").
+
+:- pragma foreign_proc("Java",
+    do_write_binary_uint32(Stream::in, U32::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    try {
+        java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(4);
+        buffer.order(java.nio.ByteOrder.nativeOrder());
+        buffer.putInt(U32);
+        ((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 4);
+        Error = null;
+    } catch (java.io.IOException e) {
+        Error = e;
+    }
+").
+
+:- pragma foreign_proc("C#",
+    do_write_binary_uint32(Stream::in, U32::in, Error::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    byte[] bytes = BitConverter.GetBytes(U32);
+    try {
+        Stream.stream.Write(bytes, 0, 4);
+        Error = null;
+    } catch (System.Exception e) {
+        Error = e;
+    }
+").
+
+write_binary_int32_le(Stream, Int32, !IO) :-
+    UInt32 = uint32.cast_from_int32(Int32),
+    write_binary_uint32_le(Stream, UInt32, !IO).
+
+write_binary_uint32_le(binary_output_stream(Stream), UInt32, !IO) :-
+    do_write_binary_uint32_le(Stream, UInt32, Error, !IO),
+    throw_on_output_error(Error, !IO).
+
+:- pred do_write_binary_uint32_le(stream::in, uint32::in, system_error::out,
+    io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_write_binary_uint32_le(Stream::in, U32::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    #if defined(MR_BIG_ENDIAN)
+        U32 = MR_uint32_reverse_bytes(U32);
+    #endif
+
+    if (MR_WRITE(*Stream, (unsigned char *)(&U32), 4) != 4) {
+        Error = errno;
+    } else {
+        Error = 0;
+    }
+").
+
+:- pragma foreign_proc("Java",
+    do_write_binary_uint32_le(Stream::in, U32::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    try {
+        java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(4);
+        buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
+        buffer.putInt(U32);
+        ((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 4);
+        Error = null;
+    } catch (java.io.IOException e) {
+        Error = e;
+    }
+").
+
+:- pragma foreign_proc("C#",
+    do_write_binary_uint32_le(Stream::in, U32::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    byte[] bytes = BitConverter.GetBytes(U32);
+    if (!BitConverter.IsLittleEndian) {
+        Array.Reverse(bytes);
+    }
+    try {
+        Stream.stream.Write(bytes, 0, 4);
+        Error = null;
+    } catch (System.Exception e) {
+        Error = e;
+    }
+").
+
+write_binary_int32_be(Stream, Int32, !IO) :-
+    UInt32 = uint32.cast_from_int32(Int32),
+    write_binary_uint32_be(Stream, UInt32, !IO).
+
+write_binary_uint32_be(binary_output_stream(Stream), UInt32, !IO) :-
+    do_write_binary_uint32_be(Stream, UInt32, Error, !IO),
+    throw_on_output_error(Error, !IO).
+
+:- pred do_write_binary_uint32_be(stream::in, uint32::in, system_error::out,
+    io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_write_binary_uint32_be(Stream::in, U32::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    #if defined(MR_LITTLE_ENDIAN)
+        U32 = MR_uint32_reverse_bytes(U32);
+    #endif
+
+    if (MR_WRITE(*Stream, (unsigned char *)(&U32), 4) != 4) {
+        Error = errno;
+    } else {
+        Error = 0;
+    }
+").
+
+:- pragma foreign_proc("Java",
+    do_write_binary_uint32_be(Stream::in, U32::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    try {
+        java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(4);
+        // Order in a byte buffer is big endian by default.
+        buffer.putInt(U32);
+        ((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 4);
+        Error = null;
+    } catch (java.io.IOException e) {
+        Error = e;
+    }
+").
+
+:- pragma foreign_proc("C#",
+    do_write_binary_uint32_be(Stream::in, U32::in, Error::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    byte[] bytes = BitConverter.GetBytes(U32);
+    if (BitConverter.IsLittleEndian) {
+        Array.Reverse(bytes);
+    }
+    try {
+        Stream.stream.Write(bytes, 0, 4);
+        Error = null;
+    } catch (System.Exception e) {
+        Error = e;
+    }
+").
+
  write_bitmap(binary_output_stream(Stream), Bitmap, !IO) :-
      ( if NumBytes = Bitmap ^ num_bytes then
          do_write_bitmap(Stream, Bitmap, 0, NumBytes, Error, !IO),
diff --git a/library/uint16.m b/library/uint16.m
index 4c04057..dbde174 100644
--- a/library/uint16.m
+++ b/library/uint16.m
@@ -33,6 +33,8 @@

  :- func cast_from_int(int) = uint16.

+:- func cast_from_int16(int16) = uint16.
+
  :- func to_int(uint16) = int.

  %--------------------------------------------------------------------------%
@@ -240,6 +242,35 @@ cast_from_int(_) = _ :-
  %---------------------------------------------------------------------------%

  :- pragma foreign_proc("C",
+    cast_from_int16(I16::in) = (U16::out),
+    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+        does_not_affect_liveness],
+"
+    U16 = (uint16_t) I16;
+").
+
+:- pragma foreign_proc("C#",
+    cast_from_int16(I6::in) = (U16::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    U16 = (ushort) I16;
+").
+
+:- pragma foreign_proc("Java",
+    cast_from_int(I16::in) = (U16::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    U16 = I16;
+").
+
+:- pragma no_determinism_warning(cast_from_int16/1).
+cast_from_int16(_) = _ :-
+    sorry($module, "uint16.cast_from_int16/1 NYI for Erlang").
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
      to_int(U16::in) = (I::out),
      [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
          does_not_affect_liveness],
diff --git a/library/uint32.m b/library/uint32.m
index f285750..fc447b0 100644
--- a/library/uint32.m
+++ b/library/uint32.m
@@ -31,6 +31,8 @@

  :- func cast_from_int(int) = uint32.

+:- func cast_from_int32(int32) = uint32.
+
  :- func cast_to_int(uint32) = int.

  %---------------------------------------------------------------------------%
@@ -265,6 +267,34 @@ cast_from_int(_) = _ :-
  %---------------------------------------------------------------------------%

  :- pragma foreign_proc("C",
+    cast_from_int32(I32::in) = (U32::out),
+    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+        does_not_affect_liveness],
+"
+    U32 = (uint32_t) I32;
+").
+
+:- pragma foreign_proc("C#",
+    cast_from_int32(I32::in) = (U32::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    U32 = (uint) I32;
+").
+
+:- pragma foreign_proc("Java",
+    cast_from_int32(I32::in) = (U32::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    U32 = I32;
+").
+
+:- pragma no_determinism_warning(cast_from_int32/1).
+cast_from_int32(_) = _ :-
+    sorry($module, "uint32.cast_from_int32/1 NYI for Erlang").
+
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
      cast_to_int(U32::in) = (I::out),
      [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
          does_not_affect_liveness],
diff --git a/runtime/Mmakefile b/runtime/Mmakefile
index 87a0e1b..93a4ddd 100644
--- a/runtime/Mmakefile
+++ b/runtime/Mmakefile
@@ -60,6 +60,7 @@ HDRS = \
  	mercury_hgc.h				\
  	mercury_hlc_types.h			\
  	mercury_ho_call.h			\
+	mercury_int.h				\
  	mercury_imp.h				\
  	mercury_init.h				\
  	mercury_label.h				\
diff --git a/runtime/mercury_imp.h b/runtime/mercury_imp.h
index 0f8bf3c..5bcecc8 100644
--- a/runtime/mercury_imp.h
+++ b/runtime/mercury_imp.h
@@ -44,6 +44,7 @@
  #include    "mercury_file.h"
  #include    "mercury_string.h"
  #include    "mercury_float.h"
+#include    "mercury_int.h"
  #include    "mercury_stack_trace.h"
  #include    "mercury_accurate_gc.h"
  #include    "mercury_stack_layout.h"
diff --git a/runtime/mercury_int.h b/runtime/mercury_int.h
index e69de29..dc35611 100644
--- a/runtime/mercury_int.h
+++ b/runtime/mercury_int.h
@@ -0,0 +1,31 @@
+// vim: ts=4 sw=4 expandtab ft=c
+
+// Copyright (C) 2017 The Mercury team.
+// This file may only be copied under the terms of the GNU Library General
+// Public License - see the file COPYING.LIB in the Mercury distribution.
+
+// mercury_int.h - integer type handling
+
+#ifndef MERCURY_INT_H
+#define MERCURY_INT_H
+
+#include "mercury_conf.h"       // for MR_BOXED_FLOAT, MR_CONSERVATIVE_GC
+#include "mercury_types.h"      // for `MR_Word'
+#include "mercury_std.h"        // for `MR_bool'
+
+#if defined(MR_GNUC) || defined(MR_CLANG)
+  #define MR_uint16_reverse_bytes(U) __builtin_bswap16((U))
+#else
+  #define MR_uint16_reverse_bytes(U) ((U >> 8) | (U << 8))
+#endif
+
+#if defined(MR_GNUC) || defined(MR_CLANG)
+  #define MR_uint32_reverse_bytes(U) __builtin_bswap32((U))
+#else
+  #define MR_uint32_reverse_bytes(U) ((U & UINT32_C(0x000000ff)) << 24 | \
+                                      (U & UINT32_C(0x0000ff00)) << 8  | \
+                                      (U & UINT32_C(0x00ff0000)) >> 8  | \
+                                      (U & UINT32_C(0xff000000)) >> 24 )
+#endif
+
+#endif // not MERCURY_INT_H
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index d199eea..4be45db 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -393,6 +393,7 @@ ORDINARY_PROGS =	\
  	write \
  	write_array \
  	write_binary_int8 \
+	write_binary_multibyte_int \
  	write_binary_uint8 \
  	write_float_special \
  	write_reg1 \
diff --git a/tests/hard_coded/write_binary_multibyte_int.exp b/tests/hard_coded/write_binary_multibyte_int.exp
index e69de29..29b9782 100644
--- a/tests/hard_coded/write_binary_multibyte_int.exp
+++ b/tests/hard_coded/write_binary_multibyte_int.exp
@@ -0,0 +1 @@
+0x0a 0x0b 0x0b 0x0a 0xaa 0xbb 0xbb 0xaa 0x0a 0x0b 0x0c 0x0d 0x0d 0x0c 0x0b 0x0a 0xaa 0xbb 0xcc 0xdd 0xdd 0xcc 0xbb 0xaa
diff --git a/tests/hard_coded/write_binary_multibyte_int.m b/tests/hard_coded/write_binary_multibyte_int.m
index e69de29..5eb9770 100644
--- a/tests/hard_coded/write_binary_multibyte_int.m
+++ b/tests/hard_coded/write_binary_multibyte_int.m
@@ -0,0 +1,100 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test writing of int16, uint16, in32 and uint32 to binary file streams.
+
+:- module write_binary_multibyte_int.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module list.
+:- import_module string.
+
+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),
+        io.write_binary_int16_le(OutputFile, 0x0b0a_i16, !IO),
+        io.write_binary_int16_be(OutputFile, 0x0b0a_i16, !IO),
+        io.write_binary_uint16_le(OutputFile, 0xbbaa_u16, !IO),
+        io.write_binary_uint16_be(OutputFile, 0xbbaa_u16, !IO),
+        io.write_binary_int32_le(OutputFile, 0x0d0c0b0a_i32, !IO),
+        io.write_binary_int32_be(OutputFile, 0x0d0c0b0a_i32, !IO),
+        io.write_binary_uint32_le(OutputFile, 0xddccbbaa_u32, !IO),
+        io.write_binary_uint32_be(OutputFile, 0xddccbbaa_u32, !IO),
+        io.close_binary_output(OutputFile, !IO),
+
+        io.open_binary_input(FileName, OpenInputResult, !IO),
+        (
+            OpenInputResult = ok(InputFile),
+            read_bytes(InputFile, [], ReadResult, !IO),
+            (
+                ReadResult = ok(Bytes),
+                io.close_binary_input(InputFile, !IO),
+                io.write_list(Bytes, " ", print_byte, !IO),
+                io.nl(!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 print_byte(int::in, io::di, io::uo) is det.
+
+print_byte(Byte, !IO) :-
+    io.format("0x%0.2x", [i(Byte)], !IO).
+
+:- pred read_bytes(io.binary_input_stream::in,
+    list(int)::in, io.res(list(int))::out, io::di, io::uo) is det.
+
+read_bytes(InputFile, !.Bytes, Result, !IO) :-
+    io.read_byte(InputFile, ReadResult, !IO),
+    (
+        ReadResult = ok(Byte),
+        !:Bytes = [Byte | !.Bytes],
+        read_bytes(InputFile, !.Bytes, Result, !IO)
+    ;
+        ReadResult = eof,
+        list.reverse(!Bytes),
+        Result = ok(!.Bytes)
+    ;
+        ReadResult = error(IO_Error),
+        Result = error(IO_Error)
+    ).
+
+%---------------------------------------------------------------------------%
+:- end_module write_binary_multibyte_int.
+%---------------------------------------------------------------------------%


More information about the reviews mailing list