1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
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'''
cmd: '''nim c --newruntime $file'''
"""
{.this: self.}
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(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 >= cap:
cap = max((cap * 3) shr 1, newLen)
if cap > 0:
if data == nil: inc allocCount
data = cast[type(data)](realloc(data, cap + 1))
proc add*(self: var mystring; y: mystring) =
let newLen = len + y.len
ensure(self, newLen)
copyMem(addr data[len], y.data, y.data.len + 1)
len = newLen
proc create*(lit: string): mystring =
let newLen = lit.len
ensure(result, newLen)
copyMem(addr result.data[result.len], unsafeAddr 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
|