Use more Natural and Positive numbers in proc parameters

- Didn't go through all modules, only the main ones I thought of
- Building the compiler and tests still work
This commit is contained in:
def 2015-04-06 01:51:28 +02:00
commit 22b4e4c2f2
10 changed files with 1196 additions and 1196 deletions

View file

@ -24,7 +24,7 @@ proc `*`*(x: int, order: SortOrder): int {.inline.} =
var y = order.ord - 1 var y = order.ord - 1
result = (x xor y) - y result = (x xor y) - y
proc reverse*[T](a: var openArray[T], first, last: int) = proc reverse*[T](a: var openArray[T], first, last: Natural) =
## reverses the array ``a[first..last]``. ## reverses the array ``a[first..last]``.
var x = first var x = first
var y = last var y = last
@ -37,7 +37,7 @@ proc reverse*[T](a: var openArray[T]) =
## reverses the array `a`. ## reverses the array `a`.
reverse(a, 0, a.high) reverse(a, 0, a.high)
proc reversed*[T](a: openArray[T], first, last: int): seq[T] = proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
## returns the reverse of the array `a[first..last]`. ## returns the reverse of the array `a[first..last]`.
result = newSeq[T](last - first + 1) result = newSeq[T](last - first + 1)
var x = first var x = first

View file

@ -19,7 +19,7 @@ import
type type
BitScalar = int BitScalar = int
const const
InitIntSetSize = 8 # must be a power of two! InitIntSetSize = 8 # must be a power of two!
TrunkShift = 9 TrunkShift = 9
BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
@ -31,11 +31,11 @@ const
type type
PTrunk = ref TTrunk PTrunk = ref TTrunk
TTrunk {.final.} = object TTrunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0 key: int # start address at bit 0
bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
TTrunkSeq = seq[PTrunk] TTrunkSeq = seq[PTrunk]
IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
counter, max: int counter, max: int
@ -44,42 +44,42 @@ type
{.deprecated: [TIntSet: IntSet].} {.deprecated: [TIntSet: IntSet].}
proc mustRehash(length, counter: int): bool {.inline.} = proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter) assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4) result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} = proc nextTry(h, maxHash: THash): THash {.inline.} =
result = ((5 * h) + 1) and maxHash result = ((5 * h) + 1) and maxHash
proc intSetGet(t: IntSet, key: int): PTrunk = proc intSetGet(t: IntSet, key: int): PTrunk =
var h = key and t.max var h = key and t.max
while t.data[h] != nil: while t.data[h] != nil:
if t.data[h].key == key: if t.data[h].key == key:
return t.data[h] return t.data[h]
h = nextTry(h, t.max) h = nextTry(h, t.max)
result = nil result = nil
proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) = proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
var h = desc.key and t.max var h = desc.key and t.max
while data[h] != nil: while data[h] != nil:
assert(data[h] != desc) assert(data[h] != desc)
h = nextTry(h, t.max) h = nextTry(h, t.max)
assert(data[h] == nil) assert(data[h] == nil)
data[h] = desc data[h] = desc
proc intSetEnlarge(t: var IntSet) = proc intSetEnlarge(t: var IntSet) =
var n: TTrunkSeq var n: TTrunkSeq
var oldMax = t.max var oldMax = t.max
t.max = ((t.max + 1) * 2) - 1 t.max = ((t.max + 1) * 2) - 1
newSeq(n, t.max + 1) newSeq(n, t.max + 1)
for i in countup(0, oldMax): for i in countup(0, oldMax):
if t.data[i] != nil: intSetRawInsert(t, n, t.data[i]) if t.data[i] != nil: intSetRawInsert(t, n, t.data[i])
swap(t.data, n) swap(t.data, n)
proc intSetPut(t: var IntSet, key: int): PTrunk = proc intSetPut(t: var IntSet, key: int): PTrunk =
var h = key and t.max var h = key and t.max
while t.data[h] != nil: while t.data[h] != nil:
if t.data[h].key == key: if t.data[h].key == key:
return t.data[h] return t.data[h]
h = nextTry(h, t.max) h = nextTry(h, t.max)
if mustRehash(t.max + 1, t.counter): intSetEnlarge(t) if mustRehash(t.max + 1, t.counter): intSetEnlarge(t)
@ -94,43 +94,43 @@ proc intSetPut(t: var IntSet, key: int): PTrunk =
t.data[h] = result t.data[h] = result
proc contains*(s: IntSet, key: int): bool = proc contains*(s: IntSet, key: int): bool =
## returns true iff `key` is in `s`. ## returns true iff `key` is in `s`.
var t = intSetGet(s, `shr`(key, TrunkShift)) var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0 result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
else: else:
result = false result = false
proc incl*(s: var IntSet, key: int) = proc incl*(s: var IntSet, key: int) =
## includes an element `key` in `s`. ## includes an element `key` in `s`.
var t = intSetPut(s, `shr`(key, TrunkShift)) var t = intSetPut(s, `shr`(key, TrunkShift))
var u = key and TrunkMask var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask) `shl`(1, u and IntMask)
proc excl*(s: var IntSet, key: int) = proc excl*(s: var IntSet, key: int) =
## excludes `key` from the set `s`. ## excludes `key` from the set `s`.
var t = intSetGet(s, `shr`(key, TrunkShift)) var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
not `shl`(1, u and IntMask) not `shl`(1, u and IntMask)
proc containsOrIncl*(s: var IntSet, key: int): bool = proc containsOrIncl*(s: var IntSet, key: int): bool =
## returns true if `s` contains `key`, otherwise `key` is included in `s` ## returns true if `s` contains `key`, otherwise `key` is included in `s`
## and false is returned. ## and false is returned.
var t = intSetGet(s, `shr`(key, TrunkShift)) var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0 result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
if not result: if not result:
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask) `shl`(1, u and IntMask)
else: else:
incl(s, key) incl(s, key)
result = false result = false
proc initIntSet*: IntSet = proc initIntSet*: IntSet =
## creates a new int set that is empty. ## creates a new int set that is empty.
newSeq(result.data, InitIntSetSize) newSeq(result.data, InitIntSetSize)
@ -140,14 +140,14 @@ proc initIntSet*: IntSet =
proc assign*(dest: var IntSet, src: IntSet) = proc assign*(dest: var IntSet, src: IntSet) =
## copies `src` to `dest`. `dest` does not need to be initialized by ## copies `src` to `dest`. `dest` does not need to be initialized by
## `initIntSet`. ## `initIntSet`.
dest.counter = src.counter dest.counter = src.counter
dest.max = src.max dest.max = src.max
newSeq(dest.data, src.data.len) newSeq(dest.data, src.data.len)
var it = src.head var it = src.head
while it != nil: while it != nil:
var h = it.key and dest.max var h = it.key and dest.max
while dest.data[h] != nil: h = nextTry(h, dest.max) while dest.data[h] != nil: h = nextTry(h, dest.max)
assert(dest.data[h] == nil) assert(dest.data[h] == nil)
@ -168,7 +168,7 @@ iterator items*(s: IntSet): int {.inline.} =
while r != nil: while r != nil:
var i = 0 var i = 0
while i <= high(r.bits): while i <= high(r.bits):
var w = r.bits[i] var w = r.bits[i]
# taking a copy of r.bits[i] here is correct, because # taking a copy of r.bits[i] here is correct, because
# modifying operations are not allowed during traversation # modifying operations are not allowed during traversation
var j = 0 var j = 0

View file

@ -114,7 +114,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter) assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4) result = (length * 2 < counter * 3) or (length - counter < 4)
proc rightSize*(count: int): int {.inline.} = proc rightSize*(count: Natural): int {.inline.} =
## Return the value of `initialSize` to support `count` items. ## Return the value of `initialSize` to support `count` items.
## ##
## If more items are expected to be added, simply add that ## If more items are expected to be added, simply add that

View file

@ -128,7 +128,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter) assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4) result = (length * 2 < counter * 3) or (length - counter < 4)
proc rightSize*(count: int): int {.inline.} = proc rightSize*(count: Natural): int {.inline.} =
## Return the value of `initialSize` to support `count` items. ## Return the value of `initialSize` to support `count` items.
## ##
## If more items are expected to be added, simply add that ## If more items are expected to be added, simply add that

View file

@ -386,7 +386,7 @@ proc split*(s: string, sep: string): seq[string] {.noSideEffect,
## `split iterator <#split.i,string,string>`_. ## `split iterator <#split.i,string,string>`_.
accumulateResult(split(s, sep)) accumulateResult(split(s, sep))
proc toHex*(x: BiggestInt, len: int): string {.noSideEffect, proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToHex".} = rtl, extern: "nsuToHex".} =
## Converts `x` to its hexadecimal representation. ## Converts `x` to its hexadecimal representation.
## ##
@ -403,7 +403,7 @@ proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
# handle negative overflow # handle negative overflow
if n == 0 and x < 0: n = -1 if n == 0 and x < 0: n = -1
proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect, proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
rtl, extern: "nsuIntToStr".} = rtl, extern: "nsuIntToStr".} =
## Converts `x` to its decimal representation. ## Converts `x` to its decimal representation.
## ##
@ -499,7 +499,7 @@ proc parseEnum*[T: enum](s: string, default: T): T =
return e return e
result = default result = default
proc repeat*(c: char, count: int): string {.noSideEffect, proc repeat*(c: char, count: Natural): string {.noSideEffect,
rtl, extern: "nsuRepeatChar".} = rtl, extern: "nsuRepeatChar".} =
## Returns a string of length `count` consisting only of ## Returns a string of length `count` consisting only of
## the character `c`. You can use this proc to left align strings. Example: ## the character `c`. You can use this proc to left align strings. Example:
@ -514,7 +514,7 @@ proc repeat*(c: char, count: int): string {.noSideEffect,
result = newString(count) result = newString(count)
for i in 0..count-1: result[i] = c for i in 0..count-1: result[i] = c
proc repeat*(s: string, n: int): string {.noSideEffect, proc repeat*(s: string, n: Natural): string {.noSideEffect,
rtl, extern: "nsuRepeatStr".} = rtl, extern: "nsuRepeatStr".} =
## Returns String `s` concatenated `n` times. Example: ## Returns String `s` concatenated `n` times. Example:
## ##
@ -523,7 +523,7 @@ proc repeat*(s: string, n: int): string {.noSideEffect,
result = newStringOfCap(n * s.len) result = newStringOfCap(n * s.len)
for i in 1..n: result.add(s) for i in 1..n: result.add(s)
template spaces*(n: int): string = repeat(' ',n) template spaces*(n: Natural): string = repeat(' ',n)
## Returns a String with `n` space characters. You can use this proc ## Returns a String with `n` space characters. You can use this proc
## to left align strings. Example: ## to left align strings. Example:
## ##
@ -535,15 +535,15 @@ template spaces*(n: int): string = repeat(' ',n)
## echo text1 & spaces(max(0, width - text1.len)) & "|" ## echo text1 & spaces(max(0, width - text1.len)) & "|"
## echo text2 & spaces(max(0, width - text2.len)) & "|" ## echo text2 & spaces(max(0, width - text2.len)) & "|"
proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count) proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} = repeat(c, count)
## deprecated: use repeat() or spaces() ## deprecated: use repeat() or spaces()
proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count) proc repeatStr*(count: Natural, s: string): string {.deprecated.} = repeat(s, count)
## deprecated: use repeat(string, count) or string.repeat(count) ## deprecated: use repeat(string, count) or string.repeat(count)
proc align*(s: string, count: int, padding = ' '): string {. proc align*(s: string, count: Natural, padding = ' '): string {.
noSideEffect, rtl, extern: "nsuAlignString".} = noSideEffect, rtl, extern: "nsuAlignString".} =
## Aligns a string `s` with `padding`, so that is of length `count`. ## Aligns a string `s` with `padding`, so that it is of length `count`.
## ##
## `padding` characters (by default spaces) are added before `s` resulting in ## `padding` characters (by default spaces) are added before `s` resulting in
## right alignment. If ``s.len >= count``, no spaces are added and `s` is ## right alignment. If ``s.len >= count``, no spaces are added and `s` is
@ -682,7 +682,7 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
inc(i) inc(i)
if suffix[i] == '\0': return true if suffix[i] == '\0': return true
proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect, proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
rtl, extern: "nsuContinuesWith".} = rtl, extern: "nsuContinuesWith".} =
## Returns true iff ``s`` continues with ``substr`` at position ``start``. ## Returns true iff ``s`` continues with ``substr`` at position ``start``.
## ##
@ -693,8 +693,8 @@ proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
if s[i+start] != substr[i]: return false if s[i+start] != substr[i]: return false
inc(i) inc(i)
proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect, proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
inline.} = {.noSideEffect, inline.} =
## Adds a separator to `dest` only if its length is bigger than `startLen`. ## Adds a separator to `dest` only if its length is bigger than `startLen`.
## ##
## A shorthand for: ## A shorthand for:
@ -784,7 +784,7 @@ proc findAux(s, sub: string, start: int, a: SkipTable): int =
inc(j, a[s[j+m]]) inc(j, a[s[j+m]])
return -1 return -1
proc find*(s, sub: string, start: int = 0): int {.noSideEffect, proc find*(s, sub: string, start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindStr".} = rtl, extern: "nsuFindStr".} =
## Searches for `sub` in `s` starting at position `start`. ## Searches for `sub` in `s` starting at position `start`.
## ##
@ -793,7 +793,7 @@ proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
preprocessSub(sub, a) preprocessSub(sub, a)
result = findAux(s, sub, start, a) result = findAux(s, sub, start, a)
proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect, proc find*(s: string, sub: char, start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindChar".} = rtl, extern: "nsuFindChar".} =
## Searches for `sub` in `s` starting at position `start`. ## Searches for `sub` in `s` starting at position `start`.
## ##
@ -802,7 +802,7 @@ proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
if sub == s[i]: return i if sub == s[i]: return i
return -1 return -1
proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect, proc find*(s: string, chars: set[char], start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindCharSet".} = rtl, extern: "nsuFindCharSet".} =
## Searches for `chars` in `s` starting at position `start`. ## Searches for `chars` in `s` starting at position `start`.
## ##
@ -933,7 +933,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
var j = findAux(s, sub, i, a) var j = findAux(s, sub, i, a)
if j < 0: break if j < 0: break
# word boundary? # word boundary?
if (j == 0 or s[j-1] notin wordChars) and if (j == 0 or s[j-1] notin wordChars) and
(j+sub.len >= s.len or s[j+sub.len] notin wordChars): (j+sub.len >= s.len or s[j+sub.len] notin wordChars):
add result, substr(s, i, j - 1) add result, substr(s, i, j - 1)
add result, by add result, by
@ -976,7 +976,7 @@ proc parseOctInt*(s: string): int {.noSideEffect,
of '\0': break of '\0': break
else: raise newException(ValueError, "invalid integer: " & s) else: raise newException(ValueError, "invalid integer: " & s)
proc toOct*(x: BiggestInt, len: int): string {.noSideEffect, proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToOct".} = rtl, extern: "nsuToOct".} =
## Converts `x` into its octal representation. ## Converts `x` into its octal representation.
## ##
@ -992,7 +992,7 @@ proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
shift = shift + 3 shift = shift + 3
mask = mask shl 3 mask = mask shl 3
proc toBin*(x: BiggestInt, len: int): string {.noSideEffect, proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToBin".} = rtl, extern: "nsuToBin".} =
## Converts `x` into its binary representation. ## Converts `x` into its binary representation.
## ##
@ -1221,7 +1221,7 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
## of significant digits to be printed. ## of significant digits to be printed.
## `precision`'s default value is the maximum number of meaningful digits ## `precision`'s default value is the maximum number of meaningful digits
## after the decimal point for Nim's ``biggestFloat`` type. ## after the decimal point for Nim's ``biggestFloat`` type.
## ##
## If ``precision == 0``, it tries to format it nicely. ## If ``precision == 0``, it tries to format it nicely.
const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e'] const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
var var
@ -1286,7 +1286,7 @@ proc findNormalized(x: string, inArray: openArray[string]): int =
return -1 return -1
proc invalidFormatString() {.noinline.} = proc invalidFormatString() {.noinline.} =
raise newException(ValueError, "invalid format string") raise newException(ValueError, "invalid format string")
proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {. proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
noSideEffect, rtl, extern: "nsuAddf".} = noSideEffect, rtl, extern: "nsuAddf".} =
@ -1416,7 +1416,7 @@ when isMainModule:
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
type MyEnum = enum enA, enB, enC, enuD, enE type MyEnum = enum enA, enB, enC, enuD, enE
doAssert parseEnum[MyEnum]("enu_D") == enuD doAssert parseEnum[MyEnum]("enu_D") == enuD

File diff suppressed because it is too large Load diff

View file

@ -173,12 +173,6 @@ proc new*(T: typedesc): ref T =
## reference to it as result value ## reference to it as result value
new(result) new(result)
proc unsafeNew*[T](a: var ref T, size: int) {.magic: "New", noSideEffect.}
## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. This is **unsafe** as it allocates an object
## of the passed ``size``. This should only be used for optimization
## purposes when you know what you're doing!
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
## leaked implementation detail. Do not use. ## leaked implementation detail. Do not use.
@ -513,7 +507,13 @@ type
ESynch: Exception ESynch: Exception
].} ].}
proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.} proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.}
## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. This is **unsafe** as it allocates an object
## of the passed ``size``. This should only be used for optimization
## purposes when you know what you're doing!
proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
## returns the size of ``x`` in bytes. Since this is a low-level proc, ## returns the size of ``x`` in bytes. Since this is a low-level proc,
## its usage is discouraged - using ``new`` for the most cases suffices ## its usage is discouraged - using ``new`` for the most cases suffices
## that one never needs to know ``x``'s size. As a special semantic rule, ## that one never needs to know ``x``'s size. As a special semantic rule,
@ -547,7 +547,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
## short notation for: ``x = pred(x, y)``. ## short notation for: ``x = pred(x, y)``.
proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.} proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.}
## creates a new sequence of type ``seq[T]`` with length ``len``. ## creates a new sequence of type ``seq[T]`` with length ``len``.
## This is equivalent to ``s = @[]; setlen(s, len)``, but more ## This is equivalent to ``s = @[]; setlen(s, len)``, but more
## efficient since no reallocation is needed. ## efficient since no reallocation is needed.
@ -565,7 +565,7 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
## inputStrings[2] = "would crash" ## inputStrings[2] = "would crash"
## #inputStrings[3] = "out of bounds" ## #inputStrings[3] = "out of bounds"
proc newSeq*[T](len = 0): seq[T] = proc newSeq*[T](len = 0.Natural): seq[T] =
## creates a new sequence of type ``seq[T]`` with length ``len``. ## creates a new sequence of type ``seq[T]`` with length ``len``.
## ##
## Note that the sequence will be filled with zeroed entries, which can be a ## Note that the sequence will be filled with zeroed entries, which can be a
@ -939,7 +939,7 @@ proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
## sequences with the array constructor: ``@[1, 2, 3]`` has the type ## sequences with the array constructor: ``@[1, 2, 3]`` has the type
## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``. ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
proc setLen*[T](s: var seq[T], newlen: int) {. proc setLen*[T](s: var seq[T], newlen: Natural) {.
magic: "SetLengthSeq", noSideEffect.} magic: "SetLengthSeq", noSideEffect.}
## sets the length of `s` to `newlen`. ## sets the length of `s` to `newlen`.
## ``T`` may be any sequence type. ## ``T`` may be any sequence type.
@ -947,14 +947,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {.
## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
## a size, use ``newSeq`` instead. ## a size, use ``newSeq`` instead.
proc setLen*(s: var string, newlen: int) {. proc setLen*(s: var string, newlen: Natural) {.
magic: "SetLengthStr", noSideEffect.} magic: "SetLengthStr", noSideEffect.}
## sets the length of `s` to `newlen`. ## sets the length of `s` to `newlen`.
## If the current length is greater than the new length, ## If the current length is greater than the new length,
## ``s`` will be truncated. `s` cannot be nil! To initialize a string with ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
## a size, use ``newString`` instead. ## a size, use ``newString`` instead.
proc newString*(len: int): string {. proc newString*(len: Natural): string {.
magic: "NewString", importc: "mnewString", noSideEffect.} magic: "NewString", importc: "mnewString", noSideEffect.}
## returns a new string of length ``len`` but with uninitialized ## returns a new string of length ``len`` but with uninitialized
## content. One needs to fill the string character after character ## content. One needs to fill the string character after character
@ -962,7 +962,7 @@ proc newString*(len: int): string {.
## optimization purposes; the same effect can be achieved with the ## optimization purposes; the same effect can be achieved with the
## ``&`` operator or with ``add``. ## ``&`` operator or with ``add``.
proc newStringOfCap*(cap: int): string {. proc newStringOfCap*(cap: Natural): string {.
magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.} magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
## returns a new string of length ``0`` but with capacity `cap`.This ## returns a new string of length ``0`` but with capacity `cap`.This
## procedure exists only for optimization purposes; the same effect can ## procedure exists only for optimization purposes; the same effect can
@ -1152,21 +1152,21 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
## is a reason why the default assignment does a deep copy of sequences ## is a reason why the default assignment does a deep copy of sequences
## and strings. ## and strings.
proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`. ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
## This is an O(1) operation. ## This is an O(1) operation.
let xl = x.len let xl = x.len
shallowCopy(x[i], x[xl-1]) shallowCopy(x[i], x[xl-1])
setLen(x, xl-1) setLen(x, xl-1)
proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} = proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
## deletes the item at index `i` by moving ``x[i+1..]`` by one position. ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
## This is an O(n) operation. ## This is an O(n) operation.
let xl = x.len let xl = x.len
for j in i..xl-2: shallowCopy(x[j], x[j+1]) for j in i..xl-2: shallowCopy(x[j], x[j+1])
setLen(x, xl-1) setLen(x, xl-1)
proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
## inserts `item` into `x` at position `i`. ## inserts `item` into `x` at position `i`.
let xl = x.len let xl = x.len
setLen(x, xl+1) setLen(x, xl+1)
@ -1312,19 +1312,19 @@ proc substr*(s: string, first, last: int): string {.
## or `limit`:idx: a string's length. ## or `limit`:idx: a string's length.
when not defined(nimrodVM): when not defined(nimrodVM):
proc zeroMem*(p: pointer, size: int) {.importc, noDecl, benign.} proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.}
## overwrites the contents of the memory at ``p`` with the value 0. ## overwrites the contents of the memory at ``p`` with the value 0.
## Exactly ``size`` bytes will be overwritten. Like any procedure ## Exactly ``size`` bytes will be overwritten. Like any procedure
## dealing with raw memory this is *unsafe*. ## dealing with raw memory this is *unsafe*.
proc copyMem*(dest, source: pointer, size: int) {. proc copyMem*(dest, source: pointer, size: Natural) {.
importc: "memcpy", header: "<string.h>", benign.} importc: "memcpy", header: "<string.h>", benign.}
## copies the contents from the memory at ``source`` to the memory ## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
## regions may not overlap. Like any procedure dealing with raw ## regions may not overlap. Like any procedure dealing with raw
## memory this is *unsafe*. ## memory this is *unsafe*.
proc moveMem*(dest, source: pointer, size: int) {. proc moveMem*(dest, source: pointer, size: Natural) {.
importc: "memmove", header: "<string.h>", benign.} importc: "memmove", header: "<string.h>", benign.}
## copies the contents from the memory at ``source`` to the memory ## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
@ -1332,7 +1332,7 @@ when not defined(nimrodVM):
## and is thus somewhat more safe than ``copyMem``. Like any procedure ## and is thus somewhat more safe than ``copyMem``. Like any procedure
## dealing with raw memory this is still *unsafe*, though. ## dealing with raw memory this is still *unsafe*, though.
proc equalMem*(a, b: pointer, size: int): bool {. proc equalMem*(a, b: pointer, size: Natural): bool {.
importc: "equalMem", noDecl, noSideEffect.} importc: "equalMem", noDecl, noSideEffect.}
## compares the memory blocks ``a`` and ``b``. ``size`` bytes will ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will
## be compared. If the blocks are equal, true is returned, false ## be compared. If the blocks are equal, true is returned, false
@ -1340,7 +1340,7 @@ when not defined(nimrodVM):
## *unsafe*. ## *unsafe*.
when hostOS != "standalone": when hostOS != "standalone":
proc alloc*(size: int): pointer {.noconv, rtl, tags: [], benign.} proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
## allocates a new memory block with at least ``size`` bytes. The ## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or ## block has to be freed with ``realloc(block, 0)`` or
## ``dealloc(block)``. The block is not initialized, so reading ## ``dealloc(block)``. The block is not initialized, so reading
@ -1355,7 +1355,7 @@ when not defined(nimrodVM):
## The allocated memory belongs to its allocating thread! ## The allocated memory belongs to its allocating thread!
## Use `createSharedU` to allocate from a shared heap. ## Use `createSharedU` to allocate from a shared heap.
cast[ptr T](alloc(T.sizeof * size)) cast[ptr T](alloc(T.sizeof * size))
proc alloc0*(size: int): pointer {.noconv, rtl, tags: [], benign.} proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
## allocates a new memory block with at least ``size`` bytes. The ## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or ## block has to be freed with ``realloc(block, 0)`` or
## ``dealloc(block)``. The block is initialized with all bytes ## ``dealloc(block)``. The block is initialized with all bytes
@ -1370,8 +1370,8 @@ when not defined(nimrodVM):
## The allocated memory belongs to its allocating thread! ## The allocated memory belongs to its allocating thread!
## Use `createShared` to allocate from a shared heap. ## Use `createShared` to allocate from a shared heap.
cast[ptr T](alloc0(T.sizeof * size)) cast[ptr T](alloc0(T.sizeof * size))
proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [], proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
benign.} benign.}
## grows or shrinks a given memory block. If p is **nil** then a new ## grows or shrinks a given memory block. If p is **nil** then a new
## memory block is returned. In either way the block has at least ## memory block is returned. In either way the block has at least
## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil** ## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@ -1398,7 +1398,7 @@ when not defined(nimrodVM):
## Use `deallocShared` to deallocate from a shared heap. ## Use `deallocShared` to deallocate from a shared heap.
proc free*[T](p: ptr T) {.inline, benign.} = proc free*[T](p: ptr T) {.inline, benign.} =
dealloc(p) dealloc(p)
proc allocShared*(size: int): pointer {.noconv, rtl, benign.} proc allocShared*(size: Natural): pointer {.noconv, rtl, benign.}
## allocates a new memory block on the shared heap with at ## allocates a new memory block on the shared heap with at
## least ``size`` bytes. The block has to be freed with ## least ``size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
@ -1412,7 +1412,7 @@ when not defined(nimrodVM):
## is not initialized, so reading from it before writing to it is ## is not initialized, so reading from it before writing to it is
## undefined behaviour! ## undefined behaviour!
cast[ptr T](allocShared(T.sizeof * size)) cast[ptr T](allocShared(T.sizeof * size))
proc allocShared0*(size: int): pointer {.noconv, rtl, benign.} proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign.}
## allocates a new memory block on the shared heap with at ## allocates a new memory block on the shared heap with at
## least ``size`` bytes. The block has to be freed with ## least ``size`` bytes. The block has to be freed with
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
@ -1425,8 +1425,8 @@ when not defined(nimrodVM):
## The block is initialized with all bytes ## The block is initialized with all bytes
## containing zero, so it is somewhat safer than ``createSharedU``. ## containing zero, so it is somewhat safer than ``createSharedU``.
cast[ptr T](allocShared0(T.sizeof * size)) cast[ptr T](allocShared0(T.sizeof * size))
proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl, proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl,
benign.} benign.}
## grows or shrinks a given memory block on the heap. If p is **nil** ## grows or shrinks a given memory block on the heap. If p is **nil**
## then a new memory block is returned. In either way the block has at ## then a new memory block is returned. In either way the block has at
## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil** ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@ -2489,37 +2489,37 @@ when not defined(JS): #and not defined(NimrodVM):
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.} proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
## retrieves the file size (in bytes) of `f`. ## retrieves the file size (in bytes) of `f`.
proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: int): int {. proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
tags: [ReadIOEffect], benign.} tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than ## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater. ## `len` (if not as many bytes are remaining), but not greater.
proc readChars*(f: File, a: var openArray[char], start, len: int): int {. proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
tags: [ReadIOEffect], benign.} tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than ## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater. ## `len` (if not as many bytes are remaining), but not greater.
proc readBuffer*(f: File, buffer: pointer, len: int): int {. proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
tags: [ReadIOEffect], benign.} tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer pointed to by `buffer`. Returns ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
## the actual number of bytes that have been read which may be less than ## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater. ## `len` (if not as many bytes are remaining), but not greater.
proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: int): int {. proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
tags: [WriteIOEffect], benign.} tags: [WriteIOEffect], benign.}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case ## the number of actual written bytes, which may be less than `len` in case
## of an error. ## of an error.
proc writeChars*(f: File, a: openArray[char], start, len: int): int {. proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
tags: [WriteIOEffect], benign.} tags: [WriteIOEffect], benign.}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case ## the number of actual written bytes, which may be less than `len` in case
## of an error. ## of an error.
proc writeBuffer*(f: File, buffer: pointer, len: int): int {. proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
tags: [WriteIOEffect], benign.} tags: [WriteIOEffect], benign.}
## writes the bytes of buffer pointed to by the parameter `buffer` to the ## writes the bytes of buffer pointed to by the parameter `buffer` to the
## file `f`. Returns the number of actual written bytes, which may be less ## file `f`. Returns the number of actual written bytes, which may be less
@ -2541,7 +2541,7 @@ when not defined(JS): #and not defined(NimrodVM):
when not defined(nimfix): when not defined(nimfix):
{.deprecated: [fileHandle: getFileHandle].} {.deprecated: [fileHandle: getFileHandle].}
proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] = proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
## of length ``len``. ## of length ``len``.
newSeq(result, len) newSeq(result, len)
@ -2811,14 +2811,14 @@ elif defined(JS):
proc getTotalMem(): int = return -1 proc getTotalMem(): int = return -1
proc dealloc(p: pointer) = discard proc dealloc(p: pointer) = discard
proc alloc(size: int): pointer = discard proc alloc(size: Natural): pointer = discard
proc alloc0(size: int): pointer = discard proc alloc0(size: Natural): pointer = discard
proc realloc(p: pointer, newsize: int): pointer = discard proc realloc(p: pointer, newsize: Natural): pointer = discard
proc allocShared(size: int): pointer = discard proc allocShared(size: Natural): pointer = discard
proc allocShared0(size: int): pointer = discard proc allocShared0(size: Natural): pointer = discard
proc deallocShared(p: pointer) = discard proc deallocShared(p: pointer) = discard
proc reallocShared(p: pointer, newsize: int): pointer = discard proc reallocShared(p: pointer, newsize: Natural): pointer = discard
when defined(JS): when defined(JS):
include "system/jssys" include "system/jssys"
@ -3164,7 +3164,7 @@ when false:
payload() payload()
when hostOS != "standalone": when hostOS != "standalone":
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} = proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} =
## inserts `item` into `x` at position `i`. ## inserts `item` into `x` at position `i`.
var xl = x.len var xl = x.len
setLen(x, xl+item.len) setLen(x, xl+item.len)

View file

@ -8,7 +8,7 @@
# #
# Low level allocator for Nim. Has been designed to support the GC. # Low level allocator for Nim. Has been designed to support the GC.
# TODO: # TODO:
# - eliminate "used" field # - eliminate "used" field
# - make searching for block O(1) # - make searching for block O(1)
{.push profiler:off.} {.push profiler:off.}
@ -21,37 +21,37 @@
# used with a size of 0: # used with a size of 0:
const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows) const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows)
when defined(posix): when defined(posix):
const const
PROT_READ = 1 # page can be read PROT_READ = 1 # page can be read
PROT_WRITE = 2 # page can be written PROT_WRITE = 2 # page can be written
MAP_PRIVATE = 2'i32 # Changes are private MAP_PRIVATE = 2'i32 # Changes are private
when defined(macosx) or defined(bsd): when defined(macosx) or defined(bsd):
const MAP_ANONYMOUS = 0x1000 const MAP_ANONYMOUS = 0x1000
elif defined(solaris): elif defined(solaris):
const MAP_ANONYMOUS = 0x100 const MAP_ANONYMOUS = 0x100
else: else:
var var
MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
proc mmap(adr: pointer, len: int, prot, flags, fildes: cint, proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
off: int): pointer {.header: "<sys/mman.h>".} off: int): pointer {.header: "<sys/mman.h>".}
proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".} proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".}
proc osAllocPages(size: int): pointer {.inline.} = proc osAllocPages(size: int): pointer {.inline.} =
result = mmap(nil, size, PROT_READ or PROT_WRITE, result = mmap(nil, size, PROT_READ or PROT_WRITE,
MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
if result == nil or result == cast[pointer](-1): if result == nil or result == cast[pointer](-1):
raiseOutOfMem() raiseOutOfMem()
proc osDeallocPages(p: pointer, size: int) {.inline} = proc osDeallocPages(p: pointer, size: int) {.inline} =
when reallyOsDealloc: munmap(p, size) when reallyOsDealloc: munmap(p, size)
elif defined(windows): elif defined(windows):
const const
MEM_RESERVE = 0x2000 MEM_RESERVE = 0x2000
MEM_COMMIT = 0x1000 MEM_COMMIT = 0x1000
MEM_TOP_DOWN = 0x100000 MEM_TOP_DOWN = 0x100000
PAGE_READWRITE = 0x04 PAGE_READWRITE = 0x04
@ -62,12 +62,12 @@ elif defined(windows):
proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType, proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
flProtect: int32): pointer {. flProtect: int32): pointer {.
header: "<windows.h>", stdcall, importc: "VirtualAlloc".} header: "<windows.h>", stdcall, importc: "VirtualAlloc".}
proc virtualFree(lpAddress: pointer, dwSize: int, proc virtualFree(lpAddress: pointer, dwSize: int,
dwFreeType: int32) {.header: "<windows.h>", stdcall, dwFreeType: int32) {.header: "<windows.h>", stdcall,
importc: "VirtualFree".} importc: "VirtualFree".}
proc osAllocPages(size: int): pointer {.inline.} = proc osAllocPages(size: int): pointer {.inline.} =
result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT, result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT,
PAGE_READWRITE) PAGE_READWRITE)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
@ -82,7 +82,7 @@ elif defined(windows):
when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE) when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE)
#VirtualFree(p, size, MEM_DECOMMIT) #VirtualFree(p, size, MEM_DECOMMIT)
else: else:
{.error: "Port memory manager to your platform".} {.error: "Port memory manager to your platform".}
# --------------------- end of non-portable code ----------------------------- # --------------------- end of non-portable code -----------------------------
@ -97,17 +97,17 @@ const
InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn! InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn!
SmallChunkSize = PageSize SmallChunkSize = PageSize
type type
PTrunk = ptr TTrunk PTrunk = ptr TTrunk
TTrunk {.final.} = object TTrunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0 key: int # start address at bit 0
bits: array[0..IntsPerTrunk-1, int] # a bit vector bits: array[0..IntsPerTrunk-1, int] # a bit vector
TTrunkBuckets = array[0..255, PTrunk] TTrunkBuckets = array[0..255, PTrunk]
TIntSet {.final.} = object TIntSet {.final.} = object
data: TTrunkBuckets data: TTrunkBuckets
type type
TAlignType = BiggestFloat TAlignType = BiggestFloat
TFreeCell {.final, pure.} = object TFreeCell {.final, pure.} = object
@ -123,14 +123,14 @@ type
prevSize: int # size of previous chunk; for coalescing prevSize: int # size of previous chunk; for coalescing
size: int # if < PageSize it is a small chunk size: int # if < PageSize it is a small chunk
used: bool # later will be optimized into prevSize... used: bool # later will be optimized into prevSize...
TSmallChunk = object of TBaseChunk TSmallChunk = object of TBaseChunk
next, prev: PSmallChunk # chunks of the same size next, prev: PSmallChunk # chunks of the same size
freeList: ptr TFreeCell freeList: ptr TFreeCell
free: int # how many bytes remain free: int # how many bytes remain
acc: int # accumulator for small object allocation acc: int # accumulator for small object allocation
data: TAlignType # start of usable memory data: TAlignType # start of usable memory
TBigChunk = object of TBaseChunk # not necessarily > PageSize! TBigChunk = object of TBaseChunk # not necessarily > PageSize!
next, prev: PBigChunk # chunks of the same (or bigger) size next, prev: PBigChunk # chunks of the same (or bigger) size
align: int align: int
@ -139,7 +139,7 @@ type
template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType) template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType) template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
proc roundup(x, v: int): int {.inline.} = proc roundup(x, v: int): int {.inline.} =
result = (x + (v-1)) and not (v-1) result = (x + (v-1)) and not (v-1)
sysAssert(result >= x, "roundup: result < x") sysAssert(result >= x, "roundup: result < x")
#return ((-x) and (v-1)) +% x #return ((-x) and (v-1)) +% x
@ -153,7 +153,7 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
# endings of big chunks. This is needed by the merging operation. The only # endings of big chunks. This is needed by the merging operation. The only
# remaining operation is best-fit for big chunks. Since there is a size-limit # remaining operation is best-fit for big chunks. Since there is a size-limit
# for big chunks (because greater than the limit means they are returned back # for big chunks (because greater than the limit means they are returned back
# to the OS), a fixed size array can be used. # to the OS), a fixed size array can be used.
type type
PLLChunk = ptr TLLChunk PLLChunk = ptr TLLChunk
@ -163,21 +163,21 @@ type
next: PLLChunk # next low-level chunk; only needed for dealloc next: PLLChunk # next low-level chunk; only needed for dealloc
PAvlNode = ptr TAvlNode PAvlNode = ptr TAvlNode
TAvlNode {.pure, final.} = object TAvlNode {.pure, final.} = object
link: array[0..1, PAvlNode] # Left (0) and right (1) links link: array[0..1, PAvlNode] # Left (0) and right (1) links
key, upperBound: int key, upperBound: int
level: int level: int
TMemRegion {.final, pure.} = object TMemRegion {.final, pure.} = object
minLargeObj, maxLargeObj: int minLargeObj, maxLargeObj: int
freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk] freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
llmem: PLLChunk llmem: PLLChunk
currMem, maxMem, freeMem: int # memory sizes (allocated from OS) currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
lastSize: int # needed for the case that OS gives us pages linearly lastSize: int # needed for the case that OS gives us pages linearly
freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
chunkStarts: TIntSet chunkStarts: TIntSet
root, deleted, last, freeAvlNodes: PAvlNode root, deleted, last, freeAvlNodes: PAvlNode
# shared: # shared:
var var
bottomData: TAvlNode bottomData: TAvlNode
@ -191,7 +191,7 @@ proc initAllocator() =
bottom.link[1] = bottom bottom.link[1] = bottom
{.pop.} {.pop.}
proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} = proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
inc(a.currMem, bytes) inc(a.currMem, bytes)
proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} = proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
@ -199,11 +199,11 @@ proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
dec(a.currMem, bytes) dec(a.currMem, bytes)
proc getMaxMem(a: var TMemRegion): int = proc getMaxMem(a: var TMemRegion): int =
# Since we update maxPagesCount only when freeing pages, # Since we update maxPagesCount only when freeing pages,
# maxPagesCount may not be up to date. Thus we use the # maxPagesCount may not be up to date. Thus we use the
# maximum of these both values here: # maximum of these both values here:
result = max(a.currMem, a.maxMem) result = max(a.currMem, a.maxMem)
proc llAlloc(a: var TMemRegion, size: int): pointer = proc llAlloc(a: var TMemRegion, size: int): pointer =
# *low-level* alloc for the memory managers data structures. Deallocation # *low-level* alloc for the memory managers data structures. Deallocation
# is done at he end of the allocator's life time. # is done at he end of the allocator's life time.
@ -251,15 +251,15 @@ proc llDeallocAll(a: var TMemRegion) =
var next = it.next var next = it.next
osDeallocPages(it, PageSize) osDeallocPages(it, PageSize)
it = next it = next
proc intSetGet(t: TIntSet, key: int): PTrunk = proc intSetGet(t: TIntSet, key: int): PTrunk =
var it = t.data[key and high(t.data)] var it = t.data[key and high(t.data)]
while it != nil: while it != nil:
if it.key == key: return it if it.key == key: return it
it = it.next it = it.next
result = nil result = nil
proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk = proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
result = intSetGet(t, key) result = intSetGet(t, key)
if result == nil: if result == nil:
result = cast[PTrunk](llAlloc(a, sizeof(result[]))) result = cast[PTrunk](llAlloc(a, sizeof(result[])))
@ -267,20 +267,20 @@ proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
t.data[key and high(t.data)] = result t.data[key and high(t.data)] = result
result.key = key result.key = key
proc contains(s: TIntSet, key: int): bool = proc contains(s: TIntSet, key: int): bool =
var t = intSetGet(s, key shr TrunkShift) var t = intSetGet(s, key shr TrunkShift)
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0 result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
else: else:
result = false result = false
proc incl(a: var TMemRegion, s: var TIntSet, key: int) = proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
var t = intSetPut(a, s, key shr TrunkShift) var t = intSetPut(a, s, key shr TrunkShift)
var u = key and TrunkMask var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask)) t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc excl(s: var TIntSet, key: int) = proc excl(s: var TIntSet, key: int) =
var t = intSetGet(s, key shr TrunkShift) var t = intSetGet(s, key shr TrunkShift)
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
@ -304,11 +304,11 @@ iterator elements(t: TIntSet): int {.inline.} =
w = w shr 1 w = w shr 1
inc(i) inc(i)
r = r.next r = r.next
proc isSmallChunk(c: PChunk): bool {.inline.} = proc isSmallChunk(c: PChunk): bool {.inline.} =
return c.size <= SmallChunkSize-smallChunkOverhead() return c.size <= SmallChunkSize-smallChunkOverhead()
proc chunkUnused(c: PChunk): bool {.inline.} = proc chunkUnused(c: PChunk): bool {.inline.} =
result = not c.used result = not c.used
iterator allObjects(m: TMemRegion): pointer {.inline.} = iterator allObjects(m: TMemRegion): pointer {.inline.} =
@ -319,7 +319,7 @@ iterator allObjects(m: TMemRegion): pointer {.inline.} =
if not chunkUnused(c): if not chunkUnused(c):
if isSmallChunk(c): if isSmallChunk(c):
var c = cast[PSmallChunk](c) var c = cast[PSmallChunk](c)
let size = c.size let size = c.size
var a = cast[ByteAddress](addr(c.data)) var a = cast[ByteAddress](addr(c.data))
let limit = a + c.acc let limit = a + c.acc
@ -334,17 +334,17 @@ proc isCell(p: pointer): bool {.inline.} =
result = cast[ptr TFreeCell](p).zeroField >% 1 result = cast[ptr TFreeCell](p).zeroField >% 1
# ------------- chunk management ---------------------------------------------- # ------------- chunk management ----------------------------------------------
proc pageIndex(c: PChunk): int {.inline.} = proc pageIndex(c: PChunk): int {.inline.} =
result = cast[ByteAddress](c) shr PageShift result = cast[ByteAddress](c) shr PageShift
proc pageIndex(p: pointer): int {.inline.} = proc pageIndex(p: pointer): int {.inline.} =
result = cast[ByteAddress](p) shr PageShift result = cast[ByteAddress](p) shr PageShift
proc pageAddr(p: pointer): PChunk {.inline.} = proc pageAddr(p: pointer): PChunk {.inline.} =
result = cast[PChunk](cast[ByteAddress](p) and not PageMask) result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
#sysAssert(Contains(allocator.chunkStarts, pageIndex(result))) #sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk = proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
incCurrMem(a, size) incCurrMem(a, size)
inc(a.freeMem, size) inc(a.freeMem, size)
result = cast[PBigChunk](osAllocPages(size)) result = cast[PBigChunk](osAllocPages(size))
@ -373,7 +373,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
result.prevSize = 0 # unknown result.prevSize = 0 # unknown
a.lastSize = size # for next request a.lastSize = size # for next request
proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) = proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
# update next.prevSize: # update next.prevSize:
var c = cast[PChunk](p) var c = cast[PChunk](p)
var nxt = cast[ByteAddress](p) +% c.size var nxt = cast[ByteAddress](p) +% c.size
@ -387,36 +387,36 @@ proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
dec(a.freeMem, size) dec(a.freeMem, size)
#c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size) #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} = proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
result = contains(a.chunkStarts, pageIndex(p)) result = contains(a.chunkStarts, pageIndex(p))
proc contains[T](list, x: T): bool = proc contains[T](list, x: T): bool =
var it = list var it = list
while it != nil: while it != nil:
if it == x: return true if it == x: return true
it = it.next it = it.next
proc writeFreeList(a: TMemRegion) = proc writeFreeList(a: TMemRegion) =
var it = a.freeChunksList var it = a.freeChunksList
c_fprintf(c_stdout, "freeChunksList: %p\n", it) c_fprintf(c_stdout, "freeChunksList: %p\n", it)
while it != nil: while it != nil:
c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n", c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n",
it, it.next, it.prev) it, it.next, it.prev)
it = it.next it = it.next
proc listAdd[T](head: var T, c: T) {.inline.} = proc listAdd[T](head: var T, c: T) {.inline.} =
sysAssert(c notin head, "listAdd 1") sysAssert(c notin head, "listAdd 1")
sysAssert c.prev == nil, "listAdd 2" sysAssert c.prev == nil, "listAdd 2"
sysAssert c.next == nil, "listAdd 3" sysAssert c.next == nil, "listAdd 3"
c.next = head c.next = head
if head != nil: if head != nil:
sysAssert head.prev == nil, "listAdd 4" sysAssert head.prev == nil, "listAdd 4"
head.prev = c head.prev = c
head = c head = c
proc listRemove[T](head: var T, c: T) {.inline.} = proc listRemove[T](head: var T, c: T) {.inline.} =
sysAssert(c in head, "listRemove") sysAssert(c in head, "listRemove")
if c == head: if c == head:
head = c.next head = c.next
sysAssert c.prev == nil, "listRemove 2" sysAssert c.prev == nil, "listRemove 2"
if head != nil: head.prev = nil if head != nil: head.prev = nil
@ -426,15 +426,15 @@ proc listRemove[T](head: var T, c: T) {.inline.} =
if c.next != nil: c.next.prev = c.prev if c.next != nil: c.next.prev = c.prev
c.next = nil c.next = nil
c.prev = nil c.prev = nil
proc updatePrevSize(a: var TMemRegion, c: PBigChunk, proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
prevSize: int) {.inline.} = prevSize: int) {.inline.} =
var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize") sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize")
if isAccessible(a, ri): if isAccessible(a, ri):
ri.prevSize = prevSize ri.prevSize = prevSize
proc freeBigChunk(a: var TMemRegion, c: PBigChunk) = proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
var c = c var c = c
sysAssert(c.size >= PageSize, "freeBigChunk") sysAssert(c.size >= PageSize, "freeBigChunk")
inc(a.freeMem, c.size) inc(a.freeMem, c.size)
@ -448,7 +448,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
inc(c.size, ri.size) inc(c.size, ri.size)
excl(a.chunkStarts, pageIndex(ri)) excl(a.chunkStarts, pageIndex(ri))
when coalescLeft: when coalescLeft:
if c.prevSize != 0: if c.prevSize != 0:
var le = cast[PChunk](cast[ByteAddress](c) -% c.prevSize) var le = cast[PChunk](cast[ByteAddress](c) -% c.prevSize)
sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4") sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4")
if isAccessible(a, le) and chunkUnused(le): if isAccessible(a, le) and chunkUnused(le):
@ -467,7 +467,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
else: else:
freeOsChunks(a, c, c.size) freeOsChunks(a, c, c.size)
proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) = proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
var rest = cast[PBigChunk](cast[ByteAddress](c) +% size) var rest = cast[PBigChunk](cast[ByteAddress](c) +% size)
sysAssert(rest notin a.freeChunksList, "splitChunk") sysAssert(rest notin a.freeChunksList, "splitChunk")
rest.size = c.size - size rest.size = c.size - size
@ -480,7 +480,7 @@ proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
incl(a, a.chunkStarts, pageIndex(rest)) incl(a, a.chunkStarts, pageIndex(rest))
listAdd(a.freeChunksList, rest) listAdd(a.freeChunksList, rest)
proc getBigChunk(a: var TMemRegion, size: int): PBigChunk = proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
# use first fit for now: # use first fit for now:
sysAssert((size and PageMask) == 0, "getBigChunk 1") sysAssert((size and PageMask) == 0, "getBigChunk 1")
sysAssert(size > 0, "getBigChunk 2") sysAssert(size > 0, "getBigChunk 2")
@ -488,7 +488,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
block search: block search:
while result != nil: while result != nil:
sysAssert chunkUnused(result), "getBigChunk 3" sysAssert chunkUnused(result), "getBigChunk 3"
if result.size == size: if result.size == size:
listRemove(a.freeChunksList, result) listRemove(a.freeChunksList, result)
break search break search
elif result.size > size: elif result.size > size:
@ -497,7 +497,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
break search break search
result = result.next result = result.next
sysAssert result != a.freeChunksList, "getBigChunk 4" sysAssert result != a.freeChunksList, "getBigChunk 4"
if size < InitialMemoryRequest: if size < InitialMemoryRequest:
result = requestOsChunks(a, InitialMemoryRequest) result = requestOsChunks(a, InitialMemoryRequest)
splitChunk(a, result, size) splitChunk(a, result, size)
else: else:
@ -507,7 +507,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
incl(a, a.chunkStarts, pageIndex(result)) incl(a, a.chunkStarts, pageIndex(result))
dec(a.freeMem, size) dec(a.freeMem, size)
proc getSmallChunk(a: var TMemRegion): PSmallChunk = proc getSmallChunk(a: var TMemRegion): PSmallChunk =
var res = getBigChunk(a, PageSize) var res = getBigChunk(a, PageSize)
sysAssert res.prev == nil, "getSmallChunk 1" sysAssert res.prev == nil, "getSmallChunk 1"
sysAssert res.next == nil, "getSmallChunk 2" sysAssert res.next == nil, "getSmallChunk 2"
@ -521,15 +521,15 @@ proc allocInv(a: TMemRegion): bool =
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks): for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
var c = a.freeSmallChunks[s] var c = a.freeSmallChunks[s]
while c != nil: while c != nil:
if c.next == c: if c.next == c:
echo "[SYSASSERT] c.next == c" echo "[SYSASSERT] c.next == c"
return false return false
if c.size != s * MemAlign: if c.size != s * MemAlign:
echo "[SYSASSERT] c.size != s * MemAlign" echo "[SYSASSERT] c.size != s * MemAlign"
return false return false
var it = c.freeList var it = c.freeList
while it != nil: while it != nil:
if it.zeroField != 0: if it.zeroField != 0:
echo "[SYSASSERT] it.zeroField != 0" echo "[SYSASSERT] it.zeroField != 0"
c_printf("%ld %p\n", it.zeroField, it) c_printf("%ld %p\n", it.zeroField, it)
return false return false
@ -544,11 +544,11 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
var size = roundup(requestedSize, MemAlign) var size = roundup(requestedSize, MemAlign)
sysAssert(size >= requestedSize, "insufficient allocated size!") sysAssert(size >= requestedSize, "insufficient allocated size!")
#c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size) #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
if size <= SmallChunkSize-smallChunkOverhead(): if size <= SmallChunkSize-smallChunkOverhead():
# allocate a small block: for small chunks, we use only its next pointer # allocate a small block: for small chunks, we use only its next pointer
var s = size div MemAlign var s = size div MemAlign
var c = a.freeSmallChunks[s] var c = a.freeSmallChunks[s]
if c == nil: if c == nil:
c = getSmallChunk(a) c = getSmallChunk(a)
c.freeList = nil c.freeList = nil
sysAssert c.size == PageSize, "rawAlloc 3" sysAssert c.size == PageSize, "rawAlloc 3"
@ -567,7 +567,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
# c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size) # c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size)
sysAssert c.size == size, "rawAlloc 6" sysAssert c.size == size, "rawAlloc 6"
if c.freeList == nil: if c.freeList == nil:
sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize, sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
"rawAlloc 7") "rawAlloc 7")
result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc) result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc)
inc(c.acc, size) inc(c.acc, size)
@ -621,9 +621,9 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
f.zeroField = 0 f.zeroField = 0
f.next = c.freeList f.next = c.freeList
c.freeList = f c.freeList = f
when overwriteFree: when overwriteFree:
# set to 0xff to check for usage after free bugs: # set to 0xff to check for usage after free bugs:
c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32, c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32,
s -% sizeof(TFreeCell)) s -% sizeof(TFreeCell))
# check if it is not in the freeSmallChunks[s] list: # check if it is not in the freeSmallChunks[s] list:
if c.free < s: if c.free < s:
@ -649,13 +649,13 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
sysAssert(allocInv(a), "rawDealloc: end") sysAssert(allocInv(a), "rawDealloc: end")
when logAlloc: cprintf("rawDealloc: %p\n", p) when logAlloc: cprintf("rawDealloc: %p\n", p)
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
if isAccessible(a, p): if isAccessible(a, p):
var c = pageAddr(p) var c = pageAddr(p)
if not chunkUnused(c): if not chunkUnused(c):
if isSmallChunk(c): if isSmallChunk(c):
var c = cast[PSmallChunk](c) var c = cast[PSmallChunk](c)
var offset = (cast[ByteAddress](p) and (PageSize-1)) -% var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead() smallChunkOverhead()
result = (c.acc >% offset) and (offset %% c.size == 0) and result = (c.acc >% offset) and (offset %% c.size == 0) and
(cast[ptr TFreeCell](p).zeroField >% 1) (cast[ptr TFreeCell](p).zeroField >% 1)
@ -673,12 +673,12 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
if not chunkUnused(c): if not chunkUnused(c):
if isSmallChunk(c): if isSmallChunk(c):
var c = cast[PSmallChunk](c) var c = cast[PSmallChunk](c)
var offset = (cast[ByteAddress](p) and (PageSize-1)) -% var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead() smallChunkOverhead()
if c.acc >% offset: if c.acc >% offset:
sysAssert(cast[ByteAddress](addr(c.data)) +% offset == sysAssert(cast[ByteAddress](addr(c.data)) +% offset ==
cast[ByteAddress](p), "offset is not what you think it is") cast[ByteAddress](p), "offset is not what you think it is")
var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +% var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +%
offset -% (offset %% c.size)) offset -% (offset %% c.size))
if d.zeroField >% 1: if d.zeroField >% 1:
result = d result = d
@ -711,13 +711,13 @@ proc ptrSize(p: pointer): int =
if not isSmallChunk(c): if not isSmallChunk(c):
dec result, bigChunkOverhead() dec result, bigChunkOverhead()
proc alloc(allocator: var TMemRegion, size: int): pointer = proc alloc(allocator: var TMemRegion, size: Natural): pointer =
result = rawAlloc(allocator, size+sizeof(TFreeCell)) result = rawAlloc(allocator, size+sizeof(TFreeCell))
cast[ptr TFreeCell](result).zeroField = 1 # mark it as used cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
sysAssert(not isAllocatedPtr(allocator, result), "alloc") sysAssert(not isAllocatedPtr(allocator, result), "alloc")
result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell)) result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell))
proc alloc0(allocator: var TMemRegion, size: int): pointer = proc alloc0(allocator: var TMemRegion, size: Natural): pointer =
result = alloc(allocator, size) result = alloc(allocator, size)
zeroMem(result, size) zeroMem(result, size)
@ -730,7 +730,7 @@ proc dealloc(allocator: var TMemRegion, p: pointer) =
rawDealloc(allocator, x) rawDealloc(allocator, x)
sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3") sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer = proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
if newsize > 0: if newsize > 0:
result = alloc0(allocator, newsize) result = alloc0(allocator, newsize)
if p != nil: if p != nil:
@ -758,7 +758,7 @@ proc deallocOsPages(a: var TMemRegion) =
proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem
proc getOccupiedMem(a: TMemRegion): int {.inline.} = proc getOccupiedMem(a: TMemRegion): int {.inline.} =
result = a.currMem - a.freeMem result = a.currMem - a.freeMem
# ---------------------- thread memory region ------------------------------- # ---------------------- thread memory region -------------------------------
@ -774,16 +774,16 @@ template instantiateForRegion(allocator: expr) =
proc deallocOsPages = deallocOsPages(allocator) proc deallocOsPages = deallocOsPages(allocator)
proc alloc(size: int): pointer = proc alloc(size: Natural): pointer =
result = alloc(allocator, size) result = alloc(allocator, size)
proc alloc0(size: int): pointer = proc alloc0(size: Natural): pointer =
result = alloc0(allocator, size) result = alloc0(allocator, size)
proc dealloc(p: pointer) = proc dealloc(p: pointer) =
dealloc(allocator, p) dealloc(allocator, p)
proc realloc(p: pointer, newsize: int): pointer = proc realloc(p: pointer, newsize: Natural): pointer =
result = realloc(allocator, p, newSize) result = realloc(allocator, p, newSize)
when false: when false:
@ -794,7 +794,7 @@ template instantiateForRegion(allocator: expr) =
inc(result, it.size) inc(result, it.size)
it = it.next it = it.next
proc getFreeMem(): int = proc getFreeMem(): int =
result = allocator.freeMem result = allocator.freeMem
#sysAssert(result == countFreeMem()) #sysAssert(result == countFreeMem())
@ -807,7 +807,7 @@ template instantiateForRegion(allocator: expr) =
var heapLock: TSysLock var heapLock: TSysLock
initSysLock(heapLock) initSysLock(heapLock)
proc allocShared(size: int): pointer = proc allocShared(size: Natural): pointer =
when hasThreadSupport: when hasThreadSupport:
acquireSys(heapLock) acquireSys(heapLock)
result = alloc(sharedHeap, size) result = alloc(sharedHeap, size)
@ -815,20 +815,20 @@ template instantiateForRegion(allocator: expr) =
else: else:
result = alloc(size) result = alloc(size)
proc allocShared0(size: int): pointer = proc allocShared0(size: Natural): pointer =
result = allocShared(size) result = allocShared(size)
zeroMem(result, size) zeroMem(result, size)
proc deallocShared(p: pointer) = proc deallocShared(p: pointer) =
when hasThreadSupport: when hasThreadSupport:
acquireSys(heapLock) acquireSys(heapLock)
dealloc(sharedHeap, p) dealloc(sharedHeap, p)
releaseSys(heapLock) releaseSys(heapLock)
else: else:
dealloc(p) dealloc(p)
proc reallocShared(p: pointer, newsize: int): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
when hasThreadSupport: when hasThreadSupport:
acquireSys(heapLock) acquireSys(heapLock)
result = realloc(sharedHeap, p, newsize) result = realloc(sharedHeap, p, newsize)
releaseSys(heapLock) releaseSys(heapLock)

View file

@ -109,24 +109,24 @@ when defined(boehmgc):
when not defined(useNimRtl): when not defined(useNimRtl):
proc alloc(size: int): pointer = proc alloc(size: Natural): pointer =
result = boehmAlloc(size) result = boehmAlloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc alloc0(size: int): pointer = proc alloc0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc realloc(p: pointer, newsize: int): pointer = proc realloc(p: pointer, newsize: Natural): pointer =
result = boehmRealloc(p, newsize) result = boehmRealloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = boehmDealloc(p) proc dealloc(p: pointer) = boehmDealloc(p)
proc allocShared(size: int): pointer = proc allocShared(size: Natural): pointer =
result = boehmAlloc(size) result = boehmAlloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc allocShared0(size: int): pointer = proc allocShared0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc reallocShared(p: pointer, newsize: int): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
result = boehmRealloc(p, newsize) result = boehmRealloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = boehmDealloc(p) proc deallocShared(p: pointer) = boehmDealloc(p)
@ -196,24 +196,24 @@ when defined(boehmgc):
elif defined(nogc) and defined(useMalloc): elif defined(nogc) and defined(useMalloc):
when not defined(useNimRtl): when not defined(useNimRtl):
proc alloc(size: int): pointer = proc alloc(size: Natural): pointer =
result = cmalloc(size) result = cmalloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc alloc0(size: int): pointer = proc alloc0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc realloc(p: pointer, newsize: int): pointer = proc realloc(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = crealloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = cfree(p) proc dealloc(p: pointer) = cfree(p)
proc allocShared(size: int): pointer = proc allocShared(size: Natural): pointer =
result = cmalloc(size) result = cmalloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc allocShared0(size: int): pointer = proc allocShared0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc reallocShared(p: pointer, newsize: int): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = crealloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = cfree(p) proc deallocShared(p: pointer) = cfree(p)

View file

@ -16,7 +16,7 @@
# of the standard library! # of the standard library!
proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>", proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>",
tags: [WriteIOEffect].} tags: [WriteIOEffect].}
proc fgets(c: cstring, n: int, f: File): cstring {. proc fgets(c: cstring, n: int, f: File): cstring {.
importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].} importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].}
@ -26,7 +26,7 @@ proc ungetc(c: cint, f: File) {.importc: "ungetc", header: "<stdio.h>",
tags: [].} tags: [].}
proc putc(c: char, stream: File) {.importc: "putc", header: "<stdio.h>", proc putc(c: char, stream: File) {.importc: "putc", header: "<stdio.h>",
tags: [WriteIOEffect].} tags: [WriteIOEffect].}
proc fprintf(f: File, frmt: cstring) {.importc: "fprintf", proc fprintf(f: File, frmt: cstring) {.importc: "fprintf",
header: "<stdio.h>", varargs, tags: [WriteIOEffect].} header: "<stdio.h>", varargs, tags: [WriteIOEffect].}
proc strlen(c: cstring): int {. proc strlen(c: cstring): int {.
importc: "strlen", header: "<string.h>", tags: [].} importc: "strlen", header: "<string.h>", tags: [].}
@ -88,18 +88,18 @@ proc readLine(f: File): TaintedString =
result = TaintedString(newStringOfCap(80)) result = TaintedString(newStringOfCap(80))
if not readLine(f, result): raiseEIO("EOF reached") if not readLine(f, result): raiseEIO("EOF reached")
proc write(f: File, i: int) = proc write(f: File, i: int) =
when sizeof(int) == 8: when sizeof(int) == 8:
fprintf(f, "%lld", i) fprintf(f, "%lld", i)
else: else:
fprintf(f, "%ld", i) fprintf(f, "%ld", i)
proc write(f: File, i: BiggestInt) = proc write(f: File, i: BiggestInt) =
when sizeof(BiggestInt) == 8: when sizeof(BiggestInt) == 8:
fprintf(f, "%lld", i) fprintf(f, "%lld", i)
else: else:
fprintf(f, "%ld", i) fprintf(f, "%ld", i)
proc write(f: File, b: bool) = proc write(f: File, b: bool) =
if b: write(f, "true") if b: write(f, "true")
else: write(f, "false") else: write(f, "false")
@ -110,7 +110,7 @@ proc write(f: File, c: char) = putc(c, f)
proc write(f: File, a: varargs[string, `$`]) = proc write(f: File, a: varargs[string, `$`]) =
for x in items(a): write(f, x) for x in items(a): write(f, x)
proc readAllBuffer(file: File): string = proc readAllBuffer(file: File): string =
# This proc is for File we want to read but don't know how many # This proc is for File we want to read but don't know how many
# bytes we need to read before the buffer is empty. # bytes we need to read before the buffer is empty.
result = "" result = ""
@ -123,8 +123,8 @@ proc readAllBuffer(file: File): string =
buffer.setLen(bytesRead) buffer.setLen(bytesRead)
result.add(buffer) result.add(buffer)
break break
proc rawFileSize(file: File): int = proc rawFileSize(file: File): int =
# this does not raise an error opposed to `getFileSize` # this does not raise an error opposed to `getFileSize`
var oldPos = ftell(file) var oldPos = ftell(file)
discard fseek(file, 0, 2) # seek the end of the file discard fseek(file, 0, 2) # seek the end of the file
@ -141,8 +141,8 @@ proc readAllFile(file: File, len: int): string =
proc readAllFile(file: File): string = proc readAllFile(file: File): string =
var len = rawFileSize(file) var len = rawFileSize(file)
result = readAllFile(file, len) result = readAllFile(file, len)
proc readAll(file: File): TaintedString = proc readAll(file: File): TaintedString =
# Separate handling needed because we need to buffer when we # Separate handling needed because we need to buffer when we
# don't know the overall length of the File. # don't know the overall length of the File.
let len = if file != stdin: rawFileSize(file) else: -1 let len = if file != stdin: rawFileSize(file) else: -1
@ -150,7 +150,7 @@ proc readAll(file: File): TaintedString =
result = readAllFile(file, len).TaintedString result = readAllFile(file, len).TaintedString
else: else:
result = readAllBuffer(file).TaintedString result = readAllBuffer(file).TaintedString
proc readFile(filename: string): TaintedString = proc readFile(filename: string): TaintedString =
var f = open(filename) var f = open(filename)
try: try:
@ -229,7 +229,7 @@ proc open(f: var File, filename: string,
elif bufSize == 0: elif bufSize == 0:
discard setvbuf(f, nil, IONBF, 0) discard setvbuf(f, nil, IONBF, 0)
proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool = proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool =
var p: pointer = freopen(filename, FormatOpen[mode], f) var p: pointer = freopen(filename, FormatOpen[mode], f)
result = p != nil result = p != nil
@ -243,23 +243,23 @@ proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
proc fwrite(buf: pointer, size, n: int, f: File): int {. proc fwrite(buf: pointer, size, n: int, f: File): int {.
importc: "fwrite", noDecl.} importc: "fwrite", noDecl.}
proc readBuffer(f: File, buffer: pointer, len: int): int = proc readBuffer(f: File, buffer: pointer, len: Natural): int =
result = fread(buffer, 1, len, f) result = fread(buffer, 1, len, f)
proc readBytes(f: File, a: var openArray[int8|uint8], start, len: int): int = proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
result = readBuffer(f, addr(a[start]), len) result = readBuffer(f, addr(a[start]), len)
proc readChars(f: File, a: var openArray[char], start, len: int): int = proc readChars(f: File, a: var openArray[char], start, len: Natural): int =
result = readBuffer(f, addr(a[start]), len) result = readBuffer(f, addr(a[start]), len)
{.push stackTrace:off, profiler:off.} {.push stackTrace:off, profiler:off.}
proc writeBytes(f: File, a: openArray[int8|uint8], start, len: int): int = proc writeBytes(f: File, a: openArray[int8|uint8], start, len: Natural): int =
var x = cast[ptr array[0..1000_000_000, int8]](a) var x = cast[ptr array[0..1000_000_000, int8]](a)
result = writeBuffer(f, addr(x[start]), len) result = writeBuffer(f, addr(x[start]), len)
proc writeChars(f: File, a: openArray[char], start, len: int): int = proc writeChars(f: File, a: openArray[char], start, len: Natural): int =
var x = cast[ptr array[0..1000_000_000, int8]](a) var x = cast[ptr array[0..1000_000_000, int8]](a)
result = writeBuffer(f, addr(x[start]), len) result = writeBuffer(f, addr(x[start]), len)
proc writeBuffer(f: File, buffer: pointer, len: int): int = proc writeBuffer(f: File, buffer: pointer, len: Natural): int =
result = fwrite(buffer, 1, len, f) result = fwrite(buffer, 1, len, f)
proc write(f: File, s: string) = proc write(f: File, s: string) =