| import LinkedNode from './linked-node'; | 
|   | 
| class LinkedList<T extends LinkedNode> { | 
|   head: T | null; | 
|   tail: T | null; | 
|   length: number; | 
|   | 
|   constructor() { | 
|     this.head = this.tail = null; | 
|     this.length = 0; | 
|   } | 
|   | 
|   append(...nodes: T[]): void { | 
|     this.insertBefore(nodes[0], null); | 
|     if (nodes.length > 1) { | 
|       this.append.apply(this, nodes.slice(1)); | 
|     } | 
|   } | 
|   | 
|   contains(node: T): boolean { | 
|     let cur, | 
|       next = this.iterator(); | 
|     while ((cur = next())) { | 
|       if (cur === node) return true; | 
|     } | 
|     return false; | 
|   } | 
|   | 
|   insertBefore(node: T | null, refNode: T | null): void { | 
|     if (!node) return | 
|     node.next = refNode; | 
|     if (refNode != null) { | 
|       node.prev = refNode.prev; | 
|       if (refNode.prev != null) { | 
|         refNode.prev.next = node; | 
|       } | 
|       refNode.prev = node; | 
|       if (refNode === this.head) { | 
|         this.head = node; | 
|       } | 
|     } else if (this.tail != null) { | 
|       this.tail.next = node; | 
|       node.prev = this.tail; | 
|       this.tail = node; | 
|     } else { | 
|       node.prev = null; | 
|       this.head = this.tail = node; | 
|     } | 
|     this.length += 1; | 
|   } | 
|   | 
|   offset(target: T): number { | 
|     let index = 0, | 
|       cur = this.head; | 
|     while (cur != null) { | 
|       if (cur === target) return index; | 
|       index += cur.length(); | 
|       cur = <T>cur.next; | 
|     } | 
|     return -1; | 
|   } | 
|   | 
|   remove(node: T): void { | 
|     if (!this.contains(node)) return; | 
|     if (node.prev != null) node.prev.next = node.next; | 
|     if (node.next != null) node.next.prev = node.prev; | 
|     if (node === this.head) this.head = <T>node.next; | 
|     if (node === this.tail) this.tail = <T>node.prev; | 
|     this.length -= 1; | 
|   } | 
|   | 
|   iterator(curNode: T | null = this.head): () => T | null { | 
|     // TODO use yield when we can | 
|     return function(): T | null { | 
|       let ret = curNode; | 
|       if (curNode != null) curNode = <T>curNode.next; | 
|       return ret; | 
|     }; | 
|   } | 
|   | 
|   find(index: number, inclusive: boolean = false): [T | null, number] { | 
|     let cur, | 
|       next = this.iterator(); | 
|     while ((cur = next())) { | 
|       let length = cur.length(); | 
|       if ( | 
|         index < length || | 
|         (inclusive && index === length && (cur.next == null || cur.next.length() !== 0)) | 
|       ) { | 
|         return [cur, index]; | 
|       } | 
|       index -= length; | 
|     } | 
|     return [null, 0]; | 
|   } | 
|   | 
|   forEach(callback: (cur: T) => void): void { | 
|     let cur, | 
|       next = this.iterator(); | 
|     while ((cur = next())) { | 
|       callback(cur); | 
|     } | 
|   } | 
|   | 
|   forEachAt( | 
|     index: number, | 
|     length: number, | 
|     callback: (cur: T, offset: number, length: number) => void, | 
|   ): void { | 
|     if (length <= 0) return; | 
|     let [startNode, offset] = this.find(index); | 
|     let cur, | 
|       curIndex = index - offset, | 
|       next = this.iterator(startNode); | 
|     while ((cur = next()) && curIndex < index + length) { | 
|       let curLength = cur.length(); | 
|       if (index > curIndex) { | 
|         callback(cur, index - curIndex, Math.min(length, curIndex + curLength - index)); | 
|       } else { | 
|         callback(cur, 0, Math.min(curLength, index + length - curIndex)); | 
|       } | 
|       curIndex += curLength; | 
|     } | 
|   } | 
|   | 
|   map(callback: (cur: T | null) => any): any[] { | 
|     return this.reduce(function(memo: (T | null)[], cur: T | null) { | 
|       memo.push(callback(cur)); | 
|       return memo; | 
|     }, []); | 
|   } | 
|   | 
|   reduce<M>(callback: (memo: M, cur: T) => M, memo: M): M { | 
|     let cur, | 
|       next = this.iterator(); | 
|     while ((cur = next())) { | 
|       memo = callback(memo, cur); | 
|     } | 
|     return memo; | 
|   } | 
| } | 
|   | 
| export default LinkedList; |