Compare commits

...

2 Commits

4 changed files with 133 additions and 19 deletions

View File

@ -1,3 +1,7 @@
# nimdeque
Various deque implementations in pure nim
Various deque implementations in pure nim. See the tests directory for usage examples
__Note__: 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!)

View File

@ -14,6 +14,19 @@
import private/queues/linked
# Exports linked queue stuff
export newLinkedDeque
export LinkedDeque
export LinkedDeque
export add
export addLeft
export contains
export items
export reversed
export len
export linked.high
export pop
export `[]`
export `[]=`
export pairs
export linked.`$`
export insert

View File

@ -70,7 +70,7 @@ proc addLeft*[T](self: LinkedDeque[T], val: T) =
self.head.next = head
head.prev = node
inc(self.size)
proc len*[T](self: LinkedDeque[T]): int =
## Returns the length of the deque.
@ -111,7 +111,32 @@ proc getNode[T](self: LinkedDeque[T], i: int): DequeNode[T] =
while pos > i:
result = result.prev
dec(pos)
proc insert*[T](self: LinkedDeque[T], pos: int, val: T) =
## Inserts the given value at the given
## position. When pos equals 0 or self.high(),
## this proc is equivalent to addLeft and add
## respectively. In all other cases, all items
## are "shifted" by 1 (shifted is in quotes because
## no shifting actually occurs, but the result is
## the same). The operation takes roughly constant
## time and the complexity becomes O(n) the closer
## the index gets to the middle of the deque
if pos == 0:
self.addLeft(val)
elif pos == self.high():
self.add(val)
else:
var node = self.getNode(pos)
var prev: DequeNode[T] = node.prev
var newNode = newDequeNode(val)
node.prev = newNode
prev.next = newNode
newNode.next = node
newNode.prev = prev
inc(self.size)
proc `[]`*[T](self: LinkedDeque[T], i: int): T =
## Implements indexing into the queue
@ -124,6 +149,18 @@ proc `[]=`*[T](self: LinkedDeque[T], i: int, val: T) =
self[i].val = val
proc `[]`*[T](self: LinkedDeque[T], i: BackwardsIndex): T =
## Implements indexing into the queue
## with backwards indeces
result = self[self.size - int(i)]
proc `[]=`*[T](self: LinkedDeque[T], i: BackwardsIndex, val: T) =
## Sets element at backwards
## position i to the given value
self[self.size - int(i)] = val
proc pop*[T](self: LinkedDeque[T], pos: int = 0): T =
## Pops an element off the queue
## at the given index (default 0).
@ -136,12 +173,22 @@ proc pop*[T](self: LinkedDeque[T], pos: int = 0): T =
if pos == 0:
self.head = self.head.next
elif pos == self.high():
self.tail = self.tail.prev
var prev = self.tail.prev
prev.next = nil
self.tail = prev
else:
node.prev.next = node.next
var prev = node.prev
var next = node.next
prev.next = node.next
next.prev = prev
result = node.val
dec(self.size)
proc pop*[T](self: LinkedDeque[T], i: BackwardsIndex): T =
## Same as self.pop but for backwards indeces
result = self.pop(self.size - int(i) - 1)
iterator items*[T](self: LinkedDeque[T]): T =
## Implements the iteration protocol

View File

@ -11,38 +11,88 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import random
import strformat
import ../src/nimdeque
when isMainModule:
const size = 10000
const size = 1000
var deque = newLinkedDeque[int]()
echo &"Generating {size} values"
for i in countup(0, size, 1):
for i in countup(0, size - 1, 1):
deque.add(i)
echo "\t- Checking length"
doAssert deque.len() == size
echo "Checking iteration"
for i in countup(0, size, 1):
for i in countup(0, size - 1, 1):
doAssert deque[i] == i
echo "Checking contains"
for i in countup(0, size, 1):
for i in countup(0, size - 1, 1):
doAssert i in deque
echo "Popping off the head"
doAssert deque.pop() == 0
echo "Popping off the tail"
doAssert deque.pop(deque.high()) == size
echo "\t- Checking length"
doAssert deque.len() == size - 1
echo "\t- Popping off the tail"
doAssert deque.pop(deque.high()) == size - 1
echo "\t- Checking length"
doAssert deque.len() == size - 2
echo "Checking new head"
doAssert deque[0] == 1
echo "Checking new tail"
doAssert deque[deque.high()] == size - 1
doAssert deque[deque.high()] == size - 2
echo "Re-checking values"
for i in countup(0, size - 2, 1):
for i in countup(0, size - 3, 1):
doAssert deque[i] == i + 1
echo "Appending value at the beginning"
echo "Checking addLeft"
deque.addLeft(0)
echo "Re-checking head"
echo "\t- Checking length"
doAssert deque.len() == size - 1
echo "\t- Re-checking head"
doAssert deque[0] == 0
echo "Re-checking values"
for i in countup(0, size - 1, 1):
for i in countup(0, size - 2, 1):
doAssert deque[i] == i
echo "Checking insert(3)"
var oldLen = deque.len()
deque.insert(3, 69420)
echo "\t- Checking length"
doAssert oldLen + 1 == deque.len()
echo "\t- Checking inserted value"
doAssert deque.pop(3) == 69420
echo "\t- Checking length"
doAssert deque.len() == oldLen
echo &"Checking insert({size - 2})"
oldLen = deque.len()
deque.insert(size - 2, 0x42362)
echo "\t- Checking length"
doAssert oldLen + 1 == deque.len()
echo "\t- Checking inserted value"
doAssert deque.pop(size - 1) == 0x42362
echo "\t- Checking length"
doAssert deque.len() == oldLen
echo &"Checking insert({size div 2})"
oldLen = deque.len()
deque.insert(size div 2, 0xf7102)
echo "\t- Checking length"
doAssert oldLen + 1 == deque.len()
echo "\t- Checking inserted value"
doAssert deque.pop(size div 2) == 0xf7102
echo "\t- Checking length"
doAssert deque.len() == oldLen
randomize()
let idx = rand(size - 1)
echo &"Checking insert({idx})"
oldLen = deque.len()
deque.insert(size - 2, idx)
echo "\t- Checking length"
doAssert oldLen + 1 == deque.len()
echo "\t- Checking inserted value"
doAssert deque.pop(size - 1) == idx
echo "\t- Checking length"
doAssert deque.len() == oldLen
echo "Checking backwards indeces"
for i in countdown(deque.high(), 1):
doAssert deque[^i] == deque[deque.len() - i]
echo "All tests passed!"