modifyable results for generics; teventemitter works

This commit is contained in:
Araq 2011-08-09 01:40:12 +02:00
commit 7000cf51b7
10 changed files with 103 additions and 40 deletions

View file

@ -10,17 +10,12 @@
## The ``sets`` module implements an efficient hash set and ordered hash set.
##
## **Note**: The data types declared here have *value semantics*: This means
## that ``=`` performs a copy of the hash table. If you are overly concerned
## with efficiency and know what you do (!), you can define the symbol
## ``shallowADT`` to compile a version that uses shallow copies instead.
## that ``=`` performs a copy of the set.
import
os, hashes, math
when defined(shallowADT):
{.pragma: myShallow, shallow.}
else:
{.pragma: myShallow.}
{.pragma: myShallow.}
type
TSlotEnum = enum seEmpty, seFilled, seDeleted

View file

@ -11,17 +11,12 @@
## a mapping from keys to values.
##
## **Note:** The data types declared here have *value semantics*: This means
## that ``=`` performs a copy of the hash table. If you are overly concerned
## with efficiency and know what you do (!), you can define the symbol
## ``shallowADT`` to compile a version that uses shallow copies instead.
## that ``=`` performs a copy of the hash table.
import
hashes, math
when defined(shallowADT):
{.pragma: myShallow, shallow.}
else:
{.pragma: myShallow.}
{.pragma: myShallow.}
type
TSlotEnum = enum seEmpty, seFilled, seDeleted
@ -40,6 +35,12 @@ iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
iterator mpairs*[A, B](t: var TTable[A, B]): tuple[key: A, val: var B] =
## iterates over any (key, value) pair in the table `t`. The values
## can be modified.
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
iterator keys*[A, B](t: TTable[A, B]): A =
## iterates over any key in the table `t`.
for h in 0..high(t.data):
@ -50,6 +51,11 @@ iterator values*[A, B](t: TTable[A, B]): B =
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].val
iterator mvalues*[A, B](t: var TTable[A, B]): var B =
## iterates over any value in the table `t`. The values can be modified.
for h in 0..high(t.data):
if t.data[h].slot == seFilled: yield t.data[h].val
const
growthFactor = 2
@ -87,6 +93,13 @@ proc `[]`*[A, B](t: TTable[A, B], key: A): B =
var index = RawGet(t, key)
if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var TTable[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var index = RawGet(t, key)
if index >= 0: result = t.data[index].val
else: raise newException(EInvalidKey, "key not found: " & $key)
proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
@ -197,6 +210,12 @@ iterator pairs*[A, B](t: TOrderedTable[A, B]): tuple[key: A, val: B] =
forAllOrderedPairs:
yield (t.data[h].key, t.data[h].val)
iterator mpairs*[A, B](t: var TOrderedTable[A, B]): tuple[key: A, val: var B] =
## iterates over any (key, value) pair in the table `t` in insertion
## order. The values can be modified.
forAllOrderedPairs:
yield (t.data[h].key, t.data[h].val)
iterator keys*[A, B](t: TOrderedTable[A, B]): A =
## iterates over any key in the table `t` in insertion order.
forAllOrderedPairs:
@ -207,6 +226,12 @@ iterator values*[A, B](t: TOrderedTable[A, B]): B =
forAllOrderedPairs:
yield t.data[h].val
iterator mvalues*[A, B](t: var TOrderedTable[A, B]): var B =
## iterates over any value in the table `t` in insertion order. The values
## can be modified.
forAllOrderedPairs:
yield t.data[h].val
proc RawGet[A, B](t: TOrderedTable[A, B], key: A): int =
rawGetImpl()
@ -218,6 +243,13 @@ proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B =
var index = RawGet(t, key)
if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var TOrderedTable[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var index = RawGet(t, key)
if index >= 0: result = t.data[index].val
else: raise newException(EInvalidKey, "key not found: " & $key)
proc hasKey*[A, B](t: TOrderedTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
@ -288,6 +320,12 @@ iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] =
for h in 0..high(t.data):
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
iterator mpairs*[A](t: var TCountTable[A]): tuple[key: A, val: var int] =
## iterates over any (key, value) pair in the table `t`. The values can
## be modified.
for h in 0..high(t.data):
if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
iterator keys*[A](t: TCountTable[A]): A =
## iterates over any key in the table `t`.
for h in 0..high(t.data):
@ -298,6 +336,11 @@ iterator values*[A](t: TCountTable[A]): int =
for h in 0..high(t.data):
if t.data[h].val != 0: yield t.data[h].val
iterator mvalues*[A](t: TCountTable[A]): var int =
## iterates over any value in the table `t`. The values can be modified.
for h in 0..high(t.data):
if t.data[h].val != 0: yield t.data[h].val
proc RawGet[A](t: TCountTable[A], key: A): int =
var h: THash = hash(key) and high(t.data) # start with real hash value
while t.data[h].val != 0:
@ -312,6 +355,13 @@ proc `[]`*[A](t: TCountTable[A], key: A): int =
var index = RawGet(t, key)
if index >= 0: result = t.data[index].val
proc mget*[A](t: var TCountTable[A], key: A): var int =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var index = RawGet(t, key)
if index >= 0: result = t.data[index].val
else: raise newException(EInvalidKey, "key not found: " & $key)
proc hasKey*[A](t: TCountTable[A], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0

View file

@ -92,13 +92,13 @@ proc `[]`*(t: PStringTable, key: string): string {.rtl, extern: "nstGet".} =
if index >= 0: result = t.data[index].val
else: result = ""
proc modGet*(t: PStringTable, key: string): var string {.
proc mget*(t: PStringTable, key: string): var string {.
rtl, extern: "nstTake".} =
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
## ``EInvalidValue`` exception is raised.
## ``EInvalidKey`` exception is raised.
var index = RawGet(t, key)
if index >= 0: result = t.data[index].val
else: raise newException(EInvalidValue, "key does not exist: " & key)
else: raise newException(EInvalidKey, "key does not exist: " & key)
proc hasKey*(t: PStringTable, key: string): bool {.rtl, extern: "nst$1".} =
## returns true iff `key` is in the table `t`.
@ -221,6 +221,6 @@ when isMainModule:
assert x["k"] == "v"
assert x["11"] == "22"
assert x["565"] == "67"
x.modGet("11") = "23"
x.mget("11") = "23"
assert x["11"] == "23"

View file

@ -215,6 +215,8 @@ type
EInvalidValue* = object of ESynch ## is the exception class for string
## and object conversion errors.
EInvalidKey* = object of EInvalidValue ## is the exception class if a key
## cannot be found in a table.
EOutOfMemory* = object of ESystem ## is the exception class for
## unsuccessful attempts to allocate