a resizable double-ended circular queue, similar to python's collection.deque.

import { assertEquals } from "jsr:@std/assert"

const deque = new Deque<number>(5)

// pushing to the front
deque.pushFront(1, 2)
assertEquals(deque.getFront(), 2)

// pushing to the rear
deque.pushBack(0, -1)
assertEquals(deque.getBack(), -1)
assertEquals(deque.getFront(), 2)

// iterating over the queue, starting from the rear-most element to the front most
assertEquals([...deque], [-1, 0, 1, 2])

// popping the front and rear
assertEquals(deque.popFront(), 2)
assertEquals(deque.popBack(), -1)
assertEquals([...deque], [0, 1])

// pushing more items into the deque than its capacity (which is `5` elements) removes elements from the other end
deque.pushFront(2, 3, 4, 5, 6)
assertEquals([...deque], [2, 3, 4, 5, 6]) // the two rear-most elements have been removed
deque.pushBack(1)
assertEquals([...deque], [1, 2, 3, 4, 5]) // the front-most element has been removed

// rotating the deque when its capacity is full
deque.rotate(2) // rotate forward/to-the-right by 2 steps
assertEquals([...deque], [4, 5, 1, 2, 3])
deque.rotate(-1) // rotate backwards/to-the-left by 1 step
assertEquals([...deque], [5, 1, 2, 3, 4])
deque.rotate(11) // rotating forward by 11 steps is equivalent to 1 forward step
assertEquals([...deque], [4, 5, 1, 2, 3])

// rotating the deque when it is partially filled
deque.popBack()
deque.popBack()
assertEquals([...deque], [1, 2, 3])
deque.rotate(1) // rotate forward by 1 step
assertEquals([...deque], [3, 1, 2])
deque.rotate(-2) // rotate backwards by 2 steps
assertEquals([...deque], [2, 3, 1])
deque.rotate(-5) // rotate backwards by 5 steps, which is equivalent to 2 backward steps
assertEquals([...deque], [1, 2, 3])

// reversing the ordering of a partially filled deque
deque.reverse()
assertEquals([...deque], [3, 2, 1])

// reversing the ordering of a completely filled deque
deque.pushBack(4, 5)
assertEquals([...deque], [5, 4, 3, 2, 1])
deque.reverse()
assertEquals([...deque], [1, 2, 3, 4, 5])

// acquiring elements through indexing using the `at` method
assertEquals(deque.at(0), 1)
assertEquals(deque.at(-1), 5) // negative indices are supported
assertEquals(deque.at(-2), 4)
assertEquals(deque.at(2), 3)
assertEquals(deque.at(11), 2) // overflowing indices are also supported
assertEquals(deque.at(-9), 2) // negative overflowing indices are supported as well

// making the deque only partially filled
deque.popFront()
deque.popFront()
assertEquals([...deque], [1, 2, 3])

// indexing using the `at` method will return `undefined` if the deque is partially filled, and the given index slot is empty.
// this is because the index provided to the `at` method circulates (i.e. modulo) around the `length` of the deque,
// as opposed to its current element `count` amount.
assertEquals(deque.at(1), 2)
assertEquals(deque.at(-1), undefined)
assertEquals(deque.at(-2), undefined)
assertEquals(deque.at(-3), 3)
assertEquals(deque.at(4), undefined)
assertEquals(deque.at(5), 1)
assertEquals(deque.at(6), 2)
assertEquals(deque.at(11), 2)
assertEquals(deque.at(-8), 3)

// to acquire items based on the index that circulates around the current element `count` amount (instead of `length`), use the `seek` method.
assertEquals(deque.seek(1), 2)
assertEquals(deque.seek(-1), 3)
assertEquals(deque.seek(-2), 2)
assertEquals(deque.seek(-3), 1)
assertEquals(deque.seek(4), 2)
assertEquals(deque.seek(5), 3)
assertEquals(deque.seek(6), 1)
assertEquals(deque.seek(11), 3)
assertEquals(deque.seek(-8), 2)

// to replace an existing item with a new one, using the `seek` index, use the `replace` method
assertEquals([...deque], [1, 2, 3])
deque.replace(0, 9)
deque.replace(10, 8)
deque.replace(-1, 7)
assertEquals([...deque], [9, 8, 7])

// to insert in-between elements, use the `insert` method
deque.insert(-1, 6, 5, 4, 3)
assertEquals([...deque], [9, 8, 7, 6, 5]) // the excess elements `4` and `3` cannot be inserted, since the length capacity of 5 has been reached.
deque.insert(-4, 77, 66)
assertEquals([...deque], [9, 8, 77, 66, 7])
deque.insert(1, 88)
assertEquals([...deque], [9, 88, 8, 77, 66])

// to resize the deque, use the `resize` method
assertEquals(deque.length, 5)
deque.resize(8)
assertEquals(deque.length, 8)
deque.insert(0, 99, 98, 97, 96)
assertEquals([...deque], [99, 98, 97, 96, 9, 88, 8, 77])
deque.resize(3) // if you resize to a shorter length, then you'll lose the excess elements from the front.
assertEquals([...deque], [99, 98, 97])
deque.resize(5)
assertEquals([...deque], [99, 98, 97])
deque.pushFront(96, 95, 94)
assertEquals([...deque], [98, 97, 96, 95, 94])

Type Parameters

  • T

Constructors

  • a double-ended circular queue, similar to python's collection.deque.

    Type Parameters

    • T

    Parameters

    • length: number

      specify the maximum length of the queue. pushing more items than the length will remove the items from the opposite side, so as to maintain the size.

    Returns Deque<T>

Properties

count: number = 0
length: number

specify the maximum length of the queue. pushing more items than the length will remove the items from the opposite side, so as to maintain the size.

Methods

  • rotates the deque steps number of positions to the right.

    if steps is negative, then it will rotate in the left direction. when the deque is not empty, rotating with step = 1 is equivalent to this.pushBack(this.popFront())

    Parameters

    • steps: number

    Returns void

  • returns the item at the specified index, relative to the rear of the deque.

    if the capacity (element count) of this deque is not full, then you may receive undefined when you provide an index where an empty element exists. in other words, this method is not aware of the number of elements currently stored in the deque.

    to obtain an element that is always within the current partial capacity limit, use the seek method instead.

    Parameters

    • index: number

      The index of the item to retrieve, relative to the rear-most element.

    Returns undefined | T

    The item at the specified index, or undefined if the index is out of range with respect to the current count number of items.

  • returns the item at the specified index, relative to the rear of the deque, ensuring that the index circulates back if it goes off the current item count amount.

    if the capacity (element count) of this deque is not full, then you may receive undefined when you provide an index where an empty element exists. in other words, this method is not aware of the number of elements currently stored in the deque.

    to obtain an element that is always within the current partial capacity limit, use the seek method instead.

    Parameters

    • seek_index: number

      The index of the item to retrieve, relative to the rear-most element.

    Returns undefined | T

    The item at the specified index (within the element count amount of this deque), or undefined if there are absolutely no items in the deque.

  • replaces the item at the specified index with a new item, always ensuring the index is bound to the current element count amount (as opposed the the full deque length), so that unoccupied element slots are not replaced. i.e. only existing items can be replaced.

    Parameters

    • seek_index: number
    • item: T

    Returns void

  • inserts additional items at the specified seek-index, shifting all items ahead of it to the front. if the deque is full, it removes the front item before adding the new additional items.

    TODO: current implementation is incomplete, because it involves too many index computations, and I'm too lazy for that. plus, president biden is going to drop the "ball" in times square today on new year's eve. obviously I wouldn't want to miss this historic moment. /s in place of a lackluster "ball drop", we got a much more exciting thunder show from the Almighty Himself!

    Parameters

    • seek_index: number
    • ...insert_items: T[]

    Returns void