nondescript/src/ndspkg/types/ndlist.nim

93 lines
2.8 KiB
Nim

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: ptr UncheckedArray[T]
List*[T] = ptr ListObj[T]
proc newList*[T](): List[T] =
result = cast[List[T]](alloc(sizeof(ListObj[T])))
result.len = 0
result.cap = 0
proc newListCopymem*[T](start: ptr T, len: int): List[T] =
result = newList[T]()
result.len = len
result.cap = len
result.entries = cast[ptr UncheckedArray[T]](alloc(sizeof(T) * len))
copyMem(result.entries, start, len * sizeof(T))
proc free*[T](list: var List[T]) =
## dealloc's the list object
list.dealloc()
proc grow[T](list: var List[T]) =
## growth the list's capacity
let newcap = if list.cap == 0: startCap else: list.cap * growthFactor
let size = newcap * sizeof(T)
if list.cap == 0:
list.entries = cast[ptr UncheckedArray[T]](size.alloc())
list.cap = newcap
else:
list.entries = cast[ptr UncheckedArray[T]](list.entries.realloc(size))
list.cap = newcap
proc add*[T](list: var List[T], item: T) =
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 =
if list == nil:
0
else:
list.len
proc `$`*[T](list: List[T]): string =
if list.len == 0:
return "@[]"
result = "@[ "
for i in countup(0, list.len - 1):
mixin `$`
result &= $list.getIndex(i)
if i < list.len - 1:
result &= ", "
result &= " ]"