diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2020-02-26 13:07:09 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-26 22:07:09 +0100 |
commit | 42dad3a836f7eed860f300e68b33d4c0b39bd1f4 (patch) | |
tree | 1d079a4107f081212a11dde90ec489c49d675cb3 /lib | |
parent | 9a93f73983945a44d891013f728e407ee421287b (diff) | |
download | Nim-42dad3a836f7eed860f300e68b33d4c0b39bd1f4.tar.gz |
tables/sharedtables/intsets/etc: fix #13496, #13504, #13505; add lots of tests (#13498) [backport]
* fix #13496 handle tombstones * add test * more tests * fix #13504; add SharedTable tests * fix #https://github.com/nim-lang/Nim/issues/13505 intsets.missingOrExcl silently gave wrong results sometimes * add test for tintsets
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/collections/intsets.nim | 22 | ||||
-rw-r--r-- | lib/pure/collections/setimpl.nim | 6 | ||||
-rw-r--r-- | lib/pure/collections/sharedtables.nim | 5 | ||||
-rw-r--r-- | lib/pure/collections/tableimpl.nim | 22 | ||||
-rw-r--r-- | lib/pure/collections/tables.nim | 14 |
5 files changed, 44 insertions, 25 deletions
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 7ca379783..1967a0149 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -330,6 +330,15 @@ proc excl*(s: var IntSet, other: IntSet) = for item in other: excl(s, item) +proc len*(s: IntSet): int {.inline.} = + ## Returns the number of elements in `s`. + if s.elems < s.a.len: + result = s.elems + else: + result = 0 + for _ in s: + inc(result) + proc missingOrExcl*(s: var IntSet, key: int): bool = ## Excludes `key` in the set `s` and tells if `key` was already missing from `s`. ## @@ -348,9 +357,9 @@ proc missingOrExcl*(s: var IntSet, key: int): bool = assert a.missingOrExcl(5) == false assert a.missingOrExcl(5) == true - var count = s.elems + var count = s.len exclImpl(s, key) - result = count == s.elems + result = count == s.len proc clear*(result: var IntSet) = ## Clears the IntSet back to an empty state. @@ -514,15 +523,6 @@ proc disjoint*(s1, s2: IntSet): bool = return false return true -proc len*(s: IntSet): int {.inline.} = - ## Returns the number of elements in `s`. - if s.elems < s.a.len: - result = s.elems - else: - result = 0 - for _ in s: - inc(result) - proc card*(s: IntSet): int {.inline.} = ## Alias for `len() <#len,IntSet>`_. result = s.len() diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index f8950e354..f7a48ab91 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -38,7 +38,7 @@ proc enlarge[A](s: var HashSet[A]) = newSeq(n, len(s.data) * growthFactor) swap(s.data, n) # n is now old seq for i in countup(0, high(n)): - if isFilled(n[i].hcode): + if isFilledAndValid(n[i].hcode): var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode) rawInsert(s, s.data, n[i].key, n[i].hcode, j) @@ -112,7 +112,7 @@ proc enlarge[A](s: var OrderedSet[A]) = swap(s.data, n) while h >= 0: var nxt = n[h].next - if isFilled(n[h].hcode): + if isFilled(n[h].hcode): # should be isFilledAndValid once tombstones are used var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode) rawInsert(s, s.data, n[h].key, n[h].hcode, j) h = nxt @@ -130,7 +130,7 @@ proc exclImpl[A](s: var OrderedSet[A], key: A): bool {.inline.} = result = true while h >= 0: var nxt = n[h].next - if isFilled(n[h].hcode): + if isFilled(n[h].hcode): # should be isFilledAndValid once tombstones are used if n[h].hcode == hc and n[h].key == key: dec s.counter result = false diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 0fbbdb3eb..27ac5e84f 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -206,6 +206,11 @@ proc del*[A, B](t: var SharedTable[A, B], key: A) = withLock t: delImpl() +proc len*[A, B](t: var SharedTable[A, B]): int = + ## number of elements in `t` + withLock t: + result = t.counter + proc init*[A, B](t: var SharedTable[A, B], initialSize = 64) = ## creates a new hash table that is empty. ## diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index aabaeeeb3..d7facda72 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -107,13 +107,23 @@ template clearImpl() {.dirty.} = t.data[i].val = default(type(t.data[i].val)) t.counter = 0 +template ctAnd(a, b): bool = + # pending https://github.com/nim-lang/Nim/issues/13502 + when a: + when b: true + else: false + else: false + template initImpl(result: typed, size: int) = - assert isPowerOfTwo(size) - result.counter = 0 - newSeq(result.data, size) - when compiles(result.first): - result.first = -1 - result.last = -1 + when ctAnd(declared(SharedTable), type(result) is SharedTable): + init(result, size) + else: + assert isPowerOfTwo(size) + result.counter = 0 + newSeq(result.data, size) + when compiles(result.first): + result.first = -1 + result.last = -1 template insertImpl() = # for CountTable checkIfInitialized() diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 2e3adc6fb..131804a22 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -1118,7 +1118,7 @@ iterator pairs*[A, B](t: TableRef[A, B]): (A, B) = ## # value: [1, 5, 7, 9] let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1140,7 +1140,7 @@ iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1161,7 +1161,7 @@ iterator keys*[A, B](t: TableRef[A, B]): A = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].key assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1182,7 +1182,7 @@ iterator values*[A, B](t: TableRef[A, B]): B = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1203,7 +1203,7 @@ iterator mvalues*[A, B](t: TableRef[A, B]): var B = let L = len(t) for h in 0 .. high(t.data): - if isFilled(t.data[h].hcode): + if isFilledAndValid(t.data[h].hcode): yield t.data[h].val assert(len(t) == L, "the length of the table changed while iterating over it") @@ -1282,6 +1282,10 @@ template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} = var h = t.first while h >= 0: var nxt = t.data[h].next + # For OrderedTable/OrderedTableRef, isFilled is ok because `del` is O(n) + # and doesn't create tombsones, but if it does start using tombstones, + # carefully replace `isFilled` by `isFilledAndValid` as appropriate for these + # table types only, ditto with `OrderedSet`. if isFilled(t.data[h].hcode): yieldStmt h = nxt |