[m-rev.] for review: add array.fill/3, array.fill_range/5 and array2d.fill/3

Julien Fischer jfischer at opturion.com
Tue Nov 6 15:41:30 AEDT 2018


For review by anyone.

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

Add array.fill/3, array.fill_range/5 and array2d.fill/3.

library/array.m:
library/array2d.m:
     Add the new predicates.

     Add a note a likely problem with another predicate.

NEWS:
     Announce them.

tests/hard_coded/Mmakfile:
tests/hard_coded/array_fill.{m,exp}:
     Add a test case.

Julien.

diff --git a/NEWS b/NEWS
index 9484bf4..30a2292 100644
--- a/NEWS
+++ b/NEWS
@@ -461,15 +461,18 @@ Changes to the Mercury standard library:
     - semidet_greatest_index/1
     - foldl_corresponding/5
     - foldl2_corresponding/7
+   - fill/3
+   - fill_range/5

     The following functions in the array module have been deprecated:

     - least_index/1
     - greatest_index/1

-* The following function has been added to the array2d module:
+* The following predicates have been added to the array2d module:

     - is_empty/1
+   - fill/3

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

diff --git a/library/array.m b/library/array.m
index 9118bd4..a4dea56 100644
--- a/library/array.m
+++ b/library/array.m
@@ -264,7 +264,7 @@
  %:- mode unsafe_lookup(array_ui, in, out) is det.
  :- mode unsafe_lookup(in, in, out) is det.

-    % set sets the nth element of an array, and returns the
+    % set sets the N'th element of an array, and returns the
      % resulting array (good opportunity for destructive update ;-).
      % Throws an exception if the index is out of bounds.
      %
@@ -377,6 +377,19 @@
  :- func shrink(array(T), int) = array(T).
  :- mode shrink(array_di, in) = array_uo is det.

+    % fill(Item, Array0, Array):
+    % Sets every element of the array to `Elem'.
+    %
+:- pred fill(T::in, array(T)::array_di, array(T)::array_uo) is det.
+
+    % fill_range(Item, Lo, Hi, !Array):
+    % Sets every element of the array with index in the range Lo..Hi
+    % (inclusive) to Item. Throws a software_error1/ exception if Lo > Hi.
+    % Throws an index_out_of_bound/0 exception if Lo or Hi is out of bounds.
+    %
+:- pred fill_range(T::in, int::in, int::in,
+     array(T)::array_di, array(T)::array_uo) is det.
+
      % from_list takes a list, and returns an array containing those
      % elements in the same order that they occurred in the list.
      %
@@ -1130,7 +1143,6 @@ ML_shrink_array(System.Array arr, int Size)
          return tmp;
      }
  }
-
  ").

  :- pragma foreign_code("Java", "
@@ -1379,6 +1391,35 @@ ML_array_resize(Object Array0, int Size, Object Item)
          return Array;
      }
  }
+
+public static Object
+ML_array_fill(Object array, int fromIndex, int toIndex, Object Item)
+{
+    if (array == null) {
+        return null;
+    }
+
+    if (array instanceof int[]) {
+        java.util.Arrays.fill(((int []) array), fromIndex, toIndex, (Integer) Item);
+    } else if (array instanceof double[]) {
+        java.util.Arrays.fill(((double []) array), fromIndex, toIndex, (Double) Item);
+    } else if (array instanceof byte[]) {
+        java.util.Arrays.fill(((byte []) array), fromIndex, toIndex, (Byte) Item);
+    } else if (array instanceof short[]) {
+        java.util.Arrays.fill(((short []) array), fromIndex, toIndex,(Short) Item);
+    } else if (array instanceof long[]) {
+        java.util.Arrays.fill(((long []) array), fromIndex, toIndex,(Long) Item);
+    } else if (array instanceof char[]) {
+        java.util.Arrays.fill(((char []) array), fromIndex, toIndex,(Character) Item);
+    } else if (array instanceof boolean[]) {
+        java.util.Arrays.fill(((boolean []) array), fromIndex, toIndex,(Boolean) Item);
+    } else if (array instanceof float[]) {
+        java.util.Arrays.fill(((float []) array), fromIndex, toIndex,(Float) Item);
+    } else {
+        java.util.Arrays.fill(((Object []) array), fromIndex, toIndex,Item);
+    }
+    return array;
+}
  ").

  init(N, X) = A :-
@@ -2042,6 +2083,7 @@ shrink(Size, !Array) :-
      Array = list_to_tuple(lists:sublist(tuple_to_list(Array0), Size))
  ").

+% JJJ FIXME: why don't we handle the other primitive types below.
  :- pragma foreign_proc("Java",
      shrink_2(Size::in, Array0::array_di, Array::array_uo),
      [will_not_call_mercury, promise_pure, thread_safe],
@@ -2067,6 +2109,44 @@ shrink(Size, !Array) :-

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

+fill(Item, !Array) :-
+    array.bounds(!.Array, Min, Max),
+    do_fill_range(Item, Min, Max, !Array).
+
+fill_range(Item, Lo, Hi, !Array) :-
+    ( if Lo > Hi then
+        unexpected($pred, "empty range")
+    else if not in_bounds(!.Array, Lo) then
+        out_of_bounds_error(!.Array, Lo, "fill_range")
+    else if not in_bounds(!.Array, Hi) then
+        out_of_bounds_error(!.Array, Hi, "fill_range")
+    else
+        do_fill_range(Item, Lo, Hi, !Array)
+    ).
+
+%---------------------------------------------------------------------------%
+
+:- pred do_fill_range(T::in, int::in, int::in,
+     array(T)::array_di, array(T)::array_uo) is det.
+
+:- pragma foreign_proc("Java",
+    do_fill_range(Item::in, Lo::in, Hi::in,
+        Array0::array_di, Array::array_uo),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    Array = jmercury.array.ML_array_fill(Array0, Lo, Hi + 1, Item);
+").
+
+do_fill_range(Item, Lo, Hi, !Array) :-
+    ( if Lo =< Hi then
+        array.unsafe_set(Lo, Item, !Array),
+        do_fill_range(Item, Lo + 1, Hi, !Array)
+    else
+        true
+    ).
+
+%---------------------------------------------------------------------------%
+
  :- pragma foreign_decl("C", "
  extern void
  ML_copy_array(MR_ArrayPtr array, MR_ConstArrayPtr old_array);
diff --git a/library/array2d.m b/library/array2d.m
index 118fbe6..74ac1a9 100644
--- a/library/array2d.m
+++ b/library/array2d.m
@@ -128,6 +128,11 @@
  %:- mode lists(array2d_ui) = out is det.
  :- mode lists(in        ) = out is det.

+    % fill(Item, !Array2d:)
+    % Sets every element of the array to Item.
+    %
+:- pred fill(T::in, array2d(T)::array2d_di, array2d(T)::array2d_uo) is det.
+
  %---------------------------------------------------------------------------%
  %---------------------------------------------------------------------------%

@@ -234,5 +239,12 @@ lists_2(IJ, J, N, A, Xs, Xss) =
       ).

  %---------------------------------------------------------------------------%
+
+fill(Item, A0, A) :-
+    A0 = array2d(M, N, Array0),
+    array.fill(Item, Array0, Array),
+    A = array2d(M, N, Array).
+
+%---------------------------------------------------------------------------%
  :- end_module array2d.
  %---------------------------------------------------------------------------%
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 39b179c..3df1bcb 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -671,6 +671,7 @@ ifeq "$(findstring profdeep,$(GRADE))" ""
  	endif
  	NON_PROFDEEP_PROGS = \
  		$(NON_PROFDEEP_PROGS_2) \
+		array_fill \
  		allow_stubs \
  		arith_int16 \
  		arith_int32 \
diff --git a/tests/hard_coded/array_fill.exp b/tests/hard_coded/array_fill.exp
index e69de29..85df1f9 100644
--- a/tests/hard_coded/array_fill.exp
+++ b/tests/hard_coded/array_fill.exp
@@ -0,0 +1,102 @@
+-------FILL--------
+Array0 = array([])
+Fill = "bar"
+Array = array([])
+-------FILL--------
+Array0 = array(["foo"])
+Fill = "bar"
+Array = array(["bar"])
+-------FILL--------
+Array0 = array(["foo", "foo", "foo"])
+Fill = "bar"
+Array = array(["bar", "bar", "bar"])
+-------FILL--------
+Array0 = array(['a', 'a', 'a'])
+Fill = 'b'
+Array = array(['b', 'b', 'b'])
+-------FILL--------
+Array0 = array([561, 561, 561])
+Fill = -561
+Array = array([-561, -561, -561])
+-------FILL--------
+Array0 = array([34u, 34u, 34u])
+Fill = 41u
+Array = array([41u, 41u, 41u])
+-------FILL--------
+Array0 = array([-128i8, -128i8, -128i8])
+Fill = 127i8
+Array = array([127i8, 127i8, 127i8])
+-------FILL--------
+Array0 = array([0u8, 0u8, 0u8])
+Fill = 255u8
+Array = array([255u8, 255u8, 255u8])
+-------FILL--------
+Array0 = array([-32768i16, -32768i16, -32768i16])
+Fill = 32767i16
+Array = array([32767i16, 32767i16, 32767i16])
+-------FILL--------
+Array0 = array([0u16, 0u16, 0u16])
+Fill = 65535u16
+Array = array([65535u16, 65535u16, 65535u16])
+-------FILL--------
+Array0 = array([-2147483648i32, -2147483648i32, -2147483648i32])
+Fill = 2147483647i32
+Array = array([2147483647i32, 2147483647i32, 2147483647i32])
+-------FILL--------
+Array0 = array([0u32, 0u32, 0u32])
+Fill = 4294967295u32
+Array = array([4294967295u32, 4294967295u32, 4294967295u32])
+-------FILL--------
+Array0 = array([-9223372036854775808i64, -9223372036854775808i64, -9223372036854775808i64])
+Fill = 9223372036854775807i64
+Array = array([9223372036854775807i64, 9223372036854775807i64, 9223372036854775807i64])
+-------FILL--------
+Array0 = array([0u64, 0u64, 0u64])
+Fill = 18446744073709551615u64
+Array = array([18446744073709551615u64, 18446744073709551615u64, 18446744073709551615u64])
+-------FILL--------
+Array0 = array([dummy, dummy, dummy])
+Fill = dummy
+Array = array([dummy, dummy, dummy])
+-------FILL--------
+Array0 = array([orange, orange, orange])
+Fill = lemon
+Array = array([lemon, lemon, lemon])
+-------FILL--------
+Array0 = array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
+Fill = [4, 5, 6]
+Array = array([[4, 5, 6], [4, 5, 6], [4, 5, 6]])
+-------FILL--------
+Array0 = array([color(0u8, 0u8, 0u8), color(0u8, 0u8, 0u8), color(0u8, 0u8, 0u8)])
+Fill = color(255u8, 255u8, 255u8)
+Array = array([color(255u8, 255u8, 255u8), color(255u8, 255u8, 255u8), color(255u8, 255u8, 255u8)])
+-------FILL RANGE-------
+Array0 = array([1, 2, 3, 4, 5, 6])
+Lo = 3
+Hi = 1
+Fill = 561
+EXCEPTION: "predicate `array.fill_range\'/5: Unexpected: empty range"
+-------FILL RANGE-------
+Array0 = array([1, 2, 3, 4, 5, 6])
+Lo = -1
+Hi = 3
+Fill = 561
+INDEX-OUT-OF-BOUNDS: "fill_range: index -1 not in range [0, 5]"
+-------FILL RANGE-------
+Array0 = array([1, 2, 3, 4, 5, 6])
+Lo = 1
+Hi = 8
+Fill = 561
+INDEX-OUT-OF-BOUNDS: "fill_range: index 8 not in range [0, 5]"
+-------FILL RANGE-------
+Array0 = array([1, 2, 3, 4, 5, 6])
+Lo = 1
+Hi = 3
+Fill = 561
+Array = array([1, 561, 561, 561, 5, 6])
+-------FILL RANGE-------
+Array0 = array([])
+Lo = 0
+Hi = 0
+Fill = 561
+INDEX-OUT-OF-BOUNDS: "fill_range: index 0 not in range [0, -1]"
diff --git a/tests/hard_coded/array_fill.m b/tests/hard_coded/array_fill.m
index e69de29..e8729fe 100644
--- a/tests/hard_coded/array_fill.m
+++ b/tests/hard_coded/array_fill.m
@@ -0,0 +1,100 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+%
+% Test array.fill/3 and array.fill_range/5.
+%
+
+:- module array_fill.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is cc_multi.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module array.
+:- import_module exception.
+:- import_module list.
+
+:- type dummy ---> dummy.
+
+:- type fruit ---> apple ; orange ; lemon.
+
+:- type color
+    --->    color(
+                red   :: uint8,
+                green :: uint8,
+                blue  :: uint8
+            ).
+
+main(!IO) :-
+    test_fill(0, "foo", "bar", !IO),
+    test_fill(1, "foo", "bar", !IO),
+    test_fill(3, "foo", "bar", !IO),
+    test_fill(3, 'a', 'b', !IO),
+    test_fill(3, 561, -561, !IO),
+    test_fill(3, 34u, 41u, !IO),
+    test_fill(3, -128i8, 127i8, !IO),
+    test_fill(3, 0u8, 255u8, !IO),
+    test_fill(3, -32768i16, 32767i16, !IO),
+    test_fill(3, 0u16, 65535u16, !IO),
+    test_fill(3, -2147483648i32, 2147483647i32, !IO),
+    test_fill(3, 0u32, 4294967295u32, !IO),
+    test_fill(3, -9223372036854775808i64, 9223372036854775807i64, !IO),
+    test_fill(3, 0u64, 18446744073709551615u64, !IO),
+    test_fill(3, dummy, dummy, !IO),
+    test_fill(3, orange, lemon, !IO),
+    test_fill(3, [1, 2, 3], [4, 5, 6], !IO),
+    test_fill(3, color(0u8, 0u8, 0u8), color(255u8, 255u8, 255u8), !IO),
+
+    test_fill_range([1, 2, 3, 4, 5, 6], 561, 3, 1, !IO),
+    test_fill_range([1, 2, 3, 4, 5, 6], 561, -1, 3, !IO),
+    test_fill_range([1, 2, 3, 4, 5, 6], 561, 1, 8, !IO),
+    test_fill_range([1, 2, 3, 4, 5, 6], 561, 1, 3, !IO),
+    test_fill_range([], 561, 0, 0, !IO).
+
+:- pred test_fill(int::in, T::in, T::in, io::di, io::uo) is det.
+
+test_fill(Size, InitElem, FillElem, !IO) :-
+    io.write_string("-------FILL--------\n", !IO),
+    array.init(Size, InitElem, Array0),
+    io.write_string("Array0 = ", !IO),
+    io.write_line(Array0, !IO),
+    io.write_string("Fill = ", !IO),
+    io.write_line(FillElem, !IO),
+    array.fill(FillElem, Array0, Array),
+    io.write_string("Array = ", !IO),
+    io.write(Array, !IO),
+    io.nl(!IO).
+
+:- pred test_fill_range(list(T)::in, T::in, int::in, int::in,
+    io::di, io::uo) is cc_multi.
+
+test_fill_range(InitElems, FillElem, Lo, Hi, !IO) :-
+    io.write_string("-------FILL RANGE-------\n", !IO),
+    Array0 = array.from_list(InitElems),
+    io.write_string("Array0 = ", !IO),
+    io.write_line(Array0, !IO),
+    io.write_string("Lo = ", !IO),
+    io.write_line(Lo, !IO),
+    io.write_string("Hi = ", !IO),
+    io.write_line(Hi, !IO),
+    io.write_string("Fill = ", !IO),
+    io.write_line(FillElem, !IO),
+    ( try [] (
+        array.fill_range(FillElem, Lo, Hi, Array0, Array)
+    ) then
+        io.write_string("Array = ", !IO),
+        io.write_line(Array, !IO)
+    catch index_out_of_bounds(S) ->
+        io.write_string("INDEX-OUT-OF-BOUNDS: ", !IO),
+        io.write_line(S, !IO)
+    catch software_error(S) ->
+        io.write_string("EXCEPTION: ", !IO),
+        io.write_line(S, !IO)
+    ).


More information about the reviews mailing list