Files
Nim/lib/generics.nim
Andreas Rumpf 8b2a9401a1 version 0.7.0
2008-11-16 22:08:15 +01:00

170 lines
4.6 KiB
Nim

#
#
# Nimrod's Runtime Library
# (c) Copyright 2008 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains basic abstract data types.
type
TListItem[T] = object
next, prev: ref TListItem[T]
data: T
TList*[T] = ref TListItem[T]
# TIndex*[T] = object
#proc succ*[T](i: TIndex[T]): TIndex[T] =
# result = i.next
#proc pred*[T](i: TIndex[T]): TIndex[T] =
# result = i.prev
#proc getIndex*[T](c: TList[T]): TIndex[TList[T]] =
# return c
proc init*[T](c: var TList[T]) {.inline.} =
c = nil
iterator items*[T](c: TList[T]): var T {.inline.} =
var it = c
while it != nil:
yield it.data
it = it.next
proc add*[T](c: var TList[T], item: T) {.inline.} =
var it: ref TListItem[T]
new(it)
it.data = item
it.prev = c.prev
it.next = c.next
c = it
proc incl*[T](c: var TList[T], item: T) =
for i in items(c):
if i == item: return
add(c, item)
proc excl*[T](c: var TList[T], item: T) =
var it: TList[T] = c
while it != nil:
if it.data == item:
# remove from list
it = it.next
proc del*[T](c: var TList[T], item: T) {.inline.} = excl(c, item)
proc hash*(p: pointer): int {.inline.} =
# Returns the hash value of a pointer. This is very fast.
return cast[TAddress](p) shr 3
proc hash*(x: int): int {.inline.} = return x
proc hash*(x: char): int {.inline.} = return ord(x)
proc hash*(x: bool): int {.inline.} = return ord(x)
proc hash*(s: string): int =
# The generic hash table implementation work on a type `T` that has a hash
# proc. Predefined for string, pointers, int, char, bool.
var h = 0
for i in 0..s.len-1:
h = h +% Ord(s[i])
h = h +% h shl 10
h = h xor (h shr 6)
h = h +% h shl 3
h = h xor (h shr 11)
h = h +% h shl 15
result = h
proc isNil*(x: int): bool {.inline.} = return x == low(int)
proc nilValue*(x: int): int {.inline.} = return low(int)
proc nilValue*(x: pointer): pointer {.inline.} = return nil
proc nilValue*(x: string): string {.inline.} = return nil
proc nilValue*[T](x: seq[T]): seq[T] {.inline.} = return nil
proc nilValue*(x: float): float {.inline.} = return NaN
proc mustRehash(len, counter: int): bool =
assert(len > counter)
result = (len * 2 < counter * 3) or (len-counter < 4)
proc nextTry(h, maxHash: int): int {.inline.} =
return ((5*%h) +% 1) and maxHash
type
TPair*[TKey, TValue] = tuple[key: TKey, val: TValue]
TTable*[TKey, TValue] =
object of TObject ## A table which stores (key, value)
## pairs. The used algorithm is hashing.
d: seq[TPair[TKey, TValue]]
counter: natural
const
growthFactor = 2 # must be power of two
proc init*[TKey, TValue](t: var TTable[TKey, TValue], capacity: natural = 32) =
newSeq(t.d, capacity)
proc len*[TKey, TValue](t: TTable[TKey, TValue]): natural = return t.counter
iterator pairs*[TKey,TValue](t: TTable[TKey,TValue]): TPair[TKey, TValue] =
for i in 0..t.d.len-1:
if not isNil(t.d[i].key):
yield (t.d[i].key, t.d[i].val)
proc TableRawGet[TKey, TValue](t: TTable[TKey, TValue], key: TKey): int =
var h = hash(key) and high(t.d)
while not isNil(t.d[h].key):
if t.d[h].key == key: return h
h = nextTry(h, high(t.d))
return -1
proc `[]`*[TKey, TValue](t: TTable[TKey, TValue], key: TKey): TValue =
var index = TableRawGet(t, key)
return if index >= 0: t.d[index].val else: nilValue(t.d[0].val)
proc TableRawInsert[TKey, TValue](data: var seq[TPair[TKey, TValue]],
key: TKey, val: TValue) =
var h = hash(key) and high(data)
while not isNil(data[h].key):
assert(data[h].key != key)
h = nextTry(h, high(data))
assert(isNil(data[h].key))
data[h].key = key
data[h].val = val
proc TableEnlarge[TKey, TValue](t: var TTable[TKey, TValue]) =
var n: seq[TPair[TKey,TValue]]
newSeq(n, len(t.d) * growthFactor)
for i in 0..high(t.d):
if not isNil(t.d[i].key):
TableRawInsert(n, t.d[i].key, t.d[i].val)
swap(t.d, n)
proc `[]=`*[TKey, TValue](t: var TTable[TKey, TValue], key: TKey, val: TValue) =
var index = TableRawGet(t, key)
if index >= 0:
t.d[index].val = val
else:
if mustRehash(len(t.d), t.counter): TableEnlarge(t)
TableRawInsert(t.d, key, val)
inc(t.counter)
proc add*[TKey, TValue](t: var TTable[TKey, TValue], key: TKey, val: TValue) =
if mustRehash(len(t.d), t.counter): TableEnlarge(t)
TableRawInsert(t.d, key, val)
inc(t.counter)
proc test =
var
t: TTable[string, int]
init(t)
t["key1"] = 1
t["key2"] = 2
t["key3"] = 3
for key, val in pairs(t):
echo(key & " = " & $val)
test()