on master help sign in
Add native fromList and initialize functions
6bef808Christian Widera
libraries/Array.elm+2−5
@@ -27,7 +27,6 @@ import List
27
27
28data Array a = Array
28data Array a = Array
29
29
30−-- TODO: make this a native function
31{-| Initialize an array. `initialize n f` creates an array of length `n` with
30{-| Initialize an array. `initialize n f` creates an array of length `n` with
32the element at index `i` initialized to the result of `(f i)`.
31the element at index `i` initialized to the result of `(f i)`.
33
32
@@ -36,8 +35,7 @@ the element at index `i` initialized to the result of `(f i)`.
36 initialize 4 (always 0) == fromList [0,0,0,0]
35 initialize 4 (always 0) == fromList [0,0,0,0]
37-}
36-}
38initialize : Int -> (Int -> a) -> Array a
37initialize : Int -> (Int -> a) -> Array a
39−initialize n initializer =
38+initialize = Native.Array.initialize
40− fromList <| List.map initializer [ 0 .. n - 1 ]
41
39
42{-| Creates an array with a given length, filled with a default element.
40{-| Creates an array with a given length, filled with a default element.
43
41
@@ -49,10 +47,9 @@ Notice that `repeat 3 x` is the same as `initialize 3 (always x)`.
49repeat : Int -> a -> Array a
47repeat : Int -> a -> Array a
50repeat n e = initialize n (always e)
48repeat n e = initialize n (always e)
51
49
52−-- TODO: make this a native function.
53{-| Create an array from a list. -}
50{-| Create an array from a list. -}
54fromList : [a] -> Array a
51fromList : [a] -> Array a
55−fromList xs = List.foldl Native.Array.push Native.Array.empty xs
52+fromList xs = Native.Array.fromList xs
56
53
57{-| Create a list of elements from an array.
54{-| Create a list of elements from an array.
58
55
libraries/Native/Array.js+98
@@ -61,6 +61,102 @@ Elm.Native.Array.make = function(elm) {
61 return newA;
61 return newA;
62 }
62 }
63
63
64+ function initialize(len, f) {
65+ if (len == 0) { return empty; }
66+ var h = Math.floor(Math.log(len)/Math.log(M));
67+ return initialize_(f, h, 0, len);
68+ }
69+
70+ function initialize_(f, h, from, to) {
71+ if (h == 0) {
72+ var table = new Array((to - from) % (M + 1));
73+ for (var i = 0; i < table.length; i++) {
74+ table[i] = f(from + i);
75+ }
76+ return { ctor:"_Array", height:0, table:table };
77+ }
78+
79+ var step = Math.pow(M, h);
80+ var table = new Array(Math.ceil((to - from) / step));
81+ var lengths = new Array(table.length);
82+ for (var i = 0; i < table.length; i++) {
83+ table[i] = initialize_( f, h - 1, from + (i * step)
84+ , Math.min(from + ((i + 1) * step), to));
85+ if (i > 0) { lengths[i] = lengths[i-1] + length(table[i]); }
86+ }
87+ return { ctor:"_Array", height:h, table:table, lengths:lengths };
88+ }
89+
90+ function fromList(list) {
91+ if (list == List.Nil) { return empty; }
92+
93+ // Allocate M sized blocks (table) and write list elements to it.
94+ var table = new Array(M);
95+ var nodes = new Array();
96+ var i = 0;
97+
98+ while (list.ctor !== '[]') {
99+ table[i] = list._0;
100+ list = list._1;
101+ i++;
102+
103+ // table is full, so we can push a leaf containing it into the
104+ // next node.
105+ if (i == M) {
106+ fromListPush({ ctor:"_Array", height:0, table:table }
107+ , nodes);
108+ table = new Array(M);
109+ i = 0;
110+ }
111+ }
112+
113+ // Maybe there is something left on the table.
114+ if (i > 0) {
115+ fromListPush({ ctor:"_Array", height:0, table:table.splice(0,i) }
116+ , nodes);
117+ }
118+
119+ // Go through all of the nodes and eventually push them into higher nodes.
120+ for (var h = 0; h < nodes.length - 1; h++) {
121+ if (nodes[h].table.length > 0) {
122+ fromListPush(nodes[h], nodes);
123+ }
124+ }
125+
126+ var head = nodes[nodes.length - 1];
127+ if (head.height > 0 && head.table.length == 1) {
128+ return head.table[0];
129+ } else {
130+ return head;
131+ }
132+ }
133+
134+ // Push a node into a higher node as a child.
135+ function fromListPush(toPush, nodes) {
136+ var h = toPush.height;
137+
138+ // Maybe the node on this height does not exist.
139+ if (nodes.length == h) {
140+ nodes.push({ ctor:"_Array", height:h + 1
141+ , table:new Array()
142+ , lengths:new Array() });
143+ }
144+
145+ nodes[h].table.push(toPush);
146+ var len = length(toPush);
147+ if (nodes[h].lengths.length > 0) {
148+ len += nodes[h].lengths[nodes[h].lengths.length - 1];
149+ }
150+ nodes[h].lengths.push(len);
151+
152+ if (nodes[h].table.length == M) {
153+ fromListPush(nodes[h], nodes);
154+ nodes[h] = { ctor:"_Array", height:h + 1
155+ , table:new Array()
156+ , lengths:new Array() };
157+ }
158+ }
159+
64 // Pushes an item via push_ to the bottom right of a tree.
160 // Pushes an item via push_ to the bottom right of a tree.
65 function push(item, a) {
161 function push(item, a) {
66 var pushed = push_(item, a);
162 var pushed = push_(item, a);
@@ -477,7 +573,9 @@ Elm.Native.Array.make = function(elm) {
477
573
478 Elm.Native.Array.values = {
574 Elm.Native.Array.values = {
479 empty:empty,
575 empty:empty,
576+ fromList:fromList,
480 toList:toList,
577 toList:toList,
578+ initialize:F2(initialize),
481 append:F2(append),
579 append:F2(append),
482 push:F2(push),
580 push:F2(push),
483 slice:F3(slice),
581 slice:F3(slice),