summary refs log tree commit diff stats
path: root/tests/destructor/tcustomstrings.nim
diff options
context:
space:
mode:
Diffstat (limited to 'tests/destructor/tcustomstrings.nim')
-rw-r--r--tests/destructor/tcustomstrings.nim97
1 files changed, 97 insertions, 0 deletions
diff --git a/tests/destructor/tcustomstrings.nim b/tests/destructor/tcustomstrings.nim
new file mode 100644
index 000000000..31891856b
--- /dev/null
+++ b/tests/destructor/tcustomstrings.nim
@@ -0,0 +1,97 @@
+discard """
+  output: '''foo bar to appendmore here
+foo bar to appendmore here
+foo bar to appendmore here
+foo bar to appendmore here
+foo bar to appendmore here
+after 20 20'''
+joinable: false
+"""
+
+type
+  mystring = object
+    len, cap: int
+    data: ptr UncheckedArray[char]
+
+var
+  allocCount, deallocCount: int
+
+proc `=destroy`*(s: var mystring) =
+  if s.data != nil:
+    dealloc(s.data)
+    inc deallocCount
+    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:
+  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 `=`*(a: var mystring; b: mystring) =
+  if a.data != nil and a.data != b.data:
+    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 + 1))
+    inc allocCount
+    copyMem(a.data, b.data, a.cap+1)
+
+proc resize(self: var mystring) =
+  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(self.data)](realloc(self.data, self.cap + 1))
+
+proc add*(self: var mystring; c: char) =
+  if self.len >= self.cap: resize(self)
+  self.data[self.len] = c
+  self.data[self.len+1] = '\0'
+  inc self.len
+
+proc ensure(self: var mystring; newLen: int) =
+  if newLen >= self.cap:
+    self.cap = max((self.cap * 3) shr 1, newLen)
+    if self.cap > 0:
+      if self.data == nil: inc allocCount
+      self.data = cast[type(self.data)](realloc(self.data, self.cap + 1))
+
+proc add*(self: var mystring; y: mystring) =
+  let newLen = self.len + y.len
+  ensure(self, newLen)
+  copyMem(addr self.data[self.len], y.data, y.data.len + 1)
+  self.len = newLen
+
+proc create*(lit: string): mystring =
+  let newLen = lit.len
+  ensure(result, newLen)
+  copyMem(addr result.data[result.len], addr lit[0], newLen + 1)
+  result.len = newLen
+
+proc `&`*(a, b: mystring): mystring =
+  result = a
+  result.add b
+
+proc main(n: int) =
+  var a: mystring
+  let b = create" to append"
+  for i in 0..<n:
+    if i > 4: break
+    a = create"foo bar"
+    let c = b & create"more here"
+    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