mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 20:17:42 +00:00
170 lines
4.6 KiB
Nim
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()
|