summary refs log tree commit diff stats
path: root/lib/core
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2018-07-11 16:39:16 +0200
committerAndreas Rumpf <rumpf_a@web.de>2018-07-11 16:39:16 +0200
commit5b59852406e3d4a494186dddf9a5702062901668 (patch)
tree8ee1df69d4b5d47ca4154d90c54201b19e43af91 /lib/core
parent16d8fab3101a8dcec846d1208de40c2c10db0160 (diff)
downloadNim-5b59852406e3d4a494186dddf9a5702062901668.tar.gz
system.substr is not implemented with compilerProcs anymore
Diffstat (limited to 'lib/core')
-rw-r--r--lib/core/allocators.nim40
-rw-r--r--lib/core/strs.nim132
2 files changed, 121 insertions, 51 deletions
diff --git a/lib/core/allocators.nim b/lib/core/allocators.nim
index 62f5e9756..74a8d3753 100644
--- a/lib/core/allocators.nim
+++ b/lib/core/allocators.nim
@@ -8,28 +8,40 @@
 #
 
 type
+  AllocatorFlag* {.pure.} = enum  ## flags describing the properties of the allocator
+    ThreadLocal ## the allocator is thread local only.
+    ZerosMem    ## the allocator always zeros the memory on an allocation
   Allocator* = ptr object {.inheritable.}
     alloc*: proc (a: Allocator; size: int; alignment: int = 8): pointer {.nimcall.}
     dealloc*: proc (a: Allocator; p: pointer; size: int) {.nimcall.}
     realloc*: proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall.}
+    flags*: set[AllocatorFlag]
 
 var
-  currentAllocator {.threadvar.}: Allocator
+  localAllocator {.threadvar.}: Allocator
+  sharedAllocator: Allocator
 
-proc getCurrentAllocator*(): Allocator =
-  result = currentAllocator
+proc getLocalAllocator*(): Allocator =
+  result = localAllocator
 
-proc setCurrentAllocator*(a: Allocator) =
-  currentAllocator = a
+proc setLocalAllocator*(a: Allocator) =
+  localAllocator = a
 
-proc alloc*(size: int; alignment: int = 8): pointer =
-  let a = getCurrentAllocator()
-  result = a.alloc(a, size, alignment)
+proc getSharedAllocator*(): Allocator =
+  result = sharedAllocator
 
-proc dealloc*(p: pointer; size: int) =
-  let a = getCurrentAllocator()
-  a.dealloc(a, p, size)
+proc setSharedAllocator*(a: Allocator) =
+  sharedAllocator = a
 
-proc realloc*(p: pointer; oldSize, newSize: int): pointer =
-  let a = getCurrentAllocator()
-  result = a.realloc(a, p, oldSize, newSize)
+when false:
+  proc alloc*(size: int; alignment: int = 8): pointer =
+    let a = getCurrentAllocator()
+    result = a.alloc(a, size, alignment)
+
+  proc dealloc*(p: pointer; size: int) =
+    let a = getCurrentAllocator()
+    a.dealloc(a, p, size)
+
+  proc realloc*(p: pointer; oldSize, newSize: int): pointer =
+    let a = getCurrentAllocator()
+    result = a.realloc(a, p, oldSize, newSize)
diff --git a/lib/core/strs.nim b/lib/core/strs.nim
index ff38aef1d..1ef4f09de 100644
--- a/lib/core/strs.nim
+++ b/lib/core/strs.nim
@@ -7,54 +7,114 @@
 #    distribution, for details about the copyright.
 #
 
-## Default string implementation used by Nim's core.
+## Default new string implementation used by Nim's core.
+
+when false:
+  # these are to be implemented or changed in the code generator.
+
+  #proc rawNewStringNoInit(space: int): NimString {.compilerProc.}
+  # seems to be unused.
+  proc rawNewString(space: int): NimString {.compilerProc.}
+  proc mnewString(len: int): NimString {.compilerProc.}
+  proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.}
+  proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.}
+  proc copyStr(s: NimString, start: int): NimString {.compilerProc.}
+  proc toNimStr(str: cstring, len: int): NimString {.compilerProc.}
+  proc cstrToNimstr(str: cstring): NimString {.compilerRtl.}
+  proc copyString(src: NimString): NimString {.compilerRtl.}
+  proc copyStringRC1(src: NimString): NimString {.compilerRtl.}
+  proc copyDeepString(src: NimString): NimString {.inline.}
+  proc addChar(s: NimString, c: char): NimString
+  proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.}
+  proc appendString(dest, src: NimString) {.compilerproc, inline.}
+  proc appendChar(dest: NimString, c: char) {.compilerproc, inline.}
+  proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.}
+  # ----------------- sequences ----------------------------------------------
+
+  proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} =
+  proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
+      compilerRtl.}
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
 
 import allocators
 
 type
-  string {.core, exportc: "NimStringV2".} = object
-    len, cap: int
-    data: ptr UncheckedArray[char]
+  StrContent = object
+    cap: int
+    region: Allocator
+    data: UncheckedArray[char]
+
+  NimString {.core.} = object
+    len: int
+    p: ptr StrContent ## invariant. Never nil
 
 const nimStrVersion {.core.} = 2
 
-template frees(s) = dealloc(s.data, s.cap + 1)
+template isLiteral(s): bool = s.len == 0 or s.p.region == nil
+
+template contentSize(cap): int = cap + 1 + sizeof(int) + sizeof(Allocator)
+
+template frees(s) =
+  if not isLiteral(s):
+    s.p.region.dealloc(s.p, contentSize(s.p.cap))
+
+proc `=destroy`(s: var NimString) =
+  frees(s)
+  s.len = 0
 
-proc `=destroy`(s: var string) =
-  if s.data != nil:
-    frees(s)
-    s.data = nil
-    s.len = 0
-    s.cap = 0
+template lose(a) =
+  frees(a)
 
-proc `=sink`(a: var string, b: string) =
+proc `=sink`(a: var NimString, b: NimString) =
   # we hope this is optimized away for not yet alive objects:
-  if a.data != nil and a.data != b.data:
-    frees(a)
+  if unlikely(a.p == b.p): return
+  lose(a)
   a.len = b.len
-  a.cap = b.cap
-  a.data = b.data
+  a.p = b.p
 
-proc `=`(a: var string; b: string) =
-  if a.data != nil and a.data != b.data:
-    frees(a)
-    a.data = nil
+proc `=`(a: var NimString; b: NimString) =
+  if unlikely(a.p == b.p): return
+  lose(a)
   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'
+  if isLiteral(b):
+    # we can shallow copy literals:
+    a.p = b.p
+  else:
+    let region = if a.p.region != nil: a.p.region else: getLocalAllocator()
+    # we have to allocate the 'cap' here, consider
+    # 'let y = newStringOfCap(); var x = y'
+    # on the other hand... These get turned into moves now.
+    a.p = cast[ptr StrContent](region.alloc(contentSize(b.len)))
+    a.p.region = region
+    a.p.cap = b.len
+    copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
+
+proc resize(old: int): int {.inline.} =
+  if old <= 0: result = 4
+  elif old < 65536: result = old * 2
+  else: result = old * 3 div 2 # for large arrays * 3/2 is better
+
+proc prepareAdd(s: var NimString; addlen: int) =
+  if isLiteral(s):
+    let oldP = s.p
+    # can't mutate a literal, so we need a fresh copy here:
+    let region = getLocalAllocator()
+    s.p = cast[ptr StrContent](region.alloc(contentSize(s.len + addlen)))
+    s.p.region = region
+    s.p.cap = s.len + addlen
+    if s.len > 0:
+      # we are about to append, so there is no need to copy the \0 terminator:
+      copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len)
+  elif s.len + addlen > s.p.cap:
+    let cap = max(s.len + addlen, resize(s.p.cap))
+    s.p = s.p.region.realloc(s.p, oldSize = contentSize(s.p.cap), newSize = contentSize(cap))
+    s.p.cap = cap
+
+proc nimAddCharV1(s: var NimString; c: char) {.compilerRtl.} =
+  prepareAdd(s, 1)
+  s.p.data[s.len] = c
+  s.p.data[s.len+1] = '\0'
   inc s.len
 
 proc ensure(s: var string; newLen: int) =
@@ -71,8 +131,6 @@ proc add*(s: var string; y: string) =
     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