@@ -1,711 +0,0 @@
1−Elm.Native.Array = {};
2−Elm.Native.Array.make = function(elm) {
3− elm.Native = elm.Native || {};
4− elm.Native.Array = elm.Native.Array || {};
5− if (elm.Native.Array.values) return elm.Native.Array.values;
6− if ('values' in Elm.Native.Array)
7− return elm.Native.Array.values = Elm.Native.Array.values;
8−
9− var List = Elm.Native.List.make(elm);
10−
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
19− // of search steps when concatting to find an index. Lower values will
20− // decrease balancing, but will increase search steps.
21− var M = 32;
22− var E = 2;
23−
24− // An empty array.
25− var empty = { ctor:"_Array", height:0, table:new Array() };
26−
27− function get(i, array) {
28− if (i < 0 || i >= length(array)) {
29− throw new Error("Index " + i + " is out of range. Check the length of " +
30− "your array first or use getMaybe or getWithDefault.");
31− }
32− return unsafeGet(i, array);
33− }
34−
35− function unsafeGet(i, array) {
36− for (var x = array.height; x > 0; x--) {
37− var slot = i >> (x * 5);
38− while (array.lengths[slot] <= i) {
39− slot++;
40− }
41− if (slot > 0) {
42− i -= array.lengths[slot - 1];
43− }
44− array = array.table[slot];
45− }
46− return array.table[i];
47− }
48−
49− // Sets the value at the index i. Only the nodes leading to i will get
50− // copied and updated.
51− function set(i, item, array) {
52− if (i < 0 || length(array) <= i) {
53− return array;
54− }
55− return unsafeSet(i, item, array);
56− }
57−
58− function unsafeSet(i, item, array) {
59− array = nodeCopy(array);
60−
61− if (array.height == 0) {
62− array.table[i] = item;
63− } else {
64− var slot = getSlot(i, array);
65− if (slot > 0) {
66− i -= array.lengths[slot - 1];
67− }
68− array.table[slot] = unsafeSet(i, item, array.table[slot]);
69− }
70− return array;
71− }
72−
73− function initialize(len, f) {
74− if (len == 0) { return empty; }
75− var h = Math.floor(Math.log(len)/Math.log(M));
76− return initialize_(f, h, 0, len);
77− }
78−
79− function initialize_(f, h, from, to) {
80− if (h == 0) {
81− var table = new Array((to - from) % (M + 1));
82− for (var i = 0; i < table.length; i++) {
83− table[i] = f(from + i);
84− }
85− return { ctor:"_Array", height:0, table:table };
86− }
87−
88− var step = Math.pow(M, h);
89− var table = new Array(Math.ceil((to - from) / step));
90− var lengths = new Array(table.length);
91− for (var i = 0; i < table.length; i++) {
92− table[i] = initialize_( f, h - 1, from + (i * step)
93− , Math.min(from + ((i + 1) * step), to));
94− lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0);
95− }
96− return { ctor:"_Array", height:h, table:table, lengths:lengths };
97− }
98−
99− function fromList(list) {
100− if (list == List.Nil) { return empty; }
101−
102− // Allocate M sized blocks (table) and write list elements to it.
103− var table = new Array(M);
104− var nodes = new Array();
105− var i = 0;
106−
107− while (list.ctor !== '[]') {
108− table[i] = list._0;
109− list = list._1;
110− i++;
111−
112− // table is full, so we can push a leaf containing it into the
113− // next node.
114− if (i == M) {
115− fromListPush({ ctor:"_Array", height:0, table:table }
116− , nodes);
117− table = new Array(M);
118− i = 0;
119− }
120− }
121−
122− // Maybe there is something left on the table.
123− if (i > 0) {
124− fromListPush({ ctor:"_Array", height:0, table:table.splice(0,i) }
125− , nodes);
126− }
127−
128− // Go through all of the nodes and eventually push them into higher nodes.
129− for (var h = 0; h < nodes.length - 1; h++) {
130− if (nodes[h].table.length > 0) {
131− fromListPush(nodes[h], nodes);
132− }
133− }
134−
135− var head = nodes[nodes.length - 1];
136− if (head.height > 0 && head.table.length == 1) {
137− return head.table[0];
138− } else {
139− return head;
140− }
141− }
142−
143− // Push a node into a higher node as a child.
144− function fromListPush(toPush, nodes) {
145− var h = toPush.height;
146−
147− // Maybe the node on this height does not exist.
148− if (nodes.length == h) {
149− nodes.push({ ctor:"_Array", height:h + 1
150− , table:new Array()
151− , lengths:new Array() });
152− }
153−
154− nodes[h].table.push(toPush);
155− var len = length(toPush);
156− if (nodes[h].lengths.length > 0) {
157− len += nodes[h].lengths[nodes[h].lengths.length - 1];
158− }
159− nodes[h].lengths.push(len);
160−
161− if (nodes[h].table.length == M) {
162− fromListPush(nodes[h], nodes);
163− nodes[h] = { ctor:"_Array", height:h + 1
164− , table:new Array()
165− , lengths:new Array() };
166− }
167− }
168−
169− // Pushes an item via push_ to the bottom right of a tree.
170− function push(item, a) {
171− var pushed = push_(item, a);
172− if (pushed !== null) {
173− return pushed;
174− }
175−
176− var newTree = create(item, a.height);
177− return siblise(a, newTree);
178− }
179−
180− // Recursively tries to push an item to the bottom-right most
181− // tree possible. If there is no space left for the item,
182− // null will be returned.
183− function push_(item, a) {
184− // Handle resursion stop at leaf level.
185− if (a.height == 0) {
186− if (a.table.length < M) {
187− var newA = { ctor:"_Array", height:0, table:a.table.slice() };
188− newA.table.push(item);
189− return newA;
190− } else {
191− return null;
192− }
193− }
194−
195− // Recursively push
196− var pushed = push_(item, botRight(a));
197−
198− // There was space in the bottom right tree, so the slot will
199− // be updated.
200− if (pushed != null) {
201− var newA = nodeCopy(a);
202− newA.table[newA.table.length - 1] = pushed;
203− newA.lengths[newA.lengths.length - 1]++;
204− return newA
205− }
206−
207− // When there was no space left, check if there is space left
208− // for a new slot with a tree which contains only the item
209− // at the bottom.
210− if (a.table.length < M) {
211− var newSlot = create(item, a.height - 1);
212− var newA = nodeCopy(a);
213− newA.table.push(newSlot);
214− newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot));
215− return newA
216− } else {
217− return null;
218− }
219− }
220−
221− // Converts an array into a list of elements.
222− function toList(a) {
223− return toList_(List.Nil, a);
224− }
225−
226− function toList_(list, a) {
227− for (var i = a.table.length - 1; i >= 0; i--) {
228− list = a.height == 0 ? List.Cons(a.table[i], list) : toList_(list, a.table[i]);
229− }
230− return list;
231− }
232−
233− // Maps a function over the elements of an array.
234− function map(f, a) {
235− var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
236− if (a.height > 0) { newA.lengths = a.lengths; }
237− for (var i = 0; i < a.table.length; i++) {
238− newA.table[i] = a.height == 0 ? f(a.table[i]) : map(f, a.table[i]);
239− }
240− return newA;
241− }
242−
243− // Maps a function over the elements with their index as first argument.
244− function indexedMap(f, a) {
245− return indexedMap_(f, a, 0);
246− }
247−
248− function indexedMap_(f, a, from) {
249− var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
250− if (a.height > 0) { newA.lengths = a.lengths; }
251− for (var i = 0; i < a.table.length; i++) {
252− newA.table[i] = a.height == 0 ? A2(f, from + i, a.table[i])
253− : indexedMap_( f, a.table[i]
254− , i == 0 ? 0 : a.lengths[i - 1]);
255− }
256− return newA;
257− }
258−
259− function foldl(f, b, a) {
260− if (a.height == 0) {
261− for (var i = 0; i < a.table.length; i++) {
262− b = A2(f, a.table[i], b);
263− }
264− } else {
265− for (var i = 0; i < a.table.length; i++) {
266− b = foldl(f, b, a.table[i]);
267− }
268− }
269− return b;
270− }
271−
272− function foldr(f, b, a) {
273− if (a.height == 0) {
274− for (var i = a.table.length; i--; ) {
275− b = A2(f, a.table[i], b);
276− }
277− } else {
278− for (var i = a.table.length; i--; ) {
279− b = foldl(f, b, a.table[i]);
280− }
281− }
282− return b;
283− }
284−
285− // TODO: currently, it slices the right, then the left. This can be
286− // optimized.
287− function slice(from, to, a) {
288− if (from < 0) { from += length(a); }
289− if (to < 0) { to += length(a); }
290− return sliceLeft(from, sliceRight(to, a));
291− }
292−
293− function sliceRight(to, a) {
294− if (to == length(a)) {
295− return a;
296− }
297−
298− // Handle leaf level.
299− if (a.height == 0) {
300− var newA = { ctor:"_Array", height:0 };
301− newA.table = a.table.slice(0, to);
302− return newA;
303− }
304−
305− // Slice the right recursively.
306− var right = getSlot(to, a);
307− var sliced = sliceRight(to - (right > 0 ? a.lengths[right - 1] : 0), a.table[right]);
308−
309− // Maybe the a node is not even needed, as sliced contains the whole slice.
310− if (right == 0) {
311− return sliced;
312− }
313−
314− // Create new node.
315− var newA = { ctor:"_Array", height:a.height
316− , table:a.table.slice(0, right)
317− , lengths:a.lengths.slice(0, right) };
318− if (sliced.table.length > 0) {
319− newA.table[right] = sliced;
320− newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
321− }
322− return newA;
323− }
324−
325− function sliceLeft(from, a) {
326− if (from == 0) {
327− return a;
328− }
329−
330− // Handle leaf level.
331− if (a.height == 0) {
332− var newA = { ctor:"_Array", height:0 };
333− newA.table = a.table.slice(from, a.table.length + 1);
334− return newA;
335− }
336−
337− // Slice the left recursively.
338− var left = getSlot(from, a);
339− var sliced = sliceLeft(from - (left > 0 ? a.lengths[left - 1] : 0), a.table[left]);
340−
341− // Maybe the a node is not even needed, as sliced contains the whole slice.
342− if (left == a.table.length - 1) {
343− return sliced;
344− }
345−
346− // Create new node.
347− var newA = { ctor:"_Array", height:a.height
348− , table:a.table.slice(left, a.table.length + 1)
349− , lengths:new Array(a.table.length - left) };
350− newA.table[0] = sliced;
351− var len = 0;
352− for (var i = 0; i < newA.table.length; i++) {
353− len += length(newA.table[i]);
354− newA.lengths[i] = len;
355− }
356−
357− return newA;
358− }
359−
360− // Appends two trees.
361− function append(a,b) {
362− if (a.table.length === 0) {
363− return b;
364− }
365− if (b.table.length === 0) {
366− return a;
367− }
368−
369− var c = append_(a, b);
370−
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) {
374− return c[1];
375− }
376− if (c[1].table.length === 0) {
377− return c[0];
378− }
379−
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;
386− }
387− c[0].lengths = c[0].lengths.concat(c[1].lengths);
388− }
389−
390− return c[0];
391− }
392−
393− if (c[0].height > 0) {
394− var toRemove = calcToRemove(a, b);
395− if (toRemove > E) {
396− c = shuffle(c[0], c[1], toRemove);
397− }
398− }
399−
400− return siblise(c[0], c[1]);
401− }
402−
403− // Returns an array of two nodes; right and left. One node _may_ be empty.
404− function append_(a, b) {
405− if (a.height === 0 && b.height === 0) {
406− return [a, b];
407− }
408−
409− if (a.height !== 1 || b.height !== 1) {
410− if (a.height === b.height) {
411− a = nodeCopy(a);
412− b = nodeCopy(b);
413− var appended = append_(botRight(a), botLeft(b));
414−
415− insertRight(a, appended[1]);
416− insertLeft(b, appended[0]);
417− } else if (a.height > b.height) {
418− a = nodeCopy(a);
419− var appended = append_(botRight(a), b);
420−
421− insertRight(a, appended[0]);
422− b = parentise(appended[1], appended[1].height + 1);
423− } else {
424− b = nodeCopy(b);
425− var appended = append_(a, botLeft(b));
426−
427− var left = appended[0].table.length === 0 ? 0 : 1;
428− var right = left === 0 ? 1 : 0;
429− insertLeft(b, appended[left]);
430− a = parentise(appended[right], appended[right].height + 1);
431− }
432− }
433−
434− // Check if balancing is needed and return based on that.
435− if (a.table.length === 0 || b.table.length === 0) {
436− return [a,b];
437− }
438−
439− var toRemove = calcToRemove(a, b);
440− if (toRemove <= E) {
441− return [a,b];
442− }
443− return shuffle(a, b, toRemove);
444− }
445−
446− // Helperfunctions for append_. Replaces a child node at the side of the parent.
447− function insertRight(parent, node) {
448− var index = parent.table.length - 1;
449− parent.table[index] = node;
450− parent.lengths[index] = length(node)
451− parent.lengths[index] += index > 0 ? parent.lengths[index - 1] : 0;
452− }
453−
454− function insertLeft(parent, node) {
455− if (node.table.length > 0) {
456− parent.table[0] = node;
457− parent.lengths[0] = length(node);
458−
459− var len = length(parent.table[0]);
460− for (var i = 1; i < parent.lengths.length; i++) {
461− len += length(parent.table[i]);
462− parent.lengths[i] = len;
463− }
464− } else {
465− parent.table.shift();
466− for (var i = 1; i < parent.lengths.length; i++) {
467− parent.lengths[i] = parent.lengths[i] - parent.lengths[0];
468− }
469− parent.lengths.shift();
470− }
471− }
472−
473− // Returns the extra search steps for E. Refer to the paper.
474− function calcToRemove(a, b) {
475− var subLengths = 0;
476− for (var i = 0; i < a.table.length; i++) {
477− subLengths += a.table[i].table.length;
478− }
479− for (var i = 0; i < b.table.length; i++) {
480− subLengths += b.table[i].table.length;
481− }
482−
483− var toRemove = a.table.length + b.table.length
484− return toRemove - (Math.floor((subLengths - 1) / M) + 1);
485− }
486−
487− // get2, set2 and saveSlot are helpers for accessing elements over two arrays.
488− function get2(a, b, index) {
489− return index < a.length ? a[index] : b[index - a.length];
490− }
491−
492− function set2(a, b, index, value) {
493− if (index < a.length) {
494− a[index] = value;
495− } else {
496− b[index - a.length] = value;
497− }
498− }
499−
500− function saveSlot(a, b, index, slot) {
501− set2(a.table, b.table, index, slot);
502−
503− var l = (index == 0 || index == a.lengths.length) ?
504− 0 : get2(a.lengths, a.lengths, index - 1);
505− set2(a.lengths, b.lengths, index, l + length(slot));
506− }
507−
508− // Creates a node or leaf with a given length at their arrays for perfomance.
509− // Is only used by shuffle.
510− function createNode(h, length) {
511− if (length < 0) { length = 0; }
512− var a = { ctor:"_Array", height:h, table:new Array(length) };
513− if (h > 0) {
514− a.lengths = new Array(length);
515− }
516− return a;
517− }
518−
519− // Returns an array of two balanced nodes.
520− function shuffle(a, b, toRemove) {
521− var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove));
522− var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove));
523−
524− // Skip the slots with size M. More precise: copy the slot references
525− // to the new node
526− var read = 0;
527− while (get2(a.table, b.table, read).table.length % M == 0) {
528− set2(newA.table, newB.table, read, get2(a.table, b.table, read));
529− set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read));
530− read++;
531− }
532−
533− // Pulling items from left to right, caching in a slot before writing
534− // it into the new nodes.
535− var write = read;
536− var slot = new createNode(a.height - 1, 0);
537− var from = 0;
538−
539− // If the current slot is still containing data, then there will be at
540− // least one more write, so we do not break this loop yet.
541− while (read - write - (slot.table.length > 0 ? 1 : 0) < toRemove) {
542− // Find out the max possible items for copying.
543− var source = get2(a.table, b.table, read);
544− var to = Math.min(M - slot.table.length, source.table.length)
545−
546− // Copy and adjust size table.
547− slot.table = slot.table.concat(source.table.slice(from, to));
548− if (slot.height > 0) {
549− var len = slot.lengths.length;
550− for (var i = len; i < len + to - from; i++) {
551− slot.lengths[i] = length(slot.table[i]);
552− slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0);
553− }
554− }
555−
556− from += to;
557−
558− // Only proceed to next slots[i] if the current one was
559− // fully copied.
560− if (source.table.length <= to) {
561− read++; from = 0;
562− }
563−
564− // Only create a new slot if the current one is filled up.
565− if (slot.table.length == M) {
566− saveSlot(newA, newB, write, slot);
567− slot = createNode(a.height - 1,0);
568− write++;
569− }
570− }
571−
572− // Cleanup after the loop. Copy the last slot into the new nodes.
573− if (slot.table.length > 0) {
574− saveSlot(newA, newB, write, slot);
575− write++;
576− }
577−
578− // Shift the untouched slots to the left
579− while (read < a.table.length + b.table.length ) {
580− saveSlot(newA, newB, write, get2(a.table, b.table, read));
581− read++; write++;
582− }
583−
584− return [newA, newB];
585− }
586−
587− // Navigation functions
588− function botRight(a) { return a.table[a.table.length - 1]; }
589− function botLeft(a) { return a.table[0]; }
590−
591− // Copies a node for updating. Note that you should not use this if
592− // only updating only one of "table" or "lengths" for performance reasons.
593− function nodeCopy(a) {
594− var newA = { ctor:"_Array", height:a.height
595− , table:a.table.slice() };
596− if (a.height > 0) { newA.lengths = a.lengths.slice(); }
597− return newA;
598− }
599−
600− // Returns how many items are in the tree.
601− function length(array) {
602− if (array.height == 0) {
603− return array.table.length;
604− } else {
605− return array.lengths[array.lengths.length - 1];
606− }
607− }
608−
609− // Calculates in which slot of "table" the item probably is, then
610− // find the exact slot via forward searching in "lengths". Returns the index.
611− function getSlot(i, a) {
612− var slot = i >> (5 * a.height);
613− while (a.lengths[slot] <= i) {
614− slot++;
615− }
616− return slot;
617− }
618−
619− // Recursively creates a tree with a given height containing
620− // only the given item.
621− function create(item, h) {
622− if (h == 0) {
623− return { ctor:"_Array", height:0
624− , table:[item] };
625− } else {
626− return { ctor:"_Array", height:h
627− , table:[create(item, h - 1)]
628− , lengths:[1] };
629− }
630− }
631−
632− // Recursively creates a tree that contains the given tree.
633− function parentise(tree, h) {
634− if (h == tree.height) {
635− return tree;
636− } else {
637− return { ctor:"_Array", height:h
638− , table:[parentise(tree, h - 1)]
639− , lengths:[length(tree)] };
640− }
641− }
642−
643− // Emphasizes blood brotherhood beneath two trees.
644− function siblise(a, b) {
645− return { ctor:"_Array", height:a.height + 1
646− , table:[a, b]
647− , lengths:[length(a), length(a) + length(b)] };
648− }
649−
650− function toJSArray(a) {
651− var jsArray = new Array(length(a));
652− toJSArray_(jsArray, 0, a);
653− return jsArray;
654− }
655−
656− function toJSArray_(jsArray, i, a) {
657− for (var t = 0; t < a.table.length; t++) {
658− if (a.height == 0) {
659− jsArray[i + t] = a.table[t];
660− } else {
661− var inc = t == 0 ? 0 : a.lengths[t - 1];
662− toJSArray_(jsArray, i + inc, a.table[t]);
663− }
664− }
665− }
666−
667− function fromJSArray(jsArray) {
668− if (jsArray.length == 0) { return empty; }
669− var h = Math.floor(Math.log(jsArray.length) / Math.log(M));
670− return fromJSArray_(jsArray, h, 0, jsArray.length);
671− }
672−
673− function fromJSArray_(jsArray, h, from, to) {
674− if (h == 0) {
675− return { ctor:"_Array", height:0
676− , table:jsArray.slice(from, to) };
677− }
678−
679− var step = Math.pow(M, h);
680− var table = new Array(Math.ceil((to - from) / step));
681− var lengths = new Array(table.length);
682− for (var i = 0; i < table.length; i++) {
683− table[i] = fromJSArray_( jsArray, h - 1, from + (i * step)
684− , Math.min(from + ((i + 1) * step), to));
685− lengths[i] = length(table[i]) + (i > 0 ? lengths[i-1] : 0);
686− }
687− return { ctor:"_Array", height:h, table:table, lengths:lengths };
688− }
689−
690− Elm.Native.Array.values = {
691− empty:empty,
692− fromList:fromList,
693− toList:toList,
694− initialize:F2(initialize),
695− append:F2(append),
696− push:F2(push),
697− slice:F3(slice),
698− get:F2(get),
699− set:F3(set),
700− map:F2(map),
701− indexedMap:F2(indexedMap),
702− foldl:F3(foldl),
703− foldr:F3(foldr),
704− length:length,
705−
706− toJSArray:toJSArray,
707− fromJSArray:fromJSArray
708− };
709−
710− return elm.Native.Array.values = Elm.Native.Array.values;
711−}