diff options
author | Araq <rumpf_a@web.de> | 2011-06-07 03:37:36 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-06-07 03:37:36 +0200 |
commit | 3bc821aa5c676869d65f1448a005dfd47f197f61 (patch) | |
tree | 16b757f5f8bcab86e46b677b8b8becd63ff04bed | |
parent | 42eb21be7b422b47732a56a1b8420b6f1b63f2c6 (diff) | |
download | Nim-3bc821aa5c676869d65f1448a005dfd47f197f61.tar.gz |
basic generic collections implemented and tested
-rwxr-xr-x | compiler/semexprs.nim | 8 | ||||
-rwxr-xr-x | lib/pure/collections/lists.nim | 55 | ||||
-rw-r--r-- | lib/pure/collections/sets.nim | 231 | ||||
-rw-r--r-- | lib/pure/collections/tables.nim | 81 | ||||
-rw-r--r-- | tests/accept/run/tlists.nim | 66 | ||||
-rw-r--r-- | tests/accept/run/tsets2.nim | 62 | ||||
-rw-r--r-- | tests/accept/run/ttables.nim | 82 | ||||
-rwxr-xr-x | todo.txt | 18 | ||||
-rwxr-xr-x | web/news.txt | 3 | ||||
-rwxr-xr-x | web/nimrod.ini | 1 |
10 files changed, 512 insertions, 95 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 25272b37d..9c1b89fe9 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -83,11 +83,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = markUsed(n, s) result = newSymNode(s, n.info) -proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) = +proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) = var diff = inheritanceDiff(castDest, src) - if diff == high(int): - GlobalError(info, errGenerated, `%`(MsgKindToString(errIllegalConvFromXtoY), [ - typeToString(src), typeToString(castDest)])) + if diff == high(int): + GlobalError(info, errGenerated, MsgKindToString(errIllegalConvFromXtoY) % [ + src.typeToString, castDest.typeToString]) proc checkConvertible(info: TLineInfo, castDest, src: PType) = const diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 10caac336..55c3d6ad9 100755 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -12,28 +12,28 @@ ## be manipulated directly for efficiency. type - TDoublyLinkedNode*[T] {.pure, - final.} = object ## a node a doubly linked list consists of + TDoublyLinkedNode* {.pure, + final.}[T] = object ## a node a doubly linked list consists of next*, prev*: ref TDoublyLinkedNode[T] value*: T PDoublyLinkedNode*[T] = ref TDoublyLinkedNode[T] - TSinglyLinkedNode*[T] {.pure, - final.} = object ## a node a singly linked list consists of + TSinglyLinkedNode* {.pure, + final.}[T] = object ## a node a singly linked list consists of next*: ref TSinglyLinkedNode[T] value*: T PSinglyLinkedNode*[T] = ref TSinglyLinkedNode[T] - TSinglyLinkedList*[T] {.pure, final.} = object ## a singly linked list + TSinglyLinkedList* {.pure, final.}[T] = object ## a singly linked list head*, tail*: PSinglyLinkedNode[T] - TDoublyLinkedList*[T] {.pure, final.} = object ## a doubly linked list + TDoublyLinkedList* {.pure, final.}[T] = object ## a doubly linked list head*, tail*: PDoublyLinkedNode[T] - TSinglyLinkedRing*[T] {.pure, final.} = object ## a singly linked ring + TSinglyLinkedRing* {.pure, final.}[T] = object ## a singly linked ring head*: PSinglyLinkedNode[T] - TDoublyLinkedRing*[T] {.pure, final.} = object ## a doubly linked ring + TDoublyLinkedRing* {.pure, final.}[T] = object ## a doubly linked ring head*: PDoublyLinkedNode[T] proc newDoublyLinkedNode*[T](value: T): PDoublyLinkedNode[T] = @@ -240,17 +240,15 @@ proc prepend*[T](L: var TSinglyLinkedRing[T], value: T) = proc append*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = ## appends a node `n` to `L`. Efficiency: O(1). - if L.tail != nil: - L.tail.next = n - n.prev = L.tail + if L.head != nil: n.next = L.head + n.prev = L.head.prev + L.head.prev.next = n + L.head.prev = n else: - # both head and tail are nil: - assert L.head == nil - L.head = n n.prev = n n.next = n - L.tail = n + L.head = n proc append*[T](L: var TDoublyLinkedRing[T], value: T) = ## appends a value to `L`. Efficiency: O(1). @@ -259,13 +257,11 @@ proc append*[T](L: var TDoublyLinkedRing[T], value: T) = proc prepend*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = ## prepends a node `n` to `L`. Efficiency: O(1). if L.head != nil: - L.head.prev = n - n.prev = L.tail n.next = L.head + n.prev = L.head.prev + L.head.prev.next = n + L.head.prev = n else: - # both head and tail are nil: - assert L.tail == nil - L.tail = n n.prev = n n.next = n L.head = n @@ -276,19 +272,14 @@ proc prepend*[T](L: var TDoublyLinkedRing[T], value: T) = proc remove*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = ## removes `n` from `L`. Efficiency: O(1). - if n == L.tail: - if n == L.head: - # only element: - L.tail = nil - L.head = nil - else: - L.tail = n.prev - elif n == L.head: - L.head = n.next n.next.prev = n.prev n.prev.next = n.next - # break cycles for the GC; not necessary, but might help: - n.next = nil - n.prev = nil + if n == L.head: + var p = L.head.prev + if p == L.head: + # only one element left: + L.head = nil + else: + L.head = L.head.prev diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim new file mode 100644 index 000000000..331881d88 --- /dev/null +++ b/lib/pure/collections/sets.nim @@ -0,0 +1,231 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## 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. + +import + os, hashes, math + +when defined(shallowADT): + {.pragma: myShallow, shallow.} +else: + {.pragma: myShallow.} + +type + TSlotEnum = enum seEmpty, seFilled, seDeleted + TKeyValuePair[A] = tuple[slot: TSlotEnum, key: A] + TKeyValuePairSeq[A] = seq[TKeyValuePair[A]] + TSet* {.final, myShallow.}[A] = object + data: TKeyValuePairSeq[A] + counter: int + +proc len*[A](s: TSet[A]): int = + ## returns the number of keys in `s`. + result = s.counter + +proc card*[A](s: TSet[A]): int = + ## alias for `len`. + result = s.counter + +iterator items*[A](s: TSet[A]): A = + ## iterates over any key in the table `t`. + for h in 0..high(s.data): + if s.data[h].slot == seFilled: yield s.data[h].key + +const + growthFactor = 2 + +proc mustRehash(length, counter: int): bool {.inline.} = + assert(length > counter) + result = (length * 2 < counter * 3) or (length - counter < 4) + +proc nextTry(h, maxHash: THash): THash {.inline.} = + result = ((5 * h) + 1) and maxHash + +template rawGetImpl() = + var h: THash = hash(key) and high(s.data) # start with real hash value + while s.data[h].slot != seEmpty: + if s.data[h].key == key and s.data[h].slot == seFilled: + return h + h = nextTry(h, high(s.data)) + result = -1 + +template rawInsertImpl() = + var h: THash = hash(key) and high(data) + while data[h].slot == seFilled: + h = nextTry(h, high(data)) + data[h].key = key + data[h].slot = seFilled + +proc RawGet[A](s: TSet[A], key: A): int = + rawGetImpl() + +proc contains*[A](s: TSet[A], key: A): bool = + ## returns true iff `key` is in `s`. + var index = RawGet(t, key) + result = index >= 0 + +proc RawInsert[A](s: var TSet[A], data: var TKeyValuePairSeq[A], key: A) = + rawInsertImpl() + +proc Enlarge[A](s: var TSet[A]) = + var n: TKeyValuePairSeq[A] + newSeq(n, len(s.data) * growthFactor) + for i in countup(0, high(s.data)): + if s.data[i].slot == seFilled: RawInsert(s, n, s.data[i].key) + swap(s.data, n) + +template inclImpl() = + var index = RawGet(s, key) + if index < 0: + if mustRehash(len(s.data), s.counter): Enlarge(s) + RawInsert(s, s.data, key) + inc(s.counter) + +template containsOrInclImpl() = + var index = RawGet(s, key) + if index >= 0: + result = true + else: + if mustRehash(len(s.data), s.counter): Enlarge(s) + RawInsert(s, s.data, key) + inc(s.counter) + +proc incl*[A](s: var TSet[A], key: A) = + ## includes an element `key` in `s`. + inclImpl() + +proc excl*[A](s: var TSet[A], key: A) = + ## excludes `key` from the set `s`. + var index = RawGet(t, key) + if index >= 0: + s.data[index].slot = seDeleted + dec(s.counter) + +proc containsOrIncl*[A](s: var TSet[A], key: A): bool = + ## returns true if `s` contains `key`, otherwise `key` is included in `s` + ## and false is returned. + containsOrInclImpl() + +proc initSet*[A](initialSize=64): TSet[A] = + ## creates a new hash set that is empty. `initialSize` needs to be + ## a power of two. + assert isPowerOfTwo(initialSize) + result.counter = 0 + newSeq(result.data, initialSize) + +proc toSet*[A](keys: openarray[A]): TSet[A] = + ## creates a new hash set that contains the given `keys`. + result = initSet[A](nextPowerOfTwo(keys.len+10)) + for key in items(keys): result.incl(key) + +template dollarImpl(): stmt = + result = "{" + for key in items(s): + if result.len > 1: result.add(", ") + result.add($key) + result.add("}") + +proc `$`*[A](s: TSet[A]): string = + ## The `$` operator for hash sets. + dollarImpl() + +# ------------------------------ ordered table ------------------------------ + +type + TOrderedKeyValuePair[A] = tuple[ + slot: TSlotEnum, next: int, key: A] + TOrderedKeyValuePairSeq[A] = seq[TOrderedKeyValuePair[A]] + TOrderedSet* {. + final, myShallow.}[A] = object ## set that remembers insertion order + data: TOrderedKeyValuePairSeq[A] + counter, first, last: int + +proc len*[A](s: TOrderedSet[A]): int {.inline.} = + ## returns the number of keys in `s`. + result = t.counter + +proc card*[A](s: TOrderedSet[A]): int {.inline.} = + ## alias for `len`. + result = t.counter + +template forAllOrderedPairs(yieldStmt: stmt) = + var h = s.first + while h >= 0: + var nxt = s.data[h].next + if s.data[h].slot == seFilled: yieldStmt + h = nxt + +iterator items*[A](s: TOrderedSet[A]): A = + ## iterates over any key in the set `s` in insertion order. + forAllOrderedPairs: + yield s.data[h].key + +proc RawGet[A](s: TOrderedSet[A], key: A): int = + rawGetImpl() + +proc contains*[A](s: TOrderedSet[A], key: A): bool = + ## returns true iff `key` is in `s`. + var index = RawGet(s, key) + result = index >= 0 + +proc RawInsert[A](s: var TOrderedSet[A], + data: var TOrderedKeyValuePairSeq[A], key: A) = + rawInsertImpl() + data[h].next = -1 + if s.first < 0: s.first = h + if s.last >= 0: data[s.last].next = h + s.last = h + +proc Enlarge[A](s: var TOrderedSet[A]) = + var n: TOrderedKeyValuePairSeq[A] + newSeq(n, len(s.data) * growthFactor) + var h = s.first + s.first = -1 + s.last = -1 + while h >= 0: + var nxt = s.data[h].next + if s.data[h].slot == seFilled: + RawInsert(s, n, s.data[h].key) + h = nxt + swap(s.data, n) + +proc incl*[A](s: var TOrderedSet[A], key: A) = + ## includes an element `key` in `s`. + inclImpl() + +proc containsOrIncl*[A](s: var TOrderedSet[A], key: A): bool = + ## returns true if `s` contains `key`, otherwise `key` is included in `s` + ## and false is returned. + containsOrInclImpl() + +proc initOrderedSet*[A](initialSize=64): TOrderedSet[A] = + ## creates a new ordered hash set that is empty. `initialSize` needs to be + ## a power of two. + assert isPowerOfTwo(initialSize) + result.counter = 0 + result.first = -1 + result.last = -1 + newSeq(result.data, initialSize) + +proc toOrderedSet*[A](keys: openarray[A]): TOrderedSet[A] = + ## creates a new ordered hash set that contains the given `keys`. + result = initOrderedSet[A](nextPowerOfTwo(keys.len+10)) + for key in items(keys): result.incl(key) + +proc `$`*[A](s: TOrderedSet[A]): string = + ## The `$` operator for ordered hash sets. + dollarImpl() + + diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index f132051da..f817ec800 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2011 Andreas Rumpf, Dominik Picheta +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -12,7 +12,7 @@ ## ## 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 don't need this behaviour, you can define the symbol +## efficiency and know what you do (!), you can define the symbol ## ``shallowADT`` to compile a version that uses shallow copies instead. import @@ -123,7 +123,7 @@ proc del*[A, B](t: var TTable[A, B], key: A) = dec(t.counter) proc initTable*[A, B](initialSize=64): TTable[A, B] = - ## creates a new hash table table that is empty. `initialSize` needs to be + ## creates a new hash table that is empty. `initialSize` needs to be ## a power of two. assert isPowerOfTwo(initialSize) result.counter = 0 @@ -132,7 +132,7 @@ proc initTable*[A, B](initialSize=64): TTable[A, B] = proc toTable*[A, B](pairs: openarray[tuple[key: A, val: B]]): TTable[A, B] = ## creates a new hash table that contains the given `pairs`. - result = initTable[A](nextPowerOfTwo(pairs.len+10)) + result = initTable[A, B](nextPowerOfTwo(pairs.len+10)) for key, val in items(pairs): result[key] = val template dollarImpl(): stmt = @@ -148,7 +148,7 @@ template dollarImpl(): stmt = result.add("}") proc `$`*[A, B](t: TTable[A, B]): string = - ## The `$` operator for string tables. + ## The `$` operator for hash tables. dollarImpl() # ------------------------------ ordered table ------------------------------ @@ -167,11 +167,11 @@ proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} = result = t.counter template forAllOrderedPairs(yieldStmt: stmt) = - var i = t.first - while i >= 0: - var nxt = t.data[i].next + var h = t.first + while h >= 0: + var nxt = t.data[h].next if t.data[h].slot == seFilled: yieldStmt - i = nxt + h = nxt iterator pairs*[A, B](t: TOrderedTable[A, B]): tuple[key: A, val: B] = ## iterates over any (key, value) pair in the table `t` in insertion @@ -204,23 +204,29 @@ 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 -proc RawInsert[A, B](t: TOrderedTable[A, B], +proc RawInsert[A, B](t: var TOrderedTable[A, B], data: var TOrderedKeyValuePairSeq[A, B], key: A, val: B) = rawInsertImpl() data[h].next = -1 - if first < 0: first = h - if last >= 0: data[last].next = h - lastEntry = h + if t.first < 0: t.first = h + if t.last >= 0: data[t.last].next = h + t.last = h -proc Enlarge[A, B](t: TOrderedTable[A, B]) = +proc Enlarge[A, B](t: var TOrderedTable[A, B]) = var n: TOrderedKeyValuePairSeq[A, B] newSeq(n, len(t.data) * growthFactor) - forAllOrderedPairs: - RawInsert(t, n, t.data[h].key, t.data[h].val) + var h = t.first + t.first = -1 + t.last = -1 + while h >= 0: + var nxt = t.data[h].next + if t.data[h].slot == seFilled: + RawInsert(t, n, t.data[h].key, t.data[h].val) + h = nxt swap(t.data, n) -proc `[]=`*[A, B](t: TOrderedTable[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: var TOrderedTable[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. putImpl() @@ -240,7 +246,7 @@ proc toOrderedTable*[A, B](pairs: openarray[tuple[key: A, for key, val in items(pairs): result[key] = val proc `$`*[A, B](t: TOrderedTable[A, B]): string = - ## The `$` operator for hash tables. + ## The `$` operator for ordered hash tables. dollarImpl() # ------------------------------ count tables ------------------------------- @@ -295,14 +301,14 @@ proc RawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]], data[h].key = key data[h].val = val -proc Enlarge[A](t: TCountTable[A]) = +proc Enlarge[A](t: var TCountTable[A]) = var n: seq[tuple[key: A, val: int]] newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): if t.data[i].val != 0: RawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) -proc `[]=`*[A](t: TCountTable[A], key: A, val: int) = +proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) = ## puts a (key, value)-pair into `t`. `val` has to be positive. assert val > 0 PutImpl() @@ -323,7 +329,7 @@ proc `$`*[A](t: TCountTable[A]): string = ## The `$` operator for count tables. dollarImpl() -proc inc*[A](t: TCountTable[A], key: A, val = 1) = +proc inc*[A](t: var TCountTable[A], key: A, val = 1) = ## increments `t[key]` by `val`. var index = RawGet(t, key) if index >= 0: @@ -351,8 +357,8 @@ proc Largest*[A](t: TCountTable[A]): tuple[key: A, val: int] = result.key = t.data[maxIdx].key result.val = t.data[maxIdx].val -proc sort*[A](t: var TCountTable[A]) = - ## sorts the count table so that the entry with the highest counter comes +proc sort*[A](t: var TCountTable[A]) = + ## sorts the count table so that the entry with the highest counter comes ## first. This is destructive! You must not modify `t` afterwards! ## You can use the iterators `pairs`, `keys`, and `values` to iterate over ## `t` in the sorted order. @@ -361,35 +367,14 @@ proc sort*[A](t: var TCountTable[A]) = var h = 1 while true: h = 3 * h + 1 - if h >= t.data.high: break - while true: + if h >= high(t.data): break + while true: h = h div 3 - for i in countup(h, t.data.high): + for i in countup(h, high(t.data)): var j = i - while t.data[j-h].val < t.data[j].val: + while t.data[j-h].val <= t.data[j].val: swap(t.data[j], t.data[j-h]) j = j-h if j < h: break if h == 1: break -when isMainModule: - var table = initHashTable[string, float]() - table["test"] = 1.2345 - table["111"] = 1.000043 - echo table - table.del("111") - echo table - #echo repr(table["111"]) - #echo(repr(table["1212"])) - table["111"] = 1.5 - table["011"] = 67.9 - echo table - table.del("test") - table.del("111") - echo table - - - echo hash("test") - echo hash("test") - - diff --git a/tests/accept/run/tlists.nim b/tests/accept/run/tlists.nim index e69de29bb..7d5379945 100644 --- a/tests/accept/run/tlists.nim +++ b/tests/accept/run/tlists.nim @@ -0,0 +1,66 @@ +discard """ + output: '''true''' +""" + +import lists + +const + data = [1, 2, 3, 4, 5, 6] + +block SinglyLinkedListTest1: + var L: TSinglyLinkedList[int] + for d in items(data): L.prepend(d) + assert($L == "[6, 5, 4, 3, 2, 1]") + + assert(4 in L) + +block SinglyLinkedListTest2: + var L: TSinglyLinkedList[string] + for d in items(data): L.prepend($d) + assert($L == "[6, 5, 4, 3, 2, 1]") + + assert("4" in L) + + +block DoublyLinkedListTest1: + var L: TDoublyLinkedList[int] + for d in items(data): L.prepend(d) + for d in items(data): L.append(d) + L.remove(L.find(1)) + assert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]") + + assert(4 in L) + +block SinglyLinkedRingTest1: + var L: TSinglyLinkedRing[int] + L.prepend(4) + assert($L == "[4]") + L.prepend(4) + + assert($L == "[4, 4]") + assert(4 in L) + + +block DoublyLinkedRingTest1: + var L: TDoublyLinkedRing[int] + L.prepend(4) + assert($L == "[4]") + L.prepend(4) + + assert($L == "[4, 4]") + assert(4 in L) + + L.append(3) + L.append(5) + assert($L == "[4, 4, 3, 5]") + + L.remove(L.find(3)) + L.remove(L.find(5)) + L.remove(L.find(4)) + L.remove(L.find(4)) + assert($L == "[]") + assert(4 notin L) + + +echo "true" + diff --git a/tests/accept/run/tsets2.nim b/tests/accept/run/tsets2.nim new file mode 100644 index 000000000..89935072f --- /dev/null +++ b/tests/accept/run/tsets2.nim @@ -0,0 +1,62 @@ +discard """ + output: '''true''' + cmd: "nimrod cc --gc:none --hints:on $# $#" +""" + +import hashes, sets + +const + data = [ + "34", "12", + "90", "0", + "1", "2", + "3", "4", + "5", "6", + "7", "8", + "9", "---00", + "10", "11", "19", + "20", "30", "40", + "50", "60", "70", + "80"] + +block tableTest1: + var t = initSet[tuple[x, y: int]]() + t.incl((0,0)) + t.incl((1,0)) + assert(not t.containsOrIncl((0,1))) + t.incl((1,1)) + + for x in 0..1: + for y in 0..1: + assert((x,y) in t) + #assert($t == + # "{(x: 0, y: 0), (x: 0, y: 1), (x: 1, y: 0), (x: 1, y: 1)}") + +block setTest2: + var t = initSet[string]() + t.incl("test") + t.incl("111") + t.incl("123") + t.excl("111") + + t.incl("012") + t.incl("123") # test duplicates + + assert "123" in t + assert "111" notin t # deleted + + for key in items(data): t.incl(key) + for key in items(data): assert key in t + + +block orderedSetTest1: + var t = data.toOrderedSet + for key in items(data): assert key in t + var i = 0 + # `items` needs to yield in insertion order: + for key in items(t): + assert key == data[i] + inc(i) + +echo "true" + diff --git a/tests/accept/run/ttables.nim b/tests/accept/run/ttables.nim index c7033bf70..72799414e 100644 --- a/tests/accept/run/ttables.nim +++ b/tests/accept/run/ttables.nim @@ -1,18 +1,84 @@ discard """ output: '''true''' + cmd: "nimrod cc --gc:none --hints:on $# $#" """ import hashes, tables -var t = initTable[tuple[x, y: int], string]() -t[(0,0)] = "00" -t[(1,0)] = "10" -t[(0,1)] = "01" -t[(1,1)] = "11" +const + data = { + "34": 123456, "12": 789, + "90": 343, "0": 34404, + "1": 344004, "2": 344774, + "3": 342244, "4": 3412344, + "5": 341232144, "6": 34214544, + "7": 3434544, "8": 344544, + "9": 34435644, "---00": 346677844, + "10": 34484, "11": 34474, "19": 34464, + "20": 34454, "30": 34141244, "40": 344114, + "50": 344490, "60": 344491, "70": 344492, + "80": 344497} -for x in 0..1: - for y in 0..1: - assert t[(x,y)] == $x & $y +block tableTest1: + var t = initTable[tuple[x, y: int], string]() + t[(0,0)] = "00" + t[(1,0)] = "10" + t[(0,1)] = "01" + t[(1,1)] = "11" + for x in 0..1: + for y in 0..1: + assert t[(x,y)] == $x & $y + assert($t == + "{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") + +block tableTest2: + var t = initTable[string, float]() + t["test"] = 1.2345 + t["111"] = 1.000043 + t["123"] = 1.23 + t.del("111") + + t["012"] = 67.9 + t["123"] = 1.5 # test overwriting + + assert t["123"] == 1.5 + assert t["111"] == 0.0 # deleted + assert(not hasKey(t, "111")) + + for key, val in items(data): t[key] = val.toFloat + for key, val in items(data): assert t[key] == val.toFloat + + +block orderedTableTest1: + var t = initOrderedTable[string, int](2) + for key, val in items(data): t[key] = val + for key, val in items(data): assert t[key] == val + var i = 0 + # `pairs` needs to yield in insertion order: + for key, val in pairs(t): + assert key == data[i][0] + assert val == data[i][1] + inc(i) + +block countTableTest1: + var s = data.toTable + var t = initCountTable[string]() + for k in s.Keys: t.inc(k) + for k in t.keys: assert t[k] == 1 + t.inc("90", 3) + t.inc("12", 2) + t.inc("34", 1) + assert t.largest()[0] == "90" + + t.sort() + var i = 0 + for k, v in t.pairs: + case i + of 0: assert k == "90" and v == 4 + of 1: assert k == "12" and v == 3 + of 2: assert k == "34" and v == 2 + else: break + inc i echo "true" diff --git a/todo.txt b/todo.txt index d060a17e9..06e46092c 100755 --- a/todo.txt +++ b/todo.txt @@ -4,12 +4,13 @@ from different heaps: n.next = otherHeapPtr * add --deadlock_prevention:on|off switch? timeout for locks? - +* test the sort implementation again High priority (version 0.9.0) ============================= +- iterators should not always be destructive! - warning for implicit openArray -> varargs convention - implement explicit varargs - tests: run modules that contain "#RUN_ME", compile the other @@ -19,7 +20,6 @@ High priority (version 0.9.0) - fix overloading resolution - wrong co-/contravariance - make ^ available as operator -- iterators should not always be destructive Bugs ---- @@ -30,12 +30,23 @@ Bugs - BUG: generic assign still buggy - Optimization: If we use a temporary for the result anyway the code gen should make use of this fact to generate better code... +- sorting with leads to a strange memory corruption! + --> system.swap or genericAssign is broken! And indeed, if reference counts + are not modified and the GC is triggered in between a swap, bad things + may happen! + + proc sort*[A](t: var TCountTable[A]) = + for i in 0 .. high(t.data)-1: + var maxIdx = i + for j in i+1 .. high(t.data): + if t.data[j].val == 3: echo "touched! ", t.data[j].key + if t.data[j].val > t.data[maxIdx].val: maxIdx = j + swap(t.data[maxIdx], t.data[i]) To implement ------------ -* hash tables and sets; count tables; ordered dicts * distinct types for array/seq indexes * implement closures for the C code generator * GC: marker procs for native Nimrod GC and Boehm GC @@ -68,6 +79,7 @@ Low priority Library ------- +- specialized bit sets; specialized string sets - locale support - conversion between character sets - bignums diff --git a/web/news.txt b/web/news.txt index c1477abbe..f048ae541 100755 --- a/web/news.txt +++ b/web/news.txt @@ -48,6 +48,9 @@ Changes affecting backwards compatibility Additions --------- +- Added ``lists`` module which contains generic linked lists. +- Added ``sets`` module which contains generic hash sets. +- Added ``tables`` module which contains generic hash tables. - Added ``scgi`` module. - Added ``smtp`` module. - Added ``re.findAll``, ``pegs.findAll``. diff --git a/web/nimrod.ini b/web/nimrod.ini index be0c67690..a7bee7492 100755 --- a/web/nimrod.ini +++ b/web/nimrod.ini @@ -38,6 +38,7 @@ srcdoc: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser" srcdoc: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors" srcdoc: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics" srcdoc: "impure/rdstdin;wrappers/zmq" +srcdoc: "pure/collections/tables;pure/collections/sets;pure/collections/lists" webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup" webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc" |