@@ -35,8 +35,10 @@ Elm.Native.Array.make = function(elm) {
35 function unsafeGet(i, array) {
35 function unsafeGet(i, array) {
36 for (var x = array.height; x > 0; x--) {
36 for (var x = array.height; x > 0; x--) {
37 var slot = i >> (x * 5);
37 var slot = i >> (x * 5);
38+ while (array.lengths[slot] <= i) {
38 if (slot > 0) {
41 if (slot > 0) {
39− while (array.lengths[slot - 1] > i) { slot--; }
40 i -= array.lengths[slot - 1];
42 i -= array.lengths[slot - 1];
42 array = array.table[slot];
44 array = array.table[slot];
@@ -311,10 +313,12 @@ Elm.Native.Array.make = function(elm) {
312 // Create new node.
314 // Create new node.
313 var newA = { ctor:"_Array", height:a.height
315 var newA = { ctor:"_Array", height:a.height
314− , table:a.table.slice(0, right + 1)
316+ , table:a.table.slice(0, right)
315− , lengths:a.lengths.slice(0, right + 1) };
317+ , lengths:a.lengths.slice(0, right) };
318+ if (sliced.table.length > 0) {
316− newA.table[right] = sliced;
319+ newA.table[right] = sliced;
317− newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
320+ newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
318 return newA;
322 return newA;
@@ -343,7 +347,7 @@ Elm.Native.Array.make = function(elm) {
343 var newA = { ctor:"_Array", height:a.height
347 var newA = { ctor:"_Array", height:a.height
344 , table:a.table.slice(left, a.table.length + 1)
348 , table:a.table.slice(left, a.table.length + 1)
345 , lengths:new Array(a.table.length - left) };
349 , lengths:new Array(a.table.length - left) };
346− newA.table[left] = sliced;
350+ newA.table[0] = sliced;
347 var len = 0;
351 var len = 0;
348 for (var i = 0; i < newA.table.length; i++) {
352 for (var i = 0; i < newA.table.length; i++) {
349 len += length(newA.table[i]);
353 len += length(newA.table[i]);
@@ -354,70 +358,116 @@ Elm.Native.Array.make = function(elm) {
356 // Appends two trees.
360 // Appends two trees.
357− // TODO: Add support for appending trees of different sizes. Current
358− // behavior will just rise the lower tree and then append them.
359 function append(a,b) {
361 function append(a,b) {
360− if (a.table.length == 0) return b;
362+ if (a.table.length === 0) {
361− if (b.table.length == 0) return a;
365+ if (b.table.length === 0) {
362− if (b.height > a.height) return append(parentise(a, b.height), b);
366+ return a;
363− if (a.height > b.height) return append(a, parentise(b, a.height));
367+ }
364− if (a.height == 0) return append(parentise(a, 1), parentise(b, 1));
366 var c = append_(a, b);
369 var c = append_(a, b);
371+ // Check if both nodes can be crunshed together.
372+ if (c[0].table.length + c[1].table.length <= M) {
373+ if (c[0].table.length === 0) {
367− if (c[1].table.length > 0) {
376+ if (c[1].table.length === 0) {
368− return siblise(c[0], c[1]);
377+ return c[0];
380+ // Adjust .table and .lengths
381+ c[0].table = c[0].table.concat(c[1].table);
382+ if (c[0].height > 0) {
383+ var len = length(c[0]);
384+ for (var i = 0; i < c[1].lengths.length; i++) {
385+ c[1].lengths[i] += len;
387+ c[0].lengths = c[0].lengths.concat(c[1].lengths);
370 return c[0];
390 return c[0];
393+ var toRemove = calcToRemove(a, b);
395+ c = shuffle(c[0], c[1], toRemove);
398+ return siblise(c[0], c[1]);
374− // Returns an array of two nodes. The second node _may_ be empty. This case
401+ // Returns an array of two nodes; right and left. One node _may_ be empty.
375− // needs to be handled by the function, that called append_. May be only
376− // called for trees with an minimal height of 1.
377 function append_(a, b) {
402 function append_(a, b) {
378− if (a.height == 1) {
403+ if (a.height === 0 && b.height === 0) {
379− // Check if balancing is needed and return based on that.
380− var toRemove = calcToRemove(a, b);
381− if (toRemove <= E) {
382− return [a,b];
404+ return [a, b];
385− return shuffle(a, b, toRemove);
407+ if (a.height !== 1 || b.height !== 1) {
408+ if (a.height === b.height) {
388− var appended = append_(botRight(a), botLeft(b));
411+ var appended = append_(botRight(a), botLeft(b));
389− a = nodeCopy(a), b = nodeCopy(b);
391− // Adjust the bottom right side of the new tree.
413+ insertRight(a, appended[1]);
392− a.table[a.table.length - 1] = appended[0];
414+ insertLeft(b, appended[0]);
393− a.lengths[a.lengths.length - 1] = length(appended[0])
415+ } else if (a.height > b.height) {
394− a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
416+ a = nodeCopy(a);
417+ var appended = append_(botRight(a), b);
396− // Adjust the bottom left side of the new tree.
397− if (appended[1].table.length > 0) {
398− b.table[0] = appended[1];
419+ insertRight(a, appended[0]);
399− b.lengths[0] = length(appended[1]);
420+ b = parentise(appended[1], appended[1].height + 1);
400− for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
401− len += length(b.table[i]);
404− } else {
421+ } else {
405− b.table.shift();
422+ b = nodeCopy(b);
406− for (var i = 1; i < b.lengths.length; i++) {
423+ var appended = append_(a, botLeft(b));
407− b.lengths[i] = b.lengths[i] - b.lengths[0];
424+
425+ var left = appended[0].table.length === 0 ? 0 : 1;
426+ var right = left === 0 ? 1 : 0;
427+ insertLeft(b, appended[left]);
428+ a = parentise(appended[right], appended[right].height + 1);
412 // Check if balancing is needed and return based on that.
432 // Check if balancing is needed and return based on that.
413− var toRemove = calcToRemove(a, b);
414− if (toRemove <= E || b.table.length == 0) {
433+ if (a.table.length === 0 || b.table.length === 0) {
415 return [a,b];
434 return [a,b];
437+ var toRemove = calcToRemove(a, b);
438+ if (toRemove <= E) {
418 return shuffle(a, b, toRemove);
441 return shuffle(a, b, toRemove);
444+ // Helperfunctions for append_. Replaces a child node at the side of the parent.
445+ function insertRight(parent, node) {
446+ var index = parent.table.length - 1;
447+ parent.table[index] = node;
448+ parent.lengths[index] = length(node)
449+ parent.lengths[index] += index > 0 ? parent.lengths[index - 1] : 0;
452+ function insertLeft(parent, node) {
453+ if (node.table.length > 0) {
454+ parent.table[0] = node;
455+ parent.lengths[0] = length(node);
457+ var len = length(parent.table[0]);
458+ for (var i = 1; i < parent.lengths.length; i++) {
459+ len += length(parent.table[i]);
460+ parent.lengths[i] = len;
463+ parent.table.shift();
464+ for (var i = 1; i < parent.lengths.length; i++) {
465+ parent.lengths[i] = parent.lengths[i] - parent.lengths[0];
467+ parent.lengths.shift();
421 // Returns the extra search steps for E. Refer to the paper.
471 // Returns the extra search steps for E. Refer to the paper.
422 function calcToRemove(a, b) {
472 function calcToRemove(a, b) {
423 var subLengths = 0;
473 var subLengths = 0;
@@ -558,7 +608,9 @@ Elm.Native.Array.make = function(elm) {
558 // find the exact slot via forward searching in "lengths". Returns the index.
608 // find the exact slot via forward searching in "lengths". Returns the index.
559 function getSlot(i, a) {
609 function getSlot(i, a) {
560 var slot = i >> (5 * a.height);
610 var slot = i >> (5 * a.height);
561− while (a.lengths[slot - 1] > i) { slot--; }
611+ while (a.lengths[slot] <= i) {
562 return slot;
614 return slot;