<commit_before>import LinkedNode from './linked-node';


class LinkedList<T extends LinkedNode> {
  head: T;
  tail: T;
  length: number;

  constructor() {
    this.head = this.tail = undefined;
    this.length = 0;
  }

  append(...nodes: T[]): void {
    this.insertBefore(nodes[0], undefined);
    if (nodes.length > 1) {
      this.append.apply(this, nodes.slice(1));
    }
  }

  insertBefore(node: T, refNode: T): void {
    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) {
      this.tail.next = node;
      node.prev = this.tail;
      this.tail = node;
    } else {
      this.head = this.tail = node;
    }
    this.length += 1;
  }

  remove(node: T): void {
    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;
    node.prev = node.next = undefined;
    this.length -= 1;
  }

  iterator(curNode: T = this.head): () => T {
    // TODO use yield when we can
    return function(): T {
      var ret = curNode;
      if (curNode != null) curNode = <T>curNode.next;
      return ret;
    }
  }

  find(index: number): [T, number] {
    var cur, next = this.iterator();
    while (cur = next()) {
      var length = cur.length();
      if (index < length) return [cur, index];
      index -= length;
    }
    return [null, 0];
  }

  forEach(callback: (cur: T) => void): void {
    var cur, next = this.iterator();
    while (cur = next()) {
      callback(cur);
    }
  }

  forEachAt(index: number, length: number, callback: (cur: T, offset: number, length: number) => void): void {
    // TODO use this.find()
    if (length === 0) return;
    var cur, curIndex = 0, next = this.iterator();
    while ((cur = next()) && curIndex < index + length) {
      var curLength = cur.length();
      if (index <= curIndex) {
        callback(cur, 0, Math.min(curLength, index + length - curIndex));
      } else if (index < curIndex + curLength) {
        callback(cur, index - curIndex, Math.min(length, curIndex + curLength - index));
      }
      curIndex += curLength;
    }
  }

  map(callback: (cur: T) => any): any[] {
    return this.reduce(function(memo, cur: T) {
      memo.push(callback(cur));
      return memo;
    }, []);
  }

  reduce<M>(callback: (memo: M, cur: T) => M, memo: M): M {<commit_msg>might as well cover negatives<commit_after>import LinkedNode from './linked-node';


class LinkedList<T extends LinkedNode> {
  head: T;
  tail: T;
  length: number;

  constructor() {
    this.head = this.tail = undefined;
    this.length = 0;
  }

  append(...nodes: T[]): void {
    this.insertBefore(nodes[0], undefined);
    if (nodes.length > 1) {
      this.append.apply(this, nodes.slice(1));
    }
  }

  insertBefore(node: T, refNode: T): void {
    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) {
      this.tail.next = node;
      node.prev = this.tail;
      this.tail = node;
    } else {
      this.head = this.tail = node;
    }
    this.length += 1;
  }

  remove(node: T): void {
    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;
    node.prev = node.next = undefined;
    this.length -= 1;
  }

  iterator(curNode: T = this.head): () => T {
    // TODO use yield when we can
    return function(): T {
      var ret = curNode;
      if (curNode != null) curNode = <T>curNode.next;
      return ret;
    }
  }

  find(index: number): [T, number] {
    var cur, next = this.iterator();
    while (cur = next()) {
      var length = cur.length();
      if (index < length) return [cur, index];
      index -= length;
    }
    return [null, 0];
  }

  forEach(callback: (cur: T) => void): void {
    var cur, next = this.iterator();
    while (cur = next()) {
      callback(cur);
    }
  }

  forEachAt(index: number, length: number, callback: (cur: T, offset: number, length: number) => void): void {
    // TODO use this.find()
    if (length <= 0) return;
    var cur, curIndex = 0, next = this.iterator();
    while ((cur = next()) && curIndex < index + length) {
      var curLength = cur.length();
      if (index <= curIndex) {
        callback(cur, 0, Math.min(curLength, index + length - curIndex));
      } else if (index < curIndex + curLength) {
        callback(cur, index - curIndex, Math.min(length, curIndex + curLength - index));
      }
      curIndex += curLength;
    }
  }

  map(callback: (cur: T) => any): any[] {
    return this.reduce(function(memo, cur: T) {
      memo.push(callback(cur));
      return memo;
    }, []);
  }

  reduce<M>(callback: (memo: M, cur: T) => M, memo: M): M {
{'fraction_non_alphanumeric': 0.16618965846212555, 'fraction_numerical': 0.003816065636328945, 'mean_word_length': 2.298930144745123, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4528059', 'n_tokens_mistral': 1821, 'n_tokens_neox': 1779, 'n_words': 478}