[m-rev.] for review: add casts to and from uint{16, 32, 64} and uint8
Julien Fischer
jfischer at opturion.com
Sun Nov 7 18:31:10 AEDT 2021
For review by anyone.
---------------------
Add casts to and from uint{16,32,64} and uint8.
While these casts can be implemented by casting via uint, the resulting code is
less readable than code that uses direct casts.
library/uint16.m:
library/uint32.m:
library/uint64.m:
Add cast_from_uint8/1 and cast_to_uint8/1 to these modules.
NEWS:
Announce the above additions.
tests/hard_coded/Mmakefile:
tests/hard_coded/uint{16,32,64}_uint_casts.{m,exp}:
Add tests for the new casts.
Julien.
diff --git a/NEWS b/NEWS
index eab0985..db2ff09 100644
--- a/NEWS
+++ b/NEWS
@@ -409,6 +409,8 @@ Changes to the Mercury standard library
- func `unchecked_bit_is_set/2`
- func `bit_is_clear/2`
- func `unchecked_bit_is_clear/2`
+ - func `cast_from_uint8/1`
+ - func `cast_to_uint8/1`
### Changes to the `uint32` module
@@ -430,6 +432,8 @@ Changes to the Mercury standard library
- func `unchecked_bit_is_set/2`
- func `bit_is_clear/2`
- func `unchecked_bit_is_clear/2`
+ - func `cast_from_uint8/1`
+ - func `cast_to_uint8/1`
### Changes to the `uint64` module
@@ -450,6 +454,8 @@ Changes to the Mercury standard library
- func `unchecked_bit_is_set/2`
- func `bit_is_clear/2`
- func `unchecked_bit_is_clear/2`
+ - func `cast_from_uint8/1`
+ - func `cast_to_uint8/1`
### Changes to the `uint8` module
diff --git a/library/uint16.m b/library/uint16.m
index 96b6a18..1493f19 100644
--- a/library/uint16.m
+++ b/library/uint16.m
@@ -108,6 +108,27 @@
%---------------------------------------------------------------------------%
%
+% Conversion to/from uint8
+%
+
+ % cast_to_uint8(U16) = U8:
+ %
+ % Convert a uint16 to a uint8.
+ % Always succeeds, but will yield a result that is mathematically equal
+ % to U16 only if U16 is in [0, 2^8 - 1].
+ %
+:- func cast_to_uint8(uint16) = uint8.
+
+ % cast_from_uint8(U8) = U16:
+ %
+ % Convert a uint8 to a uint16.
+ % Always succeeds, and yields a result that is mathemtically equal
+ % to U8.
+ %
+:- func cast_from_uint8(uint8) = uint16.
+
+%---------------------------------------------------------------------------%
+%
% Conversion to/from uint64.
%
@@ -624,6 +645,54 @@ det_from_uint(U) = U16 :-
%---------------------------------------------------------------------------%
:- pragma foreign_proc("C",
+ cast_to_uint8(U16::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ U8 = (uint8_t) U16;
+").
+
+:- pragma foreign_proc("C#",
+ cast_to_uint8(U16::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U8 = (byte) U16;
+").
+
+:- pragma foreign_proc("Java",
+ cast_to_uint8(U16::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U8 = (byte) U16;
+").
+
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
+ cast_from_uint8(U8::in) = (U16::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ U16 = (uint16_t) U8;
+").
+
+:- pragma foreign_proc("C#",
+ cast_from_uint8(U8::in) = (U16::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U16 = (ushort) U8;
+").
+
+:- pragma foreign_proc("Java",
+ cast_from_uint8(U8::in) = (U16::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U16 = (short) (U8 & 0xff);
+").
+
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
cast_to_uint64(U16::in) = (U64::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 740e37b..168f74a 100644
--- a/library/uint32.m
+++ b/library/uint32.m
@@ -102,6 +102,27 @@
%---------------------------------------------------------------------------%
%
+% Conversion to/from uint8
+%
+
+ % cast_to_uint8(U32) = U8:
+ %
+ % Convert a uint32 to a uint8.
+ % Always succeeds, but will yield a result that is mathematically equal
+ % to U32 only if U32 is in [0, 2^8 - 1].
+ %
+:- func cast_to_uint8(uint32) = uint8.
+
+ % cast_from_uint8(U8) = U32:
+ %
+ % Convert a uint8 to a uint32.
+ % Always succeeds, and yields a result that is mathemtically equal
+ % to U8.
+ %
+:- func cast_from_uint8(uint8) = uint32.
+
+%---------------------------------------------------------------------------%
+%
% Conversion to/from uint64.
%
@@ -647,6 +668,54 @@ det_from_uint(U) = U32 :-
%---------------------------------------------------------------------------%
:- pragma foreign_proc("C",
+ cast_to_uint8(U32::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ U8 = (uint8_t) U32;
+").
+
+:- pragma foreign_proc("C#",
+ cast_to_uint8(U32::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U8 = (byte) U32;
+").
+
+:- pragma foreign_proc("Java",
+ cast_to_uint8(U32::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U8 = (byte) U32;
+").
+
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
+ cast_from_uint8(U8::in) = (U32::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ U32 = (uint32_t) U8;
+").
+
+:- pragma foreign_proc("C#",
+ cast_from_uint8(U8::in) = (U32::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U32 = (uint) U8;
+").
+
+:- pragma foreign_proc("Java",
+ cast_from_uint8(U8::in) = (U32::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U32 = U8 & 0xff;
+").
+
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
cast_to_uint64(U32::in) = (U64::out),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
does_not_affect_liveness],
diff --git a/library/uint64.m b/library/uint64.m
index 0f81082..838c790 100644
--- a/library/uint64.m
+++ b/library/uint64.m
@@ -88,6 +88,27 @@
%---------------------------------------------------------------------------%
%
+% Conversion to/from uint8
+%
+
+ % cast_to_uint8(U64) = U8:
+ %
+ % Convert a uint64 to a uint8.
+ % Always succeeds, but will yield a result that is mathematically equal
+ % to U64 only if U64 is in [0, 2^8 - 1].
+ %
+:- func cast_to_uint8(uint64) = uint8.
+
+ % cast_from_uint8(U8) = U64:
+ %
+ % Convert a uint8 to a uint64.
+ % Always succeeds, and yields a result that is mathemtically equal
+ % to U8.
+ %
+:- func cast_from_uint8(uint8) = uint64.
+
+%---------------------------------------------------------------------------%
+%
% Change of signedness.
%
@@ -574,6 +595,54 @@ det_from_int(I) = U64 :-
%---------------------------------------------------------------------------%
:- pragma foreign_proc("C",
+ cast_to_uint8(U64::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ U8 = (uint8_t) U64;
+").
+
+:- pragma foreign_proc("C#",
+ cast_to_uint8(U64::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U8 = (byte) U64;
+").
+
+:- pragma foreign_proc("Java",
+ cast_to_uint8(U64::in) = (U8::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U8 = (byte) U64;
+").
+
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
+ cast_from_uint8(U8::in) = (U64::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ U64 = (uint64_t) U8;
+").
+
+:- pragma foreign_proc("C#",
+ cast_from_uint8(U8::in) = (U64::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U64 = (ulong) U8;
+").
+
+:- pragma foreign_proc("Java",
+ cast_from_uint8(U8::in) = (U64::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ U64 = (long) (U8 & 0xff);
+").
+
+%---------------------------------------------------------------------------%
+
+:- 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],
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 72779592..3d27e62 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -462,15 +462,18 @@ ORDINARY_PROGS = \
uint16_from_bytes \
uint16_switch_test \
uint16_to_string \
+ uint16_uint8_casts \
uint32_from_bytes \
uint32_switch_test \
uint32_to_string \
uint32_to_uint64 \
+ uint32_uint8_casts \
uint64_from_bytes \
uint64_ground_term \
uint64_string_conv \
uint64_switch_test \
uint64_to_string \
+ uint64_uint8_casts \
uint8_switch_test \
uint8_to_string \
uint_string_conv \
diff --git a/tests/hard_coded/uint16_uint8_casts.exp b/tests/hard_coded/uint16_uint8_casts.exp
index e69de29..02c0b25 100644
--- a/tests/hard_coded/uint16_uint8_casts.exp
+++ b/tests/hard_coded/uint16_uint8_casts.exp
@@ -0,0 +1,27 @@
+cast_from_uint8(0u8) = 0u16
+cast_from_uint8(7u8) = 7u16
+cast_from_uint8(8u8) = 8u16
+cast_from_uint8(15u8) = 15u16
+cast_from_uint8(16u8) = 16u16
+cast_from_uint8(31u8) = 31u16
+cast_from_uint8(32u8) = 32u16
+cast_from_uint8(63u8) = 63u16
+cast_from_uint8(64u8) = 64u16
+cast_from_uint8(127u8) = 127u16
+cast_from_uint8(128u8) = 128u16
+cast_from_uint8(254u8) = 254u16
+cast_from_uint8(255u8) = 255u16
+
+cast_to_uint8(0u16) = 0u8
+cast_to_uint8(7u16) = 7u8
+cast_to_uint8(8u16) = 8u8
+cast_to_uint8(15u16) = 15u8
+cast_to_uint8(16u16) = 16u8
+cast_to_uint8(31u16) = 31u8
+cast_to_uint8(32u16) = 32u8
+cast_to_uint8(63u16) = 63u8
+cast_to_uint8(64u16) = 64u8
+cast_to_uint8(127u16) = 127u8
+cast_to_uint8(128u16) = 128u8
+cast_to_uint8(254u16) = 254u8
+cast_to_uint8(255u16) = 255u8
diff --git a/tests/hard_coded/uint16_uint8_casts.m b/tests/hard_coded/uint16_uint8_casts.m
index e69de29..32592d3 100644
--- a/tests/hard_coded/uint16_uint8_casts.m
+++ b/tests/hard_coded/uint16_uint8_casts.m
@@ -0,0 +1,83 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Testing casting uint16s to/from uint8s.
+%
+%---------------------------------------------------------------------------%
+
+:- module uint16_uint8_casts.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module list.
+:- import_module string.
+:- import_module uint16.
+:- import_module uint8.
+
+%---------------------------------------------------------------------------%
+
+main(!IO) :-
+ list.foldl(do_cast_from_uint8_test, uint8s, !IO),
+ io.nl(!IO),
+ list.foldl(do_cast_to_uint8_test, uint16s, !IO).
+
+:- pred do_cast_from_uint8_test(uint8::in, io::di, io::uo) is det.
+
+do_cast_from_uint8_test(U8, !IO) :-
+ io.format("cast_from_uint8(%uu8) = %uu16\n",
+ [u8(U8), u16(cast_from_uint8(U8))], !IO).
+
+:- pred do_cast_to_uint8_test(uint16::in, io::di, io::uo) is det.
+
+do_cast_to_uint8_test(U16, !IO) :-
+ io.format("cast_to_uint8(%uu16) = %uu8\n",
+ [u16(U16), u8(cast_to_uint8(U16))], !IO).
+
+:- func uint8s = list(uint8).
+
+uint8s = [
+ 0u8,
+ 7u8,
+ 8u8,
+ 15u8,
+ 16u8,
+ 31u8,
+ 32u8,
+ 63u8,
+ 64u8,
+ 127u8,
+ 128u8,
+ 254u8,
+ 255u8
+].
+
+:- func uint16s = list(uint16).
+
+uint16s = [
+ 0u16,
+ 7u16,
+ 8u16,
+ 15u16,
+ 16u16,
+ 31u16,
+ 32u16,
+ 63u16,
+ 64u16,
+ 127u16,
+ 128u16,
+ 254u16,
+ 255u16
+].
+
+%---------------------------------------------------------------------------%
+:- end_module uint16_uint8_casts.
+%---------------------------------------------------------------------------%
diff --git a/tests/hard_coded/uint32_uint8_casts.exp b/tests/hard_coded/uint32_uint8_casts.exp
index e69de29..30f21d2 100644
--- a/tests/hard_coded/uint32_uint8_casts.exp
+++ b/tests/hard_coded/uint32_uint8_casts.exp
@@ -0,0 +1,27 @@
+cast_from_uint8(0u8) = 0u32
+cast_from_uint8(7u8) = 7u32
+cast_from_uint8(8u8) = 8u32
+cast_from_uint8(15u8) = 15u32
+cast_from_uint8(16u8) = 16u32
+cast_from_uint8(31u8) = 31u32
+cast_from_uint8(32u8) = 32u32
+cast_from_uint8(63u8) = 63u32
+cast_from_uint8(64u8) = 64u32
+cast_from_uint8(127u8) = 127u32
+cast_from_uint8(128u8) = 128u32
+cast_from_uint8(254u8) = 254u32
+cast_from_uint8(255u8) = 255u32
+
+cast_to_uint8(0u32) = 0u8
+cast_to_uint8(7u32) = 7u8
+cast_to_uint8(8u32) = 8u8
+cast_to_uint8(15u32) = 15u8
+cast_to_uint8(16u32) = 16u8
+cast_to_uint8(31u32) = 31u8
+cast_to_uint8(32u32) = 32u8
+cast_to_uint8(63u32) = 63u8
+cast_to_uint8(64u32) = 64u8
+cast_to_uint8(127u32) = 127u8
+cast_to_uint8(128u32) = 128u8
+cast_to_uint8(254u32) = 254u8
+cast_to_uint8(255u32) = 255u8
diff --git a/tests/hard_coded/uint32_uint8_casts.m b/tests/hard_coded/uint32_uint8_casts.m
index e69de29..0516844 100644
--- a/tests/hard_coded/uint32_uint8_casts.m
+++ b/tests/hard_coded/uint32_uint8_casts.m
@@ -0,0 +1,83 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test casting uint32s to/from uint8s.
+%
+%---------------------------------------------------------------------------%
+
+:- module uint32_uint8_casts.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module list.
+:- import_module string.
+:- import_module uint32.
+:- import_module uint8.
+
+%---------------------------------------------------------------------------%
+
+main(!IO) :-
+ list.foldl(do_cast_from_uint8_test, uint8s, !IO),
+ io.nl(!IO),
+ list.foldl(do_cast_to_uint8_test, uint32s, !IO).
+
+:- pred do_cast_from_uint8_test(uint8::in, io::di, io::uo) is det.
+
+do_cast_from_uint8_test(U8, !IO) :-
+ io.format("cast_from_uint8(%uu8) = %uu32\n",
+ [u8(U8), u32(cast_from_uint8(U8))], !IO).
+
+:- pred do_cast_to_uint8_test(uint32::in, io::di, io::uo) is det.
+
+do_cast_to_uint8_test(U32, !IO) :-
+ io.format("cast_to_uint8(%uu32) = %uu8\n",
+ [u32(U32), u8(cast_to_uint8(U32))], !IO).
+
+:- func uint8s = list(uint8).
+
+uint8s = [
+ 0u8,
+ 7u8,
+ 8u8,
+ 15u8,
+ 16u8,
+ 31u8,
+ 32u8,
+ 63u8,
+ 64u8,
+ 127u8,
+ 128u8,
+ 254u8,
+ 255u8
+].
+
+:- func uint32s = list(uint32).
+
+uint32s = [
+ 0u32,
+ 7u32,
+ 8u32,
+ 15u32,
+ 16u32,
+ 31u32,
+ 32u32,
+ 63u32,
+ 64u32,
+ 127u32,
+ 128u32,
+ 254u32,
+ 255u32
+].
+
+%---------------------------------------------------------------------------%
+:- end_module uint32_uint8_casts.
+%---------------------------------------------------------------------------%
diff --git a/tests/hard_coded/uint64_uint8_casts.exp b/tests/hard_coded/uint64_uint8_casts.exp
index e69de29..35103b9 100644
--- a/tests/hard_coded/uint64_uint8_casts.exp
+++ b/tests/hard_coded/uint64_uint8_casts.exp
@@ -0,0 +1,27 @@
+cast_from_uint8(0u8) = 0u64
+cast_from_uint8(7u8) = 7u64
+cast_from_uint8(8u8) = 8u64
+cast_from_uint8(15u8) = 15u64
+cast_from_uint8(16u8) = 16u64
+cast_from_uint8(31u8) = 31u64
+cast_from_uint8(32u8) = 32u64
+cast_from_uint8(63u8) = 63u64
+cast_from_uint8(64u8) = 64u64
+cast_from_uint8(127u8) = 127u64
+cast_from_uint8(128u8) = 128u64
+cast_from_uint8(254u8) = 254u64
+cast_from_uint8(255u8) = 255u64
+
+cast_to_uint8(0u64) = 0u8
+cast_to_uint8(7u64) = 7u8
+cast_to_uint8(8u64) = 8u8
+cast_to_uint8(15u64) = 15u8
+cast_to_uint8(16u64) = 16u8
+cast_to_uint8(31u64) = 31u8
+cast_to_uint8(32u64) = 32u8
+cast_to_uint8(63u64) = 63u8
+cast_to_uint8(64u64) = 64u8
+cast_to_uint8(127u64) = 127u8
+cast_to_uint8(128u64) = 128u8
+cast_to_uint8(254u64) = 254u8
+cast_to_uint8(255u64) = 255u8
diff --git a/tests/hard_coded/uint64_uint8_casts.m b/tests/hard_coded/uint64_uint8_casts.m
index e69de29..e1dc9a3 100644
--- a/tests/hard_coded/uint64_uint8_casts.m
+++ b/tests/hard_coded/uint64_uint8_casts.m
@@ -0,0 +1,83 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test casting uint64s to/from uint8s.
+%
+%---------------------------------------------------------------------------%
+
+:- module uint64_uint8_casts.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module list.
+:- import_module string.
+:- import_module uint64.
+:- import_module uint8.
+
+%---------------------------------------------------------------------------%
+
+main(!IO) :-
+ list.foldl(do_cast_from_uint8_test, uint8s, !IO),
+ io.nl(!IO),
+ list.foldl(do_cast_to_uint8_test, uint64s, !IO).
+
+:- pred do_cast_from_uint8_test(uint8::in, io::di, io::uo) is det.
+
+do_cast_from_uint8_test(U8, !IO) :-
+ io.format("cast_from_uint8(%uu8) = %uu64\n",
+ [u8(U8), u64(cast_from_uint8(U8))], !IO).
+
+:- pred do_cast_to_uint8_test(uint64::in, io::di, io::uo) is det.
+
+do_cast_to_uint8_test(U32, !IO) :-
+ io.format("cast_to_uint8(%uu64) = %uu8\n",
+ [u64(U32), u8(cast_to_uint8(U32))], !IO).
+
+:- func uint8s = list(uint8).
+
+uint8s = [
+ 0u8,
+ 7u8,
+ 8u8,
+ 15u8,
+ 16u8,
+ 31u8,
+ 32u8,
+ 63u8,
+ 64u8,
+ 127u8,
+ 128u8,
+ 254u8,
+ 255u8
+].
+
+:- func uint64s = list(uint64).
+
+uint64s = [
+ 0u64,
+ 7u64,
+ 8u64,
+ 15u64,
+ 16u64,
+ 31u64,
+ 32u64,
+ 63u64,
+ 64u64,
+ 127u64,
+ 128u64,
+ 254u64,
+ 255u64
+].
+
+%---------------------------------------------------------------------------%
+:- end_module uint64_uint8_casts.
+%---------------------------------------------------------------------------%
More information about the reviews
mailing list