nondescript/src/ndspkg/types/ndlist.nim

89 lines
2.6 KiB
Nim

import ../pointerutils
import strformat
# configure ndlist here
const boundsChecks = defined(debug)
# 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
const growthFactor = 2
# should be a natural number larger than 1
const startCap = 8
type
ListObj[T] = object
len: int
cap: int
entries: UncheckedArray[T]
List*[T] = ptr ListObj[T]
template allocSize[T](list: List[T], cap: int): int =
sizeof(ListObj[T]) + sizeof(T) * cap
proc newList*[T](): List[T] =
return cast[List[T]](nil)
proc free*[T](list: var List[T]) =
## dealloc's the list object
if list != nil:
list.dealloc()
proc grow[T](list: var List[T]) {.inline.} =
## growth the list's capacity
let newcap = if list == nil: startCap else: list.cap * growthFactor
let size = list.allocSize(newcap)
if list == nil:
list = cast[List[T]](size.alloc())
list.cap = newcap
list.len = 0
else:
list = cast[List[T]](list.realloc(size))
list.cap = newcap
proc add*[T](list: var List[T], item: T) {.inline.} =
if list == nil or list.len == list.cap:
list.grow()
list.entries[list.len] = item
list.len.inc()
proc getIndex*[T](list: List[T], index: int): T =
when boundsChecks:
if index < 0 or index >= list.len:
raise newException(Defect, &"Attempt to getIndex with an index {index} which is out of bounds (len: {$list.len}).")
list.entries[index]
proc getIndexNeg*[T](list: List[T], index: int): T =
## warning: -1 is the top value, using 0 is invalid (unlike stack.getIndexNeg)
when boundsChecks:
if index <= 0 or index > list.len:
raise newException(Defect, "Attempt to getIndexNeg with an index out of bounds.")
list.entries[list.len - index]
proc setIndex*[T](list: var List[T], index: int, item: T) =
when boundsChecks:
if index < 0 or index >= list.len:
raise newException(Defect, "Attempt to getIndex with an index out of bounds.")
list.entries[index] = item
proc setIndexNeg*[T](list: List[T], index: int, item: T) =
## warning: -1 is the top value, using 0 is invalid (unlike stack.setIndexNeg)
when boundsChecks:
if index <= 0 or index > list.len:
raise newException(Defect, "Attempt to setIndexNeg with an index out of bounds.")
list.entries[list.len - index] = item
proc getLength*[T](list: List[T]): int {.inline.} =
if list == nil:
0
else:
list.len
proc `$`*[T](list: List[T]): string =
result = "@[ "
for i in countup(0, list.len - 1):
mixin `$`
result &= $list.getIndex(i)
if i < list.len - 1:
result &= ", "
result &= " ]"