From 36cced8ff19a0c2e1b6c49fef9dbafedd95c88b9 Mon Sep 17 00:00:00 2001 From: Nocturn9x Date: Mon, 14 Mar 2022 18:29:12 +0100 Subject: [PATCH] Fixed pop() at the end, added random insertion test, added BackwardsIndex support --- README.md | 6 +++- src/private/queues/linked.nim | 36 +++++++++++++++---- tests/linked.nim | 67 +++++++++++++++++++++-------------- 3 files changed, 75 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 46fba47..b308fd5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # nimdeque -Various deque implementations in pure nim \ No newline at end of file +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!) diff --git a/src/private/queues/linked.nim b/src/private/queues/linked.nim index 29d6d7c..1be772b 100644 --- a/src/private/queues/linked.nim +++ b/src/private/queues/linked.nim @@ -113,7 +113,6 @@ proc getNode[T](self: LinkedDeque[T], i: int): DequeNode[T] = 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(), @@ -121,7 +120,9 @@ proc insert*[T](self: LinkedDeque[T], pos: int, val: T) = ## 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 constant time + ## 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(): @@ -137,7 +138,6 @@ proc insert*[T](self: LinkedDeque[T], pos: int, val: T) = inc(self.size) - proc `[]`*[T](self: LinkedDeque[T], i: int): T = ## Implements indexing into the queue result = self.getNode(i).val @@ -149,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). @@ -161,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 @@ -212,6 +234,6 @@ proc `$`*[T](self: LinkedDeque[T]): string = result = "deque([" for i, item in self: result &= $item - if i < self.len(): + if i < self.high(): result &= ", " result &= "])" \ No newline at end of file diff --git a/tests/linked.nim b/tests/linked.nim index 126d2db..68678cc 100644 --- a/tests/linked.nim +++ b/tests/linked.nim @@ -11,6 +11,7 @@ # 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 @@ -19,65 +20,79 @@ when isMainModule: 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 "Checking length" - doAssert deque.len() == size + 1 + 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 "Checking length" - doAssert deque.len() == size - echo "Popping off the tail" - doAssert deque.pop(deque.high()) == size - echo "Checking length" + 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 "Checking addLeft" deque.addLeft(0) - echo "Checking length" - doAssert deque.len() == size - 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 "Checking length" + echo "\t- Checking length" doAssert oldLen + 1 == deque.len() - echo "Checking inserted value" + echo "\t- Checking inserted value" doAssert deque.pop(3) == 69420 - echo "Checking length" + echo "\t- Checking length" doAssert deque.len() == oldLen echo &"Checking insert({size - 2})" oldLen = deque.len() deque.insert(size - 2, 0x42362) - echo "Checking length" + echo "\t- Checking length" doAssert oldLen + 1 == deque.len() - echo "Checking inserted value" - doAssert deque.pop(size - 2) == 0x42362 - echo "Checking length" + 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 "Checking length" + echo "\t- Checking length" doAssert oldLen + 1 == deque.len() - echo "Checking inserted value" + echo "\t- Checking inserted value" doAssert deque.pop(size div 2) == 0xf7102 - echo "Checking length" + 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!"