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 &= " ]"