@effect-ts/system
Version:
Effect-TS is a zero dependency set of libraries to write highly productive, purely functional TypeScript at scale.
2,212 lines (1,791 loc) • 82.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Node = exports.ListBuilder = exports.List = void 0;
exports.adjust = adjust;
exports.adjust_ = adjust_;
exports.ap = ap;
exports.ap_ = ap_;
exports.append = append;
exports.append_ = append_;
exports.backwards = backwards;
exports.builder = builder;
exports.chain = chain;
exports.chain_ = chain_;
exports.compact = compact;
exports.concat = concat;
exports.concat_ = concat_;
exports.contains = contains;
exports.contains_ = contains_;
exports.drop = drop;
exports.dropLast = dropLast;
exports.dropLast_ = dropLast_;
exports.dropRepeats = dropRepeats;
exports.dropRepeatsWith = dropRepeatsWith;
exports.dropRepeatsWith_ = dropRepeatsWith_;
exports.dropWhile = dropWhile;
exports.dropWhile_ = dropWhile_;
exports.drop_ = drop_;
exports.empty = empty;
exports.emptyPushable = emptyPushable;
exports.equals = equals;
exports.equalsWith = equalsWith;
exports.equalsWith_ = equalsWith_;
exports.equals_ = equals_;
exports.every = every;
exports.every_ = every_;
exports.filter = filter;
exports.filterMap = filterMap;
exports.filterMap_ = filterMap_;
exports.filterNot = filterNot;
exports.filterNot_ = filterNot_;
exports.filter_ = filter_;
exports.find = find;
exports.findIndex = findIndex;
exports.findIndex_ = findIndex_;
exports.findLast = findLast;
exports.findLast_ = findLast_;
exports.find_ = find_;
exports.first = first;
exports.flatten = flatten;
exports.forEach = forEach;
exports.forEach_ = forEach_;
exports.from = from;
exports.group = group;
exports.groupWith = groupWith;
exports.groupWith_ = groupWith_;
exports.indexOf = indexOf;
exports.indexOf_ = indexOf_;
exports.insert = insert;
exports.insertAll = insertAll;
exports.insertAll_ = insertAll_;
exports.insert_ = insert_;
exports.intersperse = intersperse;
exports.intersperse_ = intersperse_;
exports.isEmpty = isEmpty;
exports.isList = isList;
exports.join = join;
exports.join_ = join_;
exports.last = last;
exports.lastIndexOf = lastIndexOf;
exports.lastIndexOf_ = lastIndexOf_;
exports.list = list;
exports.map = map;
exports.map_ = map_;
exports.none = none;
exports.none_ = none_;
exports.nth = nth;
exports.nth_ = nth_;
exports.of = of;
exports.pair = pair;
exports.pair_ = pair_;
exports.partition = partition;
exports.partitionMap = partitionMap;
exports.partitionMap_ = partitionMap_;
exports.partition_ = partition_;
exports.pluck = pluck;
exports.pluck_ = pluck_;
exports.pop = pop;
exports.prepend = prepend;
exports.prepend_ = prepend_;
exports.push_ = push_;
exports.range = range;
exports.range_ = range_;
exports.reduce = reduce;
exports.reduceRight = reduceRight;
exports.reduceRight_ = reduceRight_;
exports.reduceWhile = reduceWhile;
exports.reduceWhile_ = reduceWhile_;
exports.reduce_ = reduce_;
exports.remove = remove;
exports.remove_ = remove_;
exports.repeat = repeat;
exports.repeat_ = repeat_;
exports.reverse = reverse;
exports.scan = scan;
exports.scan_ = scan_;
exports.separate = separate;
exports.size = size;
exports.slice = slice;
exports.slice_ = slice_;
exports.some = some;
exports.some_ = some_;
exports.sortWith = sortWith;
exports.sortWith_ = sortWith_;
exports.splitAt = splitAt;
exports.splitAt_ = splitAt_;
exports.splitEvery = splitEvery;
exports.splitEvery_ = splitEvery_;
exports.splitWhen = splitWhen;
exports.splitWhen_ = splitWhen_;
exports.tail = tail;
exports.take = take;
exports.takeLast = takeLast;
exports.takeLastWhile = takeLastWhile;
exports.takeLastWhile_ = takeLastWhile_;
exports.takeLast_ = takeLast_;
exports.takeWhile = takeWhile;
exports.takeWhile_ = takeWhile_;
exports.take_ = take_;
exports.times = times;
exports.times_ = times_;
exports.toArray = toArray;
exports.unsafeFind = unsafeFind;
exports.unsafeFindLast = unsafeFindLast;
exports.unsafeFindLast_ = unsafeFindLast_;
exports.unsafeFind_ = unsafeFind_;
exports.unsafeFirst = unsafeFirst;
exports.unsafeLast = unsafeLast;
exports.unsafeNth = unsafeNth;
exports.unsafeNth_ = unsafeNth_;
exports.update = update;
exports.update_ = update_;
exports.zip = zip;
exports.zipWith = zipWith;
exports.zipWith_ = zipWith_;
exports.zip_ = zip_;
var _index = /*#__PURE__*/require("../../../Function/index.js");
var O = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../../Option/index.js"));
var St = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../../../Structural/index.js"));
var Tp = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Tuple/index.js"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/**
* Forked from https://github.com/funkia/list/blob/master/src/index.ts
*
* All credits to original authors.
*
* The implementation has been forked to adapt to the double standard pipeable/data first
* available in the remaining modules and to remove the fantasy-land bias.
*/
const branchingFactor = 32;
const branchBits = 5;
const mask = 31;
function elementEquals(a, b) {
if (a === b) {
return true;
} else {
return false;
}
}
function createPath(depth, value) {
let current = value;
for (let i = 0; i < depth; ++i) {
current = new Node(undefined, [current]);
}
return current;
} // Array helper functions
function copyArray(source) {
const array = [];
for (let i = 0; i < source.length; ++i) {
array[i] = source[i];
}
return array;
}
function pushElements(source, target, offset, amount) {
for (let i = offset; i < offset + amount; ++i) {
target.push(source[i]);
}
}
function copyIndices(source, sourceStart, target, targetStart, length) {
for (let i = 0; i < length; ++i) {
target[targetStart + i] = source[sourceStart + i];
}
}
function arrayPrepend(value, array) {
const newLength = array.length + 1;
const result = new Array(newLength);
result[0] = value;
for (let i = 1; i < newLength; ++i) {
result[i] = array[i - 1];
}
return result;
}
/**
* Create a reverse _copy_ of an array.
*/
function reverseArray(array) {
return array.slice().reverse();
}
function arrayFirst(array) {
return array[0];
}
function arrayLast(array) {
return array[array.length - 1];
}
const pathResult = {
path: 0,
index: 0,
updatedOffset: 0
};
function getPath(index, offset, depth, sizes) {
if (sizes === undefined && offset !== 0) {
pathResult.updatedOffset = 0;
index = handleOffset(depth, offset, index);
}
let path = index >> depth * branchBits & mask;
if (sizes !== undefined) {
while (sizes[path] <= index) {
path++;
}
const traversed = path === 0 ? 0 : sizes[path - 1];
index -= traversed;
pathResult.updatedOffset = offset;
}
pathResult.path = path;
pathResult.index = index;
return pathResult;
}
function updateNode(node, depth, index, offset, value) {
const {
index: newIndex,
path,
updatedOffset
} = getPath(index, offset, depth, node.sizes);
const array = copyArray(node.array);
array[path] = depth > 0 ? updateNode(array[path], depth - 1, newIndex, updatedOffset, value) : value;
return new Node(node.sizes, array);
}
class Node {
constructor(sizes, array) {
this.sizes = sizes;
this.array = array;
}
}
exports.Node = Node;
function cloneNode({
array,
sizes
}) {
return new Node(sizes === undefined ? undefined : copyArray(sizes), copyArray(array));
} // This array should not be mutated. Thus a dummy element is placed in
// it. Thus the affix will not be owned and thus not mutated.
const emptyAffix = [0]; // We store a bit field in list. From right to left, the first five
// bits are suffix length, the next five are prefix length and the
// rest is depth. The functions below are for working with the bits in
// a sane way.
const affixBits = 6;
const affixMask = 0b111111;
function getSuffixSize(l) {
return l.bits & affixMask;
}
function getPrefixSize(l) {
return l.bits >> affixBits & affixMask;
}
function getDepth(l) {
return l.bits >> affixBits * 2;
}
function setPrefix(size, bits) {
return size << affixBits | bits & ~(affixMask << affixBits);
}
function setSuffix(size, bits) {
return size | bits & ~affixMask;
}
function setDepth(depth, bits) {
return depth << affixBits * 2 | bits & (affixMask | affixMask << affixBits);
}
function incrementPrefix(bits) {
return bits + (1 << affixBits);
}
function incrementSuffix(bits) {
return bits + 1;
}
function incrementDepth(bits) {
return bits + (1 << affixBits * 2);
}
function decrementDepth(bits) {
return bits - (1 << affixBits * 2);
}
/*
* Invariants that any list `l` should satisfy
*
* 1. If `l.root !== undefined` then `getSuffixSize(l) !== 0` and
* `getPrefixSize(l) !== 0`. The invariant ensures that `first` and
* `last` never have to look in the root and that they therefore
* take O(1) time.
* 2. If a tree or sub-tree does not have a size-table then all leaf
* nodes in the tree are of size 32.
*/
/**
* Represents a list of elements.
*/
class List {
constructor(bits, offset, length, prefix, root, suffix) {
this.bits = bits;
this.offset = offset;
this.length = length;
this.prefix = prefix;
this.root = root;
this.suffix = suffix;
}
[Symbol.iterator]() {
return new ForwardListIterator(this);
}
toJSON() {
return toArray(this);
}
[St.equalsSym](that) {
return that instanceof List && equalsWith_(this, that, St.equals);
}
get [St.hashSym]() {
return St.hashIterator(this[Symbol.iterator]());
}
}
exports.List = List;
function cloneList(l) {
return new List(l.bits, l.offset, l.length, l.prefix, l.root, l.suffix);
}
class ListIterator {
constructor(l, direction) {
this.l = l;
this.result = {
done: false,
value: undefined
};
this.idx = direction === 1 ? -1 : l.length;
this.prefixSize = getPrefixSize(l);
this.middleSize = l.length - getSuffixSize(l);
if (l.root !== undefined) {
const depth = getDepth(l);
this.stack = new Array(depth + 1);
this.indices = new Array(depth + 1);
let currentNode = l.root.array;
for (let i = depth; 0 <= i; --i) {
this.stack[i] = currentNode;
const idx = direction === 1 ? 0 : currentNode.length - 1;
this.indices[i] = idx;
currentNode = currentNode[idx].array;
}
this.indices[0] -= direction;
}
}
}
class ForwardListIterator extends ListIterator {
constructor(l) {
super(l, 1);
}
nextInTree() {
for (var i = 0; ++this.indices[i] === this.stack[i].length; ++i) {
this.indices[i] = 0;
}
for (; 0 < i; --i) {
this.stack[i - 1] = this.stack[i][this.indices[i]].array;
}
}
next() {
let newVal;
const idx = ++this.idx;
if (idx < this.prefixSize) {
newVal = this.l.prefix[this.prefixSize - idx - 1];
} else if (idx < this.middleSize) {
this.nextInTree();
newVal = this.stack[0][this.indices[0]];
} else if (idx < this.l.length) {
newVal = this.l.suffix[idx - this.middleSize];
} else {
this.result.done = true;
}
this.result.value = newVal;
return this.result;
}
}
class BackwardsListIterator extends ListIterator {
constructor(l) {
super(l, -1);
}
prevInTree() {
for (var i = 0; this.indices[i] === 0; ++i) {//
}
--this.indices[i];
for (; 0 < i; --i) {
const n = this.stack[i][this.indices[i]].array;
this.stack[i - 1] = n;
this.indices[i - 1] = n.length - 1;
}
}
next() {
let newVal;
const idx = --this.idx;
if (this.middleSize <= idx) {
newVal = this.l.suffix[idx - this.middleSize];
} else if (this.prefixSize <= idx) {
this.prevInTree();
newVal = this.stack[0][this.indices[0]];
} else if (0 <= idx) {
newVal = this.l.prefix[this.prefixSize - idx - 1];
} else {
this.result.done = true;
}
this.result.value = newVal;
return this.result;
}
}
/**
* Returns an iterable that iterates backwards over the given list.
*
* @complexity O(1)
*/
function backwards(l) {
return {
[Symbol.iterator]() {
return new BackwardsListIterator(l);
}
};
}
function emptyPushable() {
return new List(0, 0, 0, [], undefined, []);
}
/** Appends the value to the list by _mutating_ the list and its content. */
function push_(l, value) {
const suffixSize = getSuffixSize(l);
if (l.length === 0) {
l.bits = setPrefix(1, l.bits);
l.prefix = [value];
} else if (suffixSize < 32) {
l.bits = incrementSuffix(l.bits);
l.suffix.push(value);
} else if (l.root === undefined) {
l.root = new Node(undefined, l.suffix);
l.suffix = [value];
l.bits = setSuffix(1, l.bits);
} else {
const newNode = new Node(undefined, l.suffix);
const index = l.length - 1 - 32 + 1;
let current = l.root;
let depth = getDepth(l);
l.suffix = [value];
l.bits = setSuffix(1, l.bits);
if (index - 1 < branchingFactor ** (depth + 1)) {
for (; depth >= 0; --depth) {
const path = index >> depth * branchBits & mask;
if (path < current.array.length) {
current = current.array[path];
} else {
current.array.push(createPath(depth - 1, newNode));
break;
}
}
} else {
l.bits = incrementDepth(l.bits);
l.root = new Node(undefined, [l.root, createPath(depth, newNode)]);
}
}
l.length++;
return l;
}
/**
* Creates a list of the given elements.
*
* @complexity O(n)
*/
function list(...elements) {
const l = emptyPushable();
for (const element of elements) {
push_(l, element);
}
return l;
}
/**
* Creates an empty list.
*
* @complexity O(1)
*/
function empty() {
return new List(0, 0, 0, emptyAffix, undefined, emptyAffix);
}
/**
* Takes a single arguments and returns a singleton list that contains it.
*
* @complexity O(1)
*/
function of(a) {
return list(a);
}
/**
* Takes two arguments and returns a list that contains them.
*
* @complexity O(1)
*/
function pair(second) {
return first => pair_(first, second);
}
/**
* Takes two arguments and returns a list that contains them.
*
* @complexity O(1)
*/
function pair_(first, second) {
return new List(2, 0, 2, emptyAffix, undefined, [first, second]);
}
function from(sequence) {
const l = emptyPushable();
if (sequence.length > 0 && (sequence[0] !== undefined || 0 in sequence)) {
for (let i = 0; i < sequence.length; ++i) {
push_(l, sequence[i]);
}
} else if (Symbol.iterator in sequence) {
const iterator = sequence[Symbol.iterator]();
let cur; // tslint:disable-next-line:no-conditional-assignment
while (!(cur = iterator.next()).done) {
push_(l, cur.value);
}
}
return l;
}
/**
* Returns a list of numbers between an inclusive lower bound and an exclusive upper bound.
*
* @complexity O(n)
*/
function range(end) {
return start => range_(start, end);
}
/**
* Returns a list of numbers between an inclusive lower bound and an exclusive upper bound.
*
* @complexity O(n)
*/
function range_(start, end) {
const list = emptyPushable();
for (let i = start; i < end; ++i) {
push_(list, i);
}
return list;
}
/**
* Returns a list of a given length that contains the specified value
* in all positions.
*
* @complexity O(n)
*/
function repeat(times) {
return value => repeat_(value, times);
}
/**
* Returns a list of a given length that contains the specified value
* in all positions.
*
* @complexity O(n)
*/
function repeat_(value, times) {
const l = emptyPushable();
while (--times >= 0) {
push_(l, value);
}
return l;
}
/**
* Generates a new list by calling a function with the current index
* `n` times.
*
* @complexity O(n)
*/
function times(times) {
return func => times_(func, times);
}
/**
* Generates a new list by calling a function with the current index
* `n` times.
*
* @complexity O(n)
*/
function times_(func, times) {
const l = emptyPushable();
for (let i = 0; i < times; i++) {
push_(l, func(i));
}
return l;
}
function nodeNthDense(node, depth, index) {
let current = node;
for (; depth >= 0; --depth) {
current = current.array[index >> depth * branchBits & mask];
}
return current;
}
function handleOffset(depth, offset, index) {
index += offset;
for (; depth >= 0; --depth) {
index = index - (offset & mask << depth * branchBits);
if ((index >> depth * branchBits & mask) !== 0) {
break;
}
}
return index;
}
function nodeNth(node, depth, offset, index) {
let path;
let current = node;
while (current.sizes !== undefined) {
path = index >> depth * branchBits & mask;
while (current.sizes[path] <= index) {
path++;
}
if (path !== 0) {
index -= current.sizes[path - 1];
offset = 0; // Offset is discarded if the left spine isn't traversed
}
depth--;
current = current.array[path];
}
return nodeNthDense(current, depth, offset === 0 ? index : handleOffset(depth, offset, index));
}
/**
* Gets the nth element of the list. If `n` is out of bounds
* `undefined` is returned.
*
* @complexity O(log(n))
*/
function unsafeNth_(l, index) {
return O.toUndefined(nth_(l, index));
}
/**
* Gets the nth element of the list. If `n` is out of bounds
* `undefined` is returned.
*
* @complexity O(log(n))
*/
function unsafeNth(index) {
return l => unsafeNth_(l, index);
}
/**
* Gets the nth element of the list. If `n` is out of bounds
* `undefined` is returned.
*
* @complexity O(log(n))
*/
function nth_(l, index) {
if (index < 0 || l.length <= index) {
return O.none;
}
const prefixSize = getPrefixSize(l);
const suffixSize = getSuffixSize(l);
if (index < prefixSize) {
return O.some(l.prefix[prefixSize - index - 1]);
} else if (index >= l.length - suffixSize) {
return O.some(l.suffix[index - (l.length - suffixSize)]);
}
const {
offset
} = l;
const depth = getDepth(l);
return O.some(l.root.sizes === undefined ? nodeNthDense(l.root, depth, offset === 0 ? index - prefixSize : handleOffset(depth, offset, index - prefixSize)) : nodeNth(l.root, depth, offset, index - prefixSize));
}
/**
* Gets the nth element of the list. If `n` is out of bounds
* `undefined` is returned.
*
* @complexity O(log(n))
*/
function nth(index) {
return l => nth_(l, index);
}
function setSizes(node, height) {
let sum = 0;
const sizeTable = [];
for (let i = 0; i < node.array.length; ++i) {
sum += sizeOfSubtree(node.array[i], height - 1);
sizeTable[i] = sum;
}
node.sizes = sizeTable;
return node;
}
/**
* Returns the number of elements stored in the node.
*/
function sizeOfSubtree(node, height) {
if (height !== 0) {
if (node.sizes !== undefined) {
return arrayLast(node.sizes);
} else {
// the node is leftwise dense so all all but the last child are full
const lastSize = sizeOfSubtree(arrayLast(node.array), height - 1);
return (node.array.length - 1 << height * branchBits) + lastSize;
}
} else {
return node.array.length;
}
} // prepend & append
function affixPush(a, array, length) {
if (array.length === length) {
array.push(a);
return array;
} else {
const newArray = [];
copyIndices(array, 0, newArray, 0, length);
newArray.push(a);
return newArray;
}
}
/**
* Prepends an element to the front of a list and returns the new list.
*
* @complexity O(1)
*/
function prepend_(l, value) {
const prefixSize = getPrefixSize(l);
if (prefixSize < 32) {
return new List(incrementPrefix(l.bits), l.offset, l.length + 1, affixPush(value, l.prefix, prefixSize), l.root, l.suffix);
} else {
const newList = cloneList(l);
prependNodeToTree(newList, reverseArray(l.prefix));
const newPrefix = [value];
newList.prefix = newPrefix;
newList.length++;
newList.bits = setPrefix(1, newList.bits);
return newList;
}
}
/**
* Prepends an element to the front of a list and returns the new list.
*
* @complexity O(1)
*/
function prepend(value) {
return l => prepend_(l, value);
}
/**
* Traverses down the left edge of the tree and copies k nodes.
* Returns the last copied node.
* @param l
* @param k The number of nodes to copy. Should always be at least 1.
*/
function copyLeft(l, k) {
let currentNode = cloneNode(l.root); // copy root
l.root = currentNode; // install copy of root
for (let i = 1; i < k; ++i) {
const index = 0; // go left
if (currentNode.sizes !== undefined) {
for (let i = 0; i < currentNode.sizes.length; ++i) {
currentNode.sizes[i] += 32;
}
}
const newNode = cloneNode(currentNode.array[index]); // Install the copied node
currentNode.array[index] = newNode;
currentNode = newNode;
}
return currentNode;
}
/**
* Prepends an element to a node
*/
function nodePrepend(value, size, node) {
const array = arrayPrepend(value, node.array);
let sizes = undefined;
if (node.sizes !== undefined) {
sizes = new Array(node.sizes.length + 1);
sizes[0] = size;
for (let i = 0; i < node.sizes.length; ++i) {
sizes[i + 1] = node.sizes[i] + size;
}
}
return new Node(sizes, array);
}
/**
* Prepends a node to a tree. Either by shifting the nodes in the root
* left or by increasing the height
*/
function prependTopTree(l, depth, node) {
let newOffset;
if (l.root.array.length < branchingFactor) {
// There is space in the root, there is never a size table in this
// case
newOffset = 32 ** depth - 32;
l.root = new Node(undefined, arrayPrepend(createPath(depth - 1, node), l.root.array));
} else {
// We need to create a new root
l.bits = incrementDepth(l.bits);
const sizes = l.root.sizes === undefined ? undefined : [32, arrayLast(l.root.sizes) + 32];
newOffset = depth === 0 ? 0 : 32 ** (depth + 1) - 32;
l.root = new Node(sizes, [createPath(depth, node), l.root]);
}
return newOffset;
}
/**
* Takes a list and a node tail. It then prepends the node to the tree
* of the list.
* @param l The subject for prepending. `l` will be mutated. Nodes in
* the tree will _not_ be mutated.
* @param node The node that should be prepended to the tree.
*/
function prependNodeToTree(l, array) {
if (l.root === undefined) {
if (getSuffixSize(l) === 0) {
// ensure invariant 1
l.bits = setSuffix(array.length, l.bits);
l.suffix = array;
} else {
l.root = new Node(undefined, array);
}
return l;
} else {
const node = new Node(undefined, array);
const depth = getDepth(l);
let newOffset = 0;
if (l.root.sizes === undefined) {
if (l.offset !== 0) {
newOffset = l.offset - branchingFactor;
l.root = prependDense(l.root, depth, l.offset, node);
} else {
// in this case we can be sure that the is not room in the tree
// for the new node
newOffset = prependTopTree(l, depth, node);
}
} else {
// represents how many nodes _with size-tables_ that we should copy.
let copyableCount = 0; // go down while there is size tables
let nodesTraversed = 0;
let currentNode = l.root;
while (currentNode.sizes !== undefined && nodesTraversed < depth) {
++nodesTraversed;
if (currentNode.array.length < 32) {
// there is room if offset is > 0 or if the first node does not
// contain as many nodes as it possibly can
copyableCount = nodesTraversed;
}
currentNode = currentNode.array[0];
}
if (l.offset !== 0) {
const copiedNode = copyLeft(l, nodesTraversed);
for (let i = 0; i < copiedNode.sizes.length; ++i) {
copiedNode.sizes[i] += branchingFactor;
}
copiedNode.array[0] = prependDense(copiedNode.array[0], depth - nodesTraversed, l.offset, node);
l.offset = l.offset - branchingFactor;
return l;
} else {
if (copyableCount === 0) {
l.offset = prependTopTree(l, depth, node);
} else {
let parent;
let prependableNode; // Copy the part of the path with size tables
if (copyableCount > 1) {
parent = copyLeft(l, copyableCount - 1);
prependableNode = parent.array[0];
} else {
parent = undefined;
prependableNode = l.root;
}
const path = createPath(depth - copyableCount, node); // add offset
l.offset = 32 ** (depth - copyableCount + 1) - 32;
const prepended = nodePrepend(path, 32, prependableNode);
if (parent === undefined) {
l.root = prepended;
} else {
parent.array[0] = prepended;
}
}
return l;
}
}
l.offset = newOffset;
return l;
}
}
/**
* Prepends a node to a dense tree. The given `offset` is never zero.
*/
function prependDense(node, depth, offset, value) {
// We're indexing down `offset - 1`. At each step `path` is either 0 or -1.
const curOffset = offset >> depth * branchBits & mask;
const path = (offset - 1 >> depth * branchBits & mask) - curOffset;
if (path < 0) {
return new Node(undefined, arrayPrepend(createPath(depth - 1, value), node.array));
} else {
const array = copyArray(node.array);
array[0] = prependDense(array[0], depth - 1, offset, value);
return new Node(undefined, array);
}
}
/**
* Appends an element to the end of a list and returns the new list.
*
* @complexity O(n)
*/
function append_(l, value) {
const suffixSize = getSuffixSize(l);
if (suffixSize < 32) {
return new List(incrementSuffix(l.bits), l.offset, l.length + 1, l.prefix, l.root, affixPush(value, l.suffix, suffixSize));
}
const newSuffix = [value];
const newList = cloneList(l);
appendNodeToTree(newList, l.suffix);
newList.suffix = newSuffix;
newList.length++;
newList.bits = setSuffix(1, newList.bits);
return newList;
}
/**
* Appends an element to the end of a list and returns the new list.
*
* @complexity O(n)
*/
function append(value) {
return l => append_(l, value);
}
/**
* Gets the length of a list.
*
* @complexity `O(1)`
*/
function size(l) {
return l.length;
}
/**
* Returns the first element of the list. If the list is empty the
* function returns undefined.
*
* @complexity O(1)
*/
function unsafeFirst(l) {
return O.toUndefined(first(l));
}
/**
* Returns the first element of the list. If the list is empty the
* function returns undefined.
*
* @complexity O(1)
*/
function first(l) {
const prefixSize = getPrefixSize(l);
return prefixSize !== 0 ? O.some(l.prefix[prefixSize - 1]) : l.length !== 0 ? O.some(l.suffix[0]) : O.none;
}
/**
* Returns the last element of the list. If the list is empty the
* function returns `undefined`.
*
* @complexity O(1)
*/
function unsafeLast(l) {
return O.toUndefined(last(l));
}
/**
* Returns the last element of the list. If the list is empty the
* function returns `undefined`.
*
* @complexity O(1)
*/
function last(l) {
const suffixSize = getSuffixSize(l);
return suffixSize !== 0 ? O.some(l.suffix[suffixSize - 1]) : l.length !== 0 ? O.some(l.prefix[0]) : O.none;
} // map
function mapArray(f, array) {
const result = new Array(array.length);
for (let i = 0; i < array.length; ++i) {
result[i] = f(array[i]);
}
return result;
}
function mapNode(f, node, depth) {
if (depth !== 0) {
const {
array
} = node;
const result = new Array(array.length);
for (let i = 0; i < array.length; ++i) {
result[i] = mapNode(f, array[i], depth - 1);
}
return new Node(node.sizes, result);
} else {
return new Node(undefined, mapArray(f, node.array));
}
}
function mapPrefix(f, prefix, length) {
const newPrefix = new Array(length);
for (let i = length - 1; 0 <= i; --i) {
newPrefix[i] = f(prefix[i]);
}
return newPrefix;
}
function mapAffix(f, suffix, length) {
const newSuffix = new Array(length);
for (let i = 0; i < length; ++i) {
newSuffix[i] = f(suffix[i]);
}
return newSuffix;
}
/**
* Applies a function to each element in the given list and returns a
* new list of the values that the function return.
*
* @complexity O(n)
*/
function map_(l, f) {
return new List(l.bits, l.offset, l.length, mapPrefix(f, l.prefix, getPrefixSize(l)), l.root === undefined ? undefined : mapNode(f, l.root, getDepth(l)), mapAffix(f, l.suffix, getSuffixSize(l)));
}
/**
* Applies a function to each element in the given list and returns a
* new list of the values that the function return.
*
* @complexity O(n)
*/
function map(f) {
return l => new List(l.bits, l.offset, l.length, mapPrefix(f, l.prefix, getPrefixSize(l)), l.root === undefined ? undefined : mapNode(f, l.root, getDepth(l)), mapAffix(f, l.suffix, getSuffixSize(l)));
}
/**
* Extracts the specified property from each object in the list.
*/
function pluck_(l, key) {
return map_(l, a => a[key]);
}
/**
* Extracts the specified property from each object in the list.
*/
function pluck(key) {
return l => pluck_(l, key);
} // fold
function foldlSuffix(f, acc, array, length) {
for (let i = 0; i < length; ++i) {
acc = f(acc, array[i]);
}
return acc;
}
function foldlPrefix(f, acc, array, length) {
for (let i = length - 1; 0 <= i; --i) {
acc = f(acc, array[i]);
}
return acc;
}
function foldlNode(f, acc, node, depth) {
const {
array
} = node;
if (depth === 0) {
return foldlSuffix(f, acc, array, array.length);
}
for (let i = 0; i < array.length; ++i) {
acc = foldlNode(f, acc, array[i], depth - 1);
}
return acc;
}
/**
* Folds a function over a list. Left-associative.
*/
function reduce_(l, initial, f) {
const suffixSize = getSuffixSize(l);
const prefixSize = getPrefixSize(l);
initial = foldlPrefix(f, initial, l.prefix, prefixSize);
if (l.root !== undefined) {
initial = foldlNode(f, initial, l.root, getDepth(l));
}
return foldlSuffix(f, initial, l.suffix, suffixSize);
}
/**
* Folds a function over a list. Left-associative.
*/
function reduce(initial, f) {
return l => reduce_(l, initial, f);
}
/**
* Folds a function over a list from left to right while collecting
* all the intermediate steps in a resulting list.
*/
function scan_(l, initial, f) {
return reduce_(l, push_(emptyPushable(), initial), (l2, a) => push_(l2, f(unsafeLast(l2), a)));
}
/**
* Folds a function over a list from left to right while collecting
* all the intermediate steps in a resulting list.
*/
function scan(initial, f) {
return l => scan_(l, initial, f);
}
/**
* Invokes a given callback for each element in the list from left to
* right. Returns `undefined`.
*
* This function is very similar to map. It should be used instead of
* `map` when the mapping function has side-effects. Whereas `map`
* constructs a new list `forEach` merely returns `undefined`. This
* makes `forEach` faster when the new list is unneeded.
*
* @complexity O(n)
*/
function forEach_(l, callback) {
reduce_(l, undefined, (_, element) => callback(element));
}
/**
* Invokes a given callback for each element in the list from left to
* right. Returns `undefined`.
*
* This function is very similar to map. It should be used instead of
* `map` when the mapping function has side-effects. Whereas `map`
* constructs a new list `forEach` merely returns `undefined`. This
* makes `forEach` faster when the new list is unneeded.
*
* @complexity O(n)
*/
function forEach(callback) {
return l => forEach_(l, callback);
}
function filter_(l, predicate) {
return reduce_(l, emptyPushable(), (acc, a) => predicate(a) ? push_(acc, a) : acc);
}
function filter(predicate) {
return l => reduce_(l, emptyPushable(), (acc, a) => predicate(a) ? push_(acc, a) : acc);
}
/**
* Returns a new list that only contains the elements of the original
* list for which the f returns `Some`.
*
* @complexity O(n)
*/
function filterMap_(l, f) {
return reduce_(l, emptyPushable(), (acc, a) => {
const fa = f(a);
if (fa._tag === "Some") {
push_(acc, fa.value);
}
return acc;
});
}
/**
* Returns a new list that only contains the elements of the original
* list for which the f returns `Some`.
*
* @complexity O(n)
*/
function filterMap(f) {
return l => filterMap_(l, f);
}
/**
* Filter out optional values
*/
function compact(fa) {
return filterMap(x => x)(fa);
}
/**
* Returns a new list that only contains the elements of the original
* list for which the predicate returns `false`.
*
* @complexity O(n)
*/
function filterNot_(l, predicate) {
return reduce_(l, emptyPushable(), (acc, a) => predicate(a) ? acc : push_(acc, a));
}
/**
* Returns a new list that only contains the elements of the original
* list for which the predicate returns `false`.
*
* @complexity O(n)
*/
function filterNot(predicate) {
return l => filterNot_(l, predicate);
}
function partition_(l, predicate) {
return reduce_(l, Tp.tuple(emptyPushable(), emptyPushable()), (arr, a) => (predicate(a) ? push_(arr.get(0), a) : push_(arr.get(1), a), arr));
}
function partition(predicate) {
return l => partition_(l, predicate);
}
/**
* Splits the list into two lists. One list that contains the lefts
* and one contains the rights
*
* @complexity O(n)
*/
function partitionMap_(l, f) {
return reduce_(l, Tp.tuple(emptyPushable(), emptyPushable()), (arr, a) => {
const fa = f(a);
if (fa._tag === "Left") {
push_(arr.get(0), fa.left);
} else {
push_(arr.get(1), fa.right);
}
return arr;
});
}
/**
* Splits the list into two lists. One list that contains the lefts
* and one contains the rights
*
* @complexity O(n)
*/
function partitionMap(f) {
return l => partitionMap_(l, f);
}
/**
* Splits the list into two lists. One list that contains the lefts
* and one contains the rights
*
* @complexity O(n)
*/
function separate(l) {
return partitionMap_(l, _index.identity);
}
/**
* Concats the strings in the list separated by a specified separator.
*/
function join_(l, separator) {
return reduce_(l, "", (a, b) => a.length === 0 ? b : a + separator + b);
}
/**
* Concats the strings in the list separated by a specified separator.
*/
function join(separator) {
return l => join_(l, separator);
}
function foldrSuffix(f, initial, array, length) {
let acc = initial;
for (let i = length - 1; 0 <= i; --i) {
acc = f(array[i], acc);
}
return acc;
}
function foldrPrefix(f, initial, array, length) {
let acc = initial;
for (let i = 0; i < length; ++i) {
acc = f(array[i], acc);
}
return acc;
}
function foldrNode(f, initial, {
array
}, depth) {
if (depth === 0) {
return foldrSuffix(f, initial, array, array.length);
}
let acc = initial;
for (let i = array.length - 1; 0 <= i; --i) {
acc = foldrNode(f, acc, array[i], depth - 1);
}
return acc;
}
/**
* Folds a function over a list. Right-associative.
*
* @complexity O(n)
*/
function reduceRight_(l, initial, f) {
const suffixSize = getSuffixSize(l);
const prefixSize = getPrefixSize(l);
let acc = foldrSuffix(f, initial, l.suffix, suffixSize);
if (l.root !== undefined) {
acc = foldrNode(f, acc, l.root, getDepth(l));
}
return foldrPrefix(f, acc, l.prefix, prefixSize);
}
/**
* Folds a function over a list. Right-associative.
*
* @complexity O(n)
*/
function reduceRight(initial, f) {
return l => reduceRight_(l, initial, f);
}
/**
* Applies a list of functions to a list of values.
*/
function ap_(listF, l) {
return flatten(map_(listF, f => map_(l, f)));
}
/**
* Applies a list of functions to a list of values.
*/
function ap(l) {
return listF => ap_(listF, l);
}
/**
* Flattens a list of lists into a list. Note that this function does
* not flatten recursively. It removes one level of nesting only.
*
* @complexity O(n * log(m)), where n is the length of the outer list and m the length of the inner lists.
*/
function flatten(nested) {
return reduce_(nested, empty(), concat_);
}
/**
* Maps a function over a list and concatenates all the resulting
* lists together.
*/
function chain_(l, f) {
return flatten(map_(l, f));
}
/**
* Maps a function over a list and concatenates all the resulting
* lists together.
*/
function chain(f) {
return l => chain_(l, f);
}
function foldlArrayCb(cb, state, array, from, to) {
for (var i = from; i < to && cb(array[i], state); ++i) {//
}
return i === to;
}
function foldrArrayCb(cb, state, array, from, to) {
for (var i = from - 1; to <= i && cb(array[i], state); --i) {//
}
return i === to - 1;
}
function foldlNodeCb(cb, state, node, depth) {
const {
array
} = node;
if (depth === 0) {
return foldlArrayCb(cb, state, array, 0, array.length);
}
const to = array.length;
for (let i = 0; i < to; ++i) {
if (!foldlNodeCb(cb, state, array[i], depth - 1)) {
return false;
}
}
return true;
}
/**
* This function is a lot like a fold. But the reducer function is
* supposed to mutate its state instead of returning it. Instead of
* returning a new state it returns a boolean that tells wether or not
* to continue the fold. `true` indicates that the folding should
* continue.
*/
function foldlCb(cb, state, l) {
const prefixSize = getPrefixSize(l);
if (!foldrArrayCb(cb, state, l.prefix, prefixSize, 0) || l.root !== undefined && !foldlNodeCb(cb, state, l.root, getDepth(l))) {
return state;
}
const suffixSize = getSuffixSize(l);
foldlArrayCb(cb, state, l.suffix, 0, suffixSize);
return state;
}
function foldrNodeCb(cb, state, node, depth) {
const {
array
} = node;
if (depth === 0) {
return foldrArrayCb(cb, state, array, array.length, 0);
}
for (let i = array.length - 1; 0 <= i; --i) {
if (!foldrNodeCb(cb, state, array[i], depth - 1)) {
return false;
}
}
return true;
}
function foldrCb(cb, state, l) {
const suffixSize = getSuffixSize(l);
const prefixSize = getPrefixSize(l);
if (!foldrArrayCb(cb, state, l.suffix, suffixSize, 0) || l.root !== undefined && !foldrNodeCb(cb, state, l.root, getDepth(l))) {
return state;
}
const prefix = l.prefix;
foldlArrayCb(cb, state, l.prefix, prefix.length - prefixSize, prefix.length);
return state;
}
/**
* Similar to `foldl`. But, for each element it calls the predicate function
* _before_ the folding function and stops folding if it returns `false`.
*
* @category Folds
* @example
* const isOdd = (_acc:, x) => x % 2 === 1;
*
* const xs = L.list(1, 3, 5, 60, 777, 800);
* foldlWhile(isOdd, (n, m) => n + m, 0, xs) //=> 9
*
* const ys = L.list(2, 4, 6);
* foldlWhile(isOdd, (n, m) => n + m, 111, ys) //=> 111
*/
function foldlWhileCb(a, state) {
if (state.predicate(state.result, a) === false) {
return false;
}
state.result = state.f(state.result, a);
return true;
}
function reduceWhile_(l, initial, predicate, f) {
return foldlCb(foldlWhileCb, {
predicate,
f,
result: initial
}, l).result;
}
function reduceWhile(initial, predicate, f) {
return l => reduceWhile_(l, initial, predicate, f);
}
function everyCb(value, state) {
return state.result = state.predicate(value);
}
/**
* Returns `true` if and only if the predicate function returns `true`
* for all elements in the given list.
*
* @complexity O(n)
*/
function every_(l, predicate) {
return foldlCb(everyCb, {
predicate,
result: true
}, l).result;
}
/**
* Returns `true` if and only if the predicate function returns `true`
* for all elements in the given list.
*
* @complexity O(n)
*/
function every(predicate) {
return l => every_(l, predicate);
}
function someCb(value, state) {
return !(state.result = state.predicate(value));
}
/**
* Returns true if and only if there exists an element in the list for
* which the predicate returns true.
*
* @complexity O(n)
*/
function some_(l, predicate) {
return foldlCb(someCb, {
predicate,
result: false
}, l).result;
}
/**
* Returns true if and only if there exists an element in the list for
* which the predicate returns true.
*
* @complexity O(n)
*/
function some(predicate) {
return l => some_(l, predicate);
}
/**
* Returns `true` if and only if the predicate function returns
* `false` for every element in the given list.
*
* @complexity O(n)
*/
function none_(l, predicate) {
return !some_(l, predicate);
}
/**
* Returns `true` if and only if the predicate function returns
* `false` for every element in the given list.
*
* @complexity O(n)
*/
function none(predicate) {
return l => none_(l, predicate);
}
function findCb(value, state) {
if (state.predicate(value)) {
state.result = O.some(value);
return false;
} else {
return true;
}
}
/**
* Returns the _first_ element for which the predicate returns `true`.
* If no such element is found the function returns `undefined`.
*
* @complexity O(n)
*/
function unsafeFind_(l, predicate) {
return O.toUndefined(find_(l, predicate));
}
/**
* Returns the _first_ element for which the predicate returns `true`.
* If no such element is found the function returns `undefined`.
*
* @complexity O(n)
*/
function unsafeFind(predicate) {
return l => unsafeFind_(l, predicate);
}
/**
* Returns the _first_ element for which the predicate returns `true`.
* If no such element is found the function returns `undefined`.
*
* @complexity O(n)
*/
function find_(l, predicate) {
return foldlCb(findCb, {
predicate,
result: O.none
}, l).result;
}
/**
* Returns the _first_ element for which the predicate returns `true`.
* If no such element is found the function returns `undefined`.
*
* @complexity O(n)
*/
function find(predicate) {
return l => find_(l, predicate);
}
/**
* Returns the _last_ element for which the predicate returns `true`.
* If no such element is found the function returns `undefined`.
*
* @complexity O(n)
*/
function unsafeFindLast_(l, predicate) {
return O.toUndefined(findLast_(l, predicate));
}
/**
* Returns the _last_ element for which the predicate returns `true`.
* If no such element is found the function returns `undefined`.
*
* @complexity O(n)
*/
function unsafeFindLast(predicate) {
return l => unsafeFindLast_(l, predicate);
}
/**
* Returns the _last_ element for which the predicate returns `true`.
* If no such element is found the function returns `undefined`.
*
* @complexity O(n)
*/
function findLast_(l, predicate) {
return foldrCb(findCb, {
predicate,
result: O.none
}, l).result;
}
/**
* Returns the _last_ element for which the predicate returns `true`.
* If no such element is found the function returns `undefined`.
*
* @complexity O(n)
*/
function findLast(predicate) {
return l => findLast_(l, predicate);
}
function indexOfCb(value, state) {
++state.index;
return !(state.found = elementEquals(value, state.element));
}
/**
* Returns the index of the _first_ element in the list that is equal
* to the given element. If no such element is found `-1` is returned.
*
* @complexity O(n)
*/
function indexOf_(l, element) {
const state = {
element,
found: false,
index: -1
};
foldlCb(indexOfCb, state, l);
return state.found ? state.index : -1;
}
/**
* Returns the index of the _first_ element in the list that is equal
* to the given element. If no such element is found `-1` is returned.
*
* @complexity O(n)
*/
function indexOf(element) {
return l => indexOf_(l, element);
}
/**
* Returns the index of the _last_ element in the list that is equal
* to the given element. If no such element is found `-1` is returned.
*
* @complexity O(n)
*/
function lastIndexOf_(l, element) {
const state = {
element,
found: false,
index: 0
};
foldrCb(indexOfCb, state, l);
return state.found ? l.length - state.index : -1;
}
/**
* Returns the index of the _last_ element in the list that is equal
* to the given element. If no such element is found `-1` is returned.
*
* @complexity O(n)
*/
function lastIndexOf(element) {
return l => lastIndexOf_(l, element);
}
function findIndexCb(value, state) {
++state.index;
return !(state.found = state.predicate(value));
}
/**
* Returns the index of the `first` element for which the predicate
* returns true. If no such element is found the function returns
* `-1`.
*
* @complexity O(n)
*/
function findIndex_(l, predicate) {
const {
found,
index
} = foldlCb(findIndexCb, {
predicate,
found: false,
index: -1
}, l);
return found ? index : -1;
}
/**
* Returns the index of the `first` element for which the predicate
* returns true. If no such element is found the function returns
* `-1`.
*
* @complexity O(n)
*/
function findIndex(predicate) {
return l => findIndex_(l, predicate);
}
const containsState = {
element: undefined,
result: false
};
function containsCb(value, state) {
return !(state.result = value === state.element);
}
/**
* Returns `true` if the list contains the specified element.
* Otherwise it returns `false`.
*
* @complexity O(n)
*/
function contains_(l, element) {
containsState.element = element;
containsState.result = false;
return foldlCb(containsCb, containsState, l).result;
}
/**
* Returns `true` if the list contains the specified element.
* Otherwise it returns `false`.
*
* @complexity O(n)
*/
function contains(element) {
return l => contains_(l, element);
}
function equalsCb(value2, state) {
const {
value
} = state.iterator.next();
return state.equals = state.f(value, value2);
}
/**
* Returns true if the two lists are equivalent.
*
* @complexity O(n)
*/
function equals_(l1, l2) {
return equalsWith_(l1, l2, elementEquals);
}
/**
* Returns true if the two lists are equivalent.
*
* @complexity O(n)
*/
function equals(l2) {
return l1 => equals_(l1, l2);
}
/**
* Returns true if the two lists are equivalent when comparing each
* pair of elements with the given comparison function.
*
* @complexity O(n)
*/
function equalsWith_(l1, l2, f) {
if (l1 === l2) {
return true;
} else if (l1.length !== l2.length) {
return false;
} else {
const s = {
iterator: l2[Symbol.iterator](),
equals: true,
f
};
return foldlCb(equalsCb, s, l1).equals;
}
}
/**
* Returns true if the two lists are equivalent when comparing each
* pair of elements with the given comparison function.
*
* @complexity O(n)
*/
function equalsWith(l2, f) {
return l1 => equalsWith_(l1, l2, f);
} // concat
const eMax = 2;
function createConcatPlan(array) {
const sizes = [];
let sum = 0;
for (let i = 0; i < array.length; ++i) {
sum += array[i].array.length; // FIXME: maybe only access array once
sizes[i] = array[i].array.length;
}
const optimalLength = Math.ceil(sum / branchingFactor);
let n = array.length;
let i = 0;
if (optimalLength + eMax >= n) {
return undefined; // no rebalancing needed
}
while (optimalLength + eMax < n) {
while (sizes[i] > branchingFactor - eMax / 2) {
// Skip nodes that are already sufficiently balanced
++i;
} // the node at this index is too short
let remaining = sizes[i]; // number of elements to re-distribute
do {
const size = Math.min(remaining + sizes[i + 1], branchingFactor);
sizes[i] = size;
remaining = remaining - (size - sizes[i + 1]);
++i;
} while (remaining > 0); // Shift nodes after
for (let j = i; j <= n - 1; ++j) {
sizes[j] = sizes[j + 1];
}
--i;
--n;
}
sizes.length = n;
return sizes;
}
/**
* Combines the children of three nodes into an array. The last child
* of `left` and the first child of `right is ignored as they've been
* concatenated into `center`.
*/
function concatNodeMerge(left, center, right) {
const array = [];
if (left !== undefined) {
for (let i = 0; i < left.array.length - 1; ++i) {
array.push(left.array[i]);
}
}
for (let i = 0; i < center.array.length; ++i) {
array.push(center.array[i]);
}
if (right !== undefined) {
for (let i = 1; i < right.array.length; ++i) {
array.push(right.array[i]);
}
}
return array;
}
function executeConcatPlan(merged, plan, height) {
const result = [];
let sourceIdx = 0; // the current node we're copying from
let offset = 0; // elements in source already used
for (let toMove of plan) {
let source = merged[sourceIdx].array;
if (toMove === source.length && offset === 0) {
// source matches target exactly, reuse source
result.push(merged[sourceIdx]);
++sourceIdx;
} else {
const node = new Node(undefined, []);
while (toMo