[m-rev.] for post-commit review: add casts to and from uint32 and uint16

Julien Fischer jfischer at opturion.com
Mon Jan 3 18:18:57 AEDT 2022


For post-commit review by anyone.

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

Add casts to and from uint32 and uint16.

While these casts can be implemented by casting via uint, the resulting
code is less readable than code that uses direct casts.

library/uint32.m:
     Add cast_from_uint16/1 and cast_to_uint16/1.

NEWS:
     Announce the above additions.

tests/hard_coded/Mmakefile:
tests/hard_coded/uint32_uint16_casts.{m,exp}:
     Add tests for the new casts.

Julien.

diff --git a/NEWS b/NEWS
index bca22b4..14cc7fe 100644
--- a/NEWS
+++ b/NEWS
@@ -464,6 +464,8 @@ Changes to the Mercury standard library
      - func `unchecked_bit_is_clear/2`
      - func `cast_from_uint8/1`
      - func `cast_to_uint8/1`
+    - func `cast_from_uint16/1`
+    - func `cast_to_uint16/1`

  ### Changes to the `uint64` module

diff --git a/library/uint32.m b/library/uint32.m
index 168f74a..041f207 100644
--- a/library/uint32.m
+++ b/library/uint32.m
@@ -102,7 +102,7 @@

  %---------------------------------------------------------------------------%
  %
-% Conversion to/from uint8
+% Conversion to/from uint8.
  %

      % cast_to_uint8(U32) = U8:
@@ -123,6 +123,27 @@

  %---------------------------------------------------------------------------%
  %
+% Conversion to/from uint16.
+%
+
+    % cast_to_uint8(U32) = U16:
+    %
+    % Convert a uint32 to a uint16.
+    % Always succeeds, but will yield a result that is mathematically equal
+    % to U32 only if U32 is in [0, 2^16 - 1].
+    %
+:- func cast_to_uint16(uint32) = uint16.
+
+    % cast_from_uint16(U16) = U32:
+    %
+    % Convert a uint16 to a uint32.
+    % Always succeeds, and yields a result that is mathemtically equal
+    % to U16.
+    %
+:- func cast_from_uint16(uint16) = uint32.
+
+%---------------------------------------------------------------------------%
+%
  % Conversion to/from uint64.
  %

@@ -716,6 +737,54 @@ det_from_uint(U) = U32 :-
  %---------------------------------------------------------------------------%

  :- pragma foreign_proc("C",
+    cast_to_uint16(U32::in) = (U16::out),
+    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+        does_not_affect_liveness],
+"
+    U16 = (uint16_t) U32;
+").
+
+:- pragma foreign_proc("C#",
+    cast_to_uint16(U32::in) = (U16::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    U16 = (ushort) U32;
+").
+
+:- pragma foreign_proc("Java",
+    cast_to_uint16(U32::in) = (U16::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    U16 = (short) U32;
+").
+
+%---------------------------------------------------------------------------%
+
+:- pragma foreign_proc("C",
+    cast_from_uint16(U16::in) = (U32::out),
+    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+        does_not_affect_liveness],
+"
+    U32 = (uint32_t) U16;
+").
+
+:- pragma foreign_proc("C#",
+    cast_from_uint16(U16::in) = (U32::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    U32 = (uint) U16;
+").
+
+:- pragma foreign_proc("Java",
+    cast_from_uint16(U16::in) = (U32::out),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    U32 = U16 & 0xffff;
+").
+
+%---------------------------------------------------------------------------%
+
+:- 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/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index e4d8a96..13c7e85 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -468,6 +468,7 @@ ORDINARY_PROGS = \
  	uint32_switch_test \
  	uint32_to_string \
  	uint32_to_uint64 \
+	uint32_uint16_casts \
  	uint32_uint8_casts \
  	uint64_from_bytes \
  	uint64_ground_term \
diff --git a/tests/hard_coded/uint32_uint16_casts.exp b/tests/hard_coded/uint32_uint16_casts.exp
index e69de29..59333e2 100644
--- a/tests/hard_coded/uint32_uint16_casts.exp
+++ b/tests/hard_coded/uint32_uint16_casts.exp
@@ -0,0 +1,37 @@
+cast_from_uint16(0u16) = 0u32
+cast_from_uint16(7u16) = 7u32
+cast_from_uint16(8u16) = 8u32
+cast_from_uint16(15u16) = 15u32
+cast_from_uint16(16u16) = 16u32
+cast_from_uint16(31u16) = 31u32
+cast_from_uint16(32u16) = 32u32
+cast_from_uint16(63u16) = 63u32
+cast_from_uint16(64u16) = 64u32
+cast_from_uint16(127u16) = 127u32
+cast_from_uint16(128u16) = 128u32
+cast_from_uint16(254u16) = 254u32
+cast_from_uint16(255u16) = 255u32
+cast_from_uint16(32766u16) = 32766u32
+cast_from_uint16(32767u16) = 32767u32
+cast_from_uint16(32768u16) = 32768u32
+cast_from_uint16(65534u16) = 65534u32
+cast_from_uint16(65535u16) = 65535u32
+
+cast_to_uint16(0u32) = 0u16
+cast_to_uint16(7u32) = 7u16
+cast_to_uint16(8u32) = 8u16
+cast_to_uint16(15u32) = 15u16
+cast_to_uint16(16u32) = 16u16
+cast_to_uint16(31u32) = 31u16
+cast_to_uint16(32u32) = 32u16
+cast_to_uint16(63u32) = 63u16
+cast_to_uint16(64u32) = 64u16
+cast_to_uint16(127u32) = 127u16
+cast_to_uint16(128u32) = 128u16
+cast_to_uint16(254u32) = 254u16
+cast_to_uint16(255u32) = 255u16
+cast_to_uint16(32766u32) = 32766u16
+cast_to_uint16(32767u32) = 32767u16
+cast_to_uint16(32768u32) = 32768u16
+cast_to_uint16(65534u32) = 65534u16
+cast_to_uint16(65535u32) = 65535u16
diff --git a/tests/hard_coded/uint32_uint16_casts.m b/tests/hard_coded/uint32_uint16_casts.m
index e69de29..56de6ce 100644
--- a/tests/hard_coded/uint32_uint16_casts.m
+++ b/tests/hard_coded/uint32_uint16_casts.m
@@ -0,0 +1,93 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test casting uint32s to/from uint16s.
+%
+%---------------------------------------------------------------------------%
+
+:- module uint32_uint16_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 uint16.
+
+%---------------------------------------------------------------------------%
+
+main(!IO) :-
+    list.foldl(do_cast_from_uint16_test, uint16s, !IO),
+    io.nl(!IO),
+    list.foldl(do_cast_to_uint16_test, uint32s, !IO).
+
+:- pred do_cast_from_uint16_test(uint16::in, io::di, io::uo) is det.
+
+do_cast_from_uint16_test(U8, !IO) :-
+    io.format("cast_from_uint16(%uu16) = %uu32\n",
+        [u16(U8), u32(cast_from_uint16(U8))], !IO).
+
+:- pred do_cast_to_uint16_test(uint32::in, io::di, io::uo) is det.
+
+do_cast_to_uint16_test(U32, !IO) :-
+    io.format("cast_to_uint16(%uu32) = %uu16\n",
+        [u32(U32), u16(cast_to_uint16(U32))], !IO).
+
+:- func uint16s = list(uint16).
+
+uint16s = [
+    0u16,
+    7u16,
+    8u16,
+    15u16,
+    16u16,
+    31u16,
+    32u16,
+    63u16,
+    64u16,
+    127u16,
+    128u16,
+    254u16,
+    255u16,
+    32766u16,
+    32767u16,
+    32768u16,
+    65534u16,
+    65535u16
+].
+
+:- func uint32s = list(uint32).
+
+uint32s = [
+    0u32,
+    7u32,
+    8u32,
+    15u32,
+    16u32,
+    31u32,
+    32u32,
+    63u32,
+    64u32,
+    127u32,
+    128u32,
+    254u32,
+    255u32,
+    32766u32,
+    32767u32,
+    32768u32,
+    65534u32,
+    65535u32
+].
+
+%---------------------------------------------------------------------------%
+:- end_module uint32_uint16_casts.
+%---------------------------------------------------------------------------%


More information about the reviews mailing list