Various deque implementations in pure nim
Go to file
Nocturn9x b24d00af83 Brought back benchSize to 1.5 million 2022-03-15 17:41:05 +01:00
src Added extendLeft 2022-03-15 17:40:34 +01:00
tests Brought back benchSize to 1.5 million 2022-03-15 17:41:05 +01:00
.gitignore Initial commit 2022-03-14 10:36:41 +01:00
LICENSE Initial commit 2022-03-14 10:36:41 +01:00
README.md Updated README, added equality test and pop benchmark 2022-03-15 17:22:03 +01:00

README.md

nimdeque

Various deque implementations in pure nim. A deque (short for "double-ended queue") is a data type that is optimized for access towards its ends. A deque's most interesting feauture is the ~O(1) time that it takes to pop/append at either ends (as opposed to regular lists where appending at the beginning is an O(n) operation).


Examples

LinkedDeque

A LinkedDeque is a deque based on a doubly linked list.

import nimdeque


queue = newLinkedDeque[int]()

# Appends at the end
queue.add(1)
queue.add(2)
queue.add(3)

# Prepends at the beginning
queue.addLeft(0)
queue.addLeft(-1)
queue.addLeft(-2)

# Pops the first element in O(1) time
queue.pop()

# Pops the last element in O(1) time
queue.pop(queue.high())  
# This can also be written as
queue.pop(^1)

# Pops element at position n
queue.pop(n)

# Supports iteration
for i, e in queue:
    echo i, " ", e

# Reversed iteration too!
for e in queue.reversed():
    echo e

echo queue.len()
echo 5 in queue  # false
echo 0 in queue  # true

# Item accessing works just like regular sequence types in Nim.
# Note that the further the item is from either end of the
# queue, the higher the time it takes to retrieve it. For
# fast random access, seqs should be used instead
assert queue[0] == -1
assert queue[^1] == queue[queue.high()]

# It's possible to extend a deque with other deques or with seqs
# of compatible type
var other = newLinkedDeque[int]()
other.add(9)
other.add(10)
queue.extend(@[5, 6, 7, 8])
queue.extend(other)

# Clears the queue in O(1) time
queue.clear()
# Clears the queue in O(n) time
queue.clearPop()

Notes

  • All queue constructors take an optional maxSize argument which limits the size of the queue. The default value is 0 (no size limit). When maxSize > 0, the queue will discard elements from the head when items are added at the end and conversely pop items at the end when one is added at the head. Calling insert on a full queue will raise an IndexDefect
  • Two deques compare equal if they have the same elements inside them, in the same order. The value of maxSize is disregarded in comparisons
  • Calls to extend() do not raise any errors when the queue is full. They're merely an abstraction over a for loop calling self.add() with every item from the other iterable
  • Deques in this module do not support slicing. Use the built-in seq type if you need fast random accessing and/or slicing capabilities
  • The objects in this module are all tracked references! (Unlike the std/deques module which implements them as value types and gives var variants of each procedure)

Disclaimer

This is mostly a toy, there are no performance guarantees nor particular optimizations other than very obvious ones. With that said, the collections do work and are tested somewhat thoroughly (please report any bugs!). The tests directory contains some benchmarks as well as the test suite used to validate the behavior of the queues.

Why? There's std/deques!

  1. I was bored during my programming class
  2. That only provides a deque based on seqs
  3. The deque in that module is a value type
  4. I was bored during my programming class