diff options
-rw-r--r-- | compiler/semasgn.nim | 13 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 5 | ||||
-rw-r--r-- | tests/destructor/tcustomseqs.nim | 126 |
3 files changed, 133 insertions, 11 deletions
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 19d31ec73..cb4728097 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -318,16 +318,9 @@ proc overloadedAsgn(c: PContext; dest, src: PNode): PNode = proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = ## In the semantic pass this is called in strategic places ## to ensure we lift assignment, destructors and moves properly. - ## Since this is done in the sem* routines generics already have - ## been resolved for us and do not complicate the logic any further. - ## We have to ensure that the 'tfHasDesctructor' flags bubbles up - ## in the generic instantiations though. ## The later 'destroyer' pass depends on it. if not newDestructors or not hasDestructor(typ): return # we generate the destructor first so that other operators can depend on it: - if typ.destructor == nil: - liftBody(c, typ, attachedDestructor, info) - if typ.assignment == nil: - liftBody(c, typ, attachedAsgn, info) - if typ.sink == nil: - liftBody(c, typ, attachedSink, info) + if typ.destructor == nil: liftBody(c, typ, attachedDestructor, info) + if typ.assignment == nil: liftBody(c, typ, attachedAsgn, info) + if typ.sink == nil: liftBody(c, typ, attachedSink, info) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 5d0f0177c..3b99ea562 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -363,7 +363,10 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # '=' needs to be instantiated for generics when the type is constructed: newbody.field = cl.c.instTypeBoundOp(cl.c, opr, result, cl.info, attachedAsgn, 1) - if not newDestructors: typeBound(assignment) + if newDestructors: + typeBound(destructor) + typeBound(sink) + typeBound(assignment) let methods = skipTypes(bbody, abstractPtrs).methods for col, meth in items(methods): # we instantiate the known methods belonging to that type, this causes diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim new file mode 100644 index 000000000..45059d7de --- /dev/null +++ b/tests/destructor/tcustomseqs.nim @@ -0,0 +1,126 @@ +discard """ + output: '''1 +2 +3 +4 +5 +6 +after 1 1''' + 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 seq[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 seq[T]): ptr T = + if x.len >= x.cap: resize(x) + result = addr(x.data[x.len]) + inc x.len + +template add*[T](x: var seq[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 = + let s = createSeq(1, 2, 3, 4, 5, 6) + for i in 0 ..< s.len: + echo s[i] + +main() +echo "after ", allocCount, " ", deallocCount |