[m-rev.] for review: add array.generate/2 and array.generate_foldl/5

Julien Fischer juliensf at csse.unimelb.edu.au
Sun May 22 01:57:14 AEST 2011


Branches: main

Add procedures to the array module for creating and filling new arrays in a
single call.  (This avoids situations where the elements of a newly created
array are set to initial value which is then immediately overwritten.)

library/array.m:
 	Add the function array.generate/2 and the predicate
 	array.generate_foldl/5.

 	Add an XXX regarding some C# foreign code in this module.

NEWS:
 	Announce the new predicate and function.

tests/hard_coded/Mmakefile:
tests/hard_coded/array_gen.{m,exp}:
 	Test the new functionality.

Julien.

Index: NEWS
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/NEWS,v
retrieving revision 1.575
diff -u -r1.575 NEWS
--- NEWS	19 May 2011 16:20:54 -0000	1.575
+++ NEWS	21 May 2011 15:50:49 -0000
@@ -147,6 +147,9 @@
  * We have added additional modes with unique and mostly-unique accumulators
    to rbtree.foldl/4, rbtree.foldl2/6 and tree_bitset.foldl/4.

+* A new function, array.generate/2, and new predicate, array.generate_foldl/5,
+  can be used to create and fill new arrays.
+

  NEWS for Mercury 11.01
  ----------------------
Index: library/array.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/array.m,v
retrieving revision 1.185
diff -u -r1.185 array.m
--- library/array.m	20 May 2011 04:16:51 -0000	1.185
+++ library/array.m	21 May 2011 14:54:32 -0000
@@ -123,6 +123,33 @@
  :- func array(list(T)) = array(T).
  :- mode array(in) = array_uo is det.

+    % array.generate(Size, Generate) = Array:
+    % Create an array with bounds from 0 to Size - 1 using the function
+    % Generate to set the intial value of each element of the array.
+    % The initial value of the element at index K will be the result of
+    % calling the function Generate(K).
+    %
+:- func array.generate(int::in, (func(int) = T)::in) = (array(T)::array_uo)
+    is det.
+
+    % array.generate_foldl(Size, Generate, Array, !Acc):
+    % As above, but using a predicate with an accumulator threaded through it
+    % to generate the inital value of each element.
+    %
+:- pred array.generate_foldl(int, pred(int, T, A, A), array(T), A, A).
+:- mode array.generate_foldl(in, in(pred(in, out, in, out) is det),
+    array_uo, in, out) is det.
+:- mode array.generate_foldl(in, in(pred(in, out, mdi, muo) is det),
+    array_uo, mdi, muo) is det.
+:- mode array.generate_foldl(in, in(pred(in, out, di, uo) is det),
+    array_uo, di, uo) is det.
+:- mode array.generate_foldl(in, in(pred(in, out, in, out) is semidet),
+    array_uo, in, out) is semidet.
+:- mode array.generate_foldl(in, in(pred(in, out, mdi, muo) is semidet),
+    array_uo, mdi, muo) is semidet.
+:- mode array.generate_foldl(in, in(pred(in, out, di, uo) is semidet),
+    array_uo, di, uo) is semidet.
+
  %-----------------------------------------------------------------------------%

      % array.min returns the lower bound of the array.
@@ -766,6 +793,9 @@
  ").

  :- pragma foreign_code("C#", "
+
+// XXX What does the fill argument do here?
+//
  public static System.Array
  ML_new_array(int Size, object Item, bool fill)
  {
@@ -785,6 +815,20 @@
  }

  public static System.Array
+ML_unsafe_new_array(int Size, object Item)
+{
+    System.Array arr;
+
+    if (Item is int || Item is double || Item is char || Item is bool) {
+        arr = System.Array.CreateInstance(Item.GetType(), Size);
+    } else {
+        arr = new object[Size];
+    }
+    arr.SetValue(Item, 0);
+    return arr;
+} 
+
+public static System.Array
  ML_array_resize(System.Array arr0, int Size, object Item)
  {
      if (Size == 0) {
@@ -898,6 +942,34 @@
      return as;
  }

+public static Object
+ML_unsafe_new_array(int Size, Object Item)
+{
+    if (Item instanceof Integer) {
+        int[] as = new int[Size];
+        as[0] = (Integer) Item;
+        return as;
+    }
+    if (Item instanceof Double) {
+        double[] as = new double[Size];
+        as[0] = (Double) Item;
+        return as;
+    }
+    if (Item instanceof Character) {
+        char[] as = new char[Size];
+        as[0] = (Character) Item;
+        return as;
+    }
+    if (Item instanceof Boolean) {
+        boolean[] as = new boolean[Size];
+        as[0] = (Boolean) Item;
+        return as;
+    }
+    Object[] as = new Object[Size];
+    as[0] = Item;
+    return as;
+}
+
  public static int
  ML_array_size(Object Array)
  {
@@ -1066,6 +1138,103 @@

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

+array.generate(Size, GenFunc) = Array :-
+    compare(Result, Size, 0),
+    (
+        Result = (<),
+        error("array.generate: negative size")
+    ;
+        Result = (=),
+        make_empty_array(Array)
+    ;
+        Result = (>),
+        FirstElem = GenFunc(0),
+        Array0 = unsafe_init(Size, FirstElem),
+        Array = generate_2(1, Size, GenFunc, Array0)
+    ).
+
+:- func unsafe_init(int::in, T::in) = (array(T)::array_uo) is det.
+:- pragma foreign_proc("C",
+    unsafe_init(Size::in, FirstElem::in) = (Array::array_uo),
+    [promise_pure, will_not_call_mercury, thread_safe, will_not_modify_trail,
+        does_not_affect_liveness],
+"
+    ML_alloc_array(Array, Size + 1, MR_ALLOC_ID);
+    Array->size = Size; 
+    Array->elements[0] = FirstElem;
+").
+:- pragma foreign_proc("C#",
+    unsafe_init(Size::in, FirstElem::in) = (Array::array_uo),
+    [promise_pure, will_not_call_mercury, thread_safe],
+"
+    Array = array.ML_unsafe_new_array(Size, FirstElem);
+").
+:- pragma foreign_proc("Java",
+    unsafe_init(Size::in, FirstElem::in) = (Array::array_uo),
+    [promise_pure, will_not_call_mercury, thread_safe],
+"
+    Array = array.ML_unsafe_new_array(Size, FirstElem);
+").
+:- pragma foreign_proc("Erlang",
+    unsafe_init(Size::in, FirstElem::in) = (Array::array_uo),
+    [promise_pure, will_not_call_mercury, thread_safe],
+"
+    Array = erlang.make_tuple(Size, FirstElem)
+"). 
+
+:- func generate_2(int::in, int::in, (func(int) = T)::in, array(T)::array_di)
+    = (array(T)::array_uo) is det.
+
+generate_2(Index, Size, GenFunc, !.Array) = !:Array :- 
+    ( if Index < Size then
+        Elem = GenFunc(Index),
+        array.unsafe_set(Index, Elem, !Array),
+        !:Array = generate_2(Index + 1, Size, GenFunc, !.Array)
+      else
+        true
+    ).
+
+array.generate_foldl(Size, GenPred, Array, !Acc) :-
+    compare(Result, Size, 0),
+    (
+        Result = (<),
+        error("array.generate_foldl: negative size")
+    ;
+        Result = (=),
+        make_empty_array(Array)
+    ;
+        Result = (>),
+        GenPred(0, FirstElem, !Acc),
+        Array0 = unsafe_init(Size, FirstElem),
+        generate_foldl_2(1, Size, GenPred, Array0, Array, !Acc)
+    ).
+
+:- pred generate_foldl_2(int, int, pred(int, T, A, A),
+    array(T), array(T), A, A).
+:- mode generate_foldl_2(in, in, in(pred(in, out, in, out) is det),
+    array_di, array_uo, in, out) is det.
+:- mode generate_foldl_2(in, in, in(pred(in, out, mdi, muo) is det),
+    array_di, array_uo, mdi, muo) is det.
+:- mode generate_foldl_2(in, in, in(pred(in, out, di, uo) is det),
+    array_di, array_uo, di, uo) is det.
+:- mode generate_foldl_2(in, in, in(pred(in, out, in, out) is semidet),
+    array_di, array_uo, in, out) is semidet.
+:- mode generate_foldl_2(in, in, in(pred(in, out, mdi, muo) is semidet),
+    array_di, array_uo, mdi, muo) is semidet.
+:- mode generate_foldl_2(in, in, in(pred(in, out, di, uo) is semidet),
+    array_di, array_uo, di, uo) is semidet.
+
+generate_foldl_2(Index, Size, GenPred, !Array, !Acc) :-
+    ( if Index < Size then
+        GenPred(Index, Elem, !Acc),
+        array.unsafe_set(Index, Elem, !Array),
+        generate_foldl_2(Index + 1, Size, GenPred, !Array, !Acc)
+      else
+        true
+    ).
+
+%-----------------------------------------------------------------------------%
+
  array.min(A) = N :-
      array.min(A, N).

Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.402
diff -u -r1.402 Mmakefile
--- tests/hard_coded/Mmakefile	3 May 2011 04:31:19 -0000	1.402
+++ tests/hard_coded/Mmakefile	21 May 2011 11:42:26 -0000
@@ -10,6 +10,7 @@
  	agg \
  	array_test \
  	array_test2 \
+	array_gen \
  	backquoted_qualified_ops \
  	bag_various \
  	bidirectional \
Index: tests/hard_coded/array_gen.exp
===================================================================
RCS file: tests/hard_coded/array_gen.exp
diff -N tests/hard_coded/array_gen.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/array_gen.exp	21 May 2011 11:41:38 -0000
@@ -0,0 +1,12 @@
+array([0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
+Array2[0] = 0
+Array2[1] = 3
+Array2[2] = 6
+Array2[3] = 9
+Array2[4] = 12
+Array2[5] = 15
+Array2[6] = 18
+Array2[7] = 21
+Array2[8] = 24
+Array2[9] = 27
+array([0, 3, 6, 9, 12, 15, 18, 21, 24, 27])
Index: tests/hard_coded/array_gen.m
===================================================================
RCS file: tests/hard_coded/array_gen.m
diff -N tests/hard_coded/array_gen.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/array_gen.m	21 May 2011 11:41:38 -0000
@@ -0,0 +1,29 @@
+% Test array generators.
+%
+:- module array_gen.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module array.
+:- import_module int.
+:- import_module list.
+:- import_module string.
+
+main(!IO) :-
+	Array = array.generate(10, (func(I) = I * 2)),
+	io.write(Array, !IO),
+	io.nl(!IO),
+	array.generate_foldl(10, gen_elem, Array2, !IO),
+	io.write(Array2, !IO),
+	io.nl(!IO).
+
+:- pred gen_elem(int::in, int::out, io::di, io::uo) is det.
+
+gen_elem(Index, Result, !IO) :-
+	Result = Index * 3,
+	io.format("Array2[%d] = %d\n", [i(Index), i(Result)], !IO).

--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list