Restructured project

This commit is contained in:
Nocturn9x 2022-03-14 11:07:46 +01:00
parent f81f344d45
commit 178af73fc9
3 changed files with 213 additions and 169 deletions

View File

@ -11,173 +11,9 @@
# 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 strformat
import private/queues/linked
type
DequeNode*[T] = ref object
next: DequeNode[T]
prev: DequeNode[T]
val: T
LinkedDeque*[T] = ref object
## A collection type
## optimized for ~O(1)
## access at both ends
## based on a doubly
## linked list
head: DequeNode[T]
tail: DequeNode[T]
size: int
proc newDequeNode[T](val: T): DequeNode[T] =
## Internal proc to
## initialize an element
## for the LinkedQueue
## object
new(result)
result.val = val
proc newLinkedDeque*[T]: LinkedDeque[T] =
## Initializes a new, empty
## LinkedDeque object
new(result)
result.size = 0
proc add*[T](self: LinkedDeque[T], val: T) =
## Appends an element at the end
## of the queue
var newNode = newDequeNode(val)
if self.head == nil:
self.head = newNode
else:
newNode.prev = self.tail
self.tail.next = newNode
self.tail = newNode
inc(self.size)
proc addLeft*[T](self: LinkedDeque[T], val: T) =
## Behaves like add(), but inserts a
## value at the beginning instead
## of at the end. This operation
## takes constant time
var node = newDequeNode(val)
var head = self.head
self.head = node
self.head.next = head
head.prev = node
inc(self.size)
proc len*[T](self: LinkedDeque[T]): int =
## Returns the length of the deque.
## This operation takes constant time
result = self.size
proc high*[T](self: LinkedDeque[T]): int =
## Returns the index of the last
## element in the deque and -1 if
## the deque is empty
result = self.len() - 1
proc getNode[T](self: LinkedDeque[T], i: int): DequeNode[T] =
## Low level method for indexing and getting
## a node object back
if self.high() == -1:
raise newException(IndexDefect, "LinkedDeque is empty")
elif i > self.high():
raise newException(IndexDefect, &"{i} notin 0..{self.high()}")
var pos = 0
if i < self.high() div 2:
# If we're taking an element
# in the first half of the
# queue, we start from the
# beginning
result = self.head
while pos < i:
result = result.next
inc(pos)
else:
# Otherwise, we start from
# the end and go backwards
# at the chosen position
result = self.tail
pos = self.high()
while pos > i:
result = result.prev
dec(pos)
proc `[]`*[T](self: LinkedDeque[T], i: int): T =
## Implements indexing into the queue
result = self.getNode(i).val
proc `[]=`*[T](self: LinkedDeque[T], i: int, val: T) =
## Sets element at position i
## to the given value
self[i].val = val
proc pop*[T](self: LinkedDeque[T], pos: int = 0): T =
## Pops an element off the queue
## at the given index (default 0).
## The queue is optimized for popping
## and appending in roughly constant time
## at both ends, so this is quite fast
## if the operation is nears the ends of
## the iterable. The popped item is returned
var node = self.getNode(pos)
if pos == 0:
self.head = self.head.next
elif pos == self.high():
self.tail = self.tail.prev
else:
node.prev.next = node.next
result = node.val
dec(self.size)
iterator items*[T](self: LinkedDeque[T]): T =
## Implements the iteration protocol
## for the queue
var node = self.head
while node != nil:
yield node.val
node = node.next
iterator pairs*[T](self: LinkedDeque[T]): auto =
## Implements pairwise iteration with
## the index and the element at that
## index
var i = 0
for element in self:
yield (i, element)
inc(i)
iterator reversed*[T](self: LinkedDeque[T]): T =
## Same as self.items(), but starts at
## the end and yields the contents of
## the queue backwards
var node = self.tail
while node != nil:
yield node
node = node.prev
proc `$`*[T](self: LinkedDeque[T]): string =
## Returns a string representation
## of the deque
result = "deque(["
for i, item in self:
result &= $item
if i < self.high():
result &= ", "
result &= "])"
export newLinkedDeque
export LinkedDeque

View File

@ -0,0 +1,192 @@
# Copyright 2022 Mattia Giambirtone
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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 strformat
type
DequeNode*[T] = ref object
next: DequeNode[T]
prev: DequeNode[T]
val: T
LinkedDeque*[T] = ref object
## A collection type
## optimized for ~O(1)
## access at both ends
## based on a doubly
## linked list
head: DequeNode[T]
tail: DequeNode[T]
size: int
proc newDequeNode[T](val: T): DequeNode[T] =
## Internal proc to
## initialize an element
## for the LinkedQueue
## object
new(result)
result.val = val
proc newLinkedDeque*[T]: LinkedDeque[T] =
## Initializes a new, empty
## LinkedDeque object
new(result)
result.size = 0
proc add*[T](self: LinkedDeque[T], val: T) =
## Appends an element at the end
## of the queue
var newNode = newDequeNode(val)
if self.head == nil:
self.head = newNode
else:
newNode.prev = self.tail
self.tail.next = newNode
self.tail = newNode
inc(self.size)
proc addLeft*[T](self: LinkedDeque[T], val: T) =
## Behaves like add(), but inserts a
## value at the beginning instead
## of at the end. This operation
## takes constant time
var node = newDequeNode(val)
var head = self.head
self.head = node
self.head.next = head
head.prev = node
inc(self.size)
proc len*[T](self: LinkedDeque[T]): int =
## Returns the length of the deque.
## This operation takes constant time
result = self.size
proc high*[T](self: LinkedDeque[T]): int =
## Returns the index of the last
## element in the deque and -1 if
## the deque is empty
result = self.len() - 1
proc getNode[T](self: LinkedDeque[T], i: int): DequeNode[T] =
## Low level method for indexing and getting
## a node object back
if self.high() == -1:
raise newException(IndexDefect, "LinkedDeque is empty")
elif i > self.high():
raise newException(IndexDefect, &"{i} notin 0..{self.high()}")
var pos = 0
if i < self.high() div 2:
# If we're taking an element
# in the first half of the
# queue, we start from the
# beginning
result = self.head
while pos < i:
result = result.next
inc(pos)
else:
# Otherwise, we start from
# the end and go backwards
# at the chosen position
result = self.tail
pos = self.high()
while pos > i:
result = result.prev
dec(pos)
proc `[]`*[T](self: LinkedDeque[T], i: int): T =
## Implements indexing into the queue
result = self.getNode(i).val
proc `[]=`*[T](self: LinkedDeque[T], i: int, val: T) =
## Sets element at position i
## to the given value
self[i].val = val
proc pop*[T](self: LinkedDeque[T], pos: int = 0): T =
## Pops an element off the queue
## at the given index (default 0).
## The queue is optimized for popping
## and appending in roughly constant time
## at both ends, so this is quite fast
## if the operation is nears the ends of
## the iterable. The popped item is returned
var node = self.getNode(pos)
if pos == 0:
self.head = self.head.next
elif pos == self.high():
self.tail = self.tail.prev
else:
node.prev.next = node.next
result = node.val
dec(self.size)
iterator items*[T](self: LinkedDeque[T]): T =
## Implements the iteration protocol
## for the queue
var node = self.head
while node != nil:
yield node.val
node = node.next
iterator pairs*[T](self: LinkedDeque[T]): auto =
## Implements pairwise iteration with
## the index and the element at that
## index
var i = 0
for element in self:
yield (i, element)
inc(i)
iterator reversed*[T](self: LinkedDeque[T]): T =
## Same as self.items(), but starts at
## the end and yields the contents of
## the queue backwards
var node = self.tail
while node != nil:
yield node
node = node.prev
proc contains*[T](self: LinkedDeque[T], val: T): bool =
## Returns if the given element is in
## the deque
for element in self:
if element == val:
return true
return false
proc `$`*[T](self: LinkedDeque[T]): string =
## Returns a string representation
## of the deque
result = "deque(["
for i, item in self:
result &= $item
if i < self.high():
result &= ", "
result &= "])"

View File

@ -1,5 +1,18 @@
# Copyright 2022 Mattia Giambirtone
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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 strformat
import src/nimdeque
import ../src/nimdeque
when isMainModule:
@ -8,9 +21,12 @@ when isMainModule:
echo &"Generating {size} values"
for i in countup(0, size, 1):
deque.add(i)
echo "Checking values"
echo "Checking iteration"
for i in countup(0, size, 1):
doAssert deque[i] == i
echo "Checking contains"
for i in countup(0, size, 1):
doAssert i in deque
echo "Popping off the head"
doAssert deque.pop() == 0
echo "Popping off the tail"