summary refs log tree commit diff stats
path: root/lib/core/strs.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/core/strs.nim')
-rw-r--r--lib/core/strs.nim111
1 files changed, 111 insertions, 0 deletions
diff --git a/lib/core/strs.nim b/lib/core/strs.nim
new file mode 100644
index 000000000..1958f4974
--- /dev/null
+++ b/lib/core/strs.nim
@@ -0,0 +1,111 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Default string implementation used by Nim's core.
+
+import allocators
+
+type
+  string {.core.} = object
+    len, cap: int
+    data: ptr UncheckedArray[char]
+
+proc nimStringLiteral(x: cstring; len: int): string {.core.} =
+  string(len: len, cap: len, data: x)
+
+template frees(s) = dealloc(s.data, s.cap + 1)
+
+proc `=destroy`(s: var string) =
+  if s.data != nil:
+    frees(s)
+    s.data = nil
+    s.len = 0
+    s.cap = 0
+
+proc `=sink`(a: var string, b: string) =
+  # we hope this is optimized away for not yet alive objects:
+  if a.data != nil and a.data != b.data:
+    frees(a)
+  a.len = b.len
+  a.cap = b.cap
+  a.data = b.data
+
+proc `=`(a: var string; b: string) =
+  if a.data != nil and a.data != b.data:
+    frees(a)
+    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))
+    copyMem(a.data, b.data, a.cap+1)
+
+proc resize(s: var string) =
+  let old = s.cap
+  if old == 0: s.cap = 8
+  else: s.cap = (s.cap * 3) shr 1
+  s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1))
+
+proc add*(s: var string; c: char) =
+  if s.len >= s.cap: resize(s)
+  s.data[s.len] = c
+  s.data[s.len+1] = '\0'
+  inc s.len
+
+proc ensure(s: var string; newLen: int) =
+  let old = s.cap
+  if newLen >= old:
+    s.cap = max((old * 3) shr 1, newLen)
+    if s.cap > 0:
+      s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1))
+
+proc add*(s: var string; y: string) =
+  if y.len != 0:
+    let newLen = s.len + y.len
+    ensure(s, newLen)
+    copyMem(addr s.data[len], y.data, y.data.len + 1)
+    s.len = newLen
+
+proc len*(s: string): int {.inline.} = s.len
+
+proc newString*(len: int): string =
+  result.len = len
+  result.cap = len
+  if len > 0:
+    result.data = alloc0(len+1)
+
+converter toCString(x: string): cstring {.core.} =
+  if x.len == 0: cstring"" else: cast[cstring](x.data)
+
+proc newStringOfCap*(cap: int): string =
+  result.len = 0
+  result.cap = cap
+  if cap > 0:
+    result.data = alloc(cap+1)
+
+proc `&`*(a, b: string): string =
+  let sum = a.len + b.len
+  result = newStringOfCap(sum)
+  result.len = sum
+  copyMem(addr result.data[0], a.data, a.len)
+  copyMem(addr result.data[a.len], b.data, b.len)
+  if sum > 0:
+    result.data[sum] = '\0'
+
+proc concat(x: openArray[string]): string {.core.} =
+  ## used be the code generator to optimize 'x & y & z ...'
+  var sum = 0
+  for i in 0 ..< x.len: inc(sum, x[i].len)
+  result = newStringOfCap(sum)
+  sum = 0
+  for i in 0 ..< x.len:
+    let L = x[i].len
+    copyMem(addr result.data[sum], x[i].data, L)
+    inc(sum, L)
+