2022-02-03 03:18:11 +01:00
|
|
|
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
|
2022-02-03 04:56:16 +01:00
|
|
|
entries: ptr UncheckedArray[T]
|
2022-02-03 03:18:11 +01:00
|
|
|
List*[T] = ptr ListObj[T]
|
|
|
|
|
|
|
|
proc newList*[T](): List[T] =
|
2022-02-03 04:56:16 +01:00
|
|
|
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))
|
2022-02-03 03:18:11 +01:00
|
|
|
|
|
|
|
proc free*[T](list: var List[T]) =
|
|
|
|
## dealloc's the list object
|
2022-02-03 04:56:16 +01:00
|
|
|
list.dealloc()
|
2022-02-03 03:18:11 +01:00
|
|
|
|
|
|
|
proc grow[T](list: var List[T]) {.inline.} =
|
|
|
|
## growth the list's capacity
|
2022-02-03 04:56:16 +01:00
|
|
|
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())
|
2022-02-03 03:18:11 +01:00
|
|
|
list.cap = newcap
|
|
|
|
else:
|
2022-02-03 04:56:16 +01:00
|
|
|
list.entries = cast[ptr UncheckedArray[T]](list.entries.realloc(size))
|
2022-02-03 03:18:11 +01:00
|
|
|
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 &= " ]"
|