89 lines
2.6 KiB
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 &= " ]"
|