interface Node<T> {
  value: T;
  prev?: Node<T>;
  next?: Node<T>;
}
export class DoubleQueue<T> {
  protected head?: Node<T>;
  protected tail?: Node<T>;
  protected _size = 0;
  constructor(it?: Iterable<T>) {
    if (it) {
      for (const item of it) {
        this.push(item);
      }
    }
  }
  get size() {
    return this._size;
  }
  push(item: T) {
    const node: Node<T> = { value: item };
    if (this.size) {
      (this.tail!.next = node).prev = this.tail;
      this.tail = node;
    } else {
      this.head = this.tail = node;
    }
    this._size++;
  }
  pop(): T | undefined {
    if (!this.size) return undefined;
    const node = this.tail!;
    if (this.size === 1) {
      this.head = this.tail = undefined;
    } else {
      node.prev!.next = undefined;
    }
    this._size--;
    if (this.size === 1) this.head = this.tail;
    return node.value;
  }
  unshift(item: T) {
    const node: Node<T> = { value: item };
    if (this.size) {
      (this.head!.prev = node).next = this.head;
      this.head = node;
    } else {
      this.head = this.tail = node;
    }
    this._size++;
  }
  shift(): T | undefined {
    if (!this.size) return undefined;
    const node = this.head!;
    if (this.size === 1) {
      this.head = this.tail = undefined;
    } else {
      node.next!.prev = undefined;
    }
    this._size--;
    if (this.size === 1) this.tail = this.head;
    return node.value;
  }
  get(i: number): T | undefined {
    const reversed = i < 0;
    if (i < -this.size || i >= this.size) return undefined;
    let node = reversed ? this.tail! : this.head!;
    if (reversed) i = -i - 1;
    for (let j = 1; j <= i; j++) {
      node = reversed ? node.prev! : node.next!;
    }
    return node.value;
  }
  *iter() {
    for (let node = this.head; node; node = node.next) {
      yield node.value;
    }
  }
  [Symbol.iterator]() {
    return this.iter();
  }
  *reverseIter() {
    for (let node = this.tail; node; node = node.prev) {
      yield node.value;
    }
  }
}
