[m-rev.] for review: add uint64 to string conversin for bases 8 and 16

Julien Fischer jfischer at opturion.com
Sun Dec 13 19:37:01 AEDT 2020


For review by anyone.

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

Add uint64 to string conversion for bases 8 and 16.

library/string.m:
      Add functions for converting uint64s to strings of base 8 or base 16
      digits. For most integer types we can cast to a uint and then use the
      uint versions of these operations but for 64-bit types we cannot since
      on some of our supported platforms uints are 32-bit.

NEWS:
      Announce the additions.

tests/hard_coded/Mmakefile:
tests/hard_coded/uint64_string_conv.{m,exp}:
      Add a test of the new functions.

diff --git a/NEWS b/NEWS
index c878099..9caa794 100644
--- a/NEWS
+++ b/NEWS
@@ -152,6 +152,9 @@ Changes to the Mercury standard library
      - func `uint_to_hex_string/1`
      - func `uint_to_uc_hex_string/1`
      - func `uint_to_octal_string/1`
+    - func `uint64_to_hex_string/1`
+    - func `uint64_to_uc_hex_string/1`
+    - func `uint64_to_octal_string/1`

  * The following function symbols have been added to the type `poly_type`:

diff --git a/library/string.m b/library/string.m
index 35519ea..c02beab 100644
--- a/library/string.m
+++ b/library/string.m
@@ -1498,6 +1498,20 @@
  :- func int64_to_string(int64::in) = (string::uo) is det.
  :- func uint64_to_string(uint64::in) = (string::uo) is det.

+    % Convert an unsigned 64-bit integer to a string in base 16.
+    % Alphabetic digits will be lowercase (e.g. a-f).
+    %
+:- func uint64_to_hex_string(uint64::in) = (string::uo) is det.
+
+    % Convert an unsigned 64-bit integer to a string in base 16.
+    % Alphabetic digits will be uppercase (e.g. A-F).
+    %
+:- func uint64_to_uc_hex_string(uint64::in) = (string::uo) is det.
+
+    % Convert an unsigned 64-bit integer to a string in base 8.
+    %
+:- func uint64_to_octal_string(uint64::in) = (string::uo) is det.
+
      % Convert a float to a string.
      % In the current implementation, the resulting float will be in the form
      % that it was printed using the format string "%#.<prec>g".
@@ -5857,6 +5871,86 @@ int_to_base_string_group_2(NegN, Base, Curr, GroupLength, Sep, Str) :-

  %---------------------%

+:- pragma foreign_proc("C",
+    uint64_to_hex_string(U64::in) = (S::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail],
+"
+    char buffer[21]; // 20 for digits, 1 for nul.
+    sprintf(buffer, ""%"" PRIx64, U64);
+    MR_allocate_aligned_string_msg(S, strlen(buffer), MR_ALLOC_ID);
+    strcpy(S, buffer);
+").
+
+:- pragma foreign_proc("C#",
+    uint64_to_hex_string(U64::in) = (S::uo),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    S = U64.ToString(""x"");
+").
+
+:- pragma foreign_proc("Java",
+    uint64_to_hex_string(U64::in) = (S::uo),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    S = java.lang.Long.toHexString(U64);
+").
+
+%---------------------%
+
+:- pragma foreign_proc("C",
+    uint64_to_uc_hex_string(U64::in) = (S::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail],
+"
+    char buffer[21]; // 20 for digits, 1 for nul.
+    sprintf(buffer, ""%"" PRIX64, U64);
+    MR_allocate_aligned_string_msg(S, strlen(buffer), MR_ALLOC_ID);
+    strcpy(S, buffer);
+").
+
+:- pragma foreign_proc("C#",
+    uint64_to_uc_hex_string(U64::in) = (S::uo),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    S = U64.ToString(""X"");
+").
+
+:- pragma foreign_proc("Java",
+    uint64_to_uc_hex_string(U64::in) = (S::uo),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    S = java.lang.Long.toHexString(U64).toUpperCase();
+").
+
+:- pragma foreign_proc("C",
+    uint64_to_octal_string(U64::in) = (Str::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+        does_not_affect_liveness, no_sharing],
+"
+    char buffer[23]; // 22 for digits, 1 for nul.
+    sprintf(buffer, ""%"" PRIo64, U64);
+    MR_allocate_aligned_string_msg(Str, strlen(buffer), MR_ALLOC_ID);
+    strcpy(Str, buffer);
+").
+
+:- pragma foreign_proc("C#",
+    uint64_to_octal_string(U64::in) = (Str::uo),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    // We need to cast to a long here since C# does not provide an overloading
+    // of ToString() for ulongs.  This works since ToString() will use the
+    // unsigned representation for non-decimal bases.
+    Str = System.Convert.ToString((long) U64, 8);
+").
+
+:- pragma foreign_proc("Java",
+    uint64_to_octal_string(U64::in) = (Str::uo),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    Str = java.lang.Long.toOctalString(U64);
+").
+
+%---------------------%
+
  float_to_string(Float) = S2 :-
      float_to_string(Float, S2).

diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 1ff7d49..2ba8735 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -444,6 +444,7 @@ ORDINARY_PROGS = \
  	uint32_to_uint64 \
  	uint64_from_bytes \
  	uint64_ground_term \
+	uint64_string_conv \
  	uint64_switch_test \
  	uint8_switch_test \
  	uint_switch_test \
diff --git a/tests/hard_coded/uint64_string_conv.exp b/tests/hard_coded/uint64_string_conv.exp
index e69de29..ffe9df3 100644
--- a/tests/hard_coded/uint64_string_conv.exp
+++ b/tests/hard_coded/uint64_string_conv.exp
@@ -0,0 +1,29 @@
+Decimal                Octal                    Hex                   HEX 
+0                      0                        0                     0 
+1                      1                        1                     1 
+2                      2                        2                     2 
+3                      3                        3                     3 
+4                      4                        4                     4 
+7                      7                        7                     7 
+8                      10                       8                     8 
+9                      11                       9                     9 
+10                     12                       a                     A 
+11                     13                       b                     B 
+12                     14                       c                     C 
+13                     15                       d                     D 
+14                     16                       e                     E 
+15                     17                       f                     F 
+16                     20                       10                    10 
+32                     40                       20                    20 
+64                     100                      40                    40 
+127                    177                      7f                    7F 
+128                    200                      80                    80 
+255                    377                      ff                    FF 
+256                    400                      100                   100 
+32767                  77777                    7fff                  7FFF 
+65535                  177777                   ffff                  FFFF 
+2147483647             17777777777              7fffffff              7FFFFFFF 
+4294967295             37777777777              ffffffff              FFFFFFFF 
+9223372036854775807    777777777777777777777    7fffffffffffffff      7FFFFFFFFFFFFFFF 
+18446744073709551615   1777777777777777777777   ffffffffffffffff      FFFFFFFFFFFFFFFF 
+
diff --git a/tests/hard_coded/uint64_string_conv.m b/tests/hard_coded/uint64_string_conv.m
index e69de29..5b3e909 100644
--- a/tests/hard_coded/uint64_string_conv.m
+++ b/tests/hard_coded/uint64_string_conv.m
@@ -0,0 +1,69 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+% Test conversion of uint64s to strings.
+%---------------------------------------------------------------------------%
+
+:- module uint64_string_conv.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module list.
+:- import_module string.
+:- import_module uint64.
+
+main(!IO) :-
+    io.format("%-22s %-24s %-22s%-22s\n", [s("Decimal"), s("Octal"), s("Hex"),
+        s("HEX")], !IO),
+    list.foldl(do_test, test_values, !IO),
+    io.nl(!IO).
+
+:- pred do_test(uint64::in, io::di, io::uo) is det.
+
+do_test(U, !IO) :-
+    Decimal = uint64_to_string(U),
+    Octal = uint64_to_octal_string(U),
+    Hex = uint64_to_hex_string(U),
+    HexUC = uint64_to_uc_hex_string(U),
+    io.format("%-22s %-24s %-22s%-22s\n",
+        [s(Decimal), s(Octal), s(Hex), s(HexUC)], !IO).
+
+:- func test_values = list(uint64).
+
+test_values = [
+   0u64,
+   1u64,
+   2u64,
+   3u64,
+   4u64,
+   7u64,
+   8u64,
+   9u64,
+   10u64,
+   11u64,
+   12u64,
+   13u64,
+   14u64,
+   15u64,
+   16u64,
+   32u64,
+   64u64,
+   127u64,
+   128u64,
+   255u64,
+   256u64,
+   32767u64,
+   65535u64,
+   2147483647u64,
+   4294967295u64,
+   9223372036854775807u64,
+   18446744073709551615u64
+].


More information about the reviews mailing list