[m-rev.] for review: conversion from array/1 to array2d/1

Julien Fischer jfischer at opturion.com
Mon Nov 19 16:11:27 AEDT 2018


For review by anyone.

Conversion from array/1 to array2d/1.

Add a function that uses an array/1 value to construct an array2d/1 value
without allocating new memory for the element storage or traversing the
elements.

library/array2d.m:
     Add a function that creates an array2d/1 from an array/1 value

     Fix minor documentation issues:
     - re-order the declarations so that of from_lists/1 is directly below
       that of array2d/1.

     - s/a/an/ in a few spots.

     - add missing apostrophes.

NEWS:
     Announce the new function.

tests/hard_coded/Mmakefile:
tests/hard_coded/array2d_from_array.{m,exp}:
     Add a test case.

Julien.

diff --git a/NEWS b/NEWS
index 88d36a7..8463bba 100644
--- a/NEWS
+++ b/NEWS
@@ -474,10 +474,11 @@ Changes to the Mercury standard library:
     - least_index/1
     - greatest_index/1

-* The following predicates have been added to the array2d module:
+* The following predicates and functions have been added to the array2d module:

     - is_empty/1
     - fill/3
+   - from_array/3

  * The following predicates have been added to the time module:

diff --git a/library/array2d.m b/library/array2d.m
index c84a081..61f9837 100644
--- a/library/array2d.m
+++ b/library/array2d.m
@@ -25,7 +25,7 @@

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

-    % A array2d is a two-dimensional array stored in row-major order
+    % An array2d is a two-dimensional array stored in row-major order
      % (that is, the elements of the first row in left-to-right
      % order, followed by the elements of the second row and so forth.)
      %
@@ -46,7 +46,7 @@
  :- func init(int, int, T) = array2d(T).
  :- mode init(in, in, in) = array2d_uo is det.

-    % array2d([[X11, ..., X1N], ..., [XM1, ..., XMN]]) constructs a array2d
+    % array2d([[X11, ..., X1N], ..., [XM1, ..., XMN]]) constructs an array2d
      % of size M * N, with the special case that bounds(array2d([]), 0, 0).
      %
      % An exception is thrown if the sublists are not all the same length.
@@ -54,6 +54,20 @@
  :- func array2d(list(list(T))) = array2d(T).
  :- mode array2d(in) = array2d_uo is det.

+    % A synonym for the above.
+    %
+:- func from_lists(list(list(T))) = array2d(T).
+:- mode from_lists(in) = array2d_uo is det.
+
+    % from_array(M, N, Array) constructs an array2d of size M * N whose
+    % elements are taken from Array.  The elements in Array are added to
+    % the array2d in row-major order (see above).
+    % Throws an exception if M < or N < 0, or if the number of elements in
+    % Array does not equal M * N.
+    %
+:- func from_array(int, int, array(T)) = array2d(T).
+:- mode from_array(in, in, array_di) = array2d_uo is det.
+
      % is_empty(Array):
      % True iff Array contains zero elements.
      %
@@ -61,11 +75,6 @@
  %:- mode is_empty(array2d_ui) is semidet.
  :- mode is_empty(in) is semidet.

-    % A synonym for the above.
-    %
-:- func from_lists(list(list(T))) = array2d(T).
-:- mode from_lists(in) = array2d_uo is det.
-
      % bounds(array2d([[X11, ..., X1N], ..., [XM1, ..., XMN]), M, N)
      %
  :- pred bounds(array2d(T), int, int).
@@ -80,7 +89,7 @@
  :- mode in_bounds(in,       in,  in ) is semidet.

      % array2d([[X11, ..., X1N], ..., [XM1, ..., XMN]]) ^ elem(I, J) = X
-    % where X is the J+1th element of the I+1th row (that is, indices
+    % where X is the J+1'th element of the I+1'th row (that is, indices
      % start from zero.)
      %
      % An exception is thrown unless 0 =< I < M, 0 =< J < N.
@@ -175,11 +184,34 @@ array2d(Xss @ [Xs | _]) = T :-
            else  func_error("array2d.array2d/1: non-rectangular list of lists")
          ).

+from_lists(Xss) = array2d(Xss).
+
+from_array(M, N, Array) = Array2d :-
+    ( if
+        M >= 0,
+        N >= 0
+    then
+        array.size(Array, Size),
+        compare(Result, Size, M * N),
+        (
+            Result = (=),
+            Array2d = array2d(M, N, Array)
+        ;
+            Result = (>),
+            error("array2d.from_array: too many elements")
+        ;
+            Result = (<),
+            error("array2d.from_array: too few elements")
+        )
+    else
+        error("array2d.from_array: bounds must be non-negative")
+    ).
+
+%---------------------------------------------------------------------------%
+
  is_empty(array2d(_, _, A)) :-
      array.is_empty(A).

-from_lists(Xss) = array2d(Xss).
-
  %---------------------------------------------------------------------------%

  bounds(array2d(M, N, _A), M, N).
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index bbbbc97..dd39c13 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -676,6 +676,7 @@ ifeq "$(findstring profdeep,$(GRADE))" ""
  		array_resize \
  		array_shrink \
  		array_swap \
+		array2d_from_array \
  		allow_stubs \
  		arith_int16 \
  		arith_int32 \
diff --git a/tests/hard_coded/array2d_from_array.exp b/tests/hard_coded/array2d_from_array.exp
index e69de29..511ecf9 100644
--- a/tests/hard_coded/array2d_from_array.exp
+++ b/tests/hard_coded/array2d_from_array.exp
@@ -0,0 +1,45 @@
+------FROM ARRAY------
+Array = array([])
+M = -1
+N = -1
+EXCEPTION: "array2d.from_array: bounds must be non-negative"
+------FROM ARRAY------
+Array = array([])
+M = 0
+N = -1
+EXCEPTION: "array2d.from_array: bounds must be non-negative"
+------FROM ARRAY------
+Array = array([])
+M = -1
+N = 0
+EXCEPTION: "array2d.from_array: bounds must be non-negative"
+------FROM ARRAY------
+Array = array([])
+M = 2
+N = 2
+EXCEPTION: "array2d.from_array: too few elements"
+------FROM ARRAY------
+Array = array([1, 2, 3, 4, 5])
+M = 2
+N = 2
+EXCEPTION: "array2d.from_array: too many elements"
+------FROM ARRAY------
+Array = array([])
+M = 0
+N = 0
+Array2d = array2d(0, 0, array([]))
+------FROM ARRAY------
+Array = array([1])
+M = 1
+N = 1
+Array2d = array2d(1, 1, array([1]))
+------FROM ARRAY------
+Array = array([1, 2, 3, 4])
+M = 2
+N = 2
+Array2d = array2d(2, 2, array([1, 2, 3, 4]))
+------FROM ARRAY------
+Array = array([1, 2, 3, 4, 5, 6])
+M = 2
+N = 3
+Array2d = array2d(2, 3, array([1, 2, 3, 4, 5, 6]))
diff --git a/tests/hard_coded/array2d_from_array.m b/tests/hard_coded/array2d_from_array.m
index e69de29..219bb3c 100644
--- a/tests/hard_coded/array2d_from_array.m
+++ b/tests/hard_coded/array2d_from_array.m
@@ -0,0 +1,56 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test array2d.from_array/3.
+%
+
+:- module array2d_from_array.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is cc_multi.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module array.
+:- import_module array2d.
+:- import_module exception.
+:- import_module list.
+
+main(!IO) :-
+    test_from_array([], -1, -1, !IO),
+    test_from_array([], 0, -1, !IO),
+    test_from_array([], -1, 0, !IO),
+    test_from_array([], 2, 2, !IO),              % Too few elements.
+    test_from_array([1, 2, 3, 4, 5], 2, 2, !IO), % Too many elements.
+    test_from_array([], 0, 0, !IO),
+    test_from_array([1], 1, 1, !IO),
+    test_from_array([1, 2, 3, 4], 2, 2, !IO),
+    test_from_array([1, 2, 3, 4, 5, 6], 2, 3, !IO).
+
+:- pred test_from_array(list(int)::in, int::in, int::in,
+    io::di, io::uo) is cc_multi.
+
+test_from_array(Elems, M, N, !IO) :-
+    io.write_string("------FROM ARRAY------\n", !IO),
+    Array = array.from_list(Elems),
+    io.write_string("Array = ", !IO),
+    io.write_line(Array, !IO),
+    io.write_string("M = ", !IO),
+    io.write_line(M, !IO),
+    io.write_string("N = ", !IO),
+    io.write_line(N, !IO),
+    ( try []
+        Array2d = array2d.from_array(M, N, Array)
+    then
+        io.write_string("Array2d = ", !IO),
+        io.write_line(Array2d, !IO)
+    catch software_error(E) ->
+        io.write_string("EXCEPTION: ", !IO),
+        io.write_line(E, !IO)
+    ).


More information about the reviews mailing list