nondescript/src/ndspkg/types/ndstring.nim

69 lines
1.6 KiB
Nim
Raw Normal View History

2022-02-03 04:58:34 +01:00
import hashtable
2022-01-29 04:22:21 +01:00
2022-01-28 04:17:11 +01:00
type
NdString* = ptr object
2022-01-29 04:22:21 +01:00
len*: uint32
hash*: uint32
chars*: UncheckedArray[char]
2022-01-28 22:00:21 +01:00
proc free*(ndStr: var NdString) =
dealloc(ndStr)
# hashes
2022-01-29 04:22:21 +01:00
proc fnv1a*(ndStr: NdString): int =
2022-01-28 22:00:21 +01:00
var hash = 2166136261'u32
for i in countup(0, ndStr.len.int - 1):
hash = hash xor (ndStr.chars[i]).uint32
hash *= 16777619
2022-01-29 04:22:21 +01:00
return hash.int
2022-02-03 04:58:34 +01:00
proc fnv1a*(str: string): int =
var hash = 2166136261'u32
for i in countup(0, str.len - 1):
hash = hash xor (str[i]).uint32
hash *= 16777619
return hash.int
# equals
2022-01-29 04:22:21 +01:00
proc equal*(left, right: NdString): bool =
left == right
2022-02-03 04:58:34 +01:00
var ndStrings = newTable[NdString, NdString]()
proc newString*(str: string): NdString =
let strlen = str.len()
let hash = str.fnv1a()
let interned = ndStrings.tableFindString(str[0].unsafeAddr, strlen, hash)
if interned != nil:
return interned
let len = 8 + strlen
result = cast[NdString](alloc(len))
result.len = strlen.uint32
result.hash = hash.uint32
copyMem(result.chars[0].unsafeAddr, str[0].unsafeAddr, strlen)
discard ndStrings.tableSet(result, nil)
proc resetInternedStrings* =
ndStrings.free()
ndStrings = newTable[NdString, NdString]()
proc `$`*(ndStr: NdString): string =
result = newString(ndStr.len.int)
copyMem(result[0].unsafeAddr, ndStr.chars[0].unsafeAddr, ndStr.len.int)
proc `&`*(left, right: NdString): NdString =
# TODO optimize this later when strings will be benchmarked
newString($left & $right)
proc getLength*(ndStr: NdString): int =
ndStr.len.int
proc getIndex*(ndStr: NdString, index: int): NdString =
# TODO optimize this later
newString($($ndStr)[index])