2022-01-27 18:54:02 +01:00
|
|
|
import ../pointerutils
|
|
|
|
|
|
|
|
# configure stacks here
|
2022-01-29 07:24:58 +01:00
|
|
|
const boundsChecks = defined(debug)
|
2022-01-28 04:17:11 +01:00
|
|
|
# boundsChecks default: false, true has a large performance impact, and emitting correct code is on the compiler's job
|
|
|
|
# boundsChecking is only meant for debugging
|
2022-01-27 18:54:02 +01:00
|
|
|
const growthFactor = 2
|
2022-01-28 04:17:11 +01:00
|
|
|
# should be a natural number larger than 1
|
2022-01-27 18:54:02 +01:00
|
|
|
|
|
|
|
type
|
|
|
|
Stack*[T] = object
|
|
|
|
top: ptr T
|
|
|
|
start: ptr T
|
2022-01-28 04:17:11 +01:00
|
|
|
cap*: int
|
2022-01-27 18:54:02 +01:00
|
|
|
|
|
|
|
proc newStack*[T](startingCap: int): Stack[T] =
|
|
|
|
result.start = cast[ptr T](alloc(startingCap * sizeof(T)))
|
|
|
|
result.top = result.start.psub(sizeof(T))
|
|
|
|
result.cap = startingCap
|
|
|
|
|
2022-01-28 22:00:21 +01:00
|
|
|
proc free*[T](stack: var Stack[T]) =
|
2022-01-27 18:54:02 +01:00
|
|
|
## dealloc's the stack object
|
|
|
|
## if the stack contains pointers, those should be freed before destroying the stack
|
|
|
|
stack.cap = 0
|
|
|
|
stack.start.dealloc()
|
|
|
|
stack.start = nil
|
|
|
|
stack.top = nil
|
|
|
|
|
|
|
|
proc grow[T](stack: var Stack[T], len: int) {.inline.} =
|
|
|
|
## growth the stack's capacity and increments the top's index by one
|
|
|
|
stack.cap *= growthFactor
|
2022-01-28 04:17:11 +01:00
|
|
|
stack.start = cast[ptr T](realloc(stack.start, stack.cap * sizeof(T)))
|
2022-01-27 18:54:02 +01:00
|
|
|
stack.top = stack.start.padd(len * sizeof(T))
|
|
|
|
|
|
|
|
proc shrink[T](stack: var Stack[T]) {.inline.} =
|
|
|
|
discard
|
|
|
|
|
|
|
|
template high*[T](stack: Stack[T]): int =
|
|
|
|
stack.top.pdiff(stack.start) div sizeof(T)
|
|
|
|
|
|
|
|
template len*[T](stack: Stack[T]): int =
|
|
|
|
stack.high() + 1
|
|
|
|
|
|
|
|
proc push*[T](stack: var Stack[T], item: T) {.inline.} =
|
|
|
|
let len = stack.len()
|
|
|
|
if len == stack.cap:
|
|
|
|
stack.grow(len)
|
|
|
|
else:
|
|
|
|
stack.top = stack.top.padd(sizeof(T))
|
|
|
|
stack.top[]= item
|
|
|
|
|
|
|
|
template add*[T](stack: var Stack[T], item: T) =
|
|
|
|
stack.push(item)
|
|
|
|
|
|
|
|
proc pop*[T](stack: var Stack[T]): T {.inline.} =
|
|
|
|
when boundsChecks:
|
|
|
|
if stack.top == nil or stack.top.pless(stack.start):
|
|
|
|
raise newException(Defect, "Stacktop is nil or smaller than start.")
|
|
|
|
result = stack.top[]
|
|
|
|
stack.top = stack.top.psub(sizeof(T))
|
|
|
|
|
|
|
|
proc peek*[T](stack: Stack[T]): var T {.inline.} =
|
2022-01-28 04:17:11 +01:00
|
|
|
when boundsChecks:
|
|
|
|
if stack.top == nil or stack.top.pless(stack.start):
|
|
|
|
raise newException(Defect, "Stacktop is nil or smaller than start.")
|
2022-01-27 18:54:02 +01:00
|
|
|
stack.top[]
|
|
|
|
|
|
|
|
proc deleteTopN*[T](stack: var Stack[T], n: Natural) =
|
|
|
|
stack.top = stack.top.psub(sizeof(T) * n)
|
|
|
|
when boundsChecks:
|
|
|
|
if stack.top.pless(stack.start):
|
|
|
|
raise newException(Defect, "Stacktop sunk below the start after a deleteTopN.")
|
|
|
|
|
2022-02-03 04:56:16 +01:00
|
|
|
proc getIndex*[T](stack: Stack[T], index: int): var T =
|
2022-01-27 18:54:02 +01:00
|
|
|
when boundsChecks:
|
|
|
|
if index < 0 or index >= stack.len():
|
2022-01-29 07:24:58 +01:00
|
|
|
raise newException(Defect, &"Attempt to getIndex with an index {index} which is out of bounds (len: {stack.len()}).")
|
2022-01-27 18:54:02 +01:00
|
|
|
stack.start.padd(index * sizeof(T))[]
|
|
|
|
|
2022-02-03 04:56:16 +01:00
|
|
|
proc getIndexNeg*[T](stack: Stack[T], index: int): var T =
|
2022-01-28 04:17:11 +01:00
|
|
|
when boundsChecks:
|
|
|
|
if index < 0 or index >= stack.len():
|
|
|
|
raise newException(Defect, "Attempt to getIndexNeg with an index out of bounds.")
|
|
|
|
stack.top.psub(index * sizeof(T))[]
|
|
|
|
|
2022-01-27 18:54:02 +01:00
|
|
|
template `[]`*[T](stack: Stack[T], index: int): T =
|
|
|
|
stack.getIndex(index)
|
|
|
|
|
|
|
|
proc setIndex*[T](stack: var Stack[T], index: int, item: T) =
|
|
|
|
when boundsChecks:
|
|
|
|
if index < 0 or index >= stack.len():
|
|
|
|
raise newException(Defect, "Attempt to getIndex with an index out of bounds.")
|
|
|
|
stack.start.padd(index * sizeof(T))[]= item
|
|
|
|
|
2022-01-28 04:17:11 +01:00
|
|
|
proc setIndexNeg*[T](stack: Stack[T], index: int, item: T) =
|
|
|
|
when boundsChecks:
|
|
|
|
if index < 0 or index >= stack.len():
|
|
|
|
raise newException(Defect, "Attempt to setIndexNeg with an index out of bounds.")
|
|
|
|
stack.top.psub(index * sizeof(T))[] = item
|
|
|
|
|
|
|
|
|
2022-01-27 18:54:02 +01:00
|
|
|
template `[]=`*[T](stack: var Stack[T], index: int, item: T) =
|
|
|
|
stack.setIndex(index, item)
|