UNPKG

@techmely/utils

Version:

Collection of helpful JavaScript / TypeScript utils

207 lines (202 loc) 5.95 kB
'use strict'; /*! * @techmely/utils * Copyright(c) 2021-2024 Techmely <techmely.creation@gmail.com> * MIT Licensed */ // src/RopeSequence/RopeSequence.ts var RopeSequence = class _RopeSequence { // Create a rope representing the given array, or return the rope // itself if a rope was given. static from(values) { if (values instanceof _RopeSequence) return values; return values?.length ? new Leaf(values) : _RopeSequence.empty; } leafAppend(other) { return void 0; } leafPrepend(other) { return void 0; } sliceInner(from, to) { return new Leaf([]); } getInner(index) { return void 0; } forEachInner(f, from, to, start) { } forEachInvertedInner(f, from, to, start) { } /** * Append an array or other rope to this one, returning a new rope. */ append(other) { if (!other.length) return this; other = _RopeSequence.from(other); return !this.length && other || other.length < GOOD_LEAF_SIZE && this.leafAppend(other) || this.length < GOOD_LEAF_SIZE && other.leafPrepend(this) || this.appendInner(other); } // :: (union<[T], RopeSequence<T>>) → RopeSequence<T> // Prepend an array or other rope to this one, returning a new rope. prepend(other) { if (!other.length) return this; return _RopeSequence.from(other).append(this); } appendInner(other) { return new Append(this, other); } /** * Create a rope representing a sub-sequence of this rope. */ slice(from = 0, to = _RopeSequence.length) { if (from >= to) return _RopeSequence.empty; return this.sliceInner(Math.max(0, from), Math.min(this.length, to)); } // :: (number) → T // Retrieve the element at the given position from this rope. get(i) { if (i < 0 || i >= _RopeSequence.length) return void 0; return this.getInner(i); } // :: ((element: T, index: number) → ?bool, ?number, ?number) // Call the given function for each element between the given // indices. This tends to be more efficient than looping over the // indices and calling `get`, because it doesn't have to descend the // tree for every element. forEach(f, from = 0, to = _RopeSequence.length) { if (from <= to) this.forEachInner(f, from, to, 0); else this.forEachInvertedInner(f, from, to, 0); } // Map the given functions over the elements of the rope, producing // a flat array. map(f, from = 0, to = _RopeSequence.length) { const result = []; this.forEach((elt, i) => result.push(f(elt, i)), from, to); return result; } set length(v) { this.length = v; } get length() { return this.values.length; } }; var GOOD_LEAF_SIZE = 200; var Leaf = class _Leaf extends RopeSequence { constructor(values) { super(); this.values = values; } flatten() { return this.values; } sliceInner(from, to) { if (from === 0 && to === this.length) return this; return new _Leaf(this.values.slice(from, to)); } getInner(i) { return this.values[i]; } forEachInner(f, from, to, start) { for (let i = from; i < to; i++) if (f(this.values[i], start + i) === false) return false; } forEachInvertedInner(f, from, to, start) { for (let i = from - 1; i >= to; i--) if (f(this.values[i], start + i) === false) return false; } leafAppend(other) { if (this.length + other.length <= GOOD_LEAF_SIZE) return new _Leaf(this.values.concat(other.flatten())); } leafPrepend(other) { if (this.length + other.length <= GOOD_LEAF_SIZE) return new _Leaf(other.flatten().concat(this.values)); } set length(v) { this.length = v; } get length() { return this.values.length; } get depth() { return 0; } }; RopeSequence.empty = new Leaf([]); var Append = class _Append extends RopeSequence { constructor(left, right) { super(); this.left = left; this.right = right; this.length = left.length + right.length; this.depth = Math.max(left.depth, right.depth) + 1; } flatten() { return this.left.flatten().concat(this.right.flatten()); } getInner(i) { return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length); } forEachInner(f, from, to, start) { const leftLen = this.left.length; if (from < leftLen && this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false) return false; if (to > leftLen && this.right.forEachInner( f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen ) === false) return false; } forEachInvertedInner(f, from, to, start) { const leftLen = this.left.length; if (from > leftLen && this.right.forEachInvertedInner( f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen ) === false) return false; if (to < leftLen && this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false) return false; } sliceInner(from, to) { if (from === 0 && to === this.length) return this; const leftLen = this.left.length; if (to <= leftLen) return this.left.slice(from, to); if (from >= leftLen) return this.right.slice(from - leftLen, to - leftLen); return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen)); } leafAppend(other) { const inner = this.right.leafAppend(other); if (inner) return new _Append(this.left, inner); } leafPrepend(other) { const inner = this.left.leafPrepend(other); if (inner) return new _Append(inner, this.right); } appendInner(other) { if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1) return new _Append(this.left, new _Append(this.right, other)); return new _Append(this, other); } }; exports.GOOD_LEAF_SIZE = GOOD_LEAF_SIZE; exports.RopeSequence = RopeSequence;