diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-07-11 16:39:16 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-07-11 16:39:16 +0200 |
commit | 5b59852406e3d4a494186dddf9a5702062901668 (patch) | |
tree | 8ee1df69d4b5d47ca4154d90c54201b19e43af91 /lib/core | |
parent | 16d8fab3101a8dcec846d1208de40c2c10db0160 (diff) | |
download | Nim-5b59852406e3d4a494186dddf9a5702062901668.tar.gz |
system.substr is not implemented with compilerProcs anymore
Diffstat (limited to 'lib/core')
-rw-r--r-- | lib/core/allocators.nim | 40 | ||||
-rw-r--r-- | lib/core/strs.nim | 132 |
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 |