@effect-ts/system
Version:
Effect-TS is a zero dependency set of libraries to write highly productive, purely functional TypeScript at scale.
1,931 lines (1,764 loc) • 90.3 kB
text/typescript
// ets_tracing: off
/* eslint-disable prefer-const */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable no-var */
import type { Either } from "../../../Either/index.js"
import { identity } from "../../../Function/index.js"
import * as O from "../../../Option/index.js"
import type { Ord } from "../../../Ord/index.js"
import * as St from "../../../Structural/index.js"
import * as Tp from "../Tuple/index.js"
/**
* 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: any, b: any): boolean {
if (a === b) {
return true
} else {
return false
}
}
function createPath(depth: number, value: any): any {
let current = value
for (let i = 0; i < depth; ++i) {
current = new Node(undefined, [current])
}
return current
}
// Array helper functions
function copyArray(source: any[]): any[] {
const array = []
for (let i = 0; i < source.length; ++i) {
array[i] = source[i]
}
return array
}
function pushElements<A>(
source: A[],
target: A[],
offset: number,
amount: number
): void {
for (let i = offset; i < offset + amount; ++i) {
target.push(source[i]!)
}
}
function copyIndices(
source: any[],
sourceStart: number,
target: any[],
targetStart: number,
length: number
): void {
for (let i = 0; i < length; ++i) {
target[targetStart + i] = source[sourceStart + i]
}
}
function arrayPrepend<A>(value: A, array: A[]): A[] {
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<A>(array: A[]): A[] {
return array.slice().reverse()
}
function arrayFirst<A>(array: A[]): A {
return array[0]!
}
function arrayLast<A>(array: A[]): A {
return array[array.length - 1]!
}
const pathResult = { path: 0, index: 0, updatedOffset: 0 }
type PathResult = typeof pathResult
function getPath(
index: number,
offset: number,
depth: number,
sizes: Sizes
): PathResult {
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: Node,
depth: number,
index: number,
offset: number,
value: any
): Node {
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)
}
export type Sizes = number[] | undefined
export class Node {
constructor(public sizes: Sizes, public array: any[]) {}
}
function cloneNode({ array, sizes }: Node): Node {
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: any[] = [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: List<any>): number {
return l.bits & affixMask
}
function getPrefixSize(l: List<any>): number {
return (l.bits >> affixBits) & affixMask
}
function getDepth(l: List<any>): number {
return l.bits >> (affixBits * 2)
}
function setPrefix(size: number, bits: number): number {
return (size << affixBits) | (bits & ~(affixMask << affixBits))
}
function setSuffix(size: number, bits: number): number {
return size | (bits & ~affixMask)
}
function setDepth(depth: number, bits: number): number {
return (depth << (affixBits * 2)) | (bits & (affixMask | (affixMask << affixBits)))
}
function incrementPrefix(bits: number): number {
return bits + (1 << affixBits)
}
function incrementSuffix(bits: number): number {
return bits + 1
}
function incrementDepth(bits: number): number {
return bits + (1 << (affixBits * 2))
}
function decrementDepth(bits: number): number {
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.
*/
export class List<A> implements Iterable<A>, St.HasEquals, St.HasHash {
constructor(
readonly bits: number,
readonly offset: number,
readonly length: number,
readonly prefix: A[],
readonly root: Node | undefined,
readonly suffix: A[]
) {}
[Symbol.iterator](): Iterator<A> {
return new ForwardListIterator(this)
}
toJSON(): readonly A[] {
return toArray(this)
}
[St.equalsSym](that: unknown): boolean {
return that instanceof List && equalsWith_(this, that, St.equals)
}
get [St.hashSym](): number {
return St.hashIterator(this[Symbol.iterator]())
}
}
export type MutableList<A> = { -readonly [K in keyof List<A>]: List<A>[K] } & {
[Symbol.iterator]: () => Iterator<A>
// This property doesn't exist at run-time. It exists to prevent a
// MutableList from being assignable to a List.
"@@mutable": true
}
function cloneList<A>(l: List<A>): MutableList<A> {
return new List(l.bits, l.offset, l.length, l.prefix, l.root, l.suffix) as any
}
abstract class ListIterator<A> implements Iterator<A> {
stack: any[][] | undefined
indices: number[] | undefined
idx: number
prefixSize: number
middleSize: number
result: IteratorResult<A> = { done: false, value: undefined as any }
constructor(protected l: List<A>, direction: 1 | -1) {
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
}
}
abstract next(): IteratorResult<A>
}
class ForwardListIterator<A> extends ListIterator<A> {
constructor(l: List<A>) {
super(l, 1)
}
nextInTree(): void {
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(): IteratorResult<A> {
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<A> extends ListIterator<A> {
constructor(l: List<A>) {
super(l, -1)
}
prevInTree(): void {
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(): IteratorResult<A> {
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)
*/
export function backwards<A>(l: List<A>): Iterable<A> {
return {
[Symbol.iterator](): Iterator<A> {
return new BackwardsListIterator(l)
}
}
}
export function emptyPushable<A>(): MutableList<A> {
return new List(0, 0, 0, [], undefined, []) as any
}
/** Appends the value to the list by _mutating_ the list and its content. */
export function push_<A>(l: MutableList<A>, value: A): MutableList<A> {
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)
*/
export function list<A>(...elements: A[]): List<A> {
const l = emptyPushable<A>()
for (const element of elements) {
push_(l, element)
}
return l
}
/**
* Creates an empty list.
*
* @complexity O(1)
*/
export function empty<A = any>(): List<A> {
return new List(0, 0, 0, emptyAffix, undefined, emptyAffix)
}
/**
* Takes a single arguments and returns a singleton list that contains it.
*
* @complexity O(1)
*/
export function of<A>(a: A): List<A> {
return list(a)
}
/**
* Takes two arguments and returns a list that contains them.
*
* @complexity O(1)
*/
export function pair<A>(second: A): (first: A) => List<A> {
return (first: A) => pair_(first, second)
}
/**
* Takes two arguments and returns a list that contains them.
*
* @complexity O(1)
*/
export function pair_<A>(first: A, second: A): List<A> {
return new List(2, 0, 2, emptyAffix, undefined, [first, second])
}
/**
* Converts an array, an array-like, or an iterable into a list.
*
* @complexity O(n)
*/
export function from<A>(sequence: A[] | ArrayLike<A> | Iterable<A>): List<A>
export function from<A>(sequence: any): List<A> {
const l = emptyPushable<A>()
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)
*/
export function range(end: number): (start: number) => List<number> {
return (start) => range_(start, end)
}
/**
* Returns a list of numbers between an inclusive lower bound and an exclusive upper bound.
*
* @complexity O(n)
*/
export function range_(start: number, end: number): List<number> {
const list = emptyPushable<number>()
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)
*/
export function repeat(times: number): <A>(value: A) => List<A> {
return (value) => repeat_(value, times)
}
/**
* Returns a list of a given length that contains the specified value
* in all positions.
*
* @complexity O(n)
*/
export function repeat_<A>(value: A, times: number): List<A> {
const l = emptyPushable<A>()
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)
*/
export function times(times: number): <A>(func: (index: number) => A) => List<A> {
return (func) => times_(func, times)
}
/**
* Generates a new list by calling a function with the current index
* `n` times.
*
* @complexity O(n)
*/
export function times_<A>(func: (index: number) => A, times: number): List<A> {
const l = emptyPushable<A>()
for (let i = 0; i < times; i++) {
push_(l, func(i))
}
return l
}
function nodeNthDense(node: Node, depth: number, index: number): any {
let current = node
for (; depth >= 0; --depth) {
current = current.array[(index >> (depth * branchBits)) & mask]
}
return current
}
function handleOffset(depth: number, offset: number, index: number): number {
index += offset
for (; depth >= 0; --depth) {
index = index - (offset & (mask << (depth * branchBits)))
if (((index >> (depth * branchBits)) & mask) !== 0) {
break
}
}
return index
}
function nodeNth(node: Node, depth: number, offset: number, index: number): any {
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))
*/
export function unsafeNth_<A>(l: List<A>, index: number): A | undefined {
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))
*/
export function unsafeNth(index: number): <A>(l: List<A>) => A | undefined {
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))
*/
export function nth_<A>(l: List<A>, index: number): O.Option<A> {
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))
*/
export function nth(index: number): <A>(l: List<A>) => O.Option<A> {
return (l) => nth_(l, index)
}
function setSizes(node: Node, height: number): Node {
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: Node, height: number): number {
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>(a: A, array: A[], length: number): A[] {
if (array.length === length) {
array.push(a)
return array
} else {
const newArray: A[] = []
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)
*/
export function prepend_<A>(l: List<A>, value: A): List<A> {
const prefixSize = getPrefixSize(l)
if (prefixSize < 32) {
return new List<A>(
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)
*/
export function prepend<A>(value: A): (l: List<A>) => List<A> {
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: MutableList<any>, k: number): Node {
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: any, size: number, node: Node): 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<A>(l: MutableList<A>, depth: number, node: Node): number {
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<A>(l: MutableList<A>, array: A[]): List<A> {
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: Node | undefined
let prependableNode: Node
// 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: Node, depth: number, offset: number, value: Node): Node {
// 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)
*/
export function append_<A>(l: List<A>, value: A): List<A> {
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)
*/
export function append<A>(value: A): (l: List<A>) => List<A> {
return (l) => append_(l, value)
}
/**
* Gets the length of a list.
*
* @complexity `O(1)`
*/
export function size(l: List<any>): number {
return l.length
}
/**
* Returns the first element of the list. If the list is empty the
* function returns undefined.
*
* @complexity O(1)
*/
export function unsafeFirst<A>(l: List<A>): A | undefined {
return O.toUndefined(first(l))
}
/**
* Returns the first element of the list. If the list is empty the
* function returns undefined.
*
* @complexity O(1)
*/
export function first<A>(l: List<A>): O.Option<A> {
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)
*/
export function unsafeLast<A>(l: List<A>): A | undefined {
return O.toUndefined(last(l))
}
/**
* Returns the last element of the list. If the list is empty the
* function returns `undefined`.
*
* @complexity O(1)
*/
export function last<A>(l: List<A>): O.Option<A> {
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<A, B>(f: (a: A) => B, array: A[]): B[] {
const result = new Array(array.length)
for (let i = 0; i < array.length; ++i) {
result[i] = f(array[i]!)
}
return result
}
function mapNode<A, B>(f: (a: A) => B, node: Node, depth: number): Node {
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<A, B>(f: (a: A) => B, prefix: A[], length: number): B[] {
const newPrefix = new Array(length)
for (let i = length - 1; 0 <= i; --i) {
newPrefix[i] = f(prefix[i]!)
}
return newPrefix
}
function mapAffix<A, B>(f: (a: A) => B, suffix: A[], length: number): B[] {
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)
*/
export function map_<A, B>(l: List<A>, f: (a: A) => B): List<B> {
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)
*/
export function map<A, B>(f: (a: A) => B): (l: List<A>) => List<B> {
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.
*/
export function pluck_<A, K extends keyof A>(l: List<A>, key: K): List<A[K]> {
return map_(l, (a) => a[key])
}
/**
* Extracts the specified property from each object in the list.
*/
export function pluck<A, K extends keyof A>(key: K): (l: List<A>) => List<A[K]> {
return (l) => pluck_(l, key)
}
// fold
function foldlSuffix<A, B>(
f: (acc: B, value: A) => B,
acc: B,
array: A[],
length: number
): B {
for (let i = 0; i < length; ++i) {
acc = f(acc, array[i]!)
}
return acc
}
function foldlPrefix<A, B>(
f: (acc: B, value: A) => B,
acc: B,
array: A[],
length: number
): B {
for (let i = length - 1; 0 <= i; --i) {
acc = f(acc, array[i]!)
}
return acc
}
function foldlNode<A, B>(
f: (acc: B, value: A) => B,
acc: B,
node: Node,
depth: number
): B {
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.
*/
export function reduce_<A, B>(l: List<A>, initial: B, f: (acc: B, value: A) => B): B {
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.
*/
export function reduce<A, B>(
initial: B,
f: (acc: B, value: A) => B
): (l: List<A>) => B {
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.
*/
export function scan_<A, B>(
l: List<A>,
initial: B,
f: (acc: B, value: A) => B
): List<B> {
return reduce_(l, push_(emptyPushable<B>(), 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.
*/
export function scan<A, B>(
initial: B,
f: (acc: B, value: A) => B
): (l: List<A>) => List<B> {
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)
*/
export function forEach_<A>(l: List<A>, callback: (a: A) => void): void {
reduce_(l, undefined as void, (_, 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)
*/
export function forEach<A>(callback: (a: A) => void): (l: List<A>) => void {
return (l) => forEach_(l, callback)
}
/**
* Returns a new list that only contains the elements of the original
* list for which the predicate returns `true`.
*
* @complexity O(n)
*/
export function filter_<A, B extends A>(
l: List<A>,
predicate: (a: A) => a is B
): List<B>
export function filter_<A>(l: List<A>, predicate: (a: A) => boolean): List<A>
export function filter_<A>(l: List<A>, predicate: (a: A) => boolean): List<A> {
return 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 predicate returns `true`.
*
* @complexity O(n)
*/
export function filter<A, B extends A>(
predicate: (a: A) => a is B
): (l: List<A>) => List<B>
export function filter<A>(predicate: (a: A) => boolean): (l: List<A>) => List<A>
export function filter<A>(predicate: (a: A) => boolean): (l: List<A>) => List<A> {
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)
*/
export function filterMap_<A, B>(l: List<A>, f: (a: A) => O.Option<B>): List<B> {
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)
*/
export function filterMap<A, B>(f: (a: A) => O.Option<B>): (l: List<A>) => List<B> {
return (l) => filterMap_(l, f)
}
/**
* Filter out optional values
*/
export function compact<A>(fa: List<O.Option<A>>): List<A> {
return filterMap((x: O.Option<A>) => x)(fa)
}
/**
* Returns a new list that only contains the elements of the original
* list for which the predicate returns `false`.
*
* @complexity O(n)
*/
export function filterNot_<A>(l: List<A>, predicate: (a: A) => boolean): List<A> {
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)
*/
export function filterNot<A>(predicate: (a: A) => boolean): (l: List<A>) => List<A> {
return (l) => filterNot_(l, predicate)
}
/**
* Splits the list into two lists. One list that contains all the
* values for which the predicate returns `true` and one containing
* the values for which it returns `false`.
*
* @complexity O(n)
*/
export function partition_<A, B extends A>(
l: List<A>,
predicate: (a: A) => a is B
): Tp.Tuple<[List<B>, List<Exclude<A, B>>]>
export function partition_<A>(
l: List<A>,
predicate: (a: A) => boolean
): Tp.Tuple<[List<A>, List<A>]>
export function partition_<A>(
l: List<A>,
predicate: (a: A) => boolean
): Tp.Tuple<[List<A>, List<A>]> {
return reduce_(
l,
Tp.tuple(emptyPushable<A>(), emptyPushable<A>()) as Tp.Tuple<
[MutableList<A>, MutableList<A>]
>,
(arr, a) => (predicate(a) ? push_(arr.get(0), a) : push_(arr.get(1), a), arr)
)
}
/**
* Splits the list into two lists. One list that contains all the
* values for which the predicate returns `true` and one containing
* the values for which it returns `false`.
*
* @complexity O(n)
*/
export function partition<A, B extends A>(
predicate: (a: A) => a is B
): (l: List<A>) => Tp.Tuple<[List<B>, List<Exclude<A, B>>]>
export function partition<A>(
predicate: (a: A) => boolean
): (l: List<A>) => Tp.Tuple<[List<A>, List<A>]>
export function partition<A>(
predicate: (a: A) => boolean
): (l: List<A>) => Tp.Tuple<[List<A>, List<A>]> {
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)
*/
export function partitionMap_<A, B, C>(
l: List<A>,
f: (_: A) => Either<B, C>
): Tp.Tuple<[List<B>, List<C>]> {
return reduce_(
l,
Tp.tuple(emptyPushable<B>(), emptyPushable<C>()) as Tp.Tuple<
[MutableList<B>, MutableList<C>]
>,
(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)
*/
export function partitionMap<A, B, C>(
f: (_: A) => Either<B, C>
): (l: List<A>) => Tp.Tuple<[List<B>, List<C>]> {
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)
*/
export function separate<B, C>(l: List<Either<B, C>>): Tp.Tuple<[List<B>, List<C>]> {
return partitionMap_(l, identity)
}
/**
* Concats the strings in the list separated by a specified separator.
*/
export function join_(l: List<string>, separator: string): string {
return reduce_(l, "", (a, b) => (a.length === 0 ? b : a + separator + b))
}
/**
* Concats the strings in the list separated by a specified separator.
*/
export function join(separator: string): (l: List<string>) => string {
return (l) => join_(l, separator)
}
function foldrSuffix<A, B>(
f: (value: A, acc: B) => B,
initial: B,
array: A[],
length: number
): B {
let acc = initial
for (let i = length - 1; 0 <= i; --i) {
acc = f(array[i]!, acc)
}
return acc
}
function foldrPrefix<A, B>(
f: (value: A, acc: B) => B,
initial: B,
array: A[],
length: number
): B {
let acc = initial
for (let i = 0; i < length; ++i) {
acc = f(array[i]!, acc)
}
return acc
}
function foldrNode<A, B>(
f: (value: A, acc: B) => B,
initial: B,
{ array }: Node,
depth: number
): B {
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)
*/
export function reduceRight_<A, B>(
l: List<A>,
initial: B,
f: (value: A, acc: B) => B
): B {
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)
*/
export function reduceRight<A, B>(
initial: B,
f: (value: A, acc: B) => B
): (l: List<A>) => B {
return (l) => reduceRight_(l, initial, f)
}
/**
* Applies a list of functions to a list of values.
*/
export function ap_<A, B>(listF: List<(a: A) => B>, l: List<A>): List<B> {
return flatten(map_(listF, (f) => map_(l, f)))
}
/**
* Applies a list of functions to a list of values.
*/
export function ap<A, B>(l: List<A>): (listF: List<(a: A) => B>) => List<B> {
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.
*/
export function flatten<A>(nested: List<List<A>>): List<A> {
return reduce_<List<A>, List<A>>(nested, empty(), concat_)
}
/**
* Maps a function over a list and concatenates all the resulting
* lists together.
*/
export function chain_<A, B>(l: List<A>, f: (a: A) => List<B>): List<B> {
return flatten(map_(l, f))
}
/**
* Maps a function over a list and concatenates all the resulting
* lists together.
*/
export function chain<A, B>(f: (a: A) => List<B>): (l: List<A>) => List<B> {
return (l) => chain_(l, f)
}
// callback fold
type FoldCb<Input, State> = (input: Input, state: State) => boolean
function foldlArrayCb<A, B>(
cb: FoldCb<A, B>,
state: B,
array: A[],
from: number,
to: number
): boolean {
for (var i = from; i < to && cb(array[i]!, state); ++i) {
//
}
return i === to
}
function foldrArrayCb<A, B>(
cb: FoldCb<A, B>,
state: B,
array: A[],
from: number,
to: number
): boolean {
for (var i = from - 1; to <= i && cb(array[i]!, state); --i) {
//
}
return i === to - 1
}
function foldlNodeCb<A, B>(
cb: FoldCb<A, B>,
state: B,
node: Node,
depth: number
): boolean {
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<A, B>(cb: FoldCb<A, B>, state: B, l: List<A>): B {
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<A, B>(
cb: FoldCb<A, B>,
state: B,
node: Node,
depth: number
): boolean {
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<A, B>(cb: FoldCb<A, B>, state: B, l: List<A>): B {
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
}
// functions based on foldlCb
type FoldlWhileState<A, B> = {
predicate: (b: B, a: A) => boolean
result: B
f: (acc: B, value: A) => B
}
/**
* 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, B>(a: A, state: FoldlWhileState<A, B>): boolean {
if (state.predicate(state.result, a) === false) {
return false
}
state.result = state.f(state.result, a)
return true
}
export function reduceWhile_<A, B>(
l: List<A>,
initial: B,
predicate: (acc: B, value: A) => boolean,
f: (acc: B, value: A) => B
): B {
return foldlCb<A, FoldlWhileState<A, B>>(
foldlWhileCb,
{ predicate, f, result: initial },
l
).result
}
export function reduceWhile<A, B>(
initial: B,
predicate: (acc: B, value: A) => boolean,
f: (acc: B, value: A) => B
): (l: List<A>) => B {
return (l) => reduceWhile_(l, initial, predicate, f)
}
type PredState = {
predicate: (a: any) => boolean
result: any
}
function everyCb<A>(value: A, state: any): boolean {
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)
*/
export function every_<A>(l: List<A>, predicate: (a: A) => boolean): boolean {
return foldlCb<A, PredState>(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)
*/
export function every<A>(predicate: (a: A) => boolean): (l: List<A>) => boolean {
return (l) => every_(l, predicate)
}
function someCb<A>(value: A, state: any): boolean {
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)
*/
export function some_<A>(l: List<A>, predicate: (a: A) => boolean): boolean {
return foldlCb<A, PredState>(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)
*/
export function some<A>(predicate: (a: A) => boolean): (l: List<A>) => boolean {
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)
*/
export function none_<A>(l: List<A>, predicate: (a: A) => boolean): boolean {
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)
*/
export function none<A>(predicate: (a: A) => boolean): (l: List<A>) => boolean {
return (l) => none_(l, predicate)
}
function findCb<A>(value: A, state: PredState): boolean {
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)
*/
export function unsafeFind_<A>(
l: List<A>,
predicate: (a: A) => boolean
): A | undefined {
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)
*/
export function unsafeFind<A>(
predicate: (a: A) => boolean
): (l: List<A>) => A | undefined {
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)
*/
export function find_<A>(l: List<A>, predicate: (a: A) => boolean): O.Option<A> {
return foldlCb<A, PredState>(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)
*/
export function find<A>(predicate: (a: A) => boolean) {
return (l: List<A>) => 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)
*/
export function unsafeFindLast_<A>(
l: List<A>,
predicate: (a: A) => boolean
): A | undefined {
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)
*/
export function unsafeFindLast<A>(
predicate: (a: A) => boolean
): (l: List<A>) => A | undefined {
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)
*/
export function findLast_<A>(l: List<A>, predicate: (a: A) => boolean): O.Option<A> {
return foldrCb<A, PredState>(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)
*/
export function findLast<A>(predicate: (a: A) => boolean): (l: List<A>) => O.Option<A> {
return (l) => findLast_(l, predicate)
}
type IndexOfState = {
element: any
found: boolean
index: number
}
function indexOfCb(value: any, state: IndexOfState): boolean {
++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)
*/
export function indexOf_<A>(l: List<A>, element: A): number {
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)
*/
export function indexOf<A>(element: A): (l: List<A>) => number {
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)
*/
export function lastIndexOf_<A>(l: List<A>, element: A): number {
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)
*/
export function lastIndexOf<A>(element: A): (l: List<A>) => number {
return (l) => lastIndexOf_(l, element)
}
type FindIndexState = {
predicate: (a: any) => boolean
found: boolean
index: number
}
function findIndexCb<A>(value: A, state: FindIndexState): boolean {
++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)
*/
export function findIndex_<A>(l: List<A>, predicate: (a: A) => boolean): number {
const { found, index } = foldlCb<A, FindIndexState>(
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)
*/
export function findIndex<A>(predicate: (a: A) => boolean): (l: List<A>) => number {
return (l) => findIndex_(l, predicate)
}
type ContainsState = {
element: any
result: boolean
}
const containsState: ContainsState = {
element: undefined,