More library predicates for 64-bit integers.

library/io.m:
     Add predicates for writing 64-bit integers to binary streams.

library/int64.m:
     Add reverse_bytes/1.

library/uint64.m:
     Add reverse_bytes/1 and cast_from_int64/1.

runtime/mercury_int.h:
     Add MR_uint64_reverse_bytes.

tests/hard_coded/write_binary_multibyte_int.{m,exp}:
     Extend this test to cover 64-bit integers.
This commit is contained in:
Julien Fischer
2018-02-08 08:51:39 -05:00
parent 83d9f11eea
commit ca7ae00c36
6 changed files with 416 additions and 3 deletions

View File

@@ -221,6 +221,12 @@
%
:- func \ (int64::in) = (int64::uo) is det.
% reverse_bytes(A) = B:
% B is the value that results from reversing the bytes in the
% representation of A.
%
:- func reverse_bytes(int64) = int64.
:- func min_int64 = int64.
:- func max_int64 = int64.
@@ -486,6 +492,42 @@ odd(X) :-
%---------------------------------------------------------------------------%
:- pragma foreign_proc("C",
reverse_bytes(A::in) = (B::out),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail],
"
B = (int64_t) MR_uint64_reverse_bytes((uint64_t)A);
").
:- pragma foreign_proc("C#",
reverse_bytes(A::in) = (B::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
ulong u_A = (ulong) A;
B = (long) ((u_A & 0x00000000000000ffUL) << 56 |
(u_A & 0x000000000000ff00UL) << 40 |
(u_A & 0x0000000000ff0000UL) << 24 |
(u_A & 0x00000000ff000000UL) << 8 |
(u_A & 0x000000ff00000000UL) >> 8 |
(u_A & 0x0000ff0000000000UL) >> 24 |
(u_A & 0x00ff000000000000UL) >> 40 |
(u_A & 0xff00000000000000UL) >> 56);
").
:- pragma foreign_proc("Java",
reverse_bytes(A::in) = (B::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
B = java.lang.Long.reverseBytes(A);
").
:- pragma no_determinism_warning(reverse_bytes/1).
reverse_bytes(_) = _ :-
sorry($module, "int64.reverse_bytes/1 NYI for Erlang").
%---------------------------------------------------------------------------%
min_int64 = -9_223_372_036_854_775_808_i64.
max_int64 = 9_223_372_036_854_775_807_i64.

View File

@@ -1120,6 +1120,32 @@
:- pred write_binary_uint32_be(io.binary_output_stream::in, uint32::in,
io::di, io::uo) is det.
%---------------------%
:- pred write_binary_int64(int64::in, io::di, io::uo) is det.
:- pred write_binary_int64(io.binary_output_stream::in, int64::in,
io::di, io::uo) is det.
:- pred write_binary_int64_le(int64::in, io::di, io::uo) is det.
:- pred write_binary_int64_le(io.binary_output_stream::in, int64::in,
io::di, io::uo) is det.
:- pred write_binary_int64_be(int64::in, io::di, io::uo) is det.
:- pred write_binary_int64_be(io.binary_output_stream::in, int64::in,
io::di, io::uo) is det.
:- pred write_binary_uint64(uint64::in, io::di, io::uo) is det.
:- pred write_binary_uint64(io.binary_output_stream::in, uint64::in,
io::di, io::uo) is det.
:- pred write_binary_uint64_le(uint64::in, io::di, io::uo) is det.
:- pred write_binary_uint64_le(io.binary_output_stream::in, uint64::in,
io::di, io::uo) is det.
:- pred write_binary_uint64_be(uint64::in, io::di, io::uo) is det.
:- pred write_binary_uint64_be(io.binary_output_stream::in, uint64::in,
io::di, io::uo) is det.
%---------------------%
% Write a bitmap to the current binary output stream
@@ -1934,6 +1960,7 @@
:- import_module uint8.
:- import_module uint16.
:- import_module uint32.
:- import_module uint64.
:- use_module rtti_implementation.
:- use_module table_builtin.
@@ -8099,6 +8126,34 @@ write_binary_uint32_be(UInt32, !IO) :-
%---------------------%
write_binary_int64(Int64, !IO) :-
UInt64 = uint64.cast_from_int64(Int64),
write_binary_uint64(UInt64, !IO).
write_binary_int64_le(Int64, !IO) :-
UInt64 = uint64.cast_from_int64(Int64),
write_binary_uint64_le(UInt64, !IO).
write_binary_int64_be(Int64, !IO) :-
UInt64 = uint64.cast_from_int64(Int64),
write_binary_uint64_be(UInt64, !IO).
%---------------------%
write_binary_uint64(UInt64, !IO) :-
binary_output_stream(Stream, !IO),
write_binary_uint64(Stream, UInt64, !IO).
write_binary_uint64_le(UInt64, !IO) :-
binary_output_stream(Stream, !IO),
write_binary_uint64_le(Stream, UInt64, !IO).
write_binary_uint64_be(UInt64, !IO) :-
binary_output_stream(Stream, !IO),
write_binary_uint64_be(Stream, UInt64, !IO).
%---------------------%
write_bitmap(Bitmap, !IO) :-
binary_output_stream(Stream, !IO),
write_bitmap(Stream, Bitmap, !IO).
@@ -8840,6 +8895,184 @@ write_binary_uint32_be(binary_output_stream(Stream), UInt32, !IO) :-
%---------------------%
write_binary_int64(Stream, Int64, !IO) :-
UInt64 = uint64.cast_from_int64(Int64),
write_binary_uint64(Stream, UInt64, !IO).
write_binary_uint64(binary_output_stream(Stream), UInt64, !IO) :-
do_write_binary_uint64(Stream, UInt64, Error, !IO),
throw_on_output_error(Error, !IO).
:- pred do_write_binary_uint64(stream::in, uint64::in, system_error::out,
io::di, io::uo) is det.
:- pragma foreign_proc("C",
do_write_binary_uint64(Stream::in, U64::in, Error::out,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
"
if (MR_WRITE(*Stream, (unsigned char *)(&U64), 8) != 8) {
Error = errno;
} else {
Error = 0;
}
").
:- pragma foreign_proc("Java",
do_write_binary_uint64(Stream::in, U64::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(8);
buffer.order(java.nio.ByteOrder.nativeOrder());
buffer.putLong(U64);
((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 8);
Error = null;
} catch (java.io.IOException e) {
Error = e;
}
").
:- pragma foreign_proc("C#",
do_write_binary_uint64(Stream::in, U64::in, Error::out, _IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
"
byte[] bytes = BitConverter.GetBytes(U64);
try {
Stream.stream.Write(bytes, 0, 8);
Error = null;
} catch (System.Exception e) {
Error = e;
}
").
%---------------------%
write_binary_int64_le(Stream, Int64, !IO) :-
UInt64 = uint64.cast_from_int64(Int64),
write_binary_uint64_le(Stream, UInt64, !IO).
write_binary_uint64_le(binary_output_stream(Stream), UInt64, !IO) :-
do_write_binary_uint64_le(Stream, UInt64, Error, !IO),
throw_on_output_error(Error, !IO).
:- pred do_write_binary_uint64_le(stream::in, uint64::in, system_error::out,
io::di, io::uo) is det.
:- pragma foreign_proc("C",
do_write_binary_uint64_le(Stream::in, U64::in, Error::out,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
"
#if defined(MR_BIG_ENDIAN)
U64 = MR_uint64_reverse_bytes(U64);
#endif
if (MR_WRITE(*Stream, (unsigned char *)(&U64), 8) != 8) {
Error = errno;
} else {
Error = 0;
}
").
:- pragma foreign_proc("Java",
do_write_binary_uint64_le(Stream::in, U64::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(8);
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
buffer.putLong(U64);
((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 8);
Error = null;
} catch (java.io.IOException e) {
Error = e;
}
").
:- pragma foreign_proc("C#",
do_write_binary_uint64_le(Stream::in, U64::in, Error::out,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
"
byte[] bytes = BitConverter.GetBytes(U64);
if (!BitConverter.IsLittleEndian) {
Array.Reverse(bytes);
}
try {
Stream.stream.Write(bytes, 0, 8);
Error = null;
} catch (System.Exception e) {
Error = e;
}
").
%---------------------%
write_binary_int64_be(Stream, Int64, !IO) :-
UInt64 = uint64.cast_from_int64(Int64),
write_binary_uint64_be(Stream, UInt64, !IO).
write_binary_uint64_be(binary_output_stream(Stream), UInt64, !IO) :-
do_write_binary_uint64_be(Stream, UInt64, Error, !IO),
throw_on_output_error(Error, !IO).
:- pred do_write_binary_uint64_be(stream::in, uint64::in, system_error::out,
io::di, io::uo) is det.
:- pragma foreign_proc("C",
do_write_binary_uint64_be(Stream::in, U64::in, Error::out,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
"
#if defined(MR_LITTLE_ENDIAN)
U64 = MR_uint64_reverse_bytes(U64);
#endif
if (MR_WRITE(*Stream, (unsigned char *)(&U64), 8) != 8) {
Error = errno;
} else {
Error = 0;
}
").
:- pragma foreign_proc("Java",
do_write_binary_uint64_be(Stream::in, U64::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(8);
// Order in a byte buffer is big endian by default.
buffer.putLong(U64);
((io.MR_BinaryOutputFile) Stream).write(buffer.array(), 0, 8);
Error = null;
} catch (java.io.IOException e) {
Error = e;
}
").
:- pragma foreign_proc("C#",
do_write_binary_uint64_be(Stream::in, U64::in, Error::out,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
"
byte[] bytes = BitConverter.GetBytes(U64);
if (BitConverter.IsLittleEndian) {
Array.Reverse(bytes);
}
try {
Stream.stream.Write(bytes, 0, 8);
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),

View File

@@ -33,6 +33,8 @@
:- func cast_to_int(uint64) = int.
:- func cast_from_int64(int64) = uint64.
% from_bytes_le(Byte0, Byte1, ..., Byte7) = U64:
% U64 is the uint64 whose bytes are given in little-endian order by the
% arguments from left-to-right (i.e. Byte0 is the least significant byte
@@ -191,6 +193,12 @@
%
:- func \ (uint64::in) = (uint64::uo) is det.
% reverse_bytes(A) = B:
% B is the value that results from reversing the bytes in the
% representation of A.
%
:- func reverse_bytes(uint64) = uint64.
:- func max_uint64 = uint64.
% Convert a uint64 to a pretty_printer.doc for formatting.
@@ -309,6 +317,34 @@ cast_to_int(_) = _ :-
%---------------------------------------------------------------------------%
:- pragma foreign_proc("C",
cast_from_int64(I64::in) = (U64::out),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
does_not_affect_liveness],
"
U64 = (uint64_t) I64;
").
:- pragma foreign_proc("C#",
cast_from_int64(I64::in) = (U64::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
U64 = (ulong) I64;
").
:- pragma foreign_proc("Java",
cast_from_int64(I64::in) = (U64::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
U64 = I64;
").
:- pragma no_determinism_warning(cast_from_int64/1).
cast_from_int64(_) = _ :-
sorry($module, "uint64.cast_from_int64/1 NYI for Erlang").
%---------------------------------------------------------------------------%
:- pragma foreign_proc("C",
from_bytes_le(Byte0::in, Byte1::in, Byte2::in, Byte3::in,
Byte4::in, Byte5::in, Byte6::in, Byte7::in) = (U64::out),
@@ -438,6 +474,32 @@ odd(X) :-
%---------------------------------------------------------------------------%
:- pragma foreign_proc("C",
reverse_bytes(A::in) = (B::out),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail],
"
B = MR_uint64_reverse_bytes(A);
").
:- pragma foreign_proc("Java",
reverse_bytes(A::in) = (B::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
B = java.lang.Long.reverseBytes(A);
").
reverse_bytes(A) = B :-
B = ((A /\ 0x_0000_0000_0000_00ff_u64) << 56) \/
((A /\ 0x_0000_0000_0000_ff00_u64) << 40) \/
((A /\ 0x_0000_0000_00ff_0000_u64) << 24) \/
((A /\ 0x_0000_0000_ff00_0000_u64) << 8) \/
((A /\ 0x_0000_00ff_0000_0000_u64) >> 8) \/
((A /\ 0x_0000_ff00_0000_0000_u64) >> 24) \/
((A /\ 0x_00ff_0000_0000_0000_u64) >> 40) \/
((A /\ 0x_ff00_0000_0000_0000_u64) >> 56).
%---------------------------------------------------------------------------%
max_uint64 = 18_446_744_073_709_551_615_u64.
%---------------------------------------------------------------------------%

View File

@@ -114,4 +114,20 @@ extern MR_Integer MR_hash_uint64(uint64_t);
(U & UINT32_C(0xff000000)) >> 24 )
#endif
#if defined(MR_GNUC) || defined(MR_CLANG)
#define MR_uint64_reverse_bytes(U) __builtin_bswap64((U))
#elif defined(MR_MSVC)
#define MR_uint64_reverse_bytes(U) _byteswap_uint64((UU))
#else
#define MR_uint64_reverse_bytes(U) \
((U & UINT64_C(0x00000000000000ff)) << 56 | \
(U & UINT64_C(0x000000000000ff00)) << 40 | \
(U & UINT64_C(0x0000000000ff0000)) << 24 | \
(U & UINT64_C(0x00000000ff000000)) << 8 | \
(U & UINT64_C(0x000000ff00000000)) >> 8 | \
(U & UINT64_C(0x0000ff0000000000)) >> 24 | \
(U & UINT64_C(0x00ff000000000000)) >> 40 | \
(U & UINT64_C(0xff00000000000000)) >> 56)
#endif
#endif // not MERCURY_INT_H

View File

@@ -1 +1,56 @@
0x0a 0x0b 0x0b 0x0a 0xaa 0xbb 0xbb 0xaa 0x0a 0x0b 0x0c 0x0d 0x0d 0x0c 0x0b 0x0a 0xaa 0xbb 0xcc 0xdd 0xdd 0xcc 0xbb 0xaa
0x0a
0x0b
0x0b
0x0a
0xaa
0xbb
0xbb
0xaa
0x0a
0x0b
0x0c
0x0d
0x0d
0x0c
0x0b
0x0a
0xaa
0xbb
0xcc
0xdd
0xdd
0xcc
0xbb
0xaa
0x0a
0x0b
0x0c
0x0d
0x0e
0x0f
0x00
0x00
0x00
0x00
0x0f
0x0e
0x0d
0x0c
0x0b
0x0a
0xaa
0xbb
0xcc
0xdd
0xee
0xff
0x00
0x00
0x00
0x00
0xff
0xee
0xdd
0xcc
0xbb
0xaa

View File

@@ -2,7 +2,8 @@
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
%
% Test writing of int16, uint16, in32 and uint32 to binary file streams.
% Test writing of int16, uint16, int32, uint32, int64 and uint64 to binary file
% streams.
:- module write_binary_multibyte_int.
:- interface.
@@ -44,6 +45,10 @@ main_2(FileName, !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.write_binary_int64_le(OutputFile, 0x0f0e0d0c0b0a_i64, !IO),
io.write_binary_int64_be(OutputFile, 0x0f0e0d0c0b0a_i64, !IO),
io.write_binary_uint64_le(OutputFile, 0xffeeddccbbaa_u64, !IO),
io.write_binary_uint64_be(OutputFile, 0xffeeddccbbaa_u64, !IO),
io.close_binary_output(OutputFile, !IO),
io.open_binary_input(FileName, OpenInputResult, !IO),
@@ -53,7 +58,7 @@ main_2(FileName, !IO) :-
(
ReadResult = ok(Bytes),
io.close_binary_input(InputFile, !IO),
io.write_list(Bytes, " ", print_byte, !IO),
io.write_list(Bytes, "\n", print_byte, !IO),
io.nl(!IO)
;
ReadResult = error(IO_Error),