UNPKG

chardata-charset

Version:

CharSet class for the ucdata package

1,054 lines 39.5 kB
"use strict"; /*! * Copyright 2018 Ron Buckton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); const MIN_CODE_POINT = 0; const MAX_CODE_POINT = 0x10ffff; const MAX_ASCII_CODE_POINT = 0x7f; class Range { constructor(start, end = start) { if (end < start) throw new RangeError("'end' may not come before 'start'"); if (start < MIN_CODE_POINT) throw new RangeError(`Argument out of range: start`); if (end > MAX_CODE_POINT) throw new RangeError(`Argument out of range: end`); this.start = start; this.end = end; } get size() { return this.end - this.start + 1; } static fromStartLength(start, length) { return new Range(start, start + length); } /* istanbul ignore next */ _debugToString() { return this.size === 1 ? `(${this.start})` : `(${this.start},${this.end})`; } } Range.domain = new Range(MIN_CODE_POINT, MAX_CODE_POINT); class Tree { constructor() { this.root = Node.nil; this.codePointCount = 0; this.codePointRangeCount = 0; this.hasChanges = false; this.offBalance = false; } } class Node { constructor(tree, range) { this.tree = tree; this.parent = Node.nil; this.left = Node.nil; this.right = Node.nil; this.range = range; this.min = range; this.max = range; this.height = 1; } /* istanbul ignore next */ _debugToString(pretty) { if (this === Node.nil) return ``; const side = this === this.parent.left ? `L` : this === this.parent.right ? `R` : `N`; const extra = pretty ? ` h:${this.height}, b:${balance(this)}` : ``; return `${side}${this.range["_debugToString"]()}${extra}`; } } Node.nil = (() => { const nil = Object.create(Node.prototype); nil.tree = Object.create(Tree.prototype); nil.tree.root = nil; nil.tree.codePointCount = 0; nil.tree.codePointRangeCount = 0; nil.tree.hasChanges = false; nil.tree.offBalance = false; nil.parent = nil; nil.left = nil; nil.right = nil; nil.range = new Range(0); nil.min = nil.range; nil.max = nil.range; nil.height = 0; Object.freeze(nil.tree); Object.freeze(nil.range); Object.freeze(nil); return nil; })(); class CharSet { constructor(iterable) { this._characterClass = undefined; this._tree = new Tree(); if (iterable) { for (const value of iterable) { if (typeof value === "number") this.add(value); else if (Array.isArray(value)) this.add(value); else if (value instanceof CharSet) this.add(value); else throw new TypeError(); } } } get size() { return this._tree.codePointCount; } get characterClass() { if (this._characterClass === undefined) { let characterClass = "["; for (let n = min(this._tree.root); n !== Node.nil; n = successor(n)) { characterClass += n.range.size === 1 ? `\\u{${n.range.start.toString(16)}}` : `\\u{${n.range.start.toString(16)}}-\\u{${n.range.end.toString(16)}}`; } this._characterClass = characterClass + "]"; } return this._characterClass; } static empty() { return CharSet._empty || (CharSet._empty = Object.freeze(new CharSet())); } static any() { return CharSet._any || (CharSet._any = Object.freeze(new CharSet().add(MIN_CODE_POINT, MAX_CODE_POINT))); } static ascii() { return CharSet._ascii || (CharSet._ascii = Object.freeze(new CharSet().add(MIN_CODE_POINT, MAX_ASCII_CODE_POINT))); } static range(fromCodePoint, toCodePoint) { return new CharSet().add(fromCodePoint, toCodePoint); } static from(iterable) { return new CharSet(iterable); } static of(...args) { return new CharSet(args); } static fromStartLengthArray(array) { if (array.length % 2 !== 0) throw new TypeError(); const set = new CharSet(); if (array.length === 0) return set; const chunks = []; let start = 0; let end = array.length >> 1; let mid = start + ((end - start) >> 1); let index = mid << 1; const root = new Node(set._tree, Range.fromStartLength(array[index], array[index + 1])); set._tree.codePointRangeCount++; set._tree.codePointCount += root.range.size; chunks.push(mid + 1, end); // push the right side end = mid; let current = root; while (start < end) { mid = start + ((end - start) >> 1); index = mid << 1; const k = Range.fromStartLength(array[index], array[index + 1]); if (k.end >= current.range.start - 1) throw new TypeError(); current.left = new Node(set._tree, k); current.left.parent = current; current = current.left; set._tree.codePointRangeCount++; set._tree.codePointCount += current.range.size; chunks.push(mid + 1, end); end = mid; } while (chunks.length > 0) { end = chunks.pop(); start = chunks.pop(); if (start < end && current.right === Node.nil) { chunks.push(start, end); mid = start + ((end - start) >> 1); index = mid << 1; const k = Range.fromStartLength(array[index], array[index + 1]); if (k.start <= current.range.end + 1) throw new TypeError(); current.right = new Node(set._tree, k); current.right.parent = current; current = current.right; set._tree.codePointRangeCount++; set._tree.codePointCount += current.range.size; chunks.push(mid + 1, end); end = mid; while (start < end) { mid = start + ((end - start) >> 1); index = mid << 1; const k = Range.fromStartLength(array[index], array[index + 1]); if (k.end >= current.range.start - 1) throw new TypeError(); current.left = new Node(set._tree, k); current.left.parent = current; current = current.left; set._tree.codePointRangeCount++; set._tree.codePointCount += current.range.size; chunks.push(mid + 1, end); end = mid; } } else { recalculate(current); current = current.parent; } } recalculate(root); set._tree.root = root; return set; } has(start, end) { if (start instanceof CharSet) { return this.supersetOf(start); } let range; if (typeof start === "number") { range = new Range(start, end); } else if (Array.isArray(start) && typeof start[0] === "number" && typeof start[1] === "number") { range = new Range(start[0], start[1]); } else { throw new TypeError("Invalid argument"); } let node = this._tree.root; while (node !== Node.nil) { if (range.end < node.range.start) { node = node.left; } else if (range.start > node.range.end) { node = node.right; } else { return node.range.start <= range.start && node.range.end >= range.end; } } return false; } add(start, end) { if (Object.isFrozen(this)) throw new TypeError("Object is read-only."); if (start instanceof CharSet) { if (start._tree.codePointRangeCount === 0) return this; if (start._tree.codePointRangeCount > 1) { const tree = new Tree(); tree.root = union(tree, this._tree.root, start._tree.root); this._tree = tree; return this; } const range = start._tree.root.range; start = range.start; end = range.end; } let range; if (typeof start === "number") { range = new Range(start, end); } else if (Array.isArray(start) && typeof start[0] === "number" && typeof start[1] === "number") { range = new Range(start[0], start[1]); } else { throw new TypeError(); } this._tree.root = insert(this._tree, this._tree.root, Node.nil, range); this._tree.offBalance = false; if (this._tree.hasChanges) { this._tree.hasChanges = false; this._characterClass = undefined; } return this; } delete(start, end) { if (Object.isFrozen(this)) throw new TypeError("Object is read-only."); if (start instanceof CharSet) { if (start._tree.codePointRangeCount === 0) return this; if (start._tree.codePointRangeCount > 1) { const tree = new Tree(); tree.root = difference(tree, this._tree.root, start._tree.root); this._tree = tree; return this; } const range = start._tree.root.range; start = range.start; end = range.end; } let range; if (typeof start === "number") { range = new Range(start, end); } else if (Array.isArray(start) && typeof start[0] === "number" && typeof start[1] === "number") { range = new Range(start[0], start[1]); } else { throw new TypeError(); } this._tree.root = remove(this._tree, this._tree.root, Node.nil, range); this._tree.offBalance = false; if (this._tree.hasChanges) { this._tree.hasChanges = false; this._characterClass = undefined; return true; } return false; } clear() { if (Object.isFrozen(this)) throw new TypeError("Object is read-only."); this._tree = new Tree(); this._characterClass = undefined; } union(other) { if (!(other instanceof CharSet)) throw new TypeError(); const set = new CharSet(); set._tree.root = union(set._tree, this._tree.root, other._tree.root); return set; } intersect(other) { if (!(other instanceof CharSet)) throw new TypeError(); const set = new CharSet(); set._tree.root = intersect(set._tree, this._tree.root, other._tree.root); return set; } except(other) { if (!(other instanceof CharSet)) throw new TypeError(); const set = new CharSet(); set._tree.root = difference(set._tree, this._tree.root, other._tree.root); return set; } invert() { const set = new CharSet(); set._tree.root = difference(set._tree, new Node(this._tree, Range.domain), this._tree.root); return set; } equals(other) { if (!(other instanceof CharSet)) throw new TypeError(); if (this === other) return true; if (this._tree.root === Node.nil) return other._tree.root === Node.nil; if (other._tree.root === Node.nil) return false; let l = min(this._tree.root); let r = min(other._tree.root); while (l !== Node.nil && r !== Node.nil) { if (l.range.start !== r.range.start || l.range.end !== r.range.end) return false; l = successor(l); r = successor(r); } return l === Node.nil && r === Node.nil; } supersetOf(subset, proper) { if (!(subset instanceof CharSet)) throw new TypeError(); if (this === subset) return !proper; if (this._tree.root === Node.nil) return !proper && subset._tree.root === Node.nil; if (subset._tree.root === Node.nil) return true; let possiblyImproper = false; let supersetNode = min(this._tree.root); let subsetNode = min(subset._tree.root); while (supersetNode !== Node.nil && subsetNode !== Node.nil) { const supersetRange = supersetNode.range; const subsetRange = subsetNode.range; if (supersetRange.start === subsetRange.start && supersetRange.end === subsetRange.end) { supersetNode = successor(supersetNode); subsetNode = successor(subsetNode); } else { if (supersetRange.end < subsetRange.start) { supersetNode = successor(supersetNode); } else if (supersetRange.start <= subsetRange.start && supersetRange.end >= subsetRange.end) { subsetNode = successor(subsetNode); } else { return false; } possiblyImproper = true; } } if (supersetNode === Node.nil) possiblyImproper = true; if (subsetNode !== Node.nil) return false; if (proper && possiblyImproper) return false; return true; } subsetOf(superset, proper) { if (!(superset instanceof CharSet)) throw new TypeError(); return superset.supersetOf(this, proper); } toStartLengthArray() { const array = []; const stack = []; let node = this._tree.root; while (node !== Node.nil) { stack.push(node); node = node.left; } while ((node = stack.pop() || Node.nil) !== Node.nil) { array.push(node.range.start, node.range.size - 1); if (node.right !== Node.nil) { node = node.right; while (node !== Node.nil) { stack.push(node); node = node.left; } } } return array; } *codePoints() { for (let n = min(this._tree.root); n !== Node.nil; n = successor(n)) { for (let i = n.range.start; i <= n.range.end; i++) { yield i; } } } *codePointRanges() { for (let n = min(this._tree.root); n !== Node.nil; n = successor(n)) { yield [n.range.start, n.range.end]; } } [Symbol.iterator]() { return this.codePoints(); } /* istanbul ignore next */ get _debugCodePointRangeCount() { return this._tree.codePointRangeCount; } /* istanbul ignore next */ _debugVerify() { const set = this; const context = { codePointRangeCount: 0, codePointCount: 0 }; const seen = new Set(); visit(this._tree, this._tree.root, Node.nil); assertEqual(this._tree.codePointCount, context.codePointCount, `Incorrect code point count.`); assertEqual(this._tree.codePointRangeCount, context.codePointRangeCount, `Incorrect code point range count.`); assertEqual(this._tree.hasChanges, false, `Tree should not have pending changes.`); assertEqual(this._tree.offBalance, false, `Tree should not have pending balance adjustments.`); function visit(tree, node, parent) { if (node === Node.nil) return; assert(node.tree === tree, `Incorrect tree.`); assertEqual(node.parent, parent, `Incorrect parent.`); assert(parent !== Node.nil || tree.root === node, `Non-root node has no parent.`); assert(Math.abs(balance(node)) <= 1, `Off-balance node: ${node["_debugToString"](true)}`); if (parent.left === node) { assert(node.range.end < parent.range.start - 1, `${node["_debugToString"]()} overlaps or is adjacent to range of parent (${node.parent["_debugToString"]()})`); } if (parent.right === node) { assert(node.range.start > parent.range.end + 1, `${node["_debugToString"]()} overlaps or is adjacent to range of parent (${node.parent["_debugToString"]()})`); } assert(!seen.has(node), `Cycle exists in tree.`); context.codePointRangeCount++; context.codePointCount += node.range.size; visit(tree, node.left, node); if (node.left !== Node.nil) { assertEqual(node.min["_debugToString"](), node.left.min["_debugToString"](), `Incorrect min for node: ${node["_debugToString"]()}`); } else { assertEqual(node.min["_debugToString"](), node.range["_debugToString"](), `Incorrect min for node: ${node["_debugToString"]()}`); } visit(tree, node.right, node); if (node.right !== Node.nil) { assertEqual(node.max["_debugToString"](), node.right.max["_debugToString"](), `Incorrect max for node: ${node["_debugToString"]()}`); } else { assertEqual(node.max["_debugToString"](), node.range["_debugToString"](), `Incorrect max for node: ${node["_debugToString"]()}`); } } function assert(test, message = "Assertion failed.") { if (!test) { message += `\n${set._debugToString(true)}`; const err = new Error(message); if (Error.captureStackTrace) Error.captureStackTrace(err, assert); throw err; } } function assertEqual(actual, expected, message = "Assertion failed.") { if (expected !== actual) { message += "\n"; if (expected instanceof Node) expected = expected["_debugToString"](); if (actual instanceof Node) actual = actual["_debugToString"](); message += `Expected: ${expected}, Actual: ${actual}`; message += `\n${set._debugToString(true)}`; const err = new Error(message); if (Error.captureStackTrace) Error.captureStackTrace(err, assertEqual); throw err; } } } /* istanbul ignore next */ _debugToString(pretty) { const set = new Set(); return visit(this._tree.root, ""); function visit(node, indent) { if (node === Node.nil) return ""; if (set.has(node)) return "[Circular]"; set.add(node); let text = `${indent}${node["_debugToString"](pretty)}`; if (node.left !== Node.nil || node.right !== Node.nil) { if (!pretty) text += `{`; if (node.left !== Node.nil) { if (pretty) text += `\n`; text += visit(node.left, pretty ? ` ` + indent : ``); } if (node.right !== Node.nil) { if (pretty) text += `\n`; text += visit(node.right, pretty ? ` ` + indent : ``); } if (!pretty) text += `}`; } return text; } } } CharSet.MIN_CODE_POINT = MIN_CODE_POINT; CharSet.MAX_CODE_POINT = MAX_CODE_POINT; CharSet.MAX_ASCII_CODE_POINT = MAX_ASCII_CODE_POINT; exports.CharSet = CharSet; function balance(node) { return node.right.height - node.left.height; } function recalculate(node) { node.height = 1 + (node.left.height > node.right.height ? node.left.height : node.right.height); node.min = node.left === Node.nil ? node.range : node.left.min; node.max = node.right === Node.nil ? node.range : node.right.max; } function rotateLeft(node) { const center = node.right; node.right = center.left; center.left = node; center.parent = node.parent; node.parent = center; if (node.right !== Node.nil) node.right.parent = node; recalculate(node); recalculate(center); return center; } function rotateRight(node) { const center = node.left; node.left = center.right; center.right = node; center.parent = node.parent; node.parent = center; if (node.left !== Node.nil) node.left.parent = node; recalculate(node); recalculate(center); return center; } function rotateLeftRight(node) { const left = node.left; const center = left.right; left.right = center.left; node.left = center.right; center.left = left; center.right = node; center.parent = node.parent; left.parent = center; node.parent = center; if (left.right !== Node.nil) left.right.parent = left; if (node.left !== Node.nil) node.left.parent = node; recalculate(left); recalculate(node); recalculate(center); return center; } function rotateRightLeft(node) { const right = node.right; const center = right.left; right.left = center.right; node.right = center.left; center.left = node; center.right = right; center.parent = node.parent; node.parent = center; right.parent = center; if (node.right !== Node.nil) node.right.parent = node; if (right.left !== Node.nil) right.left.parent = right; recalculate(node); recalculate(right); recalculate(center); return center; } function insert(tree, node, parent, k) { let reuseFrame; do { if (node === Node.nil) { node = new Node(tree, k); node.parent = parent; tree.offBalance = true; tree.hasChanges = true; tree.codePointRangeCount++; tree.codePointCount += k.size; return node; } const m = node.range; if (k.end < m.start - 1) { node.left = insert(tree, node.left, node, k); reuseFrame = false; } else if (k.start > m.end + 1) { node.right = insert(tree, node.right, node, k); reuseFrame = false; } else if (k.start < m.start && node.left !== Node.nil) { if (k.start - 1 === node.left.max.end) console.log("Abuts left max end"); node.left = remove(tree, node.left, node, new Range(k.start, m.start - 1)); node.range = new Range(k.start, m.end); tree.hasChanges = true; tree.codePointCount += m.start - k.start; reuseFrame = true; // try again (reuse stack frame) } else if (k.end > m.end && node.right !== Node.nil) { node.right = remove(tree, node.right, node, new Range(m.end + 1, k.end)); node.range = new Range(m.start, k.end); tree.hasChanges = true; tree.codePointCount += k.end - m.end; reuseFrame = true; // try again (reuse stack frame) } else if (node.left !== Node.nil && k.start - 1 === node.left.max.end) { k = new Range(node.left.max.start, k.end); reuseFrame = true; } else if (node.right !== Node.nil && k.end + 1 === node.right.min.start) { k = new Range(k.start, node.right.min.end); reuseFrame = true; } else if (k.start >= m.start && k.end <= m.end) { return node; } else { node.range = new Range(Math.min(m.start, k.start), Math.max(m.end, k.end)); tree.hasChanges = true; tree.codePointCount += node.range.size - m.size; reuseFrame = false; } recalculate(node); if (tree.offBalance) { switch (balance(node)) { case 0: tree.offBalance = false; break; case 1: case -1: break; case -2: switch (balance(node.left)) { case -1: node = rotateRight(node); tree.offBalance = false; break; case 1: node = rotateLeftRight(node); tree.offBalance = false; break; } break; case 2: switch (balance(node.right)) { case -1: node = rotateRightLeft(node); tree.offBalance = false; break; case 1: node = rotateLeft(node); tree.offBalance = false; break; } break; /* istanbul ignore next */ default: throw new TypeError(`off balance: ${balance(node)}`); } } } while (reuseFrame); return node; } function remove(tree, node, parent, k) { let reuseFrame; do { if (node === Node.nil) return Node.nil; const m = node.range; if (k.end < m.start) { if (node.left === Node.nil) return node; node.left = remove(tree, node.left, node, k); reuseFrame = false; } else if (k.start > m.end) { if (node.left === Node.nil) return node; node.right = remove(tree, node.right, node, k); reuseFrame = false; } else { if (k.start < m.start) { const k_ = new Range(k.start, m.start - 1); k = new Range(m.start, k.end); node.left = remove(tree, node.left, node, k_); reuseFrame = true; // try again (reuse stack frame) } else if (k.end > m.end) { const k_ = new Range(m.end + 1, k.end); k = new Range(k.start, m.end); node.right = remove(tree, node.right, node, k_); reuseFrame = true; // try again (reuse stack frame) } else if (k.start > m.start && k.end === m.end) { node.range = new Range(m.start, k.start - 1); tree.hasChanges = true; tree.codePointCount -= m.size - node.range.size; reuseFrame = false; } else if (k.start === m.start && k.end < m.end) { node.range = new Range(k.end + 1, m.end); tree.hasChanges = true; tree.codePointCount -= m.size - node.range.size; reuseFrame = false; } else if (k.start > m.start && k.end < m.end) { node.range = new Range(m.start, k.start - 1); node.right = insert(tree, node.right, node, new Range(k.end + 1, m.end)); tree.hasChanges = true; tree.codePointCount -= k.size + 2; reuseFrame = false; } else { if (node.left !== Node.nil && node.right !== Node.nil) { let min = node.right; while (min.left !== Node.nil) min = min.left; const range = min.range; min.range = node.range; node.range = range; node.right = remove(tree, node.right, node, k); reuseFrame = false; } else { tree.hasChanges = true; tree.offBalance = true; tree.codePointCount -= node.range.size; tree.codePointRangeCount--; if (node.left !== Node.nil) { node = node.left; node.parent = parent; return node; } if (node.right !== Node.nil) { node = node.right; node.parent = parent; return node; } return Node.nil; } } } recalculate(node); if (tree.offBalance) { switch (balance(node)) { case 0: break; case -1: case 1: tree.offBalance = false; break; case -2: switch (balance(node.left)) { case -1: node = rotateRight(node); break; case 0: node = rotateRight(node); tree.offBalance = false; break; case 1: node = rotateLeftRight(node); break; } break; case 2: switch (balance(node.right)) { case -1: node = rotateRightLeft(node); break; case 0: node = rotateLeft(node); tree.offBalance = false; break; case 1: node = rotateLeft(node); break; } break; /* istanbul ignore next */ default: throw new TypeError(`off balance: ${balance(node)}`); } } } while (reuseFrame); return node; } function min(node) { while (node.left !== Node.nil) node = node.left; return node; } function successor(node) { if (node === Node.nil) return Node.nil; if (node.right !== Node.nil) return min(node.right); while (node.parent !== Node.nil && node === node.parent.right) node = node.parent; return node.parent; } function createNode(tree, left, range, right) { const node = new Node(tree, range); node.left = importSubtree(tree, left); node.right = importSubtree(tree, right); if (node.left !== Node.nil) node.left.parent = node; if (node.right !== Node.nil) node.right.parent = node; recalculate(node); return node; } function split(tree, T, k) { if (T === Node.nil) return [Node.nil, undefined, Node.nil]; let { left: L, range: m, right: R } = T; if (k.end < m.start) { const [Ll, b, Lr] = split(tree, L, k); return [Ll, b, join(tree, Lr, m, R)]; } if (k.start > m.end) { const [Rl, b, Rr] = split(tree, R, k); return [join(tree, L, m, Rl), b, Rr]; } if (k.start < m.start) { const [Ll, , Lr] = split(tree, L, new Range(k.start, m.start - 1)); L = join2(tree, Ll, Lr); k = new Range(m.start, k.end); } if (k.end > m.end) { const [Rl, , Rr] = split(tree, R, new Range(m.end + 1, k.end)); R = join2(tree, Rl, Rr); k = new Range(k.start, m.end); } if (k.start > m.start) { const k_ = new Range(m.start, k.start - 1); const [Ll, , Lr] = split(tree, L, k_); L = join(tree, Ll, k_, Lr); m = new Range(k.start, m.end); } if (k.end < m.end) { const k_ = new Range(k.end + 1, m.end); const [Rl, , Rr] = split(tree, R, k_); R = join(tree, Rl, k_, Rr); m = new Range(m.start, k.end); } return [L, m, R]; } function join(tree, Tl, k, Tr) { if (Tl.height > Tr.height + 1) return joinRight(tree, Tl, k, Tr); if (Tr.height > Tl.height + 1) return joinLeft(tree, Tl, k, Tr); return createNode(tree, Tl, k, Tr); } function joinRight(tree, Tl, kR, Tr) { const { left: l, range: kL, right: c } = Tl; if (c.height <= Tr.height + 1) { const T_ = createNode(tree, c, kR, Tr); return T_.height <= l.height + 1 ? createNode(tree, l, kL, T_) : rotateLeft(createNode(tree, l, kL, rotateRight(T_))); } else { const T_ = joinRight(tree, c, kR, Tr); const T__ = createNode(tree, l, kL, T_); return T__.height <= l.height + 1 ? T__ : rotateLeft(T__); } } function joinLeft(tree, Tl, kL, Tr) { const { left: c, range: kR, right: r } = Tr; if (c.height <= Tl.height + 1) { const T_ = createNode(tree, Tl, kL, c); return T_.height <= r.height + 1 ? createNode(tree, T_, kR, r) : rotateRight(createNode(tree, rotateLeft(T_), kR, r)); } else { const T_ = joinLeft(tree, Tl, kL, c); const T__ = createNode(tree, T_, kR, r); return T__.height <= r.height + 1 ? T__ : rotateRight(T__); } } function join2(tree, Tl, Tr) { if (Tl === Node.nil) return Tr; const [Tl_, k] = splitLast(tree, Tl); return join(tree, Tl_, k, Tr); } function splitLast(tree, T) { const { left: L, range: k, right: R } = T; if (R === Node.nil) return [L, k]; const [T_, k_] = splitLast(tree, R); return [join(tree, L, k, T_), k_]; } function importSubtree(tree, node, context) { if (node === Node.nil) return Node.nil; const root = new Node(tree, node.range); root.min = node.min; root.max = node.max; root.height = node.height; let current = node; let clone = root; if (context) context.codePointRangeCount++, context.codePointCount += clone.range.size; while (current !== Node.nil && current !== node.parent) { if (current.left !== Node.nil && clone.left === Node.nil) { clone.left = new Node(tree, current.left.range); clone.left.min = current.left.min; clone.left.max = current.left.max; clone.left.parent = clone; clone.left.height = current.left.height; clone = clone.left; current = current.left; if (context) context.codePointRangeCount++, context.codePointCount += clone.range.size; } else if (current.right !== Node.nil && clone.right === Node.nil) { clone.right = new Node(tree, current.right.range); clone.right.parent = clone; clone.right.height = current.right.height; clone.right.min = current.right.min; clone.right.max = current.right.max; clone = clone.right; current = current.right; if (context) context.codePointRangeCount++, context.codePointCount += clone.range.size; } else { if (clone === root) break; current = current.parent; clone = clone.parent; } } return root; } function union(tree, T1, T2) { if (T1 === Node.nil) return importSubtree(tree, T2, tree); if (T2 === Node.nil) return importSubtree(tree, T1, tree); const { left: L2, range: k2, right: R2 } = T2; const [L1, k1, R1] = split(tree, T1, k2); let k = k1 ? new Range(Math.min(k1.start, k2.start), Math.max(k1.end, k2.end)) : k2; let Tl = union(tree, L1, L2); let Tr = union(tree, R1, R2); if (Tl !== Node.nil) { const Tlmax = Tl.max; if (Tlmax.end === k.start - 1) { tree.codePointRangeCount--; tree.codePointCount -= Tlmax.size; const [Tll, , Tlr] = split(tree, Tl, Tlmax); Tl = join2(tree, Tll, Tlr); k = new Range(Tlmax.start, k.end); } } if (Tr !== Node.nil) { const Trmin = Tr.min; if (Trmin.start === k.end + 1) { tree.codePointRangeCount--; tree.codePointCount -= Trmin.size; const [Trl, , Trr] = split(tree, Tr, Trmin); Tr = join2(tree, Trl, Trr); k = new Range(k.start, Trmin.end); } } tree.codePointRangeCount++; tree.codePointCount += k.size; return join(tree, Tl, k, Tr); } function intersect(tree, T1, T2) { if (T1 === Node.nil) return Node.nil; if (T2 === Node.nil) return Node.nil; const { left: L2, range: k2, right: R2 } = T2; const [L1, b, R1] = split(tree, T1, k2); const Tl = intersect(tree, L1, L2); const Tr = intersect(tree, R1, R2); if (b) { const [, , T1r] = split(tree, T1, new Range(k2.start - 1)); const [Tm] = split(tree, T1r, new Range(k2.end + 1)); if (Tm !== Node.nil) { return join2(tree, join2(tree, Tl, importSubtree(tree, Tm, tree)), Tr); } } return join2(tree, Tl, Tr); } function difference(tree, T1, T2) { if (T1 === Node.nil) return Node.nil; if (T2 === Node.nil) return importSubtree(tree, T1, tree); const { left: L2, range: k2, right: R2 } = T2; const [L1, k1, R1] = split(tree, T1, k2); const Tl = difference(tree, L1, L2); const Tr = difference(tree, R1, R2); return join2(tree, Tl, Tr); } //# sourceMappingURL=charSet.js.map