Skip to content

Instantly share code, notes, and snippets.

@flaviut
Created May 20, 2014 00:41
Show Gist options
  • Save flaviut/7f2a831516301ff0f890 to your computer and use it in GitHub Desktop.
Save flaviut/7f2a831516301ff0f890 to your computer and use it in GitHub Desktop.
import exceptions
template checkBounds(idx, min, max: int) =
when not defined(release):
if idx < min or idx > max:
raiseException(errOutOfBounds, idx, min, max)
# TBuffer {{{
type
TUncheckedArray {.unchecked.} [T] = array[0 .. 0, T]
TBuffer {.unchecked.} [T] = ref object
cap: int
data: TUncheckedArray[T]
proc newBufferRaw*[T](capacity: int): TBuffer[T] =
## Creates a new buffer with capacity `capacity`. Contents are undefined
result = TBuffer[T](cap: capacity,
data: cast[TUncheckedArray[T]](
alloc(capacity * sizeof(T))))
proc newBuffer*[T](capacity: int): TBuffer[T] =
## Creates a new zero-initialized buffer with capacity `capacity`
result = TBuffer[T](cap: capacity,
data: cast[TUncheckedArray[T]](
alloc0(capacity * sizeof(T))))
proc newBuffer*[IDX, T](arr: array[IDX, T]): TBuffer[T] =
result = newBufferRaw[T](len array)
for i, elem in arr:
result[i] = elem
proc `[]`*[T](arr: TBuffer[T], idx: int): T =
checkBounds(idx, 0, arr.cap-1)
result = arr.data[idx]
proc `[]=`*[T](arr: TBuffer[T], idx: int, val: T) =
checkBounds(idx, 0, arr.cap-1)
arr.data[idx] = val
proc copy*[T](arr: TBuffer[T]): TBuffer[T] =
let newPointer = alloc(sizeof[T] * arr.cap)
copyMem(newPointer, addr arr.data, sizeof[T] * arr.cap)
result = TBuffer(cap: arr.cap, data: cast[array[0..0, T]](newPointer))
proc copy*[T](arr: TBuffer[T], first, last: int): TBuffer[T] =
## Copies the elements from `first`, inclusive, to `last`, exclusive
## For example,
## ``` {.testable, lang: "Nimrod".}
##
## ```
discard
# }}}
# String {{{
type
TFString = object
## No-bullshit, zero-terminated string type
##
## - Immutable (copy on write)
## - O(1) substrings
## - Created with FString("Foo")
low, high: int
str: TBuffer[char]
proc newFString*(size: int): TFString =
## Creates a new string with the given capacity
result = TFString(low: 0,
high: size,
str: newBuffer[char](size+1))
proc `[]`*(a: TFString, idx: int): char =
## Returns the character at `idx`.
## Takes O(1) time
checkBounds(idx, a.low, a.high-1)
result = a.str[idx + a.low]
proc `[]=`*(a: TFString, idx: int, val: char): string =
## Returns a copy of the string with the character at `idx` replaced
## Takes O(N) time
checkBounds(idx, a.low, a.high-1)
proc FString*(s: string): TFString =
result = TFString(low: 0,
high: len s,
str: newBufferRaw[char](len(s)+1))
for i, c in s:
result.str[i] = c
proc len*(s: TFString): int =
result = s.high - s.low
proc substr*(s: TFString, fromIdx, untilIdx: Natural): TFString =
## Takes a substring of `s` from `fromIdx` to `untilIdx`; `fromIdx` is
## inclusive, while `untilIdx` exclusive.
## Takes O(1) time
result = TFString(low: s.low + fromIdx,
high: s.high + untilIdx,
str: s.str)
iterator items*(s: TFString): char =
## Iterates through each character in the string
for i in 0 .. len(s)-1:
yield s[i]
iterator pairs*(s: TFString): tuple[i: int, c: char] =
## Iterates through each index and character in the string
for i in 0 .. len(s)-1:
yield (i, s[i])
proc `==`*(a, b: TFString): bool =
## Determines if the two strings are equal. Not suitable for crypto purposes,
## it returns as soon as possible.
## Takes O(N) time
## ``` {.testable, lang: "Nimrod".}
##
## ```
result = true
if a.low != b.low or
a.high != b.high or
a.str == b.str:
return false
for i, c in a:
if c != b[i]:
return false
# }}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment