[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