@@ -8,33 +8,35 @@ Elm.Native.Array.make = function(elm) {
88
99 var List = Elm.Native.List.make(elm);
1010
11− // An RRB-Tree has two distinct data types. A leaf which contains data as
12− // an array in _1, and a height in _0, that is always 0. A node has in
13− // addition its size table in _2, while _1 contains an array of nodes or
14− // leaves.
15−
16− // M is the maximal node size. 32 seems fast. E is the allowed increase
11+ // A RRB-Tree has two distinct data types.
12+ // Leaf -> "height" is always 0
13+ // "table" is an array of elements
14+ // Node -> "height" is always greater than 0
15+ // "table" is an array of child nodes
16+ // "lengths" is an array of accumulated lengths of the child nodes
17+
18+ // M is the maximal table size. 32 seems fast. E is the allowed increase
1719 // of search steps when concatting to find an index. Lower values will
1820 // decrease balancing, but will increase search steps.
1921 var M = 32;
2022 var E = 2;
2123
2224 // An empty array.
23− var empty = { ctor:"_Array", _0:0, _1:new Array() };
25+ var empty = { ctor:"_Array", height:0, table:new Array() };
2426
2527 // Gets the value at index i recursively.
2628 function get(i, a) {
27− if (a._0 == 0) {
28− if (i < a._1.length) {
29− return a._1[i];
29+ if (a.height == 0) {
30+ if (i < a.table.length) {
31+ return a.table[i];
3032 } else {
3133 throw new Error("Index "+ i +" on the array is out of range. Check the length first or you safeGet.");
3234 }
3335 }
3436
3537 var slot = getSlot(i, a);
36− var sub = slot > 0 ? a._2[slot-1] : 0;
37− return get(i - sub, a._1[slot]);
38+ var sub = slot > 0 ? a.lengths[slot-1] : 0;
39+ return get(i - sub, a.table[slot]);
3840 }
3941
4042 // Sets the value at the index i. Only the nodes leading to i will get
@@ -44,14 +46,14 @@ Elm.Native.Array.make = function(elm) {
4446 return a;
4547 }
4648 var newA = nodeCopy(a);
47− newA._1 = a._1.slice();
49+ newA.table = a.table.slice();
4850
49− if (a._0 == 0) {
50− newA._1[i] = item;
51+ if (a.height == 0) {
52+ newA.table[i] = item;
5153 } else {
5254 var slot = getSlot(i, a);
53− var sub = slot > 0 ? a._2[slot-1] : 0;
54− newA._1[slot] = set(i - sub, item, a._1[slot]);
55+ var sub = slot > 0 ? a.lengths[slot-1] : 0;
56+ newA.table[slot] = set(i - sub, item, a.table[slot]);
5557 }
5658 return newA;
5759 }
@@ -63,7 +65,7 @@ Elm.Native.Array.make = function(elm) {
6365 return pushed;
6466 }
6567
66− newTree = create(item, a._0);
68+ newTree = create(item, a.height);
6769 return siblise(a, newTree);
6870 }
6971
@@ -72,10 +74,10 @@ Elm.Native.Array.make = function(elm) {
7274 // null will be returned.
7375 function push_(item, a) {
7476 // Handle resursion stop at leaf level.
75− if (a._0 == 0) {
76− if (a._1.length < M) {
77− var newA = { ctor:"_Array", _0:0, _1:a._1.slice() };
78− newA._1.push(item);
77+ if (a.height == 0) {
78+ if (a.table.length < M) {
79+ var newA = { ctor:"_Array", height:0, table:a.table.slice() };
80+ newA.table.push(item);
7981 return newA;
8082 } else {
8183 return null;
@@ -89,19 +91,19 @@ Elm.Native.Array.make = function(elm) {
8991 // be updated.
9092 if (pushed != null) {
9193 var newA = nodeCopy(a);
92− newA._1[newA._1.length - 1] = pushed;
93− newA._2[newA._2.length - 1]++;
94+ newA.table[newA.table.length - 1] = pushed;
95+ newA.lengths[newA.lengths.length - 1]++;
9496 return newA
9597 }
9698
9799 // When there was no space left, check if there is space left
98100 // for a new slot with a tree which contains only the item
99101 // at the bottom.
100− if (a._1.length < M) {
101− var newSlot = create(item, a._0 - 1);
102+ if (a.table.length < M) {
103+ var newSlot = create(item, a.height - 1);
102104 var newA = nodeCopy(a);
103− newA._1.push(newSlot);
104− newA._2.push(newA._2[newA._2.length - 1] + length(newSlot));
105+ newA.table.push(newSlot);
106+ newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot));
105107 return newA
106108 } else {
107109 return null;
@@ -114,41 +116,41 @@ Elm.Native.Array.make = function(elm) {
114116 }
115117
116118 function elements_(list, a) {
117− for (var i = a._1.length - 1; i >= 0; i--) {
118− list = a._0 == 0 ? List.Cons(a._1[i], list) : elements_(list, a._1[i]);
119+ for (var i = a.table.length - 1; i >= 0; i--) {
120+ list = a.height == 0 ? List.Cons(a.table[i], list) : elements_(list, a.table[i]);
119121 }
120122 return list;
121123 }
122124
123125 // Maps a function over an array.
124126 function map(f, a) {
125− var newA = { ctor:"_Array", _0:a._0, _1:new Array(a._1) };
126− if (a._0 > 0) { newA._2 = a._2; }
127− for (var i = 0; i < a._1.length; i++) {
128− newA._1[i] = a._0 == 0 ? f(a._1[i]) : map(f, a._1[i]);
127+ var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
128+ if (a.height > 0) { newA.lengths = a.lengths; }
129+ for (var i = 0; i < a.table.length; i++) {
130+ newA.table[i] = a.height == 0 ? f(a.table[i]) : map(f, a.table[i]);
129131 }
130132 return newA;
131133 }
132134
133135 function assocMap(f, a) {
134− var newA = { ctor:"_Array", _0:a._0, _1:new Array(a._1) };
135− if (a._0 > 0) { newA._2 = a._2; }
136− for (var i = 0; i < a._1.length; i++) {
137− newA._1[i] = a._0 == 0 ? A2(f, i, a._1[i]) : assocMap(f, a._1[i]);
136+ var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
137+ if (a.height > 0) { newA.lengths = a.lengths; }
138+ for (var i = 0; i < a.table.length; i++) {
139+ newA.table[i] = a.height == 0 ? A2(f, i, a.table[i]) : assocMap(f, a.table[i]);
138140 }
139141 return newA;
140142 }
141143
142144 function foldl(f, b, a) {
143− for (var i = a._1.length - 1; i >= 0; i--) {
144− b = A2(f, a._0 == 0 ? a._1[i] : foldl(f, b, a._1[i]), b);
145+ for (var i = a.table.length - 1; i >= 0; i--) {
146+ b = A2(f, a.height == 0 ? a.table[i] : foldl(f, b, a.table[i]), b);
145147 }
146148 return b;
147149 }
148150
149151 function foldr(f, b, a) {
150− for (var i = 0; i < a._1.length; i++) {
151− b = A2(f, a._0 == 0 ? a._1[i] : foldr(f, b, a._1[i]), b);
152+ for (var i = 0; i < a.table.length; i++) {
153+ b = A2(f, a.height == 0 ? a.table[i] : foldr(f, b, a.table[i]), b);
152154 }
153155 return b;
154156 }
@@ -170,15 +172,15 @@ Elm.Native.Array.make = function(elm) {
170172 }
171173
172174 // Handle leaf level.
173− if (a._0 == 0) {
174− var newA = { ctor:"_Array", _0:0 };
175− newA._1 = a._1.slice(0, to + 1);
175+ if (a.height == 0) {
176+ var newA = { ctor:"_Array", height:0 };
177+ newA.table = a.table.slice(0, to + 1);
176178 return newA;
177179 }
178180
179181 // Slice the right recursively.
180182 var right = getSlot(to, a);
181− var sliced = sliceRight(to - (right > 0 ? a._2[right - 1] : 0), a._1[right]);
183+ var sliced = sliceRight(to - (right > 0 ? a.lengths[right - 1] : 0), a.table[right]);
182184
183185 // Maybe the a node is not even needed, as sliced contains the whole slice.
184186 if (right == 0) {
@@ -186,11 +188,11 @@ Elm.Native.Array.make = function(elm) {
186188 }
187189
188190 // Create new node.
189− var newA = { ctor:"_Array", _0:a._0
190− , _1:a._1.slice(0, right + 1)
191− , _2:a._2.slice(0, right + 1) };
192− newA._1[right] = sliced;
193− newA._2[right] = length(sliced) + (right > 0 ? newA._2[right - 1] : 0);
191+ var newA = { ctor:"_Array", height:a.height
192+ , table:a.table.slice(0, right + 1)
193+ , lengths:a.lengths.slice(0, right + 1) };
194+ newA.table[right] = sliced;
195+ newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
194196 return newA;
195197 }
196198
@@ -200,30 +202,30 @@ Elm.Native.Array.make = function(elm) {
200202 }
201203
202204 // Handle leaf level.
203− if (a._0 == 0) {
204− var newA = { ctor:"_Array", _0:0 };
205− newA._1 = a._1.slice(from, a._1.length + 1);
205+ if (a.height == 0) {
206+ var newA = { ctor:"_Array", height:0 };
207+ newA.table = a.table.slice(from, a.table.length + 1);
206208 return newA;
207209 }
208210
209211 // Slice the left recursively.
210212 var left = getSlot(from, a);
211− var sliced = sliceLeft(from - (left > 0 ? a._2[left - 1] : 0), a._1[left]);
213+ var sliced = sliceLeft(from - (left > 0 ? a.lengths[left - 1] : 0), a.table[left]);
212214
213215 // Maybe the a node is not even needed, as sliced contains the whole slice.
214− if (left == a._1.length - 1) {
216+ if (left == a.table.length - 1) {
215217 return sliced;
216218 }
217219
218220 // Create new node.
219− var newA = { ctor:"_Array", _0:a._0
220− , _1:a._1.slice(left, a._1.length + 1)
221− , _2:new Array(a._1.length - left) };
222− newA._1[left] = sliced;
221+ var newA = { ctor:"_Array", height:a.height
222+ , table:a.table.slice(left, a.table.length + 1)
223+ , lengths:new Array(a.table.length - left) };
224+ newA.table[left] = sliced;
223225 var len = 0;
224− for (var i = 0; i < newA._1.length; i++) {
225− len += length(newA._1[i]);
226− newA._2[i] = len;
226+ for (var i = 0; i < newA.table.length; i++) {
227+ len += length(newA.table[i]);
228+ newA.lengths[i] = len;
227229 }
228230
229231 return newA;
@@ -233,12 +235,12 @@ Elm.Native.Array.make = function(elm) {
233235 // TODO: Add support for concatting trees of different sizes. Current
234236 // behavior will just rise the lower tree and then concat them.
235237 function concat(a, b) {
236− if (b._0 > a._0) { return concat(parentise(a, b._0), b); }
237− if (a._0 > b._0) { return concat(a, parentise(b, a._0)); }
238− if (a._0 == 0) { return concat(parentise(a, 1), parentise(b, 1)); }
238+ if (b.height > a.height) { return concat(parentise(a, b.height), b); }
239+ if (a.height > b.height) { return concat(a, parentise(b, a.height)); }
240+ if (a.height == 0) { return concat(parentise(a, 1), parentise(b, 1)); }
239241
240242 var c = concat_(a, b);
241− if (c[1]._1.length > 0) {
243+ if (c[1].table.length > 0) {
242244 return siblise(c[0], c[1]);
243245 } else {
244246 return c[0];
@@ -249,7 +251,7 @@ Elm.Native.Array.make = function(elm) {
249251 // needs to be handled by the function, that called concat_. May be only
250252 // called for trees with an minimal height of 1.
251253 function concat_(a, b) {
252− if (a._0 == 1) {
254+ if (a.height == 1) {
253255 // Check if balancing is needed and return based on that.
254256 var toRemove = calcToRemove(a, b);
255257 if (toRemove <= E) {
@@ -263,29 +265,29 @@ Elm.Native.Array.make = function(elm) {
263265 a = nodeCopy(a), b = nodeCopy(b);
264266
265267 // Adjust the bottom right side of the new tree.
266− a._1[a._1.length - 1] = concated[0];
267− a._2[a._2.length - 1] = length(concated[0])
268− a._2[a._2.length - 1] += a._2.length > 1 ? a._2[a._2.length - 2] : 0;
268+ a.table[a.table.length - 1] = concated[0];
269+ a.lengths[a.lengths.length - 1] = length(concated[0])
270+ a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
269271
270272 // Adjust the bottom left side of the new tree.
271− if (concated[1]._1.length > 0) {
272− b._1[0] = concated[1];
273− b._2[0] = length(concated[1]);
274− for (var i = 1, len = length(b._1[0]); i < b._2.length; i++) {
275− len += length(b._1[i]);
276− b._2[i] = len;
273+ if (concated[1].table.length > 0) {
274+ b.table[0] = concated[1];
275+ b.lengths[0] = length(concated[1]);
276+ for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
277+ len += length(b.table[i]);
278+ b.lengths[i] = len;
277279 }
278280 } else {
279− b._1.shift();
280− for (var i = 1; i < b._2.length; i++) {
281− b._2[i] = b._2[i] - b._2[0];
281+ b.table.shift();
282+ for (var i = 1; i < b.lengths.length; i++) {
283+ b.lengths[i] = b.lengths[i] - b.lengths[0];
282284 }
283− b._2.shift();
285+ b.lengths.shift();
284286 }
285287
286288 // Check if balancing is needed and return based on that.
287289 var toRemove = calcToRemove(a, b);
288− if (toRemove <= E || b._1.length == 0) {
290+ if (toRemove <= E || b.table.length == 0) {
289291 return [a,b];
290292 }
291293
@@ -295,14 +297,14 @@ Elm.Native.Array.make = function(elm) {
295297 // Returns the extra search steps for E. Refer to the paper.
296298 function calcToRemove(a, b) {
297299 var subLengths = 0;
298− for (var i = 0; i < a._1.length; i++) {
299− subLengths += a._1[i]._1.length;
300+ for (var i = 0; i < a.table.length; i++) {
301+ subLengths += a.table[i].table.length;
300302 }
301− for (var i = 0; i < b._1.length; i++) {
302− subLengths += b._1[i]._1.length;
303+ for (var i = 0; i < b.table.length; i++) {
304+ subLengths += b.table[i].table.length;
303305 }
304306
305− var toRemove = a._1.length + b._1.length
307+ var toRemove = a.table.length + b.table.length
306308 return toRemove - (Math.floor((subLengths - 1) / M) + 1);
307309 }
308310
@@ -321,57 +323,57 @@ Elm.Native.Array.make = function(elm) {
321323
322324 // Creates a node or leaf with a given length at their arrays for perfomance.
323325 // Is only used by shuffle.
324− function createNode(height, length) {
326+ function createNode(h, length) {
325327 if (length < 0) { length = 0; }
326− var a = { ctor:"_Array", _0:height, _1:new Array(length) };
327− if (height > 0) {
328− a._2 = new Array(length);
328+ var a = { ctor:"_Array", height:h, table:new Array(length) };
329+ if (h > 0) {
330+ a.lengths = new Array(length);
329331 }
330332 return a;
331333 }
332334
333335 function saveSlot(a, b, index, slot) {
334− set2(a._1, b._1, index, slot);
336+ set2(a.table, b.table, index, slot);
335337
336− var l = (index == 0 || index == a._2.length) ?
337− 0 : get2(a._2, a._2, index - 1);
338− set2(a._2, b._2, index, l + length(slot));
338+ var l = (index == 0 || index == a.lengths.length) ?
339+ 0 : get2(a.lengths, a.lengths, index - 1);
340+ set2(a.lengths, b.lengths, index, l + length(slot));
339341 }
340342
341343 // Returns an array of two balanced nodes.
342344 function shuffle(a, b, toRemove) {
343− var newA = createNode(a._0, Math.min(M, a._1.length + b._1.length - toRemove));
344− var newB = createNode(a._0, newA._1.length - (a._1.length + b._1.length - toRemove));
345+ var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove));
346+ var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove));
345347
346348 // Skip the slots with size M. More precise: copy the slot references
347349 // to the new node
348350 var read = 0;
349− while (get2(a._1, b._1, read)._1.length % M == 0) {
350− set2(newA._1, newB._1, read, get2(a._1, b._1, read));
351− set2(newA._2, newB._2, read, get2(a._2, b._2, read));
351+ while (get2(a.table, b.table, read).table.length % M == 0) {
352+ set2(newA.table, newB.table, read, get2(a.table, b.table, read));
353+ set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read));
352354 read++;
353355 }
354356
355357 // Pulling items from left to right, caching in a slot before writing
356358 // it into the new nodes.
357359 var write = read;
358− var slot = new createNode(a._0 - 1, 0);
360+ var slot = new createNode(a.height - 1, 0);
359361 var from = 0;
360362
361363 // If the current slot is still containing data, then there will be at
362364 // least one more write, so we do not break this loop yet.
363− while (read - write - (slot._1.length > 0 ? 1 : 0) < toRemove) {
365+ while (read - write - (slot.table.length > 0 ? 1 : 0) < toRemove) {
364366 // Find out the max possible items for copying.
365− var source = get2(a._1, b._1, read);
366− var to = Math.min(M - slot._1.length, source._1.length)
367+ var source = get2(a.table, b.table, read);
368+ var to = Math.min(M - slot.table.length, source.table.length)
367369
368370 // Copy and adjust size table.
369− slot._1 = slot._1.concat(source._1.slice(from, to));
370− if (slot._0 > 0) {
371− var len = slot._2.length;
371+ slot.table = slot.table.concat(source.table.slice(from, to));
372+ if (slot.height > 0) {
373+ var len = slot.lengths.length;
372374 for (var i = len; i < len + to - from; i++) {
373− slot._2[i] = length(slot._1[i]);
374− slot._2[i] += (i > 0 ? slot._2[i - 1] : 0);
375+ slot.lengths[i] = length(slot.table[i]);
376+ slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0);
375377 }
376378 }
377379
@@ -379,60 +381,60 @@ Elm.Native.Array.make = function(elm) {
379381
380382 // Only proceed to next slots[i] if the current one was
381383 // fully copied.
382− if (source._1.length <= to) {
384+ if (source.table.length <= to) {
383385 read++; from = 0;
384386 }
385387
386388 // Only create a new slot if the current one is filled up.
387− if (slot._1.length == M) {
389+ if (slot.table.length == M) {
388390 saveSlot(newA, newB, write, slot);
389− slot = createNode(a._0 - 1,0);
391+ slot = createNode(a.height - 1,0);
390392 write++;
391393 }
392394 }
393395
394396 // Cleanup after the loop. Copy the last slot into the new nodes.
395− if (slot._1.length > 0) {
397+ if (slot.table.length > 0) {
396398 saveSlot(newA, newB, write, slot);
397399 write++;
398400 }
399401
400402 // Shift the untouched slots to the left
401− while (read < a._1.length + b._1.length ) {
402− saveSlot(newA, newB, write, get2(a._1, b._1, read));
403+ while (read < a.table.length + b.table.length ) {
404+ saveSlot(newA, newB, write, get2(a.table, b.table, read));
403405 read++; write++;
404406 }
405407
406408 return [newA, newB];
407409 }
408410
409− // Helper functions
410− function botRight(a) { return a._1[a._1.length - 1]; }
411− function botLeft(a) { return a._1[0]; }
411+ // Navigation functions
412+ function botRight(a) { return a.table[a.table.length - 1]; }
413+ function botLeft(a) { return a.table[0]; }
412414
413− // Copies a node for updating. Note that you should not use
414− // this if only updating one of _1 and _2 for performance reasons.
415+ // Copies a node for updating. Note that you should not use this if
416+ // only updating only one of "table" or "lengths" for performance reasons.
415417 function nodeCopy(a) {
416− var newA = { ctor:"_Array", _0:a._0
417− , _1:a._1.slice() };
418− if (a._0 > 0) { newA._2 = a._2.slice(); }
418+ var newA = { ctor:"_Array", height:a.height
419+ , table:a.table.slice() };
420+ if (a.height > 0) { newA.lengths = a.lengths.slice(); }
419421 return newA;
420422 }
421423
422424 // Returns how many items are in the tree.
423425 function length(a) {
424− if (a._0 == 0) {
425− return a._1.length;
426+ if (a.height == 0) {
427+ return a.table.length;
426428 } else {
427− return a._2[a._2.length - 1];
429+ return a.lengths[a.lengths.length - 1];
428430 }
429431 }
430432
431433 // Calculates in which slot the item probably is, then
432− // find the exact slot in the size table ._2. Returns the index.
434+ // find the exact slot in "lengths". Returns the index.
433435 function getSlot(i, a) {
434− var slot = Math.floor(i / (Math.pow(M, a._0)));
435− while (a._2[slot] <= i) {
436+ var slot = Math.floor(i / (Math.pow(M, a.height)));
437+ while (a.lengths[slot] <= i) {
436438 slot++
437439 }
438440 return slot;
@@ -440,33 +442,33 @@ Elm.Native.Array.make = function(elm) {
440442
441443 // Recursively creates a tree with a given height containing
442444 // only the given item.
443− function create(item, height) {
444− if (height == 0) {
445− return { ctor:"_Array", _0:0
446− , _1:[item] };
445+ function create(item, h) {
446+ if (h == 0) {
447+ return { ctor:"_Array", height:0
448+ , table:[item] };
447449 } else {
448− return { ctor:"_Array", _0:height
449− , _1:[create(item, height - 1)]
450− , _2:[1] };
450+ return { ctor:"_Array", height:h
451+ , table:[create(item, h - 1)]
452+ , lengths:[1] };
451453 }
452454 }
453455
454456 // Recursively creates a tree that contains the given tree.
455− function parentise(tree, height) {
456− if (height == tree._0) {
457+ function parentise(tree, h) {
458+ if (h == tree.height) {
457459 return tree;
458460 } else {
459− return { ctor:"_Array", _0:height
460− , _1:[parentise(tree, height - 1)]
461− , _2:[length(tree)] };
461+ return { ctor:"_Array", height:h
462+ , table:[parentise(tree, h - 1)]
463+ , lengths:[length(tree)] };
462464 }
463465 }
464466
465467 // Emphasizes blood brotherhood beneath two trees.
466468 function siblise(a, b) {
467− return { ctor:"_Array", _0:a._0 + 1
468− , _1:[a, b]
469− , _2:[length(a), length(a) + length(b)] };
469+ return { ctor:"_Array", height:a.height + 1
470+ , table:[a, b]
471+ , lengths:[length(a), length(a) + length(b)] };
470472 }
471473
472474 Elm.Native.Array.values = {