diff options
author | Araq <rumpf_a@web.de> | 2011-04-21 00:54:44 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-04-21 00:54:44 +0200 |
commit | 36c67455d4d3e5fa5222937b800f90ef811d8e86 (patch) | |
tree | 3ba25061d5b422ea9c241e98e39a43a352f139bc /lib/pure/collections | |
parent | c3b16311dd7f547c19253af757ae53d58c715ad1 (diff) | |
download | Nim-36c67455d4d3e5fa5222937b800f90ef811d8e86.tar.gz |
got rid of some arcane module names
Diffstat (limited to 'lib/pure/collections')
-rw-r--r-- | lib/pure/collections/hashtables.nim | 111 | ||||
-rwxr-xr-x | lib/pure/collections/lists.nim | 155 |
2 files changed, 263 insertions, 3 deletions
diff --git a/lib/pure/collections/hashtables.nim b/lib/pure/collections/hashtables.nim index 133db66e1..6730163c2 100644 --- a/lib/pure/collections/hashtables.nim +++ b/lib/pure/collections/hashtables.nim @@ -18,8 +18,8 @@ type TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] THashTable[A, B] = object of TObject - counter: int data: TKeyValuePairSeq[A, B] + counter: int PHashTable*[A, B] = ref THashTable[A, B] ## use this type to declare tables @@ -32,12 +32,12 @@ iterator pairs*[A, B](t: PHashTable[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 keys*[A, B](t: PHashTable[A, B]): tuple[key: A, val: B] = +iterator keys*[A, B](t: PHashTable[A, B]): A = ## iterates over any key in the table `t`. for h in 0..high(t.data): if t.data[h].slot == seFilled: yield t.data[h].key -iterator values*[A, B](t: PHashTable[A, B]): tuple[key: A, val: B] = +iterator values*[A, B](t: PHashTable[A, B]): B = ## iterates over any value in the table `t`. for h in 0..high(t.data): if t.data[h].slot == seFilled: yield t.data[h].val @@ -103,6 +103,7 @@ proc del*[A, B](t: PHashTable[A, B], key: A) = var index = RawGet(t, key) if index >= 0: t.data[index].slot = seDeleted + dec(t.counter) proc newHashTable*[A, B](initialSize = 64): PHashTable[A, B] = ## creates a new string table that is empty. `initialSize` needs to be @@ -125,6 +126,110 @@ proc `$`*[A, B](t: PHashTable[A, B]): string = result.add($val) result.add("}") + +# ------------------------------ count tables ------------------------------- + +const + deletedCount = -1 + +type + TCountTable*[A] {.final.} = object + data: seq[tuple[key: A, val: int]] + counter: int + +proc len*[A](t: TCountTable[A]): int = + ## returns the number of keys in `t`. + result = t.counter + +iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] = + ## iterates over any (key, value) pair in the table `t`. + 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](t: TCountTable[A]): A = + ## iterates over any key in the table `t`. + for h in 0..high(t.data): + if t.data[h].slot == seFilled: yield t.data[h].key + +iterator values*[A](t: TCountTable[A]): int = + ## iterates over any value in the table `t`. + for h in 0..high(t.data): + if t.data[h].slot == seFilled: 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].slot != seEmpty: + if t.data[h].key == key and t.data[h].slot == seFilled: + return h + h = nextTry(h, high(t.data)) + result = -1 + +proc `[]`*[A](t: TCountTable[A], key: A): B = + ## retrieves the value at ``t[key]``. If `key` is not in `t`, + ## default empty value for the type `B` is returned + ## and no exception is raised. One can check with ``hasKey`` whether the key + ## exists. + var index = RawGet(t, key) + if index >= 0: result = t.data[index].val + +proc hasKey*[A](t: TCountTable[A], key: A): bool = + ## returns true iff `key` is in the table `t`. + result = rawGet(t, key) >= 0 + +proc RawInsert[A](t: TCountTable[A], data: var TKeyValuePairSeq[A, B], + key: A, val: int) = + var h: THash = hash(key) and high(data) + while data[h].slot == seFilled: + h = nextTry(h, high(data)) + data[h].key = key + data[h].val = val + data[h].slot = seFilled + +proc Enlarge[A](t: TCountTable[A]) = + var n: TKeyValuePairSeq[A, B] + newSeq(n, len(t.data) * growthFactor) + for i in countup(0, high(t.data)): + if t.data[i].slot == seFilled: RawInsert(t, n, t.data[i].key, t.data[i].val) + swap(t.data, n) + +proc `[]=`*[A](t: TCountTable[A], key: A, val: int) = + ## puts a (key, value)-pair into `t`. + var index = RawGet(t, key) + if index >= 0: + t.data[index].val = val + else: + if mustRehash(len(t.data), t.counter): Enlarge(t) + RawInsert(t, t.data, key, val) + inc(t.counter) + +proc del*[A](t: TCountTable[A], key: A) = + ## deletes `key` from hash table `t`. + var index = RawGet(t, key) + if index >= 0: + t.data[index].slot = seDeleted + +proc newHashTable*[A, B](initialSize = 64): PHashTable[A, B] = + ## creates a new string table that is empty. `initialSize` needs to be + ## a power of two. + assert isPowerOfTwo(initialSize) + new(result) + result.counter = 0 + newSeq(result.data, initialSize) + +proc `$`*[A](t: TCountTable[A]): string = + ## The `$` operator for string tables. + if t.len == 0: + result = "{:}" + else: + result = "{" + for key, val in pairs(t): + if result.len > 1: result.add(", ") + result.add($key) + result.add(": ") + result.add($val) + result.add("}") + + when isMainModule: var table = newHashTable[string, float]() table["test"] = 1.2345 diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim new file mode 100755 index 000000000..cae6d4620 --- /dev/null +++ b/lib/pure/collections/lists.nim @@ -0,0 +1,155 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Implementation of singly and doubly linked lists. Because it makes no sense +## to do so, the 'next' and 'prev' pointers are not hidden from you and can +## be manipulated directly for efficiency. + +type + TDoublyLinkedNode[T] {.pure, final.} = object + next*, prev*: ref TDoublyLinkedNode[T] + value*: T + PDoublyLinkedNode*[T] = ref TDoublyLinkedNode[T] + + TSinglyLinkedNode[T] {.pure, final.} = object + next*: ref TSinglyLinkedNode[T] + value*: T + PSinglyLinkedNode*[T] = ref TSinglyLinkedNode[T] + +proc newDoublyLinkedNode*[T](value: T): PDoublyLinkedNode[T] = + ## creates a new doubly linked node with the given `value`. + new(result) + result.value = value + +proc newSinglyLinkedNode*[T](value: T): PSinglyLinkedNode[T] = + ## creates a new singly linked node with the given `value`. + new(result) + result.value = value + +iterator items*[T](n: PDoublyLinkedNode[T]): T = + ## yields every value of `x`. + var it = n + while it != nil: + yield it.value + it = it.next + +iterator items*[T](n: PSinglyLinkedNode[T]): T = + ## yields every value of `x`. + var it = n + while it != nil: + yield it.value + it = it.next + +iterator nodes*[T](n: PSinglyLinkedNode[T]): PSinglyLinkedNode[T] = + ## iterates over every node of `x`. Removing the current node from the + ## list during traversal is supported. + var it = n + while it != nil: + var nxt = it.next + yield it + it = nxt + +iterator nodes*[T](n: PDoublyLinkedNode[T]): PDoublyLinkedNode[T] = + ## iterates over every node of `x`. Removing the current node from the + ## list during traversal is supported. + var it = n + while it != nil: + var nxt = it.next + yield it + it = nxt + +proc `$`*[list: PSinglyLinkedNode|PDoublyLinkedNode](n: list): string = + ## turns a list into its string representation. + result = "[" + for x in nodes(n): + if result.len > 1: result.add(", ") + result.add($x.value) + result.add("]") + +proc find*[list: PSinglyLinkedNode|PDoublyLinkedNode, T]( + n: list, value: T): list = + ## searches in the list for a value. Returns nil if the value does not + ## exist. + for x in nodes(n): + if x.value == value: return x + +proc contains*[list: PSinglyLinkedNode|PDoublyLinkedNode, T]( + n: list, value: T): list = + ## searches in the list for a value. Returns false if the value does not + ## exist, true otherwise. + for x in nodes(n): + if x.value == value: return true + +proc prepend*[T](head: var PSinglyLinkedNode[T], + toAdd: PSinglyLinkedNode[T]) {.inline.} = + ## prepends a node to `head`. Efficiency: O(1). + toAdd.next = head + head = toAdd + +proc prepend*[T](head: var PSinglyLinkedNode[T], x: T) {.inline.} = + ## creates a new node with the value `x` and prepends that node to `head`. + ## Efficiency: O(1). + preprend(head, newSinglyLinkedNode(x)) + +proc append*[T](head: var PSinglyLinkedNode[T], + toAdd: PSinglyLinkedNode[T]) = + ## appends a node to `head`. Efficiency: O(n). + if head == nil: + head = toAdd + else: + var it = head + while it.next != nil: it = it.next + it.next = toAdd + +proc append*[T](head: var PSinglyLinkedNode[T], x: T) {.inline.} = + ## creates a new node with the value `x` and appends that node to `head`. + ## Efficiency: O(n). + append(head, newSinglyLinkedNode(x)) + + +proc prepend*[T](head: var PDoublyLinkedNode[T], + toAdd: PDoublyLinkedNode[T]) {.inline.} = + ## prepends a node to `head`. Efficiency: O(1). + if head == nil: + head = toAdd + # head.prev stores the last node: + head.prev = toAdd + else: + toAdd.next = head + toAdd.prev = head.prev # copy pointer to last element + head.prev = toAdd + head = toAdd + +proc prepend*[T](head: var PDoublyLinkedNode[T], x: T) {.inline.} = + ## creates a new node with the value `x` and prepends that node to `head`. + ## Efficiency: O(1). + preprend(head, newDoublyLinkedNode(x)) + +proc append*[T](head: var PDoublyLinkedNode[T], + toAdd: PDoublyLinkedNode[T]) {.inline.} = + ## appends a node to `head`. Efficiency: O(1). + if head == nil: + head = toAdd + # head.prev stores the last node: + head.prev = toAdd + else: + var last = head.prev + assert last.next == nil + last.next = toAdd + toAdd.prev = last + head.prev = toAdd # new last element + +proc append*[T](head: var PDoublyLinkedNode[T], x: T) {.inline.} = + ## creates a new node with the value `x` and appends that node to `head`. + ## Efficiency: O(1). + append(head, newDoublyLinkedNode(x)) + + + + |