summary refs log tree commit diff stats
path: root/tests/destructor
diff options
context:
space:
mode:
Diffstat (limited to 'tests/destructor')
-rw-r--r--tests/destructor/tatomicptrs.nim101
-rw-r--r--tests/destructor/tcustomseqs.nim143
-rw-r--r--tests/destructor/tcustomstrings.nim29
-rw-r--r--tests/destructor/tdestructor.nim6
-rw-r--r--tests/destructor/tdestructor2.nim27
-rw-r--r--tests/destructor/tdestructor3.nim8
-rw-r--r--tests/destructor/tmove_objconstr.nim59
-rw-r--r--tests/destructor/topttree.nim104
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