[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