diff options
Diffstat (limited to 'tests/destructor')
-rw-r--r-- | tests/destructor/tatomicptrs.nim | 101 | ||||
-rw-r--r-- | tests/destructor/tcustomseqs.nim | 143 | ||||
-rw-r--r-- | tests/destructor/tcustomstrings.nim | 29 | ||||
-rw-r--r-- | tests/destructor/tdestructor.nim | 6 | ||||
-rw-r--r-- | tests/destructor/tdestructor2.nim | 27 | ||||
-rw-r--r-- | tests/destructor/tdestructor3.nim | 8 | ||||
-rw-r--r-- | tests/destructor/tmove_objconstr.nim | 59 | ||||
-rw-r--r-- | tests/destructor/topttree.nim | 104 |
8 files changed, 430 insertions, 47 deletions
diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim new file mode 100644 index 000000000..d20596415 --- /dev/null +++ b/tests/destructor/tatomicptrs.nim @@ -0,0 +1,101 @@ +discard """ + output: '''allocating +allocating +allocating +55 +60 +99 +deallocating +deallocating +deallocating +''' + cmd: '''nim c --newruntime $file''' +""" + +type + SharedPtr*[T] = object + x: ptr T + +#proc isNil[T](s: SharedPtr[T]): bool {.inline.} = s.x.isNil + +template incRef(x) = + atomicInc(x.refcount) + +template decRef(x): untyped = atomicDec(x.refcount) + +proc makeShared*[T](x: T): SharedPtr[T] = + # XXX could benefit from 'sink' parameter. + # XXX could benefit from a macro that generates it. + result = cast[SharedPtr[T]](allocShared(sizeof(x))) + result.x[] = x + echo "allocating" + +proc `=destroy`*[T](dest: var SharedPtr[T]) = + var s = dest.x + if s != nil and decRef(s) == 0: + `=destroy`(s[]) + deallocShared(s) + echo "deallocating" + dest.x = nil + +proc `=`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) = + var s = src.x + if s != nil: incRef(s) + #atomicSwap(dest, s) + # XXX use an atomic store here: + swap(dest.x, s) + if s != nil and decRef(s) == 0: + `=destroy`(s[]) + deallocShared(s) + echo "deallocating" + +proc `=sink`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) = + ## XXX make this an atomic store: + if dest.x != src.x: + let s = dest.x + if s != nil: + `=destroy`(s[]) + deallocShared(s) + echo "deallocating" + dest.x = src.x + +template `.`*[T](s: SharedPtr[T]; field: untyped): untyped = + s.x.field + +template `.=`*[T](s: SharedPtr[T]; field, value: untyped) = + s.x.field = value + +from macros import unpackVarargs + +template `.()`*[T](s: SharedPtr[T]; field: untyped, args: varargs[untyped]): untyped = + unpackVarargs(s.x.field, args) + + +type + Tree = SharedPtr[TreeObj] + TreeObj = object + refcount: int + le, ri: Tree + data: int + +proc takesTree(a: Tree) = + if not a.isNil: + takesTree(a.le) + echo a.data + takesTree(a.ri) + +proc createTree(data: int): Tree = + result = makeShared(TreeObj(refcount: 1, data: data)) + +proc createTree(data: int; le, ri: Tree): Tree = + result = makeShared(TreeObj(refcount: 1, le: le, ri: ri, data: data)) + + +proc main = + let le = createTree(55) + let ri = createTree(99) + let t = createTree(60, le, ri) + takesTree(t) + +main() + diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim new file mode 100644 index 000000000..97d7c07b6 --- /dev/null +++ b/tests/destructor/tcustomseqs.nim @@ -0,0 +1,143 @@ +discard """ + output: '''1 +2 +3 +4 +5 +6 +89 +90 +90 +0 0 1 +0 1 2 +0 2 3 +1 0 4 +1 1 5 +1 2 6 +1 3 7 +after 6 6''' + cmd: '''nim c --newruntime $file''' +""" + +import typetraits + +type + myseq*[T] = object + len, cap: int + data: ptr UncheckedArray[T] + +# XXX make code memory safe for overflows in '*' +var + allocCount, deallocCount: int + +proc `=destroy`*[T](x: var myseq[T]) = + if x.data != nil: + when not supportsCopyMem(T): + for i in 0..<x.len: `=destroy`(x[i]) + dealloc(x.data) + inc deallocCount + x.data = nil + x.len = 0 + x.cap = 0 + +proc `=`*[T](a: var myseq[T]; b: myseq[T]) = + if a.data == b.data: return + if a.data != nil: + dealloc(a.data) + inc deallocCount + a.data = nil + a.len = b.len + a.cap = b.cap + if b.data != nil: + a.data = cast[type(a.data)](alloc(a.cap * sizeof(T))) + inc allocCount + when supportsCopyMem(T): + copyMem(a.data, b.data, a.cap * sizeof(T)) + else: + for i in 0..<a.len: + a.data[i] = b.data[i] + +proc `=sink`*[T](a: var myseq[T]; b: myseq[T]) = + if a.data != nil and a.data != b.data: + dealloc(a.data) + inc deallocCount + a.len = b.len + a.cap = b.cap + a.data = b.data + +proc resize[T](s: var myseq[T]) = + if s.cap == 0: s.cap = 8 + else: s.cap = (s.cap * 3) shr 1 + if s.data == nil: inc allocCount + s.data = cast[type(s.data)](realloc(s.data, s.cap * sizeof(T))) + +proc reserveSlot[T](x: var myseq[T]): ptr T = + if x.len >= x.cap: resize(x) + result = addr(x.data[x.len]) + inc x.len + +template add*[T](x: var myseq[T]; y: T) = + reserveSlot(x)[] = y + +proc shrink*[T](x: var myseq[T]; newLen: int) = + assert newLen <= x.len + assert newLen >= 0 + when not supportsCopyMem(T): + for i in countdown(x.len - 1, newLen - 1): + `=destroy`(x.data[i]) + x.len = newLen + +proc grow*[T](x: var myseq[T]; newLen: int; value: T) = + if newLen <= x.len: return + assert newLen >= 0 + if x.cap == 0: x.cap = newLen + else: x.cap = max(newLen, (x.cap * 3) shr 1) + if x.data == nil: inc allocCount + x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T))) + for i in x.len..<newLen: + x.data[i] = value + x.len = newLen + +template default[T](t: typedesc[T]): T = + var v: T + v + +proc setLen*[T](x: var myseq[T]; newLen: int) {.deprecated.} = + if newlen < x.len: shrink(x, newLen) + else: grow(x, newLen, default(T)) + +template `[]`*[T](x: myseq[T]; i: Natural): T = + assert i < x.len + x.data[i] + +template `[]=`*[T](x: myseq[T]; i: Natural; y: T) = + assert i < x.len + x.data[i] = y + +proc createSeq*[T](elems: varargs[T]): myseq[T] = + result.cap = elems.len + result.len = elems.len + result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) + inc allocCount + when supportsCopyMem(T): + copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) + else: + for i in 0..<result.len: + result.data[i] = elems[i] + +proc len*[T](x: myseq[T]): int {.inline.} = x.len + +proc main = + var s = createSeq(1, 2, 3, 4, 5, 6) + s.add 89 + s.grow s.len + 2, 90 + for i in 0 ..< s.len: + echo s[i] + + var nested = createSeq(createSeq(1, 2, 3), createSeq(4, 5, 6, 7)) + for i in 0 ..< nested.len: + for j in 0 ..< nested[i].len: + echo i, " ", j, " ", nested[i][j] + +main() +echo "after ", allocCount, " ", deallocCount diff --git a/tests/destructor/tcustomstrings.nim b/tests/destructor/tcustomstrings.nim index 2250d4772..1a78df20b 100644 --- a/tests/destructor/tcustomstrings.nim +++ b/tests/destructor/tcustomstrings.nim @@ -4,27 +4,27 @@ foo bar to appendmore here foo bar to appendmore here foo bar to appendmore here foo bar to appendmore here -after 16 16''' +after 20 20''' cmd: '''nim c --newruntime $file''' """ +{.this: self.} + type mystring = object len, cap: int data: ptr UncheckedArray[char] -{.this: self.} - var allocCount, deallocCount: int -proc `=destroy`*(self: var mystring) = - if data != nil: - dealloc(data) +proc `=destroy`*(s: var mystring) = + if s.data != nil: + dealloc(s.data) inc deallocCount - data = nil - len = 0 - cap = 0 + s.data = nil + s.len = 0 + s.cap = 0 proc `=sink`*(a: var mystring, b: mystring) = # we hope this is optimized away for not yet alive objects: @@ -48,10 +48,10 @@ proc `=`*(a: var mystring; b: mystring) = copyMem(a.data, b.data, a.cap+1) proc resize(self: var mystring) = - if cap == 0: cap = 8 - else: cap = (cap * 3) shr 1 - if data == nil: inc allocCount - data = cast[type(data)](realloc(data, cap + 1)) + if self.cap == 0: self.cap = 8 + else: self.cap = (self.cap * 3) shr 1 + if self.data == nil: inc allocCount + self.data = cast[type(data)](realloc(self.data, self.cap + 1)) proc add*(self: var mystring; c: char) = if self.len >= self.cap: resize(self) @@ -92,5 +92,8 @@ proc main(n: int) = a.add c echo cstring(a.data) + var x: array[4, mystring] + for i in 0..high(x): x[i] = create"added to array" + main(1000) echo "after ", allocCount, " ", deallocCount diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index 639dba941..c9f1caf2d 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -20,10 +20,10 @@ myobj destroyed ---- myobj destroyed ''' + cmd: '''nim c --newruntime $file''' + disabled: "true" """ -{.experimental.} - type TMyObj = object x, y: int @@ -61,7 +61,7 @@ proc `=destroy`(o: var TMyObj) = if o.p != nil: dealloc o.p echo "myobj destroyed" -proc `=destroy`(o: var TMyGeneric1) = +proc `=destroy`(o: var TMyGeneric1[int]) = echo "mygeneric1 destroyed" proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) = diff --git a/tests/destructor/tdestructor2.nim b/tests/destructor/tdestructor2.nim deleted file mode 100644 index 34fa466af..000000000 --- a/tests/destructor/tdestructor2.nim +++ /dev/null @@ -1,27 +0,0 @@ -discard """ - line: 23 - nimout: " usage of a type with a destructor in a non destructible context" -""" - -{.experimental.} - -type - TMyObj = object - x, y: int - p: pointer - -proc `=destroy`(o: var TMyObj) = - if o.p != nil: dealloc o.p - -proc open: TMyObj = - result = TMyObj(x: 1, y: 2, p: alloc(3)) - - -proc `$`(x: TMyObj): string = $x.y - -proc foo = - discard open() - -# XXX doesn't trigger this yet: -#echo open() - diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim index d0c53c7bd..3e177d3cd 100644 --- a/tests/destructor/tdestructor3.nim +++ b/tests/destructor/tdestructor3.nim @@ -2,14 +2,14 @@ discard """ output: '''assign destroy destroy -destroy Foo: 5 5 -destroy Foo: 123 -123''' +123 +destroy Foo: 5 +destroy Foo: 123''' + cmd: '''nim c --newruntime $file''' """ # bug #2821 -{.experimental.} type T = object diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim new file mode 100644 index 000000000..8aa12ed05 --- /dev/null +++ b/tests/destructor/tmove_objconstr.nim @@ -0,0 +1,59 @@ + +discard """ +output: '''test created +test destroyed 0 +1 +2 +3 +4 +Pony is dying!''' + cmd: '''nim c --newruntime $file''' +""" + +# bug #4214 +type + Data = object + data: string + rc: int + +proc `=destroy`(d: var Data) = + dec d.rc + echo d.data, " destroyed ", d.rc + +proc `=`(dst: var Data, src: Data) = + echo src.data, " copied" + dst.data = src.data & " (copy)" + dec dst.rc + inc dst.rc + +proc initData(s: string): Data = + result = Data(data: s, rc: 1) + echo s, " created" + +proc pointlessWrapper(s: string): Data = + result = initData(s) + +proc main = + var x = pointlessWrapper"test" + +when isMainModule: + main() + +# bug #985 + +type + Pony = object + name: string + +proc `=destroy`(o: var Pony) = + echo "Pony is dying!" + +proc getPony: Pony = + result.name = "Sparkles" + +iterator items(p: Pony): int = + for i in 1..4: + yield i + +for x in getPony(): + echo x diff --git a/tests/destructor/topttree.nim b/tests/destructor/topttree.nim new file mode 100644 index 000000000..924644392 --- /dev/null +++ b/tests/destructor/topttree.nim @@ -0,0 +1,104 @@ +discard """ + output: '''10.0 +60.0 +90.0 +120.0 +10.0 +60.0 +90.0 +120.0 +8 8''' + cmd: '''nim c --newruntime $file''' +""" + +import typetraits + +type + opt[T] = object + data: ptr T + +var + allocCount, deallocCount: int + +proc `=destroy`*[T](x: var opt[T]) = + if x.data != nil: + when not supportsCopyMem(T): + `=destroy`(x.data[]) + dealloc(x.data) + inc deallocCount + x.data = nil + +proc `=`*[T](a: var opt[T]; b: opt[T]) = + if a.data == b.data: return + if a.data != nil: + dealloc(a.data) + inc deallocCount + a.data = nil + if b.data != nil: + a.data = cast[type(a.data)](alloc(sizeof(T))) + inc allocCount + when supportsCopyMem(T): + copyMem(a.data, b.data, sizeof(T)) + else: + a.data[] = b.data[] + +proc `=sink`*[T](a: var opt[T]; b: opt[T]) = + if a.data != nil and a.data != b.data: + dealloc(a.data) + inc deallocCount + a.data = b.data + +proc createOpt*[T](x: T): opt[T] = + result.data = cast[type(result.data)](alloc(sizeof(T))) + inc allocCount + result.data[] = x + +template `[]`[T](x: opt[T]): T = + assert x.p != nil, "attempt to read from moved/destroyed value" + x.p[] + +template `?=`[T](it: untyped; x: opt[T]): bool = + template it: untyped {.inject.} = x.data[] + if x.data != nil: + true + else: + false + +type + Tree = object + data: float + le, ri: opt[Tree] + +proc createTree(data: float): Tree = + result.data = data + +proc insert(t: var opt[Tree]; newVal: float) = + #if it ?= t: + if t.data != nil: + if newVal < t.data[].data: + insert(t.data[].le, newVal) + elif t.data[].data < newVal: + insert(t.data[].ri, newVal) + else: + discard "already in the tree" + else: + t = createOpt(Tree(data: newVal)) + +proc write(t: opt[Tree]) = + if it ?= t: + write(it.le) + write stdout, it.data, "\n" + write(it.ri) + +proc main = + var t: opt[Tree] + insert t, 60.0 + insert t, 90.0 + insert t, 10.0 + insert t, 120.0 + write t + let copy = t + write copy + +main() +echo allocCount, " ", deallocCount |