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]) {.inline.} = ## 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) {.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 = 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 &= " ]"