Merge branch 'devel' into bugfix-2858-testament-sources-system-wide

This commit is contained in:
Oscar Campbell 2015-06-04 22:43:18 +02:00
commit cdf631c508
130 changed files with 5899 additions and 5730 deletions

View file

@ -842,7 +842,7 @@ type
data*: TIdNodePairSeq
TNodePair* = object
h*: THash # because it is expensive to compute!
h*: Hash # because it is expensive to compute!
key*: PNode
val*: int

View file

@ -14,7 +14,7 @@
import
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
proc hashNode*(p: RootRef): THash
proc hashNode*(p: RootRef): Hash
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
# Convert a tree into its YAML representation; this is used by the
# YAML code generator and it is invaluable for debugging purposes.
@ -49,7 +49,7 @@ proc strTableGet*(t: TStrTable, name: PIdent): PSym
type
TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash
h*: Hash # current hash
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
@ -65,7 +65,7 @@ proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
type
TIdentIter*{.final.} = object # iterator over all syms with same identifier
h*: THash # current hash
h*: Hash # current hash
name*: PIdent
@ -94,7 +94,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
proc lookupInRecord*(n: PNode, field: PIdent): PSym
proc getModule*(s: PSym): PSym
proc mustRehash*(length, counter: int): bool
proc nextTry*(h, maxHash: THash): THash {.inline.}
proc nextTry*(h, maxHash: Hash): Hash {.inline.}
# ------------- table[int, int] ---------------------------------------------
const
@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
else: internalError(list.info, "getSymFromList")
result = nil
proc hashNode(p: RootRef): THash =
proc hashNode(p: RootRef): Hash =
result = hash(cast[pointer](p))
proc mustRehash(length, counter: int): bool =
@ -466,7 +466,7 @@ proc debug(n: PNode) =
const
EmptySeq = @[]
proc nextTry(h, maxHash: THash): THash =
proc nextTry(h, maxHash: Hash): Hash =
result = ((5 * h) + 1) and maxHash
# For any initial h in range(maxHash), repeating that maxHash times
# generates each int in range(maxHash) exactly once (see any text on
@ -474,7 +474,7 @@ proc nextTry(h, maxHash: THash): THash =
proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
# returns true whether n is in t
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
while t.data[h] != nil:
if t.data[h] == obj:
return true
@ -482,7 +482,7 @@ proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
result = false
proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
var h: THash = hashNode(obj) and high(data)
var h: Hash = hashNode(obj) and high(data)
while data[h] != nil:
assert(data[h] != obj)
h = nextTry(h, high(data))
@ -503,7 +503,7 @@ proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
# returns true if obj is already in the string table:
var h: THash = hashNode(obj) and high(t.data)
var h: Hash = hashNode(obj) and high(t.data)
while true:
var it = t.data[h]
if it == nil: break
@ -520,7 +520,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
result = false
proc tableRawGet(t: TTable, key: RootRef): int =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
var h: Hash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key == key:
return h
@ -529,7 +529,7 @@ proc tableRawGet(t: TTable, key: RootRef): int =
proc tableSearch(t: TTable, key, closure: RootRef,
comparator: TCmpProc): RootRef =
var h: THash = hashNode(key) and high(t.data) # start with real hash value
var h: Hash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key == key:
if comparator(t.data[h].val, closure):
@ -544,7 +544,7 @@ proc tableGet(t: TTable, key: RootRef): RootRef =
else: result = nil
proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
var h: THash = hashNode(key) and high(data)
var h: Hash = hashNode(key) and high(data)
while data[h].key != nil:
assert(data[h].key != key)
h = nextTry(h, high(data))
@ -569,7 +569,7 @@ proc tablePut(t: var TTable, key, val: RootRef) =
inc(t.counter)
proc strTableContains(t: TStrTable, n: PSym): bool =
var h: THash = n.name.h and high(t.data) # start with real hash value
var h: Hash = n.name.h and high(t.data) # start with real hash value
while t.data[h] != nil:
if (t.data[h] == n):
return true
@ -577,7 +577,7 @@ proc strTableContains(t: TStrTable, n: PSym): bool =
result = false
proc strTableRawInsert(data: var TSymSeq, n: PSym) =
var h: THash = n.name.h and high(data)
var h: Hash = n.name.h and high(data)
if sfImmediate notin n.flags:
# fast path:
while data[h] != nil:
@ -606,7 +606,7 @@ proc strTableRawInsert(data: var TSymSeq, n: PSym) =
proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
assert prevSym.name.h == newSym.name.h
var h: THash = prevSym.name.h and high(data)
var h: Hash = prevSym.name.h and high(data)
while data[h] != nil:
if data[h] == prevSym:
data[h] = newSym
@ -640,7 +640,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
# It is essential that `n` is written nevertheless!
# This way the newest redefinition is picked by the semantic analyses!
assert n.name != nil
var h: THash = n.name.h and high(t.data)
var h: Hash = n.name.h and high(t.data)
var replaceSlot = -1
while true:
var it = t.data[h]
@ -666,7 +666,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
result = false
proc strTableGet(t: TStrTable, name: PIdent): PSym =
var h: THash = name.h and high(t.data)
var h: Hash = name.h and high(t.data)
while true:
result = t.data[h]
if result == nil: break
@ -694,7 +694,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
excluding: IntSet): PSym =
var h: THash = ti.h and high(tab.data)
var h: Hash = ti.h and high(tab.data)
var start = h
result = tab.data[h]
while result != nil:
@ -743,7 +743,7 @@ proc hasEmptySlot(data: TIdPairSeq): bool =
result = false
proc idTableRawGet(t: TIdTable, key: int): int =
var h: THash
var h: Hash
h = key and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key.id == key:
@ -772,7 +772,7 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
yield (t.data[i].key.id, t.data[i].val)
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
var h: THash
var h: Hash
h = key.id and high(data)
while data[h].key != nil:
assert(data[h].key.id != key.id)
@ -805,7 +805,7 @@ iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
var h: THash
var h: Hash
h = key.id and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key.id == key.id:
@ -824,7 +824,7 @@ proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
result = idNodeTableGet(t, key)
proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
var h: THash
var h: Hash
h = key.id and high(data)
while data[h].key != nil:
assert(data[h].key.id != key.id)
@ -863,7 +863,7 @@ proc initIITable(x: var TIITable) =
for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
proc iiTableRawGet(t: TIITable, key: int): int =
var h: THash
var h: Hash
h = key and high(t.data) # start with real hash value
while t.data[h].key != InvalidKey:
if t.data[h].key == key: return h
@ -876,7 +876,7 @@ proc iiTableGet(t: TIITable, key: int): int =
else: result = InvalidKey
proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
var h: THash
var h: Hash
h = key and high(data)
while data[h].key != InvalidKey:
assert(data[h].key != key)

View file

@ -18,7 +18,7 @@ import
type
TSections = array[TSymKind, Rope]
TDocumentor = object of rstgen.TRstGenerator
TDocumentor = object of rstgen.RstGenerator
modDesc: Rope # module description
id: int # for generating IDs
toc, section: TSections
@ -29,7 +29,7 @@ type
PDoc* = ref TDocumentor ## Alias to type less.
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.TMsgKind, arg: string) {.procvar.} =
msgKind: rst.MsgKind, arg: string) {.procvar.} =
# translate msg kind:
var k: msgs.TMsgKind
case msgKind
@ -53,7 +53,7 @@ proc docgenFindFile(s: string): string {.procvar.} =
proc parseRst(text, filename: string,
line, column: int, hasToc: var bool,
rstOptions: TRstParseOptions): PRstNode =
rstOptions: RstParseOptions): PRstNode =
result = rstParse(text, filename, line, column, hasToc, rstOptions,
docgenFindFile, compilerMsgHandler)

View file

@ -12,7 +12,7 @@
# id. This module is essential for the compiler's performance.
import
hashes, strutils
hashes, strutils, etcpriv
type
TIdObj* = object of RootObj
@ -23,7 +23,7 @@ type
TIdent*{.acyclic.} = object of TIdObj
s*: string
next*: PIdent # for hash-table chaining
h*: THash # hash value of s
h*: Hash # hash value of s
var firstCharIsCS*: bool = true
var buckets*: array[0..4096 * 2 - 1, PIdent]
@ -37,6 +37,8 @@ proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
while j < blen:
while a[i] == '_': inc(i)
while b[j] == '_': inc(j)
while isMagicIdentSeparatorRune(a, i): inc(i, magicIdentSeparatorRuneByteWidth)
while isMagicIdentSeparatorRune(b, j): inc(j, magicIdentSeparatorRuneByteWidth)
# tolower inlined:
var aa = a[i]
var bb = b[j]
@ -65,7 +67,7 @@ proc cmpExact(a, b: cstring, blen: int): int =
var wordCounter = 1
proc getIdent*(identifier: cstring, length: int, h: THash): PIdent =
proc getIdent*(identifier: cstring, length: int, h: Hash): PIdent =
var idx = h and high(buckets)
result = buckets[idx]
var last: PIdent = nil
@ -99,7 +101,7 @@ proc getIdent*(identifier: string): PIdent =
result = getIdent(cstring(identifier), len(identifier),
hashIgnoreStyle(identifier))
proc getIdent*(identifier: string, h: THash): PIdent =
proc getIdent*(identifier: string, h: Hash): PIdent =
result = getIdent(cstring(identifier), len(identifier), h)
proc identEq*(id: PIdent, name: string): bool =

View file

@ -986,6 +986,15 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $ty.kind & ')')
else: internalError(n.sons[0].info, "genAddr")
proc genProcForSymIfNeeded(p: PProc, s: PSym) =
if not p.g.generatedSyms.containsOrIncl(s.id):
let newp = genProc(p, s)
var owner = p
while owner != nil and owner.prc != s.owner:
owner = owner.up
if owner != nil: add(owner.locals, newp)
else: add(p.g.code, newp)
proc genSym(p: PProc, n: PNode, r: var TCompRes) =
var s = n.sym
case s.kind
@ -1021,13 +1030,8 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
discard
elif sfForward in s.flags:
p.g.forwarded.add(s)
elif not p.g.generatedSyms.containsOrIncl(s.id):
let newp = genProc(p, s)
var owner = p
while owner != nil and owner.prc != s.owner:
owner = owner.up
if owner != nil: add(owner.locals, newp)
else: add(p.g.code, newp)
else:
genProcForSymIfNeeded(p, s)
else:
if s.loc.r == nil:
internalError(n.info, "symbol has no generated name: " & s.name.s)
@ -1394,6 +1398,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
of mDotDot:
genProcForSymIfNeeded(p, n.sons[0].sym)
genCall(p, n, r)
else:
genCall(p, n, r)
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);

View file

@ -17,7 +17,7 @@
import
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
wordrecg
wordrecg, etcpriv
const
MaxLineLength* = 80 # lines longer than this lead to a warning
@ -140,10 +140,12 @@ proc isKeyword*(kind: TTokType): bool =
proc isNimIdentifier*(s: string): bool =
if s[0] in SymStartChars:
var i = 1
while i < s.len:
var sLen = s.len
while i < sLen:
if s[i] == '_':
inc(i)
if s[i] notin SymChars: return
elif isMagicIdentSeparatorRune(cstring s, i):
inc(i, magicIdentSeparatorRuneByteWidth)
if s[i] notin SymChars: return
inc(i)
result = true
@ -229,23 +231,6 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
L.dispMessage(info, msg, arg)
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
var pos = L.bufpos # use registers for pos, buf
var buf = L.buf
while true:
if buf[pos] in chars:
add(tok.literal, buf[pos])
inc(pos)
else:
break
if buf[pos] == '_':
if buf[pos+1] notin chars:
lexMessage(L, errInvalidToken, "_")
break
add(tok.literal, '_')
inc(pos)
L.bufpos = pos
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
@ -268,136 +253,195 @@ proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
result = i - start
{.pop.} # overflowChecks
template eatChar(L: var TLexer, t: var TToken, replacementChar: char) =
add(t.literal, replacementChar)
inc(L.bufpos)
template eatChar(L: var TLexer, t: var TToken) =
add(t.literal, L.buf[L.bufpos])
inc(L.bufpos)
proc getNumber(L: var TLexer): TToken =
var
pos, endpos: int
startpos, endpos: int
xi: BiggestInt
# get the base:
const literalishChars = { 'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'c',
'C', 'b', 'B', '_', '.', '\''}
const literalishCharsNoDot = literalishChars - {'.'}
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
var pos = L.bufpos # use registers for pos, buf
var buf = L.buf
while true:
if buf[pos] in chars:
add(tok.literal, buf[pos])
inc(pos)
else:
break
if buf[pos] == '_':
if buf[pos+1] notin chars:
lexMessage(L, errInvalidToken, "_")
break
add(tok.literal, '_')
inc(pos)
L.bufpos = pos
proc matchChars(L: var TLexer, tok: var TToken, chars: set[char]) =
var pos = L.bufpos # use registers for pos, buf
var buf = L.buf
while buf[pos] in chars:
add(tok.literal, buf[pos])
inc(pos)
L.bufpos = pos
proc lexMessageLitNum(L: var TLexer, msg: TMsgKind, startpos: int) =
# Used to get slightly human friendlier err messages.
# Note: the erroneous 'O' char in the character set is intentional
const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O',
'c', 'C', 'b', 'B', '_', '.', '\'', 'd', 'i', 'u'}
var msgPos = L.bufpos
var t: TToken
t.literal = ""
L.bufpos = startpos # Use L.bufpos as pos because of matchChars
matchChars(L, t, literalishChars)
# We must verify +/- specifically so that we're not past the literal
if L.buf[L.bufpos] in {'+', '-'} and
L.buf[L.bufpos - 1] in {'e', 'E'}:
add(t.literal, L.buf[L.bufpos])
inc(L.bufpos)
matchChars(L, t, literalishChars)
if L.buf[L.bufpos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}:
inc(L.bufpos)
add(t.literal, L.buf[L.bufpos])
matchChars(L, t, {'0'..'9'})
L.bufpos = msgPos
lexMessage(L, msg, t.literal)
result.tokType = tkIntLit # int literal until we know better
result.literal = ""
result.base = base10 # BUGFIX
pos = L.bufpos # make sure the literal is correct for error messages:
var eallowed = false
if L.buf[pos] == '0' and L.buf[pos+1] in {'X', 'x'}:
matchUnderscoreChars(L, result, {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x'})
result.base = base10
startpos = L.bufpos
var isAFloatLiteral = false
# First stage: find out base, make verifications, build token literal string
if L.buf[L.bufpos] == '0' and
L.buf[L.bufpos + 1] in {'X', 'x', 'o', 'O', 'c', 'C', 'b', 'B'}:
eatChar(L, result, '0')
case L.buf[L.bufpos]
of 'O':
lexMessageLitNum(L, errInvalidNumberOctalCode, startpos)
of 'x', 'X':
eatChar(L, result, 'x')
matchUnderscoreChars(L, result, {'0'..'9', 'a'..'f', 'A'..'F'})
of 'o', 'c', 'C':
eatChar(L, result, 'c')
matchUnderscoreChars(L, result, {'0'..'7'})
of 'b', 'B':
eatChar(L, result, 'b')
matchUnderscoreChars(L, result, {'0'..'1'})
else:
internalError(getLineInfo(L), "getNumber")
else:
matchUnderscoreChars(L, result, {'0'..'9', 'b', 'B', 'o', 'c', 'C'})
eallowed = true
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
add(result.literal, '.')
inc(L.bufpos)
matchUnderscoreChars(L, result, {'0'..'9'})
eallowed = true
if eallowed and L.buf[L.bufpos] in {'e', 'E'}:
add(result.literal, 'e')
inc(L.bufpos)
if L.buf[L.bufpos] in {'+', '-'}:
add(result.literal, L.buf[L.bufpos])
inc(L.bufpos)
matchUnderscoreChars(L, result, {'0'..'9'})
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
isAFloatLiteral = true
eatChar(L, result, '.')
matchUnderscoreChars(L, result, {'0'..'9'})
if L.buf[L.bufpos] in {'e', 'E'}:
isAFloatLiteral = true
eatChar(L, result, 'e')
if L.buf[L.bufpos] in {'+', '-'}:
eatChar(L, result)
matchUnderscoreChars(L, result, {'0'..'9'})
endpos = L.bufpos
if L.buf[endpos] in {'\'', 'f', 'F', 'i', 'I', 'u', 'U'}:
if L.buf[endpos] == '\'': inc(endpos)
L.bufpos = pos # restore position
case L.buf[endpos]
# Second stage, find out if there's a datatype postfix and handle it
var postPos = endpos
if L.buf[postPos] in {'\'', 'f', 'F', 'd', 'D', 'i', 'I', 'u', 'U'}:
if L.buf[postPos] == '\'':
inc(postPos)
case L.buf[postPos]
of 'f', 'F':
inc(endpos)
if (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
inc(postPos)
if (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
result.tokType = tkFloat32Lit
inc(endpos, 2)
elif (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
inc(postPos, 2)
elif (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
result.tokType = tkFloat64Lit
inc(endpos, 2)
elif (L.buf[endpos] == '1') and
(L.buf[endpos + 1] == '2') and
(L.buf[endpos + 2] == '8'):
inc(postPos, 2)
elif (L.buf[postPos] == '1') and
(L.buf[postPos + 1] == '2') and
(L.buf[postPos + 2] == '8'):
result.tokType = tkFloat128Lit
inc(endpos, 3)
else:
lexMessage(L, errInvalidNumber, result.literal & "'f" & L.buf[endpos])
inc(postPos, 3)
else: # "f" alone defaults to float32
result.tokType = tkFloat32Lit
of 'd', 'D': # ad hoc convenience shortcut for f64
inc(postPos)
result.tokType = tkFloat64Lit
of 'i', 'I':
inc(endpos)
if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
inc(postPos)
if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
result.tokType = tkInt64Lit
inc(endpos, 2)
elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
inc(postPos, 2)
elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
result.tokType = tkInt32Lit
inc(endpos, 2)
elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
inc(postPos, 2)
elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'):
result.tokType = tkInt16Lit
inc(endpos, 2)
elif (L.buf[endpos] == '8'):
inc(postPos, 2)
elif (L.buf[postPos] == '8'):
result.tokType = tkInt8Lit
inc(endpos)
inc(postPos)
else:
lexMessage(L, errInvalidNumber, result.literal & "'i" & L.buf[endpos])
lexMessageLitNum(L, errInvalidNumber, startpos)
of 'u', 'U':
inc(endpos)
if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
inc(postPos)
if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
result.tokType = tkUInt64Lit
inc(endpos, 2)
elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
inc(postPos, 2)
elif (L.buf[postPos] == '3') and (L.buf[postPos + 1] == '2'):
result.tokType = tkUInt32Lit
inc(endpos, 2)
elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
inc(postPos, 2)
elif (L.buf[postPos] == '1') and (L.buf[postPos + 1] == '6'):
result.tokType = tkUInt16Lit
inc(endpos, 2)
elif (L.buf[endpos] == '8'):
inc(postPos, 2)
elif (L.buf[postPos] == '8'):
result.tokType = tkUInt8Lit
inc(endpos)
inc(postPos)
else:
result.tokType = tkUIntLit
else: lexMessage(L, errInvalidNumber, result.literal & "'" & L.buf[endpos])
else:
L.bufpos = pos # restore position
else:
lexMessageLitNum(L, errInvalidNumber, startpos)
# Is there still a literalish char awaiting? Then it's an error!
if L.buf[postPos] in literalishCharsNoDot or
(L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}):
lexMessageLitNum(L, errInvalidNumber, startpos)
# Third stage, extract actual number
L.bufpos = startpos # restore position
var pos: int = startpos
try:
if (L.buf[pos] == '0') and
(L.buf[pos + 1] in {'x', 'X', 'b', 'B', 'o', 'O', 'c', 'C'}):
inc(pos, 2)
xi = 0 # it may be a base prefix
xi = 0 # it is a base prefix
case L.buf[pos - 1] # now look at the optional type suffix:
of 'b', 'B':
result.base = base2
while true:
case L.buf[pos]
of '2'..'9', '.':
lexMessage(L, errInvalidNumber, result.literal)
inc(pos)
of '_':
if L.buf[pos+1] notin {'0'..'1'}:
lexMessage(L, errInvalidToken, "_")
break
inc(pos)
of '0', '1':
while pos < endpos:
if L.buf[pos] != '_':
xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
inc(pos)
else: break
inc(pos)
of 'o', 'c', 'C':
result.base = base8
while true:
case L.buf[pos]
of '8'..'9', '.':
lexMessage(L, errInvalidNumber, result.literal)
inc(pos)
of '_':
if L.buf[pos+1] notin {'0'..'7'}:
lexMessage(L, errInvalidToken, "_")
break
inc(pos)
of '0'..'7':
while pos < endpos:
if L.buf[pos] != '_':
xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0'))
inc(pos)
else: break
of 'O':
lexMessage(L, errInvalidNumber, result.literal)
inc(pos)
of 'x', 'X':
result.base = base16
while true:
while pos < endpos:
case L.buf[pos]
of '_':
if L.buf[pos+1] notin {'0'..'9', 'a'..'f', 'A'..'F'}:
lexMessage(L, errInvalidToken, "_")
break
inc(pos)
of '0'..'9':
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
@ -408,8 +452,10 @@ proc getNumber(L: var TLexer): TToken =
of 'A'..'F':
xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
inc(pos)
else: break
else: internalError(getLineInfo(L), "getNumber")
else:
break
else:
internalError(getLineInfo(L), "getNumber")
case result.tokType
of tkIntLit, tkInt64Lit: result.iNumber = xi
of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
@ -425,7 +471,7 @@ proc getNumber(L: var TLexer): TToken =
# XXX: Test this on big endian machine!
of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
else: internalError(getLineInfo(L), "getNumber")
elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or
elif isAFloatLiteral or (result.tokType == tkFloat32Lit) or
(result.tokType == tkFloat64Lit):
result.fNumber = parseFloat(result.literal)
if result.tokType == tkIntLit: result.tokType = tkFloatLit
@ -441,18 +487,18 @@ proc getNumber(L: var TLexer): TToken =
if result.tokType == tkIntLit:
result.tokType = tkInt64Lit
elif result.tokType in {tkInt8Lit, tkInt16Lit, tkInt32Lit}:
lexMessage(L, errNumberOutOfRange, result.literal)
lexMessageLitNum(L, errNumberOutOfRange, startpos)
elif result.tokType == tkInt8Lit and
(result.iNumber < int8.low or result.iNumber > int8.high):
lexMessage(L, errNumberOutOfRange, result.literal)
lexMessageLitNum(L, errNumberOutOfRange, startpos)
elif result.tokType == tkInt16Lit and
(result.iNumber < int16.low or result.iNumber > int16.high):
lexMessage(L, errNumberOutOfRange, result.literal)
lexMessageLitNum(L, errNumberOutOfRange, startpos)
except ValueError:
lexMessage(L, errInvalidNumber, result.literal)
lexMessageLitNum(L, errInvalidNumber, startpos)
except OverflowError, RangeError:
lexMessage(L, errNumberOutOfRange, result.literal)
L.bufpos = endpos
lexMessageLitNum(L, errNumberOutOfRange, startpos)
L.bufpos = postPos
proc handleHexChar(L: var TLexer, xi: var int) =
case L.buf[L.bufpos]
@ -625,23 +671,34 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
inc(L.bufpos) # skip '
proc getSymbol(L: var TLexer, tok: var TToken) =
var h: THash = 0
var h: Hash = 0
var pos = L.bufpos
var buf = L.buf
while true:
var c = buf[pos]
case c
of 'a'..'z', '0'..'9', '\x80'..'\xFF':
h = h !& ord(c)
if c == '\226' and
buf[pos+1] == '\128' and
buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode
if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars:
lexMessage(L, errInvalidToken, "–")
break
inc(pos, magicIdentSeparatorRuneByteWidth)
else:
h = h !& ord(c)
inc(pos)
of 'A'..'Z':
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h !& ord(c)
inc(pos)
of '_':
if buf[pos+1] notin SymChars:
lexMessage(L, errInvalidToken, "_")
break
inc(pos)
else: break
inc(pos)
h = !$h
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
L.bufpos = pos
@ -652,7 +709,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
proc endOperator(L: var TLexer, tok: var TToken, pos: int,
hash: THash) {.inline.} =
hash: Hash) {.inline.} =
var h = !$hash
tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr
@ -662,7 +719,7 @@ proc endOperator(L: var TLexer, tok: var TToken, pos: int,
proc getOperator(L: var TLexer, tok: var TToken) =
var pos = L.bufpos
var buf = L.buf
var h: THash = 0
var h: Hash = 0
while true:
var c = buf[pos]
if c notin OpChars: break

View file

@ -17,10 +17,9 @@ type
errIntLiteralExpected, errInvalidCharacterConstant,
errClosingTripleQuoteExpected, errClosingQuoteExpected,
errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
errNewlineExpected,
errInvalidModuleName,
errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
@ -143,6 +142,7 @@ const
errInvalidToken: "invalid token: $1",
errLineTooLong: "line too long",
errInvalidNumber: "$1 is not a valid number",
errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
errNumberOutOfRange: "number $1 out of valid range",
errNnotAllowedInCharacter: "\\n not allowed in character literal",
errClosingBracketExpected: "closing ']' expected, but end of file reached",

View file

@ -12,7 +12,7 @@
import
hashes, ast, astalgo, types
proc hashTree(n: PNode): THash =
proc hashTree(n: PNode): Hash =
if n == nil: return
result = ord(n.kind)
case n.kind
@ -53,8 +53,8 @@ proc treesEquivalent(a, b: PNode): bool =
result = true
if result: result = sameTypeOrNil(a.typ, b.typ)
proc nodeTableRawGet(t: TNodeTable, k: THash, key: PNode): int =
var h: THash = k and high(t.data)
proc nodeTableRawGet(t: TNodeTable, k: Hash, key: PNode): int =
var h: Hash = k and high(t.data)
while t.data[h].key != nil:
if (t.data[h].h == k) and treesEquivalent(t.data[h].key, key):
return h
@ -66,9 +66,9 @@ proc nodeTableGet*(t: TNodeTable, key: PNode): int =
if index >= 0: result = t.data[index].val
else: result = low(int)
proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode,
proc nodeTableRawInsert(data: var TNodePairSeq, k: Hash, key: PNode,
val: int) =
var h: THash = k and high(data)
var h: Hash = k and high(data)
while data[h].key != nil: h = nextTry(h, high(data))
assert(data[h].key == nil)
data[h].h = k
@ -77,7 +77,7 @@ proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode,
proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) =
var n: TNodePairSeq
var k: THash = hashTree(key)
var k: Hash = hashTree(key)
var index = nodeTableRawGet(t, k, key)
if index >= 0:
assert(t.data[index].key != nil)
@ -94,7 +94,7 @@ proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) =
proc nodeTableTestOrSet*(t: var TNodeTable, key: PNode, val: int): int =
var n: TNodePairSeq
var k: THash = hashTree(key)
var k: Hash = hashTree(key)
var index = nodeTableRawGet(t, k, key)
if index >= 0:
assert(t.data[index].key != nil)

View file

@ -276,7 +276,7 @@ Numerical constants are of a single type and have the form::
bindigit = '0'..'1'
HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*
DEC_LIT = digit ( ['_'] digit )*
OCT_LIT = '0o' octdigit ( ['_'] octdigit )*
OCT_LIT = '0' ('o' | 'c' | 'C') octdigit ( ['_'] octdigit )*
BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*
INT_LIT = HEX_LIT
@ -297,15 +297,17 @@ Numerical constants are of a single type and have the form::
exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
FLOAT_LIT = digit (['_'] digit)* (('.' (['_'] digit)* [exponent]) |exponent)
FLOAT32_LIT = HEX_LIT '\'' ('f'|'F') '32'
| (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32'
FLOAT64_LIT = HEX_LIT '\'' ('f'|'F') '64'
| (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64'
FLOAT32_SUFFIX = ('f' | 'F') ['32']
FLOAT32_LIT = HEX_LIT '\'' FLOAT32_SUFFIX
| (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT32_SUFFIX
FLOAT64_SUFFIX = ( ('f' | 'F') '64' ) | 'd' | 'D'
FLOAT64_LIT = HEX_LIT '\'' FLOAT64_SUFFIX
| (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT64_SUFFIX
As can be seen in the productions, numerical constants can contain underscores
for readability. Integer and floating point literals may be given in decimal (no
prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal
prefix), binary (prefix ``0b``), octal (prefix ``0o`` or ``0c``) and hexadecimal
(prefix ``0x``) notation.
There exists a literal for each numerical type that is
@ -331,8 +333,11 @@ The type suffixes are:
``'u16`` uint16
``'u32`` uint32
``'u64`` uint64
``'f`` float32
``'d`` float64
``'f32`` float32
``'f64`` float64
``'f128`` float128
================= =========================
Floating point literals may also be in binary, octal or hexadecimal
@ -344,8 +349,8 @@ is approximately 1.72826e35 according to the IEEE floating point standard.
Operators
---------
In Nim one can define his own operators. An operator is any
combination of the following characters::
Nim allows user defined operators. An operator is any combination of the
following characters::
= + - * / < >
@ $ ~ & % |
@ -355,7 +360,7 @@ These keywords are also operators:
``and or not xor shl shr div mod in notin is isnot of``.
`=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they
are used for other notational purposes.
are used for other notational purposes.
``*:`` is as a special case the two tokens `*`:tok: and `:`:tok:
(to support ``var v*: T``).

View file

@ -12,44 +12,46 @@
include "system/syslocks"
type
TLock* = TSysLock ## Nim lock; whether this is re-entrant
Lock* = SysLock ## Nim lock; whether this is re-entrant
## or not is unspecified!
TCond* = TSysCond ## Nim condition variable
proc initLock*(lock: var TLock) {.inline.} =
Cond* = SysCond ## Nim condition variable
{.deprecated: [TLock: Lock, TCond: Cond].}
proc initLock*(lock: var Lock) {.inline.} =
## Initializes the given lock.
initSysLock(lock)
proc deinitLock*(lock: var TLock) {.inline.} =
proc deinitLock*(lock: var Lock) {.inline.} =
## Frees the resources associated with the lock.
deinitSys(lock)
proc tryAcquire*(lock: var TLock): bool =
proc tryAcquire*(lock: var Lock): bool =
## Tries to acquire the given lock. Returns `true` on success.
result = tryAcquireSys(lock)
proc acquire*(lock: var TLock) =
proc acquire*(lock: var Lock) =
## Acquires the given lock.
acquireSys(lock)
proc release*(lock: var TLock) =
proc release*(lock: var Lock) =
## Releases the given lock.
releaseSys(lock)
proc initCond*(cond: var TCond) {.inline.} =
proc initCond*(cond: var Cond) {.inline.} =
## Initializes the given condition variable.
initSysCond(cond)
proc deinitCond*(cond: var TCond) {.inline.} =
proc deinitCond*(cond: var Cond) {.inline.} =
## Frees the resources associated with the lock.
deinitSysCond(cond)
proc wait*(cond: var TCond, lock: var TLock) {.inline.} =
proc wait*(cond: var Cond, lock: var Lock) {.inline.} =
## waits on the condition variable `cond`.
waitSysCond(cond, lock)
proc signal*(cond: var TCond) {.inline.} =
proc signal*(cond: var Cond) {.inline.} =
## sends a signal to the condition variable `cond`.
signalSysCond(cond)

View file

@ -9,7 +9,7 @@
## This module implements an interface to Nim's `runtime type information`:idx:
## (`RTTI`:idx:).
## Note that even though ``TAny`` and its operations hide the nasty low level
## Note that even though ``Any`` and its operations hide the nasty low level
## details from its clients, it remains inherently unsafe!
##
## See the `marshal <marshal.html>`_ module for what this module allows you
@ -23,7 +23,7 @@ include "system/hti.nim"
{.pop.}
type
TAnyKind* = enum ## what kind of ``any`` it is
AnyKind* = enum ## what kind of ``any`` it is
akNone = 0, ## invalid any
akBool = 1, ## any represents a ``bool``
akChar = 2, ## any represents a ``char``
@ -55,9 +55,9 @@ type
akUInt32 = 43, ## any represents an unsigned int32
akUInt64 = 44, ## any represents an unsigned int64
TAny* = object ## can represent any nim value; NOTE: the wrapped
Any* = object ## can represent any nim value; NOTE: the wrapped
## value can be modified with its wrapper! This means
## that ``TAny`` keeps a non-traced pointer to its
## that ``Any`` keeps a non-traced pointer to its
## wrapped value and **must not** live longer than
## its wrapped value.
value: pointer
@ -69,6 +69,7 @@ type
TGenericSeq {.importc.} = object
len, space: int
PGenSeq = ptr TGenericSeq
{.deprecated: [TAny: Any, TAnyKind: AnyKind].}
const
GenericSeqSize = (2 * sizeof(int))
@ -103,58 +104,58 @@ proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
else:
result = n.sons[n.len]
proc newAny(value: pointer, rawType: PNimType): TAny =
proc newAny(value: pointer, rawType: PNimType): Any =
result.value = value
result.rawType = rawType
when declared(system.TVarSlot):
proc toAny*(x: TVarSlot): TAny {.inline.} =
## constructs a ``TAny`` object from a variable slot ``x``.
when declared(system.VarSlot):
proc toAny*(x: VarSlot): Any {.inline.} =
## constructs a ``Any`` object from a variable slot ``x``.
## This captures `x`'s address, so `x` can be modified with its
## ``TAny`` wrapper! The client needs to ensure that the wrapper
## ``Any`` wrapper! The client needs to ensure that the wrapper
## **does not** live longer than `x`!
## This is provided for easier reflection capabilities of a debugger.
result.value = x.address
result.rawType = x.typ
proc toAny*[T](x: var T): TAny {.inline.} =
## constructs a ``TAny`` object from `x`. This captures `x`'s address, so
## `x` can be modified with its ``TAny`` wrapper! The client needs to ensure
proc toAny*[T](x: var T): Any {.inline.} =
## constructs a ``Any`` object from `x`. This captures `x`'s address, so
## `x` can be modified with its ``Any`` wrapper! The client needs to ensure
## that the wrapper **does not** live longer than `x`!
result.value = addr(x)
result.rawType = cast[PNimType](getTypeInfo(x))
proc kind*(x: TAny): TAnyKind {.inline.} =
proc kind*(x: Any): AnyKind {.inline.} =
## get the type kind
result = TAnyKind(ord(x.rawType.kind))
result = AnyKind(ord(x.rawType.kind))
proc size*(x: TAny): int {.inline.} =
proc size*(x: Any): int {.inline.} =
## returns the size of `x`'s type.
result = x.rawType.size
proc baseTypeKind*(x: TAny): TAnyKind {.inline.} =
proc baseTypeKind*(x: Any): AnyKind {.inline.} =
## get the base type's kind; ``akNone`` is returned if `x` has no base type.
if x.rawType.base != nil:
result = TAnyKind(ord(x.rawType.base.kind))
result = AnyKind(ord(x.rawType.base.kind))
proc baseTypeSize*(x: TAny): int {.inline.} =
proc baseTypeSize*(x: Any): int {.inline.} =
## returns the size of `x`'s basetype.
if x.rawType.base != nil:
result = x.rawType.base.size
proc invokeNew*(x: TAny) =
proc invokeNew*(x: Any) =
## performs ``new(x)``. `x` needs to represent a ``ref``.
assert x.rawType.kind == tyRef
var z = newObj(x.rawType, x.rawType.base.size)
genericAssign(x.value, addr(z), x.rawType)
proc invokeNewSeq*(x: TAny, len: int) =
proc invokeNewSeq*(x: Any, len: int) =
## performs ``newSeq(x, len)``. `x` needs to represent a ``seq``.
assert x.rawType.kind == tySequence
var z = newSeq(x.rawType, len)
genericShallowAssign(x.value, addr(z), x.rawType)
proc extendSeq*(x: TAny) =
proc extendSeq*(x: Any) =
## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``.
assert x.rawType.kind == tySequence
var y = cast[ptr PGenSeq](x.value)[]
@ -164,7 +165,7 @@ proc extendSeq*(x: TAny) =
cast[ppointer](x.value)[] = z
#genericShallowAssign(x.value, addr(z), x.rawType)
proc setObjectRuntimeType*(x: TAny) =
proc setObjectRuntimeType*(x: Any) =
## this needs to be called to set `x`'s runtime object type field.
assert x.rawType.kind == tyObject
objectInit(x.value, x.rawType)
@ -173,7 +174,7 @@ proc skipRange(x: PNimType): PNimType {.inline.} =
result = x
if result.kind == tyRange: result = result.base
proc `[]`*(x: TAny, i: int): TAny =
proc `[]`*(x: Any, i: int): Any =
## accessor for an any `x` that represents an array or a sequence.
case x.rawType.kind
of tyArray:
@ -190,7 +191,7 @@ proc `[]`*(x: TAny, i: int): TAny =
return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base)
else: assert false
proc `[]=`*(x: TAny, i: int, y: TAny) =
proc `[]=`*(x: Any, i: int, y: Any) =
## accessor for an any `x` that represents an array or a sequence.
case x.rawType.kind
of tyArray:
@ -209,7 +210,7 @@ proc `[]=`*(x: TAny, i: int, y: TAny) =
genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType)
else: assert false
proc len*(x: TAny): int =
proc len*(x: Any): int =
## len for an any `x` that represents an array or a sequence.
case x.rawType.kind
of tyArray: result = x.rawType.size div x.rawType.base.size
@ -217,20 +218,20 @@ proc len*(x: TAny): int =
else: assert false
proc base*(x: TAny): TAny =
## returns base TAny (useful for inherited object types).
proc base*(x: Any): Any =
## returns base Any (useful for inherited object types).
result.rawType = x.rawType.base
result.value = x.value
proc isNil*(x: TAny): bool =
proc isNil*(x: Any): bool =
## `isNil` for an any `x` that represents a sequence, string, cstring,
## proc or some pointer type.
assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer,
tySequence, tyProc}
result = isNil(cast[ppointer](x.value)[])
proc getPointer*(x: TAny): pointer =
proc getPointer*(x: Any): pointer =
## retrieve the pointer value out of `x`. ``x`` needs to be of kind
## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``,
## ``akPointer``, ``akSequence``.
@ -238,7 +239,7 @@ proc getPointer*(x: TAny): pointer =
tySequence, tyProc}
result = cast[ppointer](x.value)[]
proc setPointer*(x: TAny, y: pointer) =
proc setPointer*(x: Any, y: pointer) =
## sets the pointer value of `x`. ``x`` needs to be of kind
## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``,
## ``akPointer``, ``akSequence``.
@ -247,7 +248,7 @@ proc setPointer*(x: TAny, y: pointer) =
cast[ppointer](x.value)[] = y
proc fieldsAux(p: pointer, n: ptr TNimNode,
ret: var seq[tuple[name: cstring, any: TAny]]) =
ret: var seq[tuple[name: cstring, any: Any]]) =
case n.kind
of nkNone: assert(false)
of nkSlot:
@ -260,7 +261,7 @@ proc fieldsAux(p: pointer, n: ptr TNimNode,
ret.add((n.name, newAny(p +!! n.offset, n.typ)))
if m != nil: fieldsAux(p, m, ret)
iterator fields*(x: TAny): tuple[name: string, any: TAny] =
iterator fields*(x: Any): tuple[name: string, any: Any] =
## iterates over every active field of the any `x` that represents an object
## or a tuple.
assert x.rawType.kind in {tyTuple, tyObject}
@ -269,7 +270,7 @@ iterator fields*(x: TAny): tuple[name: string, any: TAny] =
# XXX BUG: does not work yet, however is questionable anyway
when false:
if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
var ret: seq[tuple[name: cstring, any: TAny]] = @[]
var ret: seq[tuple[name: cstring, any: Any]] = @[]
if t.kind == tyObject:
while true:
fieldsAux(p, t.node, ret)
@ -314,7 +315,7 @@ proc getFieldNode(p: pointer, n: ptr TNimNode,
var m = selectBranch(p, n)
if m != nil: result = getFieldNode(p, m, name)
proc `[]=`*(x: TAny, fieldName: string, value: TAny) =
proc `[]=`*(x: Any, fieldName: string, value: Any) =
## sets a field of `x`; `x` represents an object or a tuple.
var t = x.rawType
# XXX BUG: does not work yet, however is questionable anyway
@ -328,7 +329,7 @@ proc `[]=`*(x: TAny, fieldName: string, value: TAny) =
else:
raise newException(ValueError, "invalid field name: " & fieldName)
proc `[]`*(x: TAny, fieldName: string): TAny =
proc `[]`*(x: Any, fieldName: string): Any =
## gets a field of `x`; `x` represents an object or a tuple.
var t = x.rawType
# XXX BUG: does not work yet, however is questionable anyway
@ -342,44 +343,44 @@ proc `[]`*(x: TAny, fieldName: string): TAny =
else:
raise newException(ValueError, "invalid field name: " & fieldName)
proc `[]`*(x: TAny): TAny =
proc `[]`*(x: Any): Any =
## dereference operation for the any `x` that represents a ptr or a ref.
assert x.rawType.kind in {tyRef, tyPtr}
result.value = cast[ppointer](x.value)[]
result.rawType = x.rawType.base
proc `[]=`*(x, y: TAny) =
proc `[]=`*(x, y: Any) =
## dereference operation for the any `x` that represents a ptr or a ref.
assert x.rawType.kind in {tyRef, tyPtr}
assert y.rawType == x.rawType.base
genericAssign(cast[ppointer](x.value)[], y.value, y.rawType)
proc getInt*(x: TAny): int =
proc getInt*(x: Any): int =
## retrieve the int value out of `x`. `x` needs to represent an int.
assert skipRange(x.rawType).kind == tyInt
result = cast[ptr int](x.value)[]
proc getInt8*(x: TAny): int8 =
proc getInt8*(x: Any): int8 =
## retrieve the int8 value out of `x`. `x` needs to represent an int8.
assert skipRange(x.rawType).kind == tyInt8
result = cast[ptr int8](x.value)[]
proc getInt16*(x: TAny): int16 =
proc getInt16*(x: Any): int16 =
## retrieve the int16 value out of `x`. `x` needs to represent an int16.
assert skipRange(x.rawType).kind == tyInt16
result = cast[ptr int16](x.value)[]
proc getInt32*(x: TAny): int32 =
proc getInt32*(x: Any): int32 =
## retrieve the int32 value out of `x`. `x` needs to represent an int32.
assert skipRange(x.rawType).kind == tyInt32
result = cast[ptr int32](x.value)[]
proc getInt64*(x: TAny): int64 =
proc getInt64*(x: Any): int64 =
## retrieve the int64 value out of `x`. `x` needs to represent an int64.
assert skipRange(x.rawType).kind == tyInt64
result = cast[ptr int64](x.value)[]
proc getBiggestInt*(x: TAny): BiggestInt =
proc getBiggestInt*(x: Any): BiggestInt =
## retrieve the integer value out of `x`. `x` needs to represent
## some integer, a bool, a char, an enum or a small enough bit set.
## The value might be sign-extended to ``BiggestInt``.
@ -405,7 +406,7 @@ proc getBiggestInt*(x: TAny): BiggestInt =
of tyUInt32: result = BiggestInt(cast[ptr uint32](x.value)[])
else: assert false
proc setBiggestInt*(x: TAny, y: BiggestInt) =
proc setBiggestInt*(x: Any, y: BiggestInt) =
## sets the integer value of `x`. `x` needs to represent
## some integer, a bool, a char, an enum or a small enough bit set.
var t = skipRange(x.rawType)
@ -430,36 +431,36 @@ proc setBiggestInt*(x: TAny, y: BiggestInt) =
of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
else: assert false
proc getUInt*(x: TAny): uint =
proc getUInt*(x: Any): uint =
## retrieve the uint value out of `x`, `x` needs to represent an uint.
assert skipRange(x.rawType).kind == tyUInt
result = cast[ptr uint](x.value)[]
proc getUInt8*(x: TAny): uint8 =
proc getUInt8*(x: Any): uint8 =
## retrieve the uint8 value out of `x`, `x` needs to represent an
## uint8.
assert skipRange(x.rawType).kind == tyUInt8
result = cast[ptr uint8](x.value)[]
proc getUInt16*(x: TAny): uint16 =
proc getUInt16*(x: Any): uint16 =
## retrieve the uint16 value out of `x`, `x` needs to represent an
## uint16.
assert skipRange(x.rawType).kind == tyUInt16
result = cast[ptr uint16](x.value)[]
proc getUInt32*(x: TAny): uint32 =
proc getUInt32*(x: Any): uint32 =
## retrieve the uint32 value out of `x`, `x` needs to represent an
## uint32.
assert skipRange(x.rawType).kind == tyUInt32
result = cast[ptr uint32](x.value)[]
proc getUInt64*(x: TAny): uint64 =
proc getUInt64*(x: Any): uint64 =
## retrieve the uint64 value out of `x`, `x` needs to represent an
## uint64.
assert skipRange(x.rawType).kind == tyUInt64
result = cast[ptr uint64](x.value)[]
proc getBiggestUint*(x: TAny): uint64 =
proc getBiggestUint*(x: Any): uint64 =
## retrieve the unsigned integer value out of `x`. `x` needs to
## represent an unsigned integer.
var t = skipRange(x.rawType)
@ -471,7 +472,7 @@ proc getBiggestUint*(x: TAny): uint64 =
of tyUInt64: result = uint64(cast[ptr uint64](x.value)[])
else: assert false
proc setBiggestUint*(x: TAny; y: uint64) =
proc setBiggestUint*(x: Any; y: uint64) =
## sets the unsigned integer value of `c`. `c` needs to represent an
## unsigned integer.
var t = skipRange(x.rawType)
@ -483,25 +484,25 @@ proc setBiggestUint*(x: TAny; y: uint64) =
of tyUInt64: cast[ptr uint64](x.value)[] = uint64(y)
else: assert false
proc getChar*(x: TAny): char =
proc getChar*(x: Any): char =
## retrieve the char value out of `x`. `x` needs to represent a char.
var t = skipRange(x.rawType)
assert t.kind == tyChar
result = cast[ptr char](x.value)[]
proc getBool*(x: TAny): bool =
proc getBool*(x: Any): bool =
## retrieve the bool value out of `x`. `x` needs to represent a bool.
var t = skipRange(x.rawType)
assert t.kind == tyBool
result = cast[ptr bool](x.value)[]
proc skipRange*(x: TAny): TAny =
proc skipRange*(x: Any): Any =
## skips the range information of `x`.
assert x.rawType.kind == tyRange
result.rawType = x.rawType.base
result.value = x.value
proc getEnumOrdinal*(x: TAny, name: string): int =
proc getEnumOrdinal*(x: Any, name: string): int =
## gets the enum field ordinal from `name`. `x` needs to represent an enum
## but is only used to access the type information. In case of an error
## ``low(int)`` is returned.
@ -517,7 +518,7 @@ proc getEnumOrdinal*(x: TAny, name: string): int =
return s[i].offset
result = low(int)
proc getEnumField*(x: TAny, ordinalValue: int): string =
proc getEnumField*(x: Any, ordinalValue: int): string =
## gets the enum field name as a string. `x` needs to represent an enum
## but is only used to access the type information. The field name of
## `ordinalValue` is returned.
@ -535,26 +536,26 @@ proc getEnumField*(x: TAny, ordinalValue: int): string =
if s[i].offset == e: return $s[i].name
result = $e
proc getEnumField*(x: TAny): string =
proc getEnumField*(x: Any): string =
## gets the enum field name as a string. `x` needs to represent an enum.
result = getEnumField(x, getBiggestInt(x).int)
proc getFloat*(x: TAny): float =
proc getFloat*(x: Any): float =
## retrieve the float value out of `x`. `x` needs to represent an float.
assert skipRange(x.rawType).kind == tyFloat
result = cast[ptr float](x.value)[]
proc getFloat32*(x: TAny): float32 =
proc getFloat32*(x: Any): float32 =
## retrieve the float32 value out of `x`. `x` needs to represent an float32.
assert skipRange(x.rawType).kind == tyFloat32
result = cast[ptr float32](x.value)[]
proc getFloat64*(x: TAny): float64 =
proc getFloat64*(x: Any): float64 =
## retrieve the float64 value out of `x`. `x` needs to represent an float64.
assert skipRange(x.rawType).kind == tyFloat64
result = cast[ptr float64](x.value)[]
proc getBiggestFloat*(x: TAny): BiggestFloat =
proc getBiggestFloat*(x: Any): BiggestFloat =
## retrieve the float value out of `x`. `x` needs to represent
## some float. The value is extended to ``BiggestFloat``.
case skipRange(x.rawType).kind
@ -563,7 +564,7 @@ proc getBiggestFloat*(x: TAny): BiggestFloat =
of tyFloat64: result = BiggestFloat(cast[ptr float64](x.value)[])
else: assert false
proc setBiggestFloat*(x: TAny, y: BiggestFloat) =
proc setBiggestFloat*(x: Any, y: BiggestFloat) =
## sets the float value of `x`. `x` needs to represent
## some float.
case skipRange(x.rawType).kind
@ -572,29 +573,29 @@ proc setBiggestFloat*(x: TAny, y: BiggestFloat) =
of tyFloat64: cast[ptr float64](x.value)[] = y
else: assert false
proc getString*(x: TAny): string =
proc getString*(x: Any): string =
## retrieve the string value out of `x`. `x` needs to represent a string.
assert x.rawType.kind == tyString
if not isNil(cast[ptr pointer](x.value)[]):
result = cast[ptr string](x.value)[]
proc setString*(x: TAny, y: string) =
proc setString*(x: Any, y: string) =
## sets the string value of `x`. `x` needs to represent a string.
assert x.rawType.kind == tyString
cast[ptr string](x.value)[] = y
proc getCString*(x: TAny): cstring =
proc getCString*(x: Any): cstring =
## retrieve the cstring value out of `x`. `x` needs to represent a cstring.
assert x.rawType.kind == tyCString
result = cast[ptr cstring](x.value)[]
proc assign*(x, y: TAny) =
## copies the value of `y` to `x`. The assignment operator for ``TAny``
proc assign*(x, y: Any) =
## copies the value of `y` to `x`. The assignment operator for ``Any``
## does NOT do this; it performs a shallow copy instead!
assert y.rawType == x.rawType
genericAssign(x.value, y.value, y.rawType)
iterator elements*(x: TAny): int =
iterator elements*(x: Any): int =
## iterates over every element of `x` that represents a Nim bitset.
assert x.rawType.kind == tySet
var typ = x.rawType
@ -616,7 +617,7 @@ iterator elements*(x: TAny): int =
if (u and (1'i64 shl int64(i))) != 0'i64:
yield i+typ.node.len
proc inclSetElement*(x: TAny, elem: int) =
proc inclSetElement*(x: Any, elem: int) =
## includes an element `elem` in `x`. `x` needs to represent a Nim bitset.
assert x.rawType.kind == tySet
var typ = x.rawType

View file

@ -13,27 +13,28 @@
import strutils, mysql
type
TDbConn* = PMySQL ## encapsulates a database connection
TRow* = seq[string] ## a row of a dataset. NULL database values will be
DbConn* = PMySQL ## encapsulates a database connection
Row* = seq[string] ## a row of a dataset. NULL database values will be
## transformed always to the empty string.
EDb* = object of IOError ## exception that is raised if a database error occurs
TSqlQuery* = distinct string ## an SQL query string
SqlQuery* = distinct string ## an SQL query string
FDb* = object of IOEffect ## effect that denotes a database operation
FReadDb* = object of FDb ## effect that denotes a read operation
FWriteDb* = object of FDb ## effect that denotes a write operation
{.deprecated: [TRow: Row, TSqlQuery: SqlQuery, TDbConn: DbConn].}
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
## constructs a TSqlQuery from the string `query`. This is supposed to be
proc sql*(query: string): SqlQuery {.noSideEffect, inline.} =
## constructs a SqlQuery from the string `query`. This is supposed to be
## used as a raw-string-literal modifier:
## ``sql"update user set counter = counter + 1"``
##
## If assertions are turned off, it does nothing. If assertions are turned
## on, later versions will check the string for valid syntax.
result = TSqlQuery(query)
result = SqlQuery(query)
proc dbError(db: TDbConn) {.noreturn.} =
proc dbError(db: DbConn) {.noreturn.} =
## raises an EDb exception.
var e: ref EDb
new(e)
@ -48,7 +49,7 @@ proc dbError*(msg: string) {.noreturn.} =
raise e
when false:
proc dbQueryOpt*(db: TDbConn, query: string, args: varargs[string, `$`]) =
proc dbQueryOpt*(db: DbConn, query: string, args: varargs[string, `$`]) =
var stmt = mysql_stmt_init(db)
if stmt == nil: dbError(db)
if mysql_stmt_prepare(stmt, query, len(query)) != 0:
@ -65,7 +66,7 @@ proc dbQuote*(s: string): string =
else: add(result, c)
add(result, '\'')
proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
result = ""
var a = 0
for c in items(string(formatstr)):
@ -78,23 +79,23 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc tryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool {.
proc tryExec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {.
tags: [FReadDB, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var q = dbFormat(query, args)
return mysql.realQuery(db, q, q.len) == 0'i32
proc rawExec(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) =
proc rawExec(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) =
var q = dbFormat(query, args)
if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db)
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDB, FWriteDb].} =
## executes the query and raises EDB if not successful.
var q = dbFormat(query, args)
if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db)
proc newRow(L: int): TRow =
proc newRow(L: int): Row =
newSeq(result, L)
for i in 0..L-1: result[i] = ""
@ -103,8 +104,8 @@ proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) =
while mysql.fetchRow(sqlres) != nil: discard
mysql.freeResult(sqlres)
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator fastRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
## query, the results can be undefined. For MySQL this is the case!.
@ -126,10 +127,10 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
yield result
properFreeResult(sqlres, row)
proc getRow*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
proc getRow*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## retrieves a single row. If the query doesn't return any rows, this proc
## will return a TRow with empty strings for each column.
## will return a Row with empty strings for each column.
rawExec(db, query, args)
var sqlres = mysql.useResult(db)
if sqlres != nil:
@ -145,8 +146,8 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
add(result[i], row[i])
properFreeResult(sqlres, row)
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
proc getAllRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): seq[Row] {.tags: [FReadDB].} =
## executes the query and returns the whole result dataset.
result = @[]
rawExec(db, query, args)
@ -168,12 +169,12 @@ proc getAllRows*(db: TDbConn, query: TSqlQuery,
inc(j)
mysql.freeResult(sqlres)
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator rows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## same as `fastRows`, but slower and safe.
for r in items(getAllRows(db, query, args)): yield r
proc getValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -183,7 +184,7 @@ proc getValue*(db: TDbConn, query: TSqlQuery,
result = row[0]
break
proc tryInsertId*(db: TDbConn, query: TSqlQuery,
proc tryInsertId*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error.
@ -193,14 +194,14 @@ proc tryInsertId*(db: TDbConn, query: TSqlQuery,
else:
result = mysql.insertId(db)
proc insertId*(db: TDbConn, query: TSqlQuery,
proc insertId*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row.
result = tryInsertID(db, query, args)
if result < 0: dbError(db)
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.
tags: [FReadDB, FWriteDb].} =
## runs the query (typically "UPDATE") and returns the
@ -208,11 +209,11 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
rawExec(db, query, args)
result = mysql.affectedRows(db)
proc close*(db: TDbConn) {.tags: [FDb].} =
proc close*(db: DbConn) {.tags: [FDb].} =
## closes the database connection.
if db != nil: mysql.close(db)
proc open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): DbConn {.
tags: [FDb].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established.
@ -230,8 +231,8 @@ proc open*(connection, user, password, database: string): TDbConn {.
db_mysql.close(result)
dbError(errmsg)
proc setEncoding*(connection: TDbConn, encoding: string): bool {.
proc setEncoding*(connection: DbConn, encoding: string): bool {.
tags: [FDb].} =
## sets the encoding of a database connection, returns true for
## success, false for failure.
result = mysql.set_character_set(connection, encoding) == 0
result = mysql.set_character_set(connection, encoding) == 0

View file

@ -13,28 +13,30 @@
import strutils, postgres
type
TDbConn* = PPGconn ## encapsulates a database connection
TRow* = seq[string] ## a row of a dataset. NULL database values will be
DbConn* = PPGconn ## encapsulates a database connection
Row* = seq[string] ## a row of a dataset. NULL database values will be
## transformed always to the empty string.
EDb* = object of IOError ## exception that is raised if a database error occurs
TSqlQuery* = distinct string ## an SQL query string
TSqlPrepared* = distinct string ## a identifier for the prepared queries
SqlQuery* = distinct string ## an SQL query string
SqlPrepared* = distinct string ## a identifier for the prepared queries
FDb* = object of IOEffect ## effect that denotes a database operation
FReadDb* = object of FDb ## effect that denotes a read operation
FWriteDb* = object of FDb ## effect that denotes a write operation
{.deprecated: [TRow: Row, TSqlQuery: SqlQuery, TDbConn: DbConn,
TSqlPrepared: SqlPrepared].}
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
## constructs a TSqlQuery from the string `query`. This is supposed to be
proc sql*(query: string): SqlQuery {.noSideEffect, inline.} =
## constructs a SqlQuery from the string `query`. This is supposed to be
## used as a raw-string-literal modifier:
## ``sql"update user set counter = counter + 1"``
##
## If assertions are turned off, it does nothing. If assertions are turned
## on, later versions will check the string for valid syntax.
result = TSqlQuery(query)
result = SqlQuery(query)
proc dbError*(db: TDbConn) {.noreturn.} =
proc dbError*(db: DbConn) {.noreturn.} =
## raises an EDb exception.
var e: ref EDb
new(e)
@ -56,7 +58,7 @@ proc dbQuote*(s: string): string =
else: add(result, c)
add(result, '\'')
proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
result = ""
var a = 0
for c in items(string(formatstr)):
@ -69,7 +71,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc tryExec*(db: TDbConn, query: TSqlQuery,
proc tryExec*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var arr = allocCStringArray(args)
@ -79,7 +81,7 @@ proc tryExec*(db: TDbConn, query: TSqlQuery,
result = pqresultStatus(res) == PGRES_COMMAND_OK
pqclear(res)
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDB, FWriteDb].} =
## executes the query and raises EDB if not successful.
var arr = allocCStringArray(args)
@ -89,7 +91,7 @@ proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
pqclear(res)
proc exec*(db: TDbConn, stmtName: TSqlPrepared,
proc exec*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string]) {.tags: [FReadDB, FWriteDb].} =
var arr = allocCStringArray(args)
var res = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
@ -98,11 +100,11 @@ proc exec*(db: TDbConn, stmtName: TSqlPrepared,
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
pqclear(res)
proc newRow(L: int): TRow =
proc newRow(L: int): Row =
newSeq(result, L)
for i in 0..L-1: result[i] = ""
proc setupQuery(db: TDbConn, query: TSqlQuery,
proc setupQuery(db: DbConn, query: SqlQuery,
args: varargs[string]): PPGresult =
var arr = allocCStringArray(args)
result = pqexecParams(db, query.string, int32(args.len), nil, arr,
@ -110,7 +112,7 @@ proc setupQuery(db: TDbConn, query: TSqlQuery,
deallocCStringArray(arr)
if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
proc setupQuery(db: TDbConn, stmtName: TSqlPrepared,
proc setupQuery(db: DbConn, stmtName: SqlPrepared,
args: varargs[string]): PPGresult =
var arr = allocCStringArray(args)
result = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
@ -118,13 +120,13 @@ proc setupQuery(db: TDbConn, stmtName: TSqlPrepared,
deallocCStringArray(arr)
if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
proc prepare*(db: TDbConn; stmtName: string, query: TSqlQuery;
nParams: int): TSqlPrepared =
proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
nParams: int): SqlPrepared =
var res = pqprepare(db, stmtName, query.string, int32(nParams), nil)
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
return TSqlPrepared(stmtName)
return SqlPrepared(stmtName)
proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
for col in 0..cols-1:
setLen(r[col], 0)
let x = pqgetvalue(res, line, col)
@ -133,8 +135,8 @@ proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
else:
add(r[col], x)
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator fastRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
## query, the results can be undefined. For Postgres it is safe though.
@ -146,8 +148,8 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
yield result
pqclear(res)
iterator fastRows*(db: TDbConn, stmtName: TSqlPrepared,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator fastRows*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## executes the prepared query and iterates over the result dataset.
var res = setupQuery(db, stmtName, args)
var L = pqNfields(res)
@ -157,44 +159,44 @@ iterator fastRows*(db: TDbConn, stmtName: TSqlPrepared,
yield result
pqClear(res)
proc getRow*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
proc getRow*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## retrieves a single row. If the query doesn't return any rows, this proc
## will return a TRow with empty strings for each column.
## will return a Row with empty strings for each column.
var res = setupQuery(db, query, args)
var L = pqnfields(res)
result = newRow(L)
setRow(res, result, 0, L)
pqclear(res)
proc getRow*(db: TDbConn, stmtName: TSqlPrepared,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
proc getRow*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
var res = setupQuery(db, stmtName, args)
var L = pqNfields(res)
result = newRow(L)
setRow(res, result, 0, L)
pqClear(res)
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
proc getAllRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): seq[Row] {.tags: [FReadDB].} =
## executes the query and returns the whole result dataset.
result = @[]
for r in fastRows(db, query, args):
result.add(r)
proc getAllRows*(db: TDbConn, stmtName: TSqlPrepared,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
proc getAllRows*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): seq[Row] {.tags: [FReadDB].} =
## executes the prepared query and returns the whole result dataset.
result = @[]
for r in fastRows(db, stmtName, args):
result.add(r)
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
iterator rows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDB].} =
## same as `fastRows`, but slower and safe.
for r in items(getAllRows(db, query, args)): yield r
proc getValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -202,20 +204,20 @@ proc getValue*(db: TDbConn, query: TSqlQuery,
var x = pqgetvalue(setupQuery(db, query, args), 0, 0)
result = if isNil(x): "" else: $x
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
proc tryInsertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].}=
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error. For Postgre this adds
## ``RETURNING id`` to the query, so it only works if your primary key is
## named ``id``.
var x = pqgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"),
var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING id"),
args), 0, 0)
if not isNil(x):
result = parseBiggestInt($x)
else:
result = -1
proc insertID*(db: TDbConn, query: TSqlQuery,
proc insertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row. For Postgre this adds
@ -224,7 +226,7 @@ proc insertID*(db: TDbConn, query: TSqlQuery,
result = tryInsertID(db, query, args)
if result < 0: dbError(db)
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [
FReadDB, FWriteDb].} =
## executes the query (typically "UPDATE") and returns the
@ -235,11 +237,11 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
result = parseBiggestInt($pqcmdTuples(res))
pqclear(res)
proc close*(db: TDbConn) {.tags: [FDb].} =
proc close*(db: DbConn) {.tags: [FDb].} =
## closes the database connection.
if db != nil: pqfinish(db)
proc open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): DbConn {.
tags: [FDb].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established.
@ -261,8 +263,8 @@ proc open*(connection, user, password, database: string): TDbConn {.
result = pqsetdbLogin(nil, nil, nil, nil, database, user, password)
if pqStatus(result) != CONNECTION_OK: dbError(result) # result = nil
proc setEncoding*(connection: TDbConn, encoding: string): bool {.
proc setEncoding*(connection: DbConn, encoding: string): bool {.
tags: [FDb].} =
## sets the encoding of a database connection, returns true for
## success, false for failure.
return pqsetClientEncoding(connection, encoding) == 0
return pqsetClientEncoding(connection, encoding) == 0

View file

@ -13,27 +13,28 @@
import strutils, sqlite3
type
TDbConn* = PSqlite3 ## encapsulates a database connection
TRow* = seq[string] ## a row of a dataset. NULL database values will be
DbConn* = PSqlite3 ## encapsulates a database connection
Row* = seq[string] ## a row of a dataset. NULL database values will be
## transformed always to the empty string.
EDb* = object of IOError ## exception that is raised if a database error occurs
TSqlQuery* = distinct string ## an SQL query string
SqlQuery* = distinct string ## an SQL query string
FDb* = object of IOEffect ## effect that denotes a database operation
FReadDb* = object of FDb ## effect that denotes a read operation
FWriteDb* = object of FDb ## effect that denotes a write operation
{.deprecated: [TRow: Row, TSqlQuery: SqlQuery, TDbConn: DbConn].}
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
## constructs a TSqlQuery from the string `query`. This is supposed to be
proc sql*(query: string): SqlQuery {.noSideEffect, inline.} =
## constructs a SqlQuery from the string `query`. This is supposed to be
## used as a raw-string-literal modifier:
## ``sql"update user set counter = counter + 1"``
##
## If assertions are turned off, it does nothing. If assertions are turned
## on, later versions will check the string for valid syntax.
result = TSqlQuery(query)
result = SqlQuery(query)
proc dbError(db: TDbConn) {.noreturn.} =
proc dbError(db: DbConn) {.noreturn.} =
## raises an EDb exception.
var e: ref EDb
new(e)
@ -55,7 +56,7 @@ proc dbQuote(s: string): string =
else: add(result, c)
add(result, '\'')
proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
result = ""
var a = 0
for c in items(string(formatstr)):
@ -65,7 +66,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc tryExec*(db: TDbConn, query: TSqlQuery,
proc tryExec*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): bool {.tags: [FReadDb, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var q = dbFormat(query, args)
@ -74,29 +75,29 @@ proc tryExec*(db: TDbConn, query: TSqlQuery,
if step(stmt) == SQLITE_DONE:
result = finalize(stmt) == SQLITE_OK
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDb, FWriteDb].} =
## executes the query and raises EDB if not successful.
if not tryExec(db, query, args): dbError(db)
proc newRow(L: int): TRow =
proc newRow(L: int): Row =
newSeq(result, L)
for i in 0..L-1: result[i] = ""
proc setupQuery(db: TDbConn, query: TSqlQuery,
proc setupQuery(db: DbConn, query: SqlQuery,
args: varargs[string]): Pstmt =
var q = dbFormat(query, args)
if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
proc setRow(stmt: Pstmt, r: var TRow, cols: cint) =
proc setRow(stmt: Pstmt, r: var Row, cols: cint) =
for col in 0..cols-1:
setLen(r[col], column_bytes(stmt, col)) # set capacity
setLen(r[col], 0)
let x = column_text(stmt, col)
if not isNil(x): add(r[col], x)
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDb].} =
iterator fastRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDb].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
## query, the results can be undefined. For Sqlite it is safe though.
@ -108,10 +109,10 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
yield result
if finalize(stmt) != SQLITE_OK: dbError(db)
proc getRow*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDb].} =
proc getRow*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDb].} =
## retrieves a single row. If the query doesn't return any rows, this proc
## will return a TRow with empty strings for each column.
## will return a Row with empty strings for each column.
var stmt = setupQuery(db, query, args)
var L = (column_count(stmt))
result = newRow(L)
@ -119,19 +120,19 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
setRow(stmt, result, L)
if finalize(stmt) != SQLITE_OK: dbError(db)
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDb].} =
proc getAllRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): seq[Row] {.tags: [FReadDb].} =
## executes the query and returns the whole result dataset.
result = @[]
for r in fastRows(db, query, args):
result.add(r)
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDb].} =
iterator rows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [FReadDb].} =
## same as `FastRows`, but slower and safe.
for r in fastRows(db, query, args): yield r
proc getValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDb].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -148,7 +149,7 @@ proc getValue*(db: TDbConn, query: TSqlQuery,
result = ""
if finalize(stmt) != SQLITE_OK: dbError(db)
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
proc tryInsertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64
{.tags: [FWriteDb], raises: [].} =
## executes the query (typically "INSERT") and returns the
@ -162,7 +163,7 @@ proc tryInsertID*(db: TDbConn, query: TSqlQuery,
if finalize(stmt) != SQLITE_OK:
result = -1
proc insertID*(db: TDbConn, query: TSqlQuery,
proc insertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row. For Postgre this adds
@ -171,7 +172,7 @@ proc insertID*(db: TDbConn, query: TSqlQuery,
result = tryInsertID(db, query, args)
if result < 0: dbError(db)
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.
tags: [FReadDb, FWriteDb].} =
## executes the query (typically "UPDATE") and returns the
@ -179,21 +180,21 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
exec(db, query, args)
result = changes(db)
proc close*(db: TDbConn) {.tags: [FDb].} =
proc close*(db: DbConn) {.tags: [FDb].} =
## closes the database connection.
if sqlite3.close(db) != SQLITE_OK: dbError(db)
proc open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): DbConn {.
tags: [FDb].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established. Only the ``connection`` parameter is used for ``sqlite``.
var db: TDbConn
var db: DbConn
if sqlite3.open(connection, db) == SQLITE_OK:
result = db
else:
dbError(db)
proc setEncoding*(connection: TDbConn, encoding: string): bool {.
proc setEncoding*(connection: DbConn, encoding: string): bool {.
tags: [FDb].} =
## sets the encoding of a database connection, returns true for
## success, false for failure.

View file

@ -17,23 +17,24 @@ from sdl import PSurface # Bug
from sdl_ttf import openFont, closeFont
type
TRect* = tuple[x, y, width, height: int]
TPoint* = tuple[x, y: int]
Rect* = tuple[x, y, width, height: int]
Point* = tuple[x, y: int]
PSurface* = ref TSurface ## a surface to draw onto
TSurface* {.pure, final.} = object
PSurface* = ref Surface ## a surface to draw onto
Surface* {.pure, final.} = object
w*, h*: Natural
s*: sdl.PSurface
EGraphics* = object of IOError
TFont {.pure, final.} = object
Font {.pure, final.} = object
f: sdl_ttf.PFont
color: sdl.TColor
PFont* = ref TFont ## represents a font
color: sdl.Color
PFont* = ref Font ## represents a font
{.deprecated: [TSurface: Surface, TFont: Font, TRect: Rect, TPoint: Point].}
proc toSdlColor*(c: Color): sdl.TColor =
## Convert colors.TColor to sdl.TColor
proc toSdlColor*(c: Color): sdl.Color =
## Convert colors.Color to sdl.Color
var x = c.extractRGB
result.r = x.r and 0xff
result.g = x.g and 0xff
@ -45,8 +46,8 @@ proc createSdlColor*(sur: PSurface, c: Color, alpha: int = 0): int32 =
return sdl.mapRGBA(sur.s.format, x.r and 0xff, x.g and 0xff,
x.b and 0xff, alpha and 0xff)
proc toSdlRect*(r: TRect): sdl.TRect =
## Convert ``graphics.TRect`` to ``sdl.TRect``.
proc toSdlRect*(r: Rect): sdl.Rect =
## Convert ``graphics.Rect`` to ``sdl.Rect``.
result.x = int16(r.x)
result.y = int16(r.y)
result.w = uint16(r.width)
@ -103,8 +104,9 @@ proc writeToBMP*(sur: PSurface, filename: string) =
raise newException(IOError, "cannot write: " & filename)
type
TPixels = array[0..1000_000-1, int32]
PPixels = ptr TPixels
Pixels = array[0..1000_000-1, int32]
PPixels = ptr Pixels
{.deprecated: [TPixels: Pixels].}
template setPix(video, pitch, x, y, col: expr): stmt =
video[y * pitch + x] = int32(col)
@ -128,7 +130,7 @@ proc setPixel(sur: PSurface, x, y: Natural, col: colors.Color) {.inline.} =
#pixs[y * (sur.s.pitch div colSize) + x] = int(col)
setPix(pixs, sur.s.pitch.int div ColSize, x, y, col)
proc `[]`*(sur: PSurface, p: TPoint): Color =
proc `[]`*(sur: PSurface, p: Point): Color =
## get pixel at position `p`. No range checking is done!
result = getPixel(sur, p.x, p.y)
@ -136,7 +138,7 @@ proc `[]`*(sur: PSurface, x, y: int): Color =
## get pixel at position ``(x, y)``. No range checking is done!
result = getPixel(sur, x, y)
proc `[]=`*(sur: PSurface, p: TPoint, col: Color) =
proc `[]=`*(sur: PSurface, p: Point, col: Color) =
## set the pixel at position `p`. No range checking is done!
setPixel(sur, p.x, p.y, col)
@ -144,10 +146,10 @@ proc `[]=`*(sur: PSurface, x, y: int, col: Color) =
## set the pixel at position ``(x, y)``. No range checking is done!
setPixel(sur, x, y, col)
proc blit*(destSurf: PSurface, destRect: TRect, srcSurf: PSurface,
srcRect: TRect) =
proc blit*(destSurf: PSurface, destRect: Rect, srcSurf: PSurface,
srcRect: Rect) =
## Copies ``srcSurf`` into ``destSurf``
var destTRect, srcTRect: sdl.TRect
var destTRect, srcTRect: sdl.Rect
destTRect.x = int16(destRect.x)
destTRect.y = int16(destRect.y)
@ -168,7 +170,7 @@ proc textBounds*(text: string, font = defaultFont): tuple[width, height: int] =
result.width = int(w)
result.height = int(h)
proc drawText*(sur: PSurface, p: TPoint, text: string, font = defaultFont) =
proc drawText*(sur: PSurface, p: Point, text: string, font = defaultFont) =
## Draws text with a transparent background, at location ``p`` with the given
## font.
var textSur: PSurface # This surface will have the text drawn on it
@ -179,7 +181,7 @@ proc drawText*(sur: PSurface, p: TPoint, text: string, font = defaultFont) =
# Merge the text surface with sur
sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
proc drawText*(sur: PSurface, p: TPoint, text: string,
proc drawText*(sur: PSurface, p: Point, text: string,
bg: Color, font = defaultFont) =
## Draws text, at location ``p`` with font ``font``. ``bg``
## is the background color.
@ -189,7 +191,7 @@ proc drawText*(sur: PSurface, p: TPoint, text: string,
# Merge the text surface with sur
sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
proc drawCircle*(sur: PSurface, p: TPoint, r: Natural, color: Color) =
proc drawCircle*(sur: PSurface, p: Point, r: Natural, color: Color) =
## draws a circle with center `p` and radius `r` with the given color
## onto the surface `sur`.
var video = cast[PPixels](sur.s.pixels)
@ -229,7 +231,7 @@ proc `>-<`(val: int, s: PSurface): int {.inline.} =
proc `>|<`(val: int, s: PSurface): int {.inline.} =
return if val < 0: 0 elif val >= s.h: s.h-1 else: val
proc drawLine*(sur: PSurface, p1, p2: TPoint, color: Color) =
proc drawLine*(sur: PSurface, p1, p2: Point, color: Color) =
## draws a line between the two points `p1` and `p2` with the given color
## onto the surface `sur`.
var stepx, stepy: int = 0
@ -291,7 +293,7 @@ proc drawVerLine*(sur: PSurface, x, y, h: Natural, color: Color) =
for i in 0 .. min(sur.s.h-y, h)-1:
setPix(video, pitch, x, y + i, color)
proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: Color) =
proc fillCircle*(s: PSurface, p: Point, r: Natural, color: Color) =
## draws a circle with center `p` and radius `r` with the given color
## onto the surface `sur` and fills it.
var a = 1 - r
@ -319,7 +321,7 @@ proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: Color) =
drawVerLine(s, x - py - 1, y - px, px, color)
px = px + 1
proc drawRect*(sur: PSurface, r: TRect, color: Color) =
proc drawRect*(sur: PSurface, r: Rect, color: Color) =
## draws a rectangle.
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch.int div ColSize
@ -337,7 +339,7 @@ proc drawRect*(sur: PSurface, r: TRect, color: Color) =
setPix(video, pitch, r.x, r.y + i, color)
setPix(video, pitch, r.x + minW - 1, r.y + i, color) # Draw right side
proc fillRect*(sur: PSurface, r: TRect, col: Color) =
proc fillRect*(sur: PSurface, r: Rect, col: Color) =
## Fills a rectangle using sdl's ``FillRect`` function.
var rect = toSdlRect(r)
if sdl.fillRect(sur.s, addr(rect), sur.createSdlColor(col)) == -1:
@ -424,7 +426,7 @@ template cround(x: expr): expr = ipart(x + 0.5)
template fpart(x: expr): expr = x - ipart(x)
template rfpart(x: expr): expr = 1.0 - fpart(x)
proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: Color) =
proc drawLineAA*(sur: PSurface, p1, p2: Point, color: Color) =
## Draws a anti-aliased line from ``p1`` to ``p2``, using Xiaolin Wu's
## line algorithm
var (x1, x2, y1, y2) = (p1.x.toFloat(), p2.x.toFloat(),
@ -490,9 +492,9 @@ proc fillSurface*(sur: PSurface, color: Color) =
template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
immediate.} =
## Simple template which creates an event loop. ``Event`` is the name of the
## variable containing the TEvent object.
## variable containing the Event object.
while true:
var event: sdl.TEvent
var event: sdl.Event
if sdl.waitEvent(addr(event)) == 1:
actions

View file

@ -135,7 +135,7 @@ else:
var cur, old: Termios
discard fd.tcgetattr(cur.addr)
old = cur
cur.c_lflag = cur.c_lflag and not Tcflag(ECHO)
cur.c_lflag = cur.c_lflag and not Cflag(ECHO)
discard fd.tcsetattr(TCSADRAIN, cur.addr)
stdout.write prompt
result = stdin.readLine(password)

View file

@ -15,11 +15,12 @@
import openssl, strutils, os
type
TSecureSocket* = object
SecureSocket* = object
ssl: SslPtr
bio: BIO
{.deprecated: [TSecureSocket: SecureSocket].}
proc connect*(sock: var TSecureSocket, address: string,
proc connect*(sock: var SecureSocket, address: string,
port: int): int =
## Connects to the specified `address` on the specified `port`.
## Returns the result of the certificate validation.
@ -52,7 +53,7 @@ proc connect*(sock: var TSecureSocket, address: string,
result = SSL_get_verify_result(sock.ssl)
proc recvLine*(sock: TSecureSocket, line: var TaintedString): bool =
proc recvLine*(sock: SecureSocket, line: var TaintedString): bool =
## Acts in a similar fashion to the `recvLine` in the sockets module.
## Returns false when no data is available to be read.
## `Line` must be initialized and not nil!
@ -71,19 +72,19 @@ proc recvLine*(sock: TSecureSocket, line: var TaintedString): bool =
add(line.string, c)
proc send*(sock: TSecureSocket, data: string) =
proc send*(sock: SecureSocket, data: string) =
## Writes `data` to the socket.
if BIO_write(sock.bio, data, data.len.cint) <= 0:
raiseOSError(osLastError())
proc close*(sock: TSecureSocket) =
proc close*(sock: SecureSocket) =
## Closes the socket
if BIO_free(sock.bio) <= 0:
ERR_print_errors_fp(stderr)
raiseOSError(osLastError())
when not defined(testing) and isMainModule:
var s: TSecureSocket
var s: SecureSocket
echo connect(s, "smtp.gmail.com", 465)
#var buffer: array[0..255, char]

View file

@ -13,18 +13,18 @@ import
streams, libzip, times, os, strutils
type
TZipArchive* = object of RootObj ## represents a zip archive
ZipArchive* = object of RootObj ## represents a zip archive
mode: FileMode
w: PZip
{.deprecated: [TZipArchive: ZipArchive].}
proc zipError(z: var TZipArchive) =
proc zipError(z: var ZipArchive) =
var e: ref IOError
new(e)
e.msg = $zip_strerror(z.w)
raise e
proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool =
proc open*(z: var ZipArchive, filename: string, mode: FileMode = fmRead): bool =
## Opens a zip file for reading, writing or appending. All file modes are
## supported. Returns true iff successful, false otherwise.
var err, flags: int32
@ -38,11 +38,11 @@ proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool
z.mode = mode
result = z.w != nil
proc close*(z: var TZipArchive) =
proc close*(z: var ZipArchive) =
## Closes a zip file.
zip_close(z.w)
proc createDir*(z: var TZipArchive, dir: string) =
proc createDir*(z: var ZipArchive, dir: string) =
## Creates a directory within the `z` archive. This does not fail if the
## directory already exists. Note that for adding a file like
## ``"path1/path2/filename"`` it is not necessary
@ -52,7 +52,7 @@ proc createDir*(z: var TZipArchive, dir: string) =
discard zip_add_dir(z.w, dir)
zip_error_clear(z.w)
proc addFile*(z: var TZipArchive, dest, src: string) =
proc addFile*(z: var ZipArchive, dest, src: string) =
## Adds the file `src` to the archive `z` with the name `dest`. `dest`
## may contain a path that will be created.
assert(z.mode != fmRead)
@ -67,13 +67,13 @@ proc addFile*(z: var TZipArchive, dest, src: string) =
zip_source_free(zipsrc)
zipError(z)
proc addFile*(z: var TZipArchive, file: string) =
proc addFile*(z: var ZipArchive, file: string) =
## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is
## the name of the destination.
addFile(z, file, file)
proc mySourceCallback(state, data: pointer, len: int,
cmd: TZipSourceCmd): int {.cdecl.} =
cmd: ZipSourceCmd): int {.cdecl.} =
var src = cast[Stream](state)
case cmd
of ZIP_SOURCE_OPEN:
@ -86,7 +86,7 @@ proc mySourceCallback(state, data: pointer, len: int,
zip_stat_init(stat)
stat.size = high(int32)-1 # we don't know the size
stat.mtime = getTime()
result = sizeof(TZipStat)
result = sizeof(ZipStat)
of ZIP_SOURCE_ERROR:
var err = cast[ptr array[0..1, cint]](data)
err[0] = ZIP_ER_INTERNAL
@ -95,7 +95,7 @@ proc mySourceCallback(state, data: pointer, len: int,
of constZIP_SOURCE_FREE: GC_unref(src)
else: assert(false)
proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
proc addFile*(z: var ZipArchive, dest: string, src: Stream) =
## Adds a file named with `dest` to the archive `z`. `dest`
## may contain a path. The file's content is read from the `src` stream.
assert(z.mode != fmRead)
@ -114,7 +114,7 @@ type
atEnd: bool
PZipFileStream* =
ref TZipFileStream ## a reader stream of a file within a zip archive
ref ZipFileStream ## a reader stream of a file within a zip archive
proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f)
proc fsAtEnd(s: Stream): bool = PZipFileStream(s).atEnd
@ -134,7 +134,7 @@ proc newZipFileStream(f: PZipFile): PZipFileStream =
# ----------------------------------------------------------------------------
proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
proc getStream*(z: var ZipArchive, filename: string): PZipFileStream =
## returns a stream that can be used to read the file named `filename`
## from the archive `z`. Returns nil in case of an error.
## The returned stream does not support the `setPosition`, `getPosition`,
@ -142,7 +142,7 @@ proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
var x = zip_fopen(z.w, filename, 0'i32)
if x != nil: result = newZipFileStream(x)
iterator walkFiles*(z: var TZipArchive): string =
iterator walkFiles*(z: var ZipArchive): string =
## walks over all files in the archive `z` and returns the filename
## (including the path).
var i = 0'i32
@ -152,7 +152,7 @@ iterator walkFiles*(z: var TZipArchive): string =
inc(i)
proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
proc extractFile*(z: var ZipArchive, srcFile: string, dest: Stream) =
## extracts a file from the zip archive `z` to the destination stream.
var strm = getStream(z, srcFile)
while true:
@ -162,13 +162,13 @@ proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
dest.flush()
strm.close()
proc extractFile*(z: var TZipArchive, srcFile: string, dest: string) =
proc extractFile*(z: var ZipArchive, srcFile: string, dest: string) =
## extracts a file from the zip archive `z` to the destination filename.
var file = newFileStream(dest, fmWrite)
extractFile(z, srcFile, file)
file.close()
proc extractAll*(z: var TZipArchive, dest: string) =
proc extractAll*(z: var ZipArchive, dest: string) =
## extracts all files from archive `z` to the destination directory.
for file in walkFiles(z):
if file.endsWith("/"):
@ -177,7 +177,7 @@ proc extractAll*(z: var TZipArchive, dest: string) =
extractFile(z, file, dest / file)
when not defined(testing) and isMainModule:
var zip: TZipArchive
var zip: ZipArchive
if not zip.open("nim-0.11.0.zip"):
raise newException(IOError, "opening zip failed")
zip.extractAll("test")

View file

@ -15,7 +15,7 @@ import
strutils
type
TTokenClass* = enum
TokenClass* = enum
gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber,
gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit,
gtLongStringLit, gtCharLit, gtEscapeSequence, # escape sequence like \xff
@ -23,20 +23,22 @@ type
gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler,
gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel,
gtReference, gtOther
TGeneralTokenizer* = object of RootObj
kind*: TTokenClass
GeneralTokenizer* = object of RootObj
kind*: TokenClass
start*, length*: int
buf: cstring
pos: int
state: TTokenClass
state: TokenClass
TSourceLanguage* = enum
SourceLanguage* = enum
langNone, langNim, langNimrod, langCpp, langCsharp, langC, langJava
{.deprecated: [TSourceLanguage: SourceLanguage, TTokenClass: TokenClass,
TGeneralTokenizer: GeneralTokenizer].}
const
sourceLanguageToStr*: array[TSourceLanguage, string] = ["none",
sourceLanguageToStr*: array[SourceLanguage, string] = ["none",
"Nim", "Nimrod", "C++", "C#", "C", "Java"]
tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace",
tokenClassToStr*: array[TokenClass, string] = ["Eof", "None", "Whitespace",
"DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber",
"Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit",
"EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment",
@ -58,29 +60,29 @@ const
"template", "try", "tuple", "type", "using", "var", "when", "while", "with",
"without", "xor", "yield"]
proc getSourceLanguage*(name: string): TSourceLanguage =
for i in countup(succ(low(TSourceLanguage)), high(TSourceLanguage)):
proc getSourceLanguage*(name: string): SourceLanguage =
for i in countup(succ(low(SourceLanguage)), high(SourceLanguage)):
if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0:
return i
result = langNone
proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: cstring) =
proc initGeneralTokenizer*(g: var GeneralTokenizer, buf: cstring) =
g.buf = buf
g.kind = low(TTokenClass)
g.kind = low(TokenClass)
g.start = 0
g.length = 0
g.state = low(TTokenClass)
g.state = low(TokenClass)
var pos = 0 # skip initial whitespace:
while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
g.pos = pos
proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) =
proc initGeneralTokenizer*(g: var GeneralTokenizer, buf: string) =
initGeneralTokenizer(g, cstring(buf))
proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) =
proc deinitGeneralTokenizer*(g: var GeneralTokenizer) =
discard
proc nimGetKeyword(id: string): TTokenClass =
proc nimGetKeyword(id: string): TokenClass =
for k in nimKeywords:
if cmpIgnoreStyle(id, k) == 0: return gtKeyword
result = gtIdentifier
@ -92,7 +94,7 @@ proc nimGetKeyword(id: string): TTokenClass =
else:
result = gtIdentifier
proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int =
proc nimNumberPostfix(g: var GeneralTokenizer, position: int): int =
var pos = position
if g.buf[pos] == '\'':
inc(pos)
@ -110,7 +112,7 @@ proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int =
discard
result = pos
proc nimNumber(g: var TGeneralTokenizer, position: int): int =
proc nimNumber(g: var GeneralTokenizer, position: int): int =
const decChars = {'0'..'9', '_'}
var pos = position
g.kind = gtDecNumber
@ -130,7 +132,7 @@ const
OpChars = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
proc nimNextToken(g: var TGeneralTokenizer) =
proc nimNextToken(g: var GeneralTokenizer) =
const
hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'}
octChars = {'0'..'7', '_'}
@ -278,7 +280,7 @@ proc nimNextToken(g: var TGeneralTokenizer) =
assert false, "nimNextToken: produced an empty token"
g.pos = pos
proc generalNumber(g: var TGeneralTokenizer, position: int): int =
proc generalNumber(g: var GeneralTokenizer, position: int): int =
const decChars = {'0'..'9'}
var pos = position
g.kind = gtDecNumber
@ -294,7 +296,7 @@ proc generalNumber(g: var TGeneralTokenizer, position: int): int =
while g.buf[pos] in decChars: inc(pos)
result = pos
proc generalStrLit(g: var TGeneralTokenizer, position: int): int =
proc generalStrLit(g: var GeneralTokenizer, position: int): int =
const
decChars = {'0'..'9'}
hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
@ -355,12 +357,13 @@ proc isKeywordIgnoreCase(x: openArray[string], y: string): int =
result = - 1
type
TTokenizerFlag = enum
TokenizerFlag = enum
hasPreprocessor, hasNestedComments
TTokenizerFlags = set[TTokenizerFlag]
TokenizerFlags = set[TokenizerFlag]
{.deprecated: [TTokenizerFlag: TokenizerFlag, TTokenizerFlags: TokenizerFlags].}
proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
flags: TTokenizerFlags) =
proc clikeNextToken(g: var GeneralTokenizer, keywords: openArray[string],
flags: TokenizerFlags) =
const
hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
octChars = {'0'..'7'}
@ -493,7 +496,7 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
assert false, "clikeNextToken: produced an empty token"
g.pos = pos
proc cNextToken(g: var TGeneralTokenizer) =
proc cNextToken(g: var GeneralTokenizer) =
const
keywords: array[0..36, string] = ["_Bool", "_Complex", "_Imaginary", "auto",
"break", "case", "char", "const", "continue", "default", "do", "double",
@ -503,7 +506,7 @@ proc cNextToken(g: var TGeneralTokenizer) =
"volatile", "while"]
clikeNextToken(g, keywords, {hasPreprocessor})
proc cppNextToken(g: var TGeneralTokenizer) =
proc cppNextToken(g: var GeneralTokenizer) =
const
keywords: array[0..47, string] = ["asm", "auto", "break", "case", "catch",
"char", "class", "const", "continue", "default", "delete", "do", "double",
@ -514,7 +517,7 @@ proc cppNextToken(g: var TGeneralTokenizer) =
"union", "unsigned", "virtual", "void", "volatile", "while"]
clikeNextToken(g, keywords, {hasPreprocessor})
proc csharpNextToken(g: var TGeneralTokenizer) =
proc csharpNextToken(g: var GeneralTokenizer) =
const
keywords: array[0..76, string] = ["abstract", "as", "base", "bool", "break",
"byte", "case", "catch", "char", "checked", "class", "const", "continue",
@ -529,7 +532,7 @@ proc csharpNextToken(g: var TGeneralTokenizer) =
"virtual", "void", "volatile", "while"]
clikeNextToken(g, keywords, {hasPreprocessor})
proc javaNextToken(g: var TGeneralTokenizer) =
proc javaNextToken(g: var GeneralTokenizer) =
const
keywords: array[0..52, string] = ["abstract", "assert", "boolean", "break",
"byte", "case", "catch", "char", "class", "const", "continue", "default",
@ -541,7 +544,7 @@ proc javaNextToken(g: var TGeneralTokenizer) =
"try", "void", "volatile", "while"]
clikeNextToken(g, keywords, {})
proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) =
proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) =
case lang
of langNone: assert false
of langNim, langNimrod: nimNextToken(g)

View file

@ -15,7 +15,7 @@ import
os, strutils, rstast
type
TRstParseOption* = enum ## options for the RST parser
RstParseOption* = enum ## options for the RST parser
roSkipPounds, ## skip ``#`` at line beginning (documentation
## embedded in Nim comments)
roSupportSmilies, ## make the RST parser support smilies like ``:)``
@ -23,14 +23,14 @@ type
## it for sandboxing)
roSupportMarkdown ## support additional features of markdown
TRstParseOptions* = set[TRstParseOption]
RstParseOptions* = set[RstParseOption]
TMsgClass* = enum
MsgClass* = enum
mcHint = "Hint",
mcWarning = "Warning",
mcError = "Error"
TMsgKind* = enum ## the possible messages
MsgKind* = enum ## the possible messages
meCannotOpenFile,
meExpected,
meGridTableNotImplemented,
@ -42,12 +42,14 @@ type
mwUnsupportedLanguage,
mwUnsupportedField
TMsgHandler* = proc (filename: string, line, col: int, msgKind: TMsgKind,
MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind,
arg: string) {.nimcall.} ## what to do in case of an error
TFindFileHandler* = proc (filename: string): string {.nimcall.}
FindFileHandler* = proc (filename: string): string {.nimcall.}
{.deprecated: [TRstParseOptions: RstParseOptions, TRstParseOption: RstParseOption,
TMsgKind: MsgKind].}
const
messages: array [TMsgKind, string] = [
messages: array [MsgKind, string] = [
meCannotOpenFile: "cannot open '$1'",
meExpected: "'$1' expected",
meGridTableNotImplemented: "grid table is not implemented",
@ -111,23 +113,24 @@ const
}
type
TTokType = enum
TokType = enum
tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther
TToken = object # a RST token
kind*: TTokType # the type of the token
Token = object # a RST token
kind*: TokType # the type of the token
ival*: int # the indentation or parsed integer value
symbol*: string # the parsed symbol as string
line*, col*: int # line and column of the token
TTokenSeq = seq[TToken]
TLexer = object of RootObj
TokenSeq = seq[Token]
Lexer = object of RootObj
buf*: cstring
bufpos*: int
line*, col*, baseIndent*: int
skipPounds*: bool
{.deprecated: [TTokType: TokType, TToken: Token, TTokenSeq: TokenSeq,
TLexer: Lexer].}
proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
proc getThing(L: var Lexer, tok: var Token, s: set[char]) =
tok.kind = tkWord
tok.line = L.line
tok.col = L.col
@ -139,7 +142,7 @@ proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
inc(L.col, pos - L.bufpos)
L.bufpos = pos
proc getAdornment(L: var TLexer, tok: var TToken) =
proc getAdornment(L: var Lexer, tok: var Token) =
tok.kind = tkAdornment
tok.line = L.line
tok.col = L.col
@ -152,7 +155,7 @@ proc getAdornment(L: var TLexer, tok: var TToken) =
inc(L.col, pos - L.bufpos)
L.bufpos = pos
proc getIndentAux(L: var TLexer, start: int): int =
proc getIndentAux(L: var Lexer, start: int): int =
var pos = start
var buf = L.buf
# skip the newline (but include it in the token!)
@ -181,7 +184,7 @@ proc getIndentAux(L: var TLexer, start: int): int =
result = getIndentAux(L, pos)
L.bufpos = pos # no need to set back buf
proc getIndent(L: var TLexer, tok: var TToken) =
proc getIndent(L: var Lexer, tok: var Token) =
tok.col = 0
tok.kind = tkIndent # skip the newline (but include it in the token!)
tok.ival = getIndentAux(L, L.bufpos)
@ -191,7 +194,7 @@ proc getIndent(L: var TLexer, tok: var TToken) =
tok.ival = max(tok.ival - L.baseIndent, 0)
tok.symbol = "\n" & spaces(tok.ival)
proc rawGetTok(L: var TLexer, tok: var TToken) =
proc rawGetTok(L: var Lexer, tok: var Token) =
tok.symbol = ""
tok.ival = 0
var c = L.buf[L.bufpos]
@ -222,8 +225,8 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
inc(L.col)
tok.col = max(tok.col - L.baseIndent, 0)
proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
var L: TLexer
proc getTokens(buffer: string, skipPounds: bool, tokens: var TokenSeq): int =
var L: Lexer
var length = len(tokens)
L.buf = cstring(buffer)
L.line = 0 # skip UTF-8 BOM
@ -253,31 +256,31 @@ proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
tokens[0].kind = tkIndent
type
TLevelMap = array[char, int]
TSubstitution = object
LevelMap = array[char, int]
Substitution = object
key*: string
value*: PRstNode
TSharedState = object
options: TRstParseOptions # parsing options
SharedState = object
options: RstParseOptions # parsing options
uLevel, oLevel: int # counters for the section levels
subs: seq[TSubstitution] # substitutions
refs: seq[TSubstitution] # references
underlineToLevel: TLevelMap # Saves for each possible title adornment
subs: seq[Substitution] # substitutions
refs: seq[Substitution] # references
underlineToLevel: LevelMap # Saves for each possible title adornment
# character its level in the
# current document.
# This is for single underline adornments.
overlineToLevel: TLevelMap # Saves for each possible title adornment
overlineToLevel: LevelMap # Saves for each possible title adornment
# character its level in the current
# document.
# This is for over-underline adornments.
msgHandler: TMsgHandler # How to handle errors.
findFile: TFindFileHandler # How to find files.
msgHandler: MsgHandler # How to handle errors.
findFile: FindFileHandler # How to find files.
PSharedState = ref TSharedState
TRstParser = object of RootObj
PSharedState = ref SharedState
RstParser = object of RootObj
idx*: int
tok*: TTokenSeq
tok*: TokenSeq
s*: PSharedState
indentStack*: seq[int]
filename*: string
@ -285,8 +288,12 @@ type
hasToc*: bool
EParseError* = object of ValueError
{.deprecated: [TLevelMap: LevelMap, TSubstitution: Substitution,
TSharedState: SharedState, TRstParser: RstParser,
TMsgHandler: MsgHandler, TFindFileHandler: FindFileHandler,
TMsgClass: MsgClass].}
proc whichMsgClass*(k: TMsgKind): TMsgClass =
proc whichMsgClass*(k: MsgKind): MsgClass =
## returns which message class `k` belongs to.
case ($k)[1]
of 'e', 'E': result = mcError
@ -294,7 +301,7 @@ proc whichMsgClass*(k: TMsgKind): TMsgClass =
of 'h', 'H': result = mcHint
else: assert false, "msgkind does not fit naming scheme"
proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
proc defaultMsgHandler*(filename: string, line, col: int, msgkind: MsgKind,
arg: string) {.procvar.} =
let mc = msgkind.whichMsgClass
let a = messages[msgkind] % arg
@ -306,9 +313,9 @@ proc defaultFindFile*(filename: string): string {.procvar.} =
if existsFile(filename): result = filename
else: result = ""
proc newSharedState(options: TRstParseOptions,
findFile: TFindFileHandler,
msgHandler: TMsgHandler): PSharedState =
proc newSharedState(options: RstParseOptions,
findFile: FindFileHandler,
msgHandler: MsgHandler): PSharedState =
new(result)
result.subs = @[]
result.refs = @[]
@ -316,34 +323,34 @@ proc newSharedState(options: TRstParseOptions,
result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler
result.findFile = if not isNil(findFile): findFile else: defaultFindFile
proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) =
p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
p.col + p.tok[p.idx].col, msgKind, arg)
proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) =
proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string, line, col: int) =
p.s.msgHandler(p.filename, p.line + line,
p.col + col, msgKind, arg)
proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
proc rstMessage(p: RstParser, msgKind: MsgKind) =
p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
p.col + p.tok[p.idx].col, msgKind,
p.tok[p.idx].symbol)
when false:
proc corrupt(p: TRstParser) =
proc corrupt(p: RstParser) =
assert p.indentStack[0] == 0
for i in 1 .. high(p.indentStack): assert p.indentStack[i] < 1_000
proc currInd(p: TRstParser): int =
proc currInd(p: RstParser): int =
result = p.indentStack[high(p.indentStack)]
proc pushInd(p: var TRstParser, ind: int) =
proc pushInd(p: var RstParser, ind: int) =
add(p.indentStack, ind)
proc popInd(p: var TRstParser) =
proc popInd(p: var RstParser) =
if len(p.indentStack) > 1: setLen(p.indentStack, len(p.indentStack) - 1)
proc initParser(p: var TRstParser, sharedState: PSharedState) =
proc initParser(p: var RstParser, sharedState: PSharedState) =
p.indentStack = @[0]
p.tok = @[]
p.idx = 0
@ -393,7 +400,7 @@ proc rstnodeToRefname(n: PRstNode): string =
var b = false
rstnodeToRefnameAux(n, result, b)
proc findSub(p: var TRstParser, n: PRstNode): int =
proc findSub(p: var RstParser, n: PRstNode): int =
var key = addNodes(n)
# the spec says: if no exact match, try one without case distinction:
for i in countup(0, high(p.s.subs)):
@ -404,7 +411,7 @@ proc findSub(p: var TRstParser, n: PRstNode): int =
return i
result = -1
proc setSub(p: var TRstParser, key: string, value: PRstNode) =
proc setSub(p: var RstParser, key: string, value: PRstNode) =
var length = len(p.s.subs)
for i in countup(0, length - 1):
if key == p.s.subs[i].key:
@ -414,7 +421,7 @@ proc setSub(p: var TRstParser, key: string, value: PRstNode) =
p.s.subs[length].key = key
p.s.subs[length].value = value
proc setRef(p: var TRstParser, key: string, value: PRstNode) =
proc setRef(p: var RstParser, key: string, value: PRstNode) =
var length = len(p.s.refs)
for i in countup(0, length - 1):
if key == p.s.refs[i].key:
@ -427,15 +434,15 @@ proc setRef(p: var TRstParser, key: string, value: PRstNode) =
p.s.refs[length].key = key
p.s.refs[length].value = value
proc findRef(p: var TRstParser, key: string): PRstNode =
proc findRef(p: var RstParser, key: string): PRstNode =
for i in countup(0, high(p.s.refs)):
if key == p.s.refs[i].key:
return p.s.refs[i].value
proc newLeaf(p: var TRstParser): PRstNode =
proc newLeaf(p: var RstParser): PRstNode =
result = newRstNode(rnLeaf, p.tok[p.idx].symbol)
proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
proc getReferenceName(p: var RstParser, endStr: string): PRstNode =
var res = newRstNode(rnInner)
while true:
case p.tok[p.idx].kind
@ -453,17 +460,17 @@ proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
inc(p.idx)
result = res
proc untilEol(p: var TRstParser): PRstNode =
proc untilEol(p: var RstParser): PRstNode =
result = newRstNode(rnInner)
while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
add(result, newLeaf(p))
inc(p.idx)
proc expect(p: var TRstParser, tok: string) =
proc expect(p: var RstParser, tok: string) =
if p.tok[p.idx].symbol == tok: inc(p.idx)
else: rstMessage(p, meExpected, tok)
proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
proc isInlineMarkupEnd(p: RstParser, markup: string): bool =
result = p.tok[p.idx].symbol == markup
if not result:
return # Rule 3:
@ -480,7 +487,7 @@ proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"):
result = false
proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
proc isInlineMarkupStart(p: RstParser, markup: string): bool =
var d: char
result = p.tok[p.idx].symbol == markup
if not result:
@ -507,7 +514,7 @@ proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
else: d = '\0'
if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
proc match(p: TRstParser, start: int, expr: string): bool =
proc match(p: RstParser, start: int, expr: string): bool =
# regular expressions are:
# special char exact match
# 'w' tkWord
@ -562,7 +569,7 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) =
for i in countup(0, sep - incr): add(a, n.sons[i])
for i in countup(sep + 1, len(n) - 2): add(b, n.sons[i])
proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode =
result = n
if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"):
inc(p.idx)
@ -606,7 +613,7 @@ proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
add(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
inc(p.idx, 3)
proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
proc matchVerbatim(p: RstParser, start: int, expr: string): int =
result = start
var j = 0
while j < expr.len and result < p.tok.len and
@ -615,7 +622,7 @@ proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
inc result
if j < expr.len: result = 0
proc parseSmiley(p: var TRstParser): PRstNode =
proc parseSmiley(p: var RstParser): PRstNode =
if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
for key, val in items(Smilies):
let m = matchVerbatim(p, p.idx, key)
@ -631,12 +638,12 @@ when false:
'$', '(', ')', '~', '_', '?', '+', '-', '=', '\\', '.', '&',
'\128'..'\255'}
proc isUrl(p: TRstParser, i: int): bool =
proc isUrl(p: RstParser, i: int): bool =
result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and
(p.tok[i+3].kind == tkWord) and
(p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"])
proc parseUrl(p: var TRstParser, father: PRstNode) =
proc parseUrl(p: var RstParser, father: PRstNode) =
#if p.tok[p.idx].symbol[strStart] == '<':
if isUrl(p, p.idx):
var n = newRstNode(rnStandaloneHyperlink)
@ -656,7 +663,7 @@ proc parseUrl(p: var TRstParser, father: PRstNode) =
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
add(father, n)
proc parseBackslash(p: var TRstParser, father: PRstNode) =
proc parseBackslash(p: var RstParser, father: PRstNode) =
assert(p.tok[p.idx].kind == tkPunct)
if p.tok[p.idx].symbol == "\\\\":
add(father, newRstNode(rnLeaf, "\\"))
@ -671,7 +678,7 @@ proc parseBackslash(p: var TRstParser, father: PRstNode) =
inc(p.idx)
when false:
proc parseAdhoc(p: var TRstParser, father: PRstNode, verbatim: bool) =
proc parseAdhoc(p: var RstParser, father: PRstNode, verbatim: bool) =
if not verbatim and isURL(p, p.idx):
var n = newRstNode(rnStandaloneHyperlink)
while true:
@ -694,7 +701,7 @@ when false:
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
add(father, n)
proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
proc parseUntil(p: var RstParser, father: PRstNode, postfix: string,
interpretBackslash: bool) =
let
line = p.tok[p.idx].line
@ -725,7 +732,7 @@ proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
inc(p.idx)
else: rstMessage(p, meExpected, postfix, line, col)
proc parseMarkdownCodeblock(p: var TRstParser): PRstNode =
proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
var args = newRstNode(rnDirArg)
if p.tok[p.idx].kind == tkWord:
add(args, newLeaf(p))
@ -755,7 +762,7 @@ proc parseMarkdownCodeblock(p: var TRstParser): PRstNode =
add(result, nil)
add(result, lb)
proc parseInline(p: var TRstParser, father: PRstNode) =
proc parseInline(p: var RstParser, father: PRstNode) =
case p.tok[p.idx].kind
of tkPunct:
if isInlineMarkupStart(p, "***"):
@ -810,7 +817,7 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
inc(p.idx)
else: discard
proc getDirective(p: var TRstParser): string =
proc getDirective(p: var RstParser): string =
if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord:
var j = p.idx
inc(p.idx)
@ -830,7 +837,7 @@ proc getDirective(p: var TRstParser): string =
else:
result = ""
proc parseComment(p: var TRstParser): PRstNode =
proc parseComment(p: var RstParser): PRstNode =
case p.tok[p.idx].kind
of tkIndent, tkEof:
if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent:
@ -851,34 +858,35 @@ proc parseComment(p: var TRstParser): PRstNode =
result = nil
type
TDirKind = enum # must be ordered alphabetically!
DirKind = enum # must be ordered alphabetically!
dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents,
dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle
{.deprecated: [TDirKind: DirKind].}
const
DirIds: array[0..12, string] = ["", "author", "authors", "code",
"code-block", "container", "contents", "figure", "image", "include",
"index", "raw", "title"]
proc getDirKind(s: string): TDirKind =
proc getDirKind(s: string): DirKind =
let i = find(DirIds, s)
if i >= 0: result = TDirKind(i)
if i >= 0: result = DirKind(i)
else: result = dkNone
proc parseLine(p: var TRstParser, father: PRstNode) =
proc parseLine(p: var RstParser, father: PRstNode) =
while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
else: break
proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
proc parseUntilNewline(p: var RstParser, father: PRstNode) =
while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
of tkEof, tkIndent: break
proc parseSection(p: var TRstParser, result: PRstNode) {.gcsafe.}
proc parseField(p: var TRstParser): PRstNode =
proc parseSection(p: var RstParser, result: PRstNode) {.gcsafe.}
proc parseField(p: var RstParser): PRstNode =
## Returns a parsed rnField node.
##
## rnField nodes have two children nodes, a rnFieldName and a rnFieldBody.
@ -897,7 +905,7 @@ proc parseField(p: var TRstParser): PRstNode =
add(result, fieldname)
add(result, fieldbody)
proc parseFields(p: var TRstParser): PRstNode =
proc parseFields(p: var RstParser): PRstNode =
## Parses fields for a section or directive block.
##
## This proc may return nil if the parsing doesn't find anything of value,
@ -947,8 +955,8 @@ proc getArgument(n: PRstNode): string =
if n.sons[0] == nil: result = ""
else: result = addNodes(n.sons[0])
proc parseDotDot(p: var TRstParser): PRstNode {.gcsafe.}
proc parseLiteralBlock(p: var TRstParser): PRstNode =
proc parseDotDot(p: var RstParser): PRstNode {.gcsafe.}
proc parseLiteralBlock(p: var RstParser): PRstNode =
result = newRstNode(rnLiteralBlock)
var n = newRstNode(rnLeaf, "")
if p.tok[p.idx].kind == tkIndent:
@ -974,13 +982,13 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
inc(p.idx)
add(result, n)
proc getLevel(map: var TLevelMap, lvl: var int, c: char): int =
proc getLevel(map: var LevelMap, lvl: var int, c: char): int =
if map[c] == 0:
inc(lvl)
map[c] = lvl
result = map[c]
proc tokenAfterNewline(p: TRstParser): int =
proc tokenAfterNewline(p: RstParser): int =
result = p.idx
while true:
case p.tok[result].kind
@ -991,28 +999,28 @@ proc tokenAfterNewline(p: TRstParser): int =
break
else: inc(result)
proc isLineBlock(p: TRstParser): bool =
proc isLineBlock(p: RstParser): bool =
var j = tokenAfterNewline(p)
result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or
(p.tok[j].col > p.tok[p.idx].col)
proc predNL(p: TRstParser): bool =
proc predNL(p: RstParser): bool =
result = true
if p.idx > 0:
result = p.tok[p.idx-1].kind == tkIndent and
p.tok[p.idx-1].ival == currInd(p)
proc isDefList(p: TRstParser): bool =
proc isDefList(p: RstParser): bool =
var j = tokenAfterNewline(p)
result = (p.tok[p.idx].col < p.tok[j].col) and
(p.tok[j].kind in {tkWord, tkOther, tkPunct}) and
(p.tok[j - 2].symbol != "::")
proc isOptionList(p: TRstParser): bool =
proc isOptionList(p: RstParser): bool =
result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
match(p, p.idx, "/w") or match(p, p.idx, "//w")
proc whichSection(p: TRstParser): TRstNodeKind =
proc whichSection(p: RstParser): RstNodeKind =
case p.tok[p.idx].kind
of tkAdornment:
if match(p, p.idx + 1, "ii"): result = rnTransition
@ -1053,7 +1061,7 @@ proc whichSection(p: TRstParser): TRstNodeKind =
else: result = rnParagraph
else: result = rnLeaf
proc parseLineBlock(p: var TRstParser): PRstNode =
proc parseLineBlock(p: var RstParser): PRstNode =
result = nil
if p.tok[p.idx + 1].kind == tkWhite:
var col = p.tok[p.idx].col
@ -1072,7 +1080,7 @@ proc parseLineBlock(p: var TRstParser): PRstNode =
break
popInd(p)
proc parseParagraph(p: var TRstParser, result: PRstNode) =
proc parseParagraph(p: var RstParser, result: PRstNode) =
while true:
case p.tok[p.idx].kind
of tkIndent:
@ -1103,7 +1111,7 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
parseInline(p, result)
else: break
proc parseHeadline(p: var TRstParser): PRstNode =
proc parseHeadline(p: var RstParser): PRstNode =
result = newRstNode(rnHeadline)
parseUntilNewline(p, result)
assert(p.tok[p.idx].kind == tkIndent)
@ -1113,12 +1121,13 @@ proc parseHeadline(p: var TRstParser): PRstNode =
result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
type
TIntSeq = seq[int]
IntSeq = seq[int]
{.deprecated: [TIntSeq: IntSeq].}
proc tokEnd(p: TRstParser): int =
proc tokEnd(p: RstParser): int =
result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1
proc getColumns(p: var TRstParser, cols: var TIntSeq) =
proc getColumns(p: var RstParser, cols: var IntSeq) =
var L = 0
while true:
inc(L)
@ -1133,15 +1142,15 @@ proc getColumns(p: var TRstParser, cols: var TIntSeq) =
# last column has no limit:
cols[L - 1] = 32000
proc parseDoc(p: var TRstParser): PRstNode {.gcsafe.}
proc parseDoc(p: var RstParser): PRstNode {.gcsafe.}
proc parseSimpleTable(p: var TRstParser): PRstNode =
proc parseSimpleTable(p: var RstParser): PRstNode =
var
cols: TIntSeq
cols: IntSeq
row: seq[string]
i, last, line: int
c: char
q: TRstParser
q: RstParser
a, b: PRstNode
result = newRstNode(rnTable)
cols = @[]
@ -1188,13 +1197,13 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
add(a, b)
add(result, a)
proc parseTransition(p: var TRstParser): PRstNode =
proc parseTransition(p: var RstParser): PRstNode =
result = newRstNode(rnTransition)
inc(p.idx)
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
proc parseOverline(p: var TRstParser): PRstNode =
proc parseOverline(p: var RstParser): PRstNode =
var c = p.tok[p.idx].symbol[0]
inc(p.idx, 2)
result = newRstNode(rnOverline)
@ -1213,7 +1222,7 @@ proc parseOverline(p: var TRstParser): PRstNode =
inc(p.idx) # XXX: check?
if p.tok[p.idx].kind == tkIndent: inc(p.idx)
proc parseBulletList(p: var TRstParser): PRstNode =
proc parseBulletList(p: var RstParser): PRstNode =
result = nil
if p.tok[p.idx + 1].kind == tkWhite:
var bullet = p.tok[p.idx].symbol
@ -1233,7 +1242,7 @@ proc parseBulletList(p: var TRstParser): PRstNode =
break
popInd(p)
proc parseOptionList(p: var TRstParser): PRstNode =
proc parseOptionList(p: var RstParser): PRstNode =
result = newRstNode(rnOptionList)
while true:
if isOptionList(p):
@ -1262,7 +1271,7 @@ proc parseOptionList(p: var TRstParser): PRstNode =
else:
break
proc parseDefinitionList(p: var TRstParser): PRstNode =
proc parseDefinitionList(p: var RstParser): PRstNode =
result = nil
var j = tokenAfterNewline(p) - 1
if (j >= 1) and (p.tok[j].kind == tkIndent) and
@ -1298,7 +1307,7 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
break
if len(result) == 0: result = nil
proc parseEnumList(p: var TRstParser): PRstNode =
proc parseEnumList(p: var RstParser): PRstNode =
const
wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "]
wildpos: array[0..2, int] = [1, 0, 0]
@ -1328,11 +1337,11 @@ proc parseEnumList(p: var TRstParser): PRstNode =
dec(p.idx, wildpos[w] + 3)
result = nil
proc sonKind(father: PRstNode, i: int): TRstNodeKind =
proc sonKind(father: PRstNode, i: int): RstNodeKind =
result = rnLeaf
if i < len(father): result = father.sons[i].kind
proc parseSection(p: var TRstParser, result: PRstNode) =
proc parseSection(p: var RstParser, result: PRstNode) =
while true:
var leave = false
assert(p.idx >= 0)
@ -1380,16 +1389,16 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
result.sons[0].kind = rnInner
proc parseSectionWrapper(p: var TRstParser): PRstNode =
proc parseSectionWrapper(p: var RstParser): PRstNode =
result = newRstNode(rnInner)
parseSection(p, result)
while (result.kind == rnInner) and (len(result) == 1):
result = result.sons[0]
proc `$`(t: TToken): string =
proc `$`(t: Token): string =
result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol)
proc parseDoc(p: var TRstParser): PRstNode =
proc parseDoc(p: var RstParser): PRstNode =
result = parseSectionWrapper(p)
if p.tok[p.idx].kind != tkEof:
when false:
@ -1403,12 +1412,14 @@ proc parseDoc(p: var TRstParser): PRstNode =
rstMessage(p, meGeneralParseError)
type
TDirFlag = enum
DirFlag = enum
hasArg, hasOptions, argIsFile, argIsWord
TDirFlags = set[TDirFlag]
TSectionParser = proc (p: var TRstParser): PRstNode {.nimcall.}
DirFlags = set[DirFlag]
SectionParser = proc (p: var RstParser): PRstNode {.nimcall.}
{.deprecated: [TDirFlag: DirFlag, TDirFlags: DirFlags,
TSectionParser: SectionParser].}
proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode =
## Parses arguments and options for a directive block.
##
## A directive block will always have three sons: the arguments for the
@ -1446,11 +1457,11 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
options = parseFields(p)
add(result, options)
proc indFollows(p: TRstParser): bool =
proc indFollows(p: RstParser): bool =
result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p)
proc parseDirective(p: var TRstParser, flags: TDirFlags,
contentParser: TSectionParser): PRstNode =
proc parseDirective(p: var RstParser, flags: DirFlags,
contentParser: SectionParser): PRstNode =
## Returns a generic rnDirective tree.
##
## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil.
@ -1463,13 +1474,13 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags,
else:
add(result, nil)
proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
proc parseDirBody(p: var RstParser, contentParser: SectionParser): PRstNode =
if indFollows(p):
pushInd(p, p.tok[p.idx].ival)
result = contentParser(p)
popInd(p)
proc dirInclude(p: var TRstParser): PRstNode =
proc dirInclude(p: var RstParser): PRstNode =
#
#The following options are recognized:
#
@ -1498,7 +1509,7 @@ proc dirInclude(p: var TRstParser): PRstNode =
result = newRstNode(rnLiteralBlock)
add(result, newRstNode(rnLeaf, readFile(path)))
else:
var q: TRstParser
var q: RstParser
initParser(q, p.s)
q.filename = filename
q.col += getTokens(readFile(path), false, q.tok)
@ -1507,7 +1518,7 @@ proc dirInclude(p: var TRstParser): PRstNode =
# InternalError("Too many binary zeros in include file")
result = parseDoc(q)
proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
proc dirCodeBlock(p: var RstParser, nimrodExtension = false): PRstNode =
## Parses a code block.
##
## Code blocks are rnDirective trees with a `kind` of rnCodeBlock. See the
@ -1548,35 +1559,35 @@ proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
result.kind = rnCodeBlock
proc dirContainer(p: var TRstParser): PRstNode =
proc dirContainer(p: var RstParser): PRstNode =
result = parseDirective(p, {hasArg}, parseSectionWrapper)
assert(result.kind == rnDirective)
assert(len(result) == 3)
result.kind = rnContainer
proc dirImage(p: var TRstParser): PRstNode =
proc dirImage(p: var RstParser): PRstNode =
result = parseDirective(p, {hasOptions, hasArg, argIsFile}, nil)
result.kind = rnImage
proc dirFigure(p: var TRstParser): PRstNode =
proc dirFigure(p: var RstParser): PRstNode =
result = parseDirective(p, {hasOptions, hasArg, argIsFile},
parseSectionWrapper)
result.kind = rnFigure
proc dirTitle(p: var TRstParser): PRstNode =
proc dirTitle(p: var RstParser): PRstNode =
result = parseDirective(p, {hasArg}, nil)
result.kind = rnTitle
proc dirContents(p: var TRstParser): PRstNode =
proc dirContents(p: var RstParser): PRstNode =
result = parseDirective(p, {hasArg}, nil)
result.kind = rnContents
proc dirIndex(p: var TRstParser): PRstNode =
proc dirIndex(p: var RstParser): PRstNode =
result = parseDirective(p, {}, parseSectionWrapper)
result.kind = rnIndex
proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
contentParser: TSectionParser) =
proc dirRawAux(p: var RstParser, result: var PRstNode, kind: RstNodeKind,
contentParser: SectionParser) =
var filename = getFieldValue(result, "file")
if filename.len > 0:
var path = p.s.findFile(filename)
@ -1590,7 +1601,7 @@ proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
result.kind = kind
add(result, parseDirBody(p, contentParser))
proc dirRaw(p: var TRstParser): PRstNode =
proc dirRaw(p: var RstParser): PRstNode =
#
#The following options are recognized:
#
@ -1610,7 +1621,7 @@ proc dirRaw(p: var TRstParser): PRstNode =
else:
dirRawAux(p, result, rnRaw, parseSectionWrapper)
proc parseDotDot(p: var TRstParser): PRstNode =
proc parseDotDot(p: var RstParser): PRstNode =
result = nil
var col = p.tok[p.idx].col
inc(p.idx)
@ -1667,7 +1678,7 @@ proc parseDotDot(p: var TRstParser): PRstNode =
else:
result = parseComment(p)
proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode =
result = n
if n == nil: return
case n.kind
@ -1696,10 +1707,10 @@ proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
proc rstParse*(text, filename: string,
line, column: int, hasToc: var bool,
options: TRstParseOptions,
findFile: TFindFileHandler = nil,
msgHandler: TMsgHandler = nil): PRstNode =
var p: TRstParser
options: RstParseOptions,
findFile: FindFileHandler = nil,
msgHandler: MsgHandler = nil): PRstNode =
var p: RstParser
initParser(p, newSharedState(options, findFile, msgHandler))
p.filename = filename
p.line = line

View file

@ -12,7 +12,7 @@
import strutils, json
type
TRstNodeKind* = enum ## the possible node kinds of an PRstNode
RstNodeKind* = enum ## the possible node kinds of an PRstNode
rnInner, # an inner node or a root
rnHeadline, # a headline
rnOverline, # an over- and underlined headline
@ -62,24 +62,26 @@ type
# leaf val
PRstNode* = ref TRstNode ## an RST node
TRstNodeSeq* = seq[PRstNode]
TRstNode* {.acyclic, final.} = object ## an RST node's description
kind*: TRstNodeKind ## the node's kind
PRstNode* = ref RstNode ## an RST node
RstNodeSeq* = seq[PRstNode]
RstNode* {.acyclic, final.} = object ## an RST node's description
kind*: RstNodeKind ## the node's kind
text*: string ## valid for leafs in the AST; and the title of
## the document or the section
level*: int ## valid for some node kinds
sons*: TRstNodeSeq ## the node's sons
sons*: RstNodeSeq ## the node's sons
{.deprecated: [TRstNodeKind: RstNodeKind, TRstNodeSeq: RstNodeSeq,
TRstNode: RstNode].}
proc len*(n: PRstNode): int =
result = len(n.sons)
proc newRstNode*(kind: TRstNodeKind): PRstNode =
proc newRstNode*(kind: RstNodeKind): PRstNode =
new(result)
result.sons = @[]
result.kind = kind
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
proc newRstNode*(kind: RstNodeKind, s: string): PRstNode =
result = newRstNode(kind)
result.text = s
@ -94,18 +96,19 @@ proc addIfNotNil*(father, son: PRstNode) =
type
TRenderContext {.pure.} = object
RenderContext {.pure.} = object
indent: int
verbatim: int
{.deprecated: [TRenderContext: RenderContext].}
proc renderRstToRst(d: var TRenderContext, n: PRstNode,
proc renderRstToRst(d: var RenderContext, n: PRstNode,
result: var string) {.gcsafe.}
proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
proc renderRstSons(d: var RenderContext, n: PRstNode, result: var string) =
for i in countup(0, len(n) - 1):
renderRstToRst(d, n.sons[i], result)
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
proc renderRstToRst(d: var RenderContext, n: PRstNode, result: var string) =
# this is needed for the index generation; it may also be useful for
# debugging, but most code is already debugged...
const
@ -284,7 +287,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
proc renderRstToRst*(n: PRstNode, result: var string) =
## renders `n` into its string representation and appends to `result`.
var d: TRenderContext
var d: RenderContext
renderRstToRst(d, n, result)
proc renderRstToJsonNode(node: PRstNode): JsonNode =

View file

@ -18,7 +18,7 @@
## document you provide yourself, so it won't contain the usual ``<header>`` or
## ``<body>`` parts.
##
## You can also create a ``TRstGenerator`` structure and populate it with the
## You can also create a ``RstGenerator`` structure and populate it with the
## other lower level methods to finally build complete documents. This requires
## many options and tweaking, but you are not limited to snippets and can
## generate `LaTeX documents <https://en.wikipedia.org/wiki/LaTeX>`_ too.
@ -31,29 +31,29 @@ const
IndexExt* = ".idx"
type
TOutputTarget* = enum ## which document type to generate
OutputTarget* = enum ## which document type to generate
outHtml, # output is HTML
outLatex # output is Latex
TTocEntry = object
TocEntry = object
n*: PRstNode
refname*, header*: string
TMetaEnum* = enum
MetaEnum* = enum
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
TRstGenerator* = object of RootObj
target*: TOutputTarget
RstGenerator* = object of RootObj
target*: OutputTarget
config*: StringTableRef
splitAfter*: int # split too long entries in the TOC
tocPart*: seq[TTocEntry]
tocPart*: seq[TocEntry]
hasToc*: bool
theIndex: string # Contents of the index file to be dumped at the end.
options*: TRstParseOptions
findFile*: TFindFileHandler
msgHandler*: TMsgHandler
options*: RstParseOptions
findFile*: FindFileHandler
msgHandler*: MsgHandler
filename*: string
meta*: array[TMetaEnum, string]
meta*: array[MetaEnum, string]
currentSection: string ## \
## Stores the empty string or the last headline/overline found in the rst
## document, so it can be used as a prettier name for term index generation.
@ -61,14 +61,15 @@ type
## Keeps count of same text index terms to generate different identifiers
## for hyperlinks. See renderIndexTerm proc for details.
PDoc = var TRstGenerator ## Alias to type less.
PDoc = var RstGenerator ## Alias to type less.
CodeBlockParams = object ## Stores code block params.
numberLines: bool ## True if the renderer has to show line numbers.
startLine: int ## The starting line of the code block, by default 1.
langStr: string ## Input string used to specify the language.
lang: TSourceLanguage ## Type of highlighting, by default none.
lang: SourceLanguage ## Type of highlighting, by default none.
{.deprecated: [TRstGenerator: RstGenerator, TTocEntry: TocEntry,
TOutputTarget: OutputTarget, TMetaEnum: MetaEnum].}
proc init(p: var CodeBlockParams) =
## Default initialisation of CodeBlockParams to sane values.
@ -76,14 +77,14 @@ proc init(p: var CodeBlockParams) =
p.lang = langNone
p.langStr = ""
proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
proc initRstGenerator*(g: var RstGenerator, target: OutputTarget,
config: StringTableRef, filename: string,
options: TRstParseOptions,
findFile: TFindFileHandler=nil,
msgHandler: TMsgHandler=nil) =
## Initializes a ``TRstGenerator``.
options: RstParseOptions,
findFile: FindFileHandler=nil,
msgHandler: MsgHandler=nil) =
## Initializes a ``RstGenerator``.
##
## You need to call this before using a ``TRstGenerator`` with any other
## You need to call this before using a ``RstGenerator`` with any other
## procs in this module. Pass a non ``nil`` ``StringTableRef`` value as
## `config` with parameters used by the HTML output generator. If you don't
## know what to use, pass the results of the `defaultConfig()
@ -96,7 +97,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
## filename``. This default title can be overriden by the embedded rst, but
## it helps to prettify the generated index if no title is found.
##
## The ``TRstParseOptions``, ``TFindFileHandler`` and ``TMsgHandler`` types
## The ``RstParseOptions``, ``FindFileHandler`` and ``MsgHandler`` types
## are defined in the the `packages/docutils/rst module <rst.html>`_.
## ``options`` selects the behaviour of the rst parser.
##
@ -120,7 +121,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
##
## import packages/docutils/rstgen
##
## var gen: TRstGenerator
## var gen: RstGenerator
## gen.initRstGenerator(outHtml, defaultConfig(), "filename", {})
g.config = config
g.target = target
@ -141,7 +142,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
if s != "": g.splitAfter = parseInt(s)
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
proc writeIndexFile*(g: var RstGenerator, outfile: string) =
## Writes the current index buffer to the specified output file.
##
## You previously need to add entries to the index with the `setIndexTerm()
@ -183,7 +184,7 @@ proc addTexChar(dest: var string, c: char) =
var splitter*: string = "<wbr />"
proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
proc escChar*(target: OutputTarget, dest: var string, c: char) {.inline.} =
case target
of outHtml: addXmlChar(dest, c)
of outLatex: addTexChar(dest, c)
@ -200,7 +201,7 @@ proc nextSplitPoint*(s: string, start: int): int =
inc(result)
dec(result) # last valid index
proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
proc esc*(target: OutputTarget, s: string, splitAfter = -1): string =
result = ""
if splitAfter >= 0:
var partLen = 0
@ -217,16 +218,16 @@ proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
for i in countup(0, len(s) - 1): escChar(target, result, s[i])
proc disp(target: TOutputTarget, xml, tex: string): string =
proc disp(target: OutputTarget, xml, tex: string): string =
if target != outLatex: result = xml
else: result = tex
proc dispF(target: TOutputTarget, xml, tex: string,
proc dispF(target: OutputTarget, xml, tex: string,
args: varargs[string]): string =
if target != outLatex: result = xml % args
else: result = tex % args
proc dispA(target: TOutputTarget, dest: var string,
proc dispA(target: OutputTarget, dest: var string,
xml, tex: string, args: varargs[string]) =
if target != outLatex: addf(dest, xml, args)
else: addf(dest, tex, args)
@ -234,10 +235,10 @@ proc dispA(target: TOutputTarget, dest: var string,
proc `or`(x, y: string): string {.inline.} =
result = if x.isNil: y else: x
proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string)
## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
##
## Before using this proc you need to initialise a ``TRstGenerator`` with
## Before using this proc you need to initialise a ``RstGenerator`` with
## ``initRstGenerator`` and parse a rst file with ``rstParse`` from the
## `packages/docutils/rst module <rst.html>`_. Example:
##
@ -277,7 +278,7 @@ proc unquoteIndexColumn(text: string): string =
## Returns the unquoted version generated by ``quoteIndexColumn``.
result = text.replace("\\t", "\t").replace("\\n", "\n").replace("\\\\", "\\")
proc setIndexTerm*(d: var TRstGenerator, id, term: string,
proc setIndexTerm*(d: var RstGenerator, id, term: string,
linkTitle, linkDesc = "") =
## Adds a `term` to the index using the specified hyperlink identifier.
##
@ -351,30 +352,30 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
[id, term])
type
TIndexEntry = object
IndexEntry = object
keyword: string
link: string
linkTitle: string ## If not nil, contains a prettier text for the href
linkDesc: string ## If not nil, the title attribute of the final href
TIndexedDocs = Table[TIndexEntry, seq[TIndexEntry]] ## \
IndexedDocs = Table[IndexEntry, seq[IndexEntry]] ## \
## Contains the index sequences for doc types.
##
## The key is a *fake* TIndexEntry which will contain the title of the
## The key is a *fake* IndexEntry which will contain the title of the
## document in the `keyword` field and `link` will contain the html
## filename for the document. `linkTitle` and `linkDesc` will be nil.
##
## The value indexed by this TIndexEntry is a sequence with the real index
## The value indexed by this IndexEntry is a sequence with the real index
## entries found in the ``.idx`` file.
{.deprecated: [TIndexEntry: IndexEntry, TIndexedDocs: IndexedDocs].}
proc cmp(a, b: TIndexEntry): int =
## Sorts two ``TIndexEntry`` first by `keyword` field, then by `link`.
proc cmp(a, b: IndexEntry): int =
## Sorts two ``IndexEntry`` first by `keyword` field, then by `link`.
result = cmpIgnoreStyle(a.keyword, b.keyword)
if result == 0:
result = cmpIgnoreStyle(a.link, b.link)
proc hash(x: TIndexEntry): THash =
proc hash(x: IndexEntry): Hash =
## Returns the hash for the combined fields of the type.
##
## The hash is computed as the chained hash of the individual string hashes.
@ -385,7 +386,7 @@ proc hash(x: TIndexEntry): THash =
result = result !& (x.linkDesc or "").hash
result = !$result
proc `<-`(a: var TIndexEntry, b: TIndexEntry) =
proc `<-`(a: var IndexEntry, b: IndexEntry) =
shallowCopy a.keyword, b.keyword
shallowCopy a.link, b.link
if b.linkTitle.isNil: a.linkTitle = nil
@ -393,7 +394,7 @@ proc `<-`(a: var TIndexEntry, b: TIndexEntry) =
if b.linkDesc.isNil: a.linkDesc = nil
else: shallowCopy a.linkDesc, b.linkDesc
proc sortIndex(a: var openArray[TIndexEntry]) =
proc sortIndex(a: var openArray[IndexEntry]) =
# we use shellsort here; fast and simple
let n = len(a)
var h = 1
@ -403,7 +404,7 @@ proc sortIndex(a: var openArray[TIndexEntry]) =
while true:
h = h div 3
for i in countup(h, n - 1):
var v: TIndexEntry
var v: IndexEntry
v <- a[i]
var j = i
while cmp(a[j-h], v) >= 0:
@ -413,7 +414,7 @@ proc sortIndex(a: var openArray[TIndexEntry]) =
a[j] <- v
if h == 1: break
proc generateSymbolIndex(symbols: seq[TIndexEntry]): string =
proc generateSymbolIndex(symbols: seq[IndexEntry]): string =
result = ""
var i = 0
while i < symbols.len:
@ -466,7 +467,7 @@ proc indentToLevel(level: var int, newLevel: int): string =
result = repeat("</ul>", level - newLevel)
level = newLevel
proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
proc generateDocumentationTOC(entries: seq[IndexEntry]): string =
## Returns the sequence of index entries in an HTML hierarchical list.
result = ""
# Build a list of levels and extracted titles to make processing easier.
@ -507,12 +508,12 @@ proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
assert(not titleRef.isNil,
"Can't use this proc on an API index, docs always have a title entry")
proc generateDocumentationIndex(docs: TIndexedDocs): string =
proc generateDocumentationIndex(docs: IndexedDocs): string =
## Returns all the documentation TOCs in an HTML hierarchical list.
result = ""
# Sort the titles to generate their toc in alphabetical order.
var titles = toSeq(keys[TIndexEntry, seq[TIndexEntry]](docs))
var titles = toSeq(keys[IndexEntry, seq[IndexEntry]](docs))
sort(titles, cmp)
for title in titles:
@ -520,12 +521,12 @@ proc generateDocumentationIndex(docs: TIndexedDocs): string =
result.add("<ul><li><a href=\"" &
title.link & "\">" & title.keyword & "</a>\n" & tocList & "</ul>\n")
proc generateDocumentationJumps(docs: TIndexedDocs): string =
proc generateDocumentationJumps(docs: IndexedDocs): string =
## Returns a plain list of hyperlinks to documentation TOCs in HTML.
result = "Documents: "
# Sort the titles to generate their toc in alphabetical order.
var titles = toSeq(keys[TIndexEntry, seq[TIndexEntry]](docs))
var titles = toSeq(keys[IndexEntry, seq[IndexEntry]](docs))
sort(titles, cmp)
var chunks: seq[string] = @[]
@ -545,14 +546,14 @@ proc generateModuleJumps(modules: seq[string]): string =
result.add(chunks.join(", ") & ".<br>")
proc readIndexDir(dir: string):
tuple[modules: seq[string], symbols: seq[TIndexEntry], docs: TIndexedDocs] =
## Walks `dir` reading ``.idx`` files converting them in TIndexEntry items.
tuple[modules: seq[string], symbols: seq[IndexEntry], docs: IndexedDocs] =
## Walks `dir` reading ``.idx`` files converting them in IndexEntry items.
##
## Returns the list of found module names, the list of free symbol entries
## and the different documentation indexes. The list of modules is sorted.
## See the documentation of ``mergeIndexes`` for details.
result.modules = @[]
result.docs = initTable[TIndexEntry, seq[TIndexEntry]](32)
result.docs = initTable[IndexEntry, seq[IndexEntry]](32)
newSeq(result.symbols, 15_000)
setLen(result.symbols, 0)
var L = 0
@ -560,8 +561,8 @@ proc readIndexDir(dir: string):
for kind, path in walkDir(dir):
if kind == pcFile and path.endsWith(IndexExt):
var
fileEntries: seq[TIndexEntry]
title: TIndexEntry
fileEntries: seq[IndexEntry]
title: IndexEntry
F = 0
newSeq(fileEntries, 500)
setLen(fileEntries, 0)
@ -662,7 +663,7 @@ proc mergeIndexes*(dir: string): string =
proc stripTOCHTML(s: string): string =
## Ugly quick hack to remove HTML tags from TOC titles.
##
## A TTocEntry.header field already contains rendered HTML tags. Instead of
## A TocEntry.header field already contains rendered HTML tags. Instead of
## implementing a proper version of renderRstToOut() which recursively
## renders an rst tree to plain text, we simply remove text found between
## angled brackets. Given the limited possibilities of rst inside TOC titles
@ -728,12 +729,12 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
dispA(d.target, result,
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
"\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int,
proc renderTocEntries*(d: var RstGenerator, j: var int, lvl: int,
result: var string) =
var tmp = ""
while j <= high(d.tocPart):
@ -878,7 +879,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr)
for letter in m.text: escChar(d.target, result, letter)
else:
var g: TGeneralTokenizer
var g: GeneralTokenizer
initGeneralTokenizer(g, m.text)
while true:
getNextToken(g, params.lang)
@ -1214,7 +1215,7 @@ $content
# ---------- forum ---------------------------------------------------------
proc rstToHtml*(s: string, options: TRstParseOptions,
proc rstToHtml*(s: string, options: RstParseOptions,
config: StringTableRef): string =
## Converts an input rst string into embeddable HTML.
##
@ -1233,7 +1234,7 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
## # --> <em>Hello</em> <strong>world</strong>!
##
## If you need to allow the rst ``include`` directive or tweak the generated
## output you have to create your own ``TRstGenerator`` with
## output you have to create your own ``RstGenerator`` with
## ``initRstGenerator`` and related procs.
proc myFindFile(filename: string): string =
@ -1241,7 +1242,7 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
result = ""
const filen = "input"
var d: TRstGenerator
var d: RstGenerator
initRstGenerator(d, outHtml, config, filen, options, myFindFile,
rst.defaultMsgHandler)
var dummyHasToc = false

View file

@ -12,14 +12,15 @@
# Get the platform-dependent flags.
# Structure describing an inotify event.
type
Tinotify_event*{.pure, final, importc: "struct inotify_event",
InotifyEvent*{.pure, final, importc: "struct inotify_event",
header: "<sys/inotify.h>".} = object
wd*{.importc: "wd".}: cint # Watch descriptor.
mask*{.importc: "mask".}: uint32 # Watch mask.
cookie*{.importc: "cookie".}: uint32 # Cookie to synchronize two events.
len*{.importc: "len".}: uint32 # Length (including NULs) of name.
name*{.importc: "name".}: char # Name.
{.deprecated: [Tinotify_event: InotifyEvent].}
# Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH.
const
IN_ACCESS* = 0x00000001 # File was accessed.
@ -69,4 +70,4 @@ proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint{.
cdecl, importc: "inotify_add_watch", header: "<sys/inotify.h>".}
# Remove the watch specified by WD from the inotify instance FD.
proc inotify_rm_watch*(fd: cint; wd: cint): cint{.cdecl,
importc: "inotify_rm_watch", header: "<sys/inotify.h>".}
importc: "inotify_rm_watch", header: "<sys/inotify.h>".}

View file

@ -24,5 +24,5 @@ const
# fn should be of type proc (a2: pointer): void {.cdecl.}
proc clone*(fn: pointer; child_stack: pointer; flags: cint;
arg: pointer; ptid: ptr TPid; tls: pointer;
ctid: ptr TPid): cint {.importc, header: "<sched.h>".}
arg: pointer; ptid: ptr Pid; tls: pointer;
ctid: ptr Pid): cint {.importc, header: "<sched.h>".}

File diff suppressed because it is too large Load diff

View file

@ -12,17 +12,18 @@ import posix
type
Speed* = cuint
Tcflag* = cuint
Cflag* = cuint
{.deprecated: [Tcflag: Cflag].}
const
NCCS* = 32
type
Termios* {.importc: "struct termios", header: "<termios.h>".} = object
c_iflag*: Tcflag # input mode flags
c_oflag*: Tcflag # output mode flags
c_cflag*: Tcflag # control mode flags
c_lflag*: Tcflag # local mode flags
c_iflag*: Cflag # input mode flags
c_oflag*: Cflag # output mode flags
c_cflag*: Cflag # control mode flags
c_lflag*: Cflag # local mode flags
c_line*: cuchar # line discipline
c_cc*: array[NCCS, cuchar] # control characters
@ -258,4 +259,4 @@ proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
header: "<termios.h>".}
# Get process group ID for session leader for controlling terminal FD.
proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "<termios.h>".}
proc tcGetSid*(fd: cint): Pid {.importc: "tcgetsid", header: "<termios.h>".}

View file

@ -16,7 +16,7 @@
## .. code-block:: nim
##
## var
## a: TActorPool[int, void]
## a: ActorPool[int, void]
## createActorPool(a)
## for i in 0 .. < 300:
## a.spawn(i, proc (x: int) {.thread.} = echo x)
@ -30,75 +30,76 @@
from os import sleep
type
TTask*[TIn, TOut] = object{.pure, final.} ## a task
when TOut isnot void:
receiver*: ptr TChannel[TOut] ## the receiver channel of the response
action*: proc (x: TIn): TOut {.thread.} ## action to execute;
Task*[In, Out] = object{.pure, final.} ## a task
when Out isnot void:
receiver*: ptr Channel[Out] ## the receiver channel of the response
action*: proc (x: In): Out {.thread.} ## action to execute;
## sometimes useful
shutDown*: bool ## set to tell an actor to shut-down
data*: TIn ## the data to process
data*: In ## the data to process
TActor[TIn, TOut] = object{.pure, final.}
i: TChannel[TTask[TIn, TOut]]
t: TThread[ptr TActor[TIn, TOut]]
Actor[In, Out] = object{.pure, final.}
i: Channel[Task[In, Out]]
t: TThread[ptr Actor[In, Out]]
PActor*[TIn, TOut] = ptr TActor[TIn, TOut] ## an actor
proc spawn*[TIn, TOut](action: proc(
self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
PActor*[In, Out] = ptr Actor[In, Out] ## an actor
{.deprecated: [TTask: Task, TActor: Actor].}
proc spawn*[In, Out](action: proc(
self: PActor[In, Out]){.thread.}): PActor[In, Out] =
## creates an actor; that is a thread with an inbox. The caller MUST call
## ``join`` because that also frees the actor's associated resources.
result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
result = cast[PActor[In, Out]](allocShared0(sizeof(result[])))
open(result.i)
createThread(result.t, action, result)
proc inbox*[TIn, TOut](self: PActor[TIn, TOut]): ptr TChannel[TIn] =
proc inbox*[In, Out](self: PActor[In, Out]): ptr Channel[In] =
## gets a pointer to the associated inbox of the actor `self`.
result = addr(self.i)
proc running*[TIn, TOut](a: PActor[TIn, TOut]): bool =
proc running*[In, Out](a: PActor[In, Out]): bool =
## returns true if the actor `a` is running.
result = running(a.t)
proc ready*[TIn, TOut](a: PActor[TIn, TOut]): bool =
proc ready*[In, Out](a: PActor[In, Out]): bool =
## returns true if the actor `a` is ready to process new messages.
result = ready(a.i)
proc join*[TIn, TOut](a: PActor[TIn, TOut]) =
proc join*[In, Out](a: PActor[In, Out]) =
## joins an actor.
joinThread(a.t)
close(a.i)
deallocShared(a)
proc recv*[TIn, TOut](a: PActor[TIn, TOut]): TTask[TIn, TOut] =
proc recv*[In, Out](a: PActor[In, Out]): Task[In, Out] =
## receives a task from `a`'s inbox.
result = recv(a.i)
proc send*[TIn, TOut, X, Y](receiver: PActor[TIn, TOut], msg: TIn,
proc send*[In, Out, X, Y](receiver: PActor[In, Out], msg: In,
sender: PActor[X, Y]) =
## sends a message to `a`'s inbox.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
t.receiver = addr(sender.i)
shallowCopy(t.data, msg)
send(receiver.i, t)
proc send*[TIn, TOut](receiver: PActor[TIn, TOut], msg: TIn,
sender: ptr TChannel[TOut] = nil) =
proc send*[In, Out](receiver: PActor[In, Out], msg: In,
sender: ptr Channel[Out] = nil) =
## sends a message to `receiver`'s inbox.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
t.receiver = sender
shallowCopy(t.data, msg)
send(receiver.i, t)
proc sendShutdown*[TIn, TOut](receiver: PActor[TIn, TOut]) =
proc sendShutdown*[In, Out](receiver: PActor[In, Out]) =
## send a shutdown message to `receiver`.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
t.shutdown = true
send(receiver.i, t)
proc reply*[TIn, TOut](t: TTask[TIn, TOut], m: TOut) =
proc reply*[In, Out](t: Task[In, Out], m: Out) =
## sends a message to io's output message box.
when TOut is void:
when Out is void:
{.error: "you cannot reply to a void outbox".}
assert t.receiver != nil
send(t.receiver[], m)
@ -107,34 +108,35 @@ proc reply*[TIn, TOut](t: TTask[TIn, TOut], m: TOut) =
# ----------------- actor pools ----------------------------------------------
type
TActorPool*[TIn, TOut] = object{.pure, final.} ## an actor pool
actors: seq[PActor[TIn, TOut]]
when TOut isnot void:
outputs: TChannel[TOut]
ActorPool*[In, Out] = object{.pure, final.} ## an actor pool
actors: seq[PActor[In, Out]]
when Out isnot void:
outputs: Channel[Out]
{.deprecated: [TActorPool: ActorPool].}
proc `^`*[T](f: ptr TChannel[T]): T =
proc `^`*[T](f: ptr Channel[T]): T =
## alias for 'recv'.
result = recv(f[])
proc poolWorker[TIn, TOut](self: PActor[TIn, TOut]) {.thread.} =
proc poolWorker[In, Out](self: PActor[In, Out]) {.thread.} =
while true:
var m = self.recv
if m.shutDown: break
when TOut is void:
when Out is void:
m.action(m.data)
else:
send(m.receiver[], m.action(m.data))
#self.reply()
proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
proc createActorPool*[In, Out](a: var ActorPool[In, Out], poolSize = 4) =
## creates an actor pool.
newSeq(a.actors, poolSize)
when TOut isnot void:
when Out isnot void:
open(a.outputs)
for i in 0 .. < a.actors.len:
a.actors[i] = spawn(poolWorker[TIn, TOut])
a.actors[i] = spawn(poolWorker[In, Out])
proc sync*[TIn, TOut](a: var TActorPool[TIn, TOut], polling=50) =
proc sync*[In, Out](a: var ActorPool[In, Out], polling=50) =
## waits for every actor of `a` to finish with its work. Currently this is
## implemented as polling every `polling` ms and has a slight chance
## of failing since we check for every actor to be in `ready` state and not
@ -157,18 +159,18 @@ proc sync*[TIn, TOut](a: var TActorPool[TIn, TOut], polling=50) =
if allReadyCount > 1: break
sleep(polling)
proc terminate*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
proc terminate*[In, Out](a: var ActorPool[In, Out]) =
## terminates each actor in the actor pool `a` and frees the
## resources attached to `a`.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
t.shutdown = true
for i in 0.. <a.actors.len: send(a.actors[i].i, t)
for i in 0.. <a.actors.len: join(a.actors[i])
when TOut isnot void:
when Out isnot void:
close(a.outputs)
a.actors = nil
proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
proc join*[In, Out](a: var ActorPool[In, Out]) =
## short-cut for `sync` and then `terminate`.
sync(a)
terminate(a)
@ -202,28 +204,28 @@ template schedule =
else:
raise newException(DeadThreadError, "cannot send message; thread died")
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
action: proc (input: TIn): TOut {.thread.}
): ptr TChannel[TOut] =
proc spawn*[In, Out](p: var ActorPool[In, Out], input: In,
action: proc (input: In): Out {.thread.}
): ptr Channel[Out] =
## uses the actor pool to run ``action(input)`` concurrently.
## `spawn` is guaranteed to not block.
var t: TTask[TIn, TOut]
var t: Task[In, Out]
setupTask()
result = addr(p.outputs)
t.receiver = result
schedule()
proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
action: proc (input: TIn) {.thread.}) =
proc spawn*[In](p: var ActorPool[In, void], input: In,
action: proc (input: In) {.thread.}) =
## uses the actor pool to run ``action(input)`` concurrently.
## `spawn` is guaranteed to not block.
var t: TTask[TIn, void]
var t: Task[In, void]
setupTask()
schedule()
when not defined(testing) and isMainModule:
var
a: TActorPool[int, void]
a: ActorPool[int, void]
createActorPool(a)
for i in 0 .. < 300:
a.spawn(i, proc (x: int) {.thread.} = echo x)

View file

@ -323,32 +323,34 @@ proc processTimers(p: PDispatcherBase) =
when defined(windows) or defined(nimdoc):
import winlean, sets, hashes
type
TCompletionKey = Dword
CompletionKey = Dword
TCompletionData* = object
fd*: TAsyncFD # TODO: Rename this.
cb*: proc (fd: TAsyncFD, bytesTransferred: Dword,
CompletionData* = object
fd*: AsyncFD # TODO: Rename this.
cb*: proc (fd: AsyncFD, bytesTransferred: Dword,
errcode: OSErrorCode) {.closure,gcsafe.}
PDispatcher* = ref object of PDispatcherBase
ioPort: THandle
handles: HashSet[TAsyncFD]
ioPort: Handle
handles: HashSet[AsyncFD]
TCustomOverlapped = object of TOVERLAPPED
data*: TCompletionData
CustomOverlapped = object of TOVERLAPPED
data*: CompletionData
PCustomOverlapped* = ref TCustomOverlapped
PCustomOverlapped* = ref CustomOverlapped
TAsyncFD* = distinct int
AsyncFD* = distinct int
{.deprecated: [TCompletionKey: CompletionKey, TAsyncFD: AsyncFD,
TCustomOverlapped: CustomOverlapped, TCompletionData: CompletionData].}
proc hash(x: TAsyncFD): THash {.borrow.}
proc `==`*(x: TAsyncFD, y: TAsyncFD): bool {.borrow.}
proc hash(x: AsyncFD): Hash {.borrow.}
proc `==`*(x: AsyncFD, y: AsyncFD): bool {.borrow.}
proc newDispatcher*(): PDispatcher =
## Creates a new Dispatcher instance.
new result
result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
result.handles = initSet[TAsyncFD]()
result.handles = initSet[AsyncFD]()
result.timers = @[]
var gDisp{.threadvar.}: PDispatcher ## Global dispatcher
@ -357,15 +359,15 @@ when defined(windows) or defined(nimdoc):
if gDisp.isNil: gDisp = newDispatcher()
result = gDisp
proc register*(fd: TAsyncFD) =
proc register*(fd: AsyncFD) =
## Registers ``fd`` with the dispatcher.
let p = getGlobalDispatcher()
if createIoCompletionPort(fd.THandle, p.ioPort,
cast[TCompletionKey](fd), 1) == 0:
if createIoCompletionPort(fd.Handle, p.ioPort,
cast[CompletionKey](fd), 1) == 0:
raiseOSError(osLastError())
p.handles.incl(fd)
proc verifyPresence(fd: TAsyncFD) =
proc verifyPresence(fd: AsyncFD) =
## Ensures that file descriptor has been registered with the dispatcher.
let p = getGlobalDispatcher()
if fd notin p.handles:
@ -394,7 +396,7 @@ when defined(windows) or defined(nimdoc):
# TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
if res:
# This is useful for ensuring the reliability of the overlapped struct.
assert customOverlapped.data.fd == lpCompletionKey.TAsyncFD
assert customOverlapped.data.fd == lpCompletionKey.AsyncFD
customOverlapped.data.cb(customOverlapped.data.fd,
lpNumberOfBytesTransferred, OSErrorCode(-1))
@ -402,7 +404,7 @@ when defined(windows) or defined(nimdoc):
else:
let errCode = osLastError()
if customOverlapped != nil:
assert customOverlapped.data.fd == lpCompletionKey.TAsyncFD
assert customOverlapped.data.fd == lpCompletionKey.AsyncFD
customOverlapped.data.cb(customOverlapped.data.fd,
lpNumberOfBytesTransferred, errCode)
GC_unref(customOverlapped)
@ -480,7 +482,7 @@ when defined(windows) or defined(nimdoc):
dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
RemoteSockaddr, RemoteSockaddrLength)
proc connect*(socket: TAsyncFD, address: string, port: Port,
proc connect*(socket: AsyncFD, address: string, port: Port,
af = AF_INET): Future[void] =
## Connects ``socket`` to server at ``address:port``.
##
@ -506,8 +508,8 @@ when defined(windows) or defined(nimdoc):
# http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
retFuture.complete()
@ -542,7 +544,7 @@ when defined(windows) or defined(nimdoc):
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
return retFuture
proc recv*(socket: TAsyncFD, size: int,
proc recv*(socket: AsyncFD, size: int,
flags = {SocketFlag.SafeDisconn}): Future[string] =
## Reads **up to** ``size`` bytes from ``socket``. Returned future will
## complete once all the data requested is read, a part of the data has been
@ -570,8 +572,8 @@ when defined(windows) or defined(nimdoc):
var flagsio = flags.toOSFlags().Dword
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
if bytesCount == 0 and dataBuf.buf[0] == '\0':
@ -634,7 +636,7 @@ when defined(windows) or defined(nimdoc):
# free ``ol``.
return retFuture
proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
proc recvInto*(socket: AsyncFD, buf: cstring, size: int,
flags = {SocketFlag.SafeDisconn}): Future[int] =
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``, which must
## at least be of that size. Returned future will complete once all the
@ -665,8 +667,8 @@ when defined(windows) or defined(nimdoc):
var flagsio = flags.toOSFlags().Dword
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
if bytesCount == 0 and dataBuf.buf[0] == '\0':
@ -721,7 +723,7 @@ when defined(windows) or defined(nimdoc):
# free ``ol``.
return retFuture
proc send*(socket: TAsyncFD, data: string,
proc send*(socket: AsyncFD, data: string,
flags = {SocketFlag.SafeDisconn}): Future[void] =
## Sends ``data`` to ``socket``. The returned future will complete once all
## data has been sent.
@ -735,8 +737,8 @@ when defined(windows) or defined(nimdoc):
var bytesReceived, lowFlags: Dword
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
retFuture.complete()
@ -764,8 +766,8 @@ when defined(windows) or defined(nimdoc):
# free ``ol``.
return retFuture
proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: TAsyncFD]] =
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: AsyncFD]] =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection and the remote address of the client.
## The future will complete when the connection is successfully accepted.
@ -778,7 +780,7 @@ when defined(windows) or defined(nimdoc):
## flag is specified then this error will not be raised and instead
## accept will be called again.
verifyPresence(socket)
var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]("acceptAddr")
var retFuture = newFuture[tuple[address: string, client: AsyncFD]]("acceptAddr")
var clientSock = newRawSocket()
if clientSock == osInvalidSocket: raiseOSError(osLastError())
@ -803,11 +805,11 @@ when defined(windows) or defined(nimdoc):
dwLocalAddressLength, dwRemoteAddressLength,
addr localSockaddr, addr localLen,
addr remoteSockaddr, addr remoteLen)
register(clientSock.TAsyncFD)
register(clientSock.AsyncFD)
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
retFuture.complete(
(address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
client: clientSock.TAsyncFD)
client: clientSock.AsyncFD)
)
template failAccept(errcode): stmt =
@ -824,8 +826,8 @@ when defined(windows) or defined(nimdoc):
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: socket, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
completeAccept()
@ -853,26 +855,26 @@ when defined(windows) or defined(nimdoc):
return retFuture
proc newAsyncRawSocket*(domain, typ, protocol: cint): TAsyncFD =
proc newAsyncRawSocket*(domain, typ, protocol: cint): AsyncFD =
## Creates a new socket and registers it with the dispatcher implicitly.
result = newRawSocket(domain, typ, protocol).TAsyncFD
result = newRawSocket(domain, typ, protocol).AsyncFD
result.SocketHandle.setBlocking(false)
register(result)
proc newAsyncRawSocket*(domain: Domain = AF_INET,
typ: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
protocol: Protocol = IPPROTO_TCP): AsyncFD =
## Creates a new socket and registers it with the dispatcher implicitly.
result = newRawSocket(domain, typ, protocol).TAsyncFD
result = newRawSocket(domain, typ, protocol).AsyncFD
result.SocketHandle.setBlocking(false)
register(result)
proc closeSocket*(socket: TAsyncFD) =
proc closeSocket*(socket: AsyncFD) =
## Closes a socket and ensures that it is unregistered.
socket.SocketHandle.close()
getGlobalDispatcher().handles.excl(socket)
proc unregister*(fd: TAsyncFD) =
proc unregister*(fd: AsyncFD) =
## Unregisters ``fd``.
getGlobalDispatcher().handles.excl(fd)
@ -892,18 +894,19 @@ else:
MSG_NOSIGNAL
type
TAsyncFD* = distinct cint
TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
AsyncFD* = distinct cint
Callback = proc (fd: AsyncFD): bool {.closure,gcsafe.}
PData* = ref object of RootRef
fd: TAsyncFD
readCBs: seq[TCallback]
writeCBs: seq[TCallback]
fd: AsyncFD
readCBs: seq[Callback]
writeCBs: seq[Callback]
PDispatcher* = ref object of PDispatcherBase
selector: Selector
{.deprecated: [TAsyncFD: AsyncFD, TCallback: Callback].}
proc `==`*(x, y: TAsyncFD): bool {.borrow.}
proc `==`*(x, y: AsyncFD): bool {.borrow.}
proc newDispatcher*(): PDispatcher =
new result
@ -915,18 +918,18 @@ else:
if gDisp.isNil: gDisp = newDispatcher()
result = gDisp
proc update(fd: TAsyncFD, events: set[Event]) =
proc update(fd: AsyncFD, events: set[Event]) =
let p = getGlobalDispatcher()
assert fd.SocketHandle in p.selector
discard p.selector.update(fd.SocketHandle, events)
proc register*(fd: TAsyncFD) =
proc register*(fd: AsyncFD) =
let p = getGlobalDispatcher()
var data = PData(fd: fd, readCBs: @[], writeCBs: @[])
p.selector.register(fd.SocketHandle, {}, data.RootRef)
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): AsyncFD =
result = newRawSocket(domain, typ, protocol).AsyncFD
result.SocketHandle.setBlocking(false)
when defined(macosx):
result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
@ -934,29 +937,29 @@ else:
proc newAsyncRawSocket*(domain: Domain = AF_INET,
typ: SockType = SOCK_STREAM,
protocol: Protocol = IPPROTO_TCP): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD
protocol: Protocol = IPPROTO_TCP): AsyncFD =
result = newRawSocket(domain, typ, protocol).AsyncFD
result.SocketHandle.setBlocking(false)
when defined(macosx):
result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
register(result)
proc closeSocket*(sock: TAsyncFD) =
proc closeSocket*(sock: AsyncFD) =
let disp = getGlobalDispatcher()
sock.SocketHandle.close()
disp.selector.unregister(sock.SocketHandle)
proc unregister*(fd: TAsyncFD) =
proc unregister*(fd: AsyncFD) =
getGlobalDispatcher().selector.unregister(fd.SocketHandle)
proc addRead*(fd: TAsyncFD, cb: TCallback) =
proc addRead*(fd: AsyncFD, cb: Callback) =
let p = getGlobalDispatcher()
if fd.SocketHandle notin p.selector:
raise newException(ValueError, "File descriptor not registered.")
p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
update(fd, p.selector[fd.SocketHandle].events + {EvRead})
proc addWrite*(fd: TAsyncFD, cb: TCallback) =
proc addWrite*(fd: AsyncFD, cb: Callback) =
let p = getGlobalDispatcher()
if fd.SocketHandle notin p.selector:
raise newException(ValueError, "File descriptor not registered.")
@ -967,7 +970,7 @@ else:
let p = getGlobalDispatcher()
for info in p.selector.select(timeout):
let data = PData(info.key.data)
assert data.fd == info.key.fd.TAsyncFD
assert data.fd == info.key.fd.AsyncFD
#echo("In poll ", data.fd.cint)
if EvError in info.events:
closeSocket(data.fd)
@ -1005,11 +1008,11 @@ else:
processTimers(p)
proc connect*(socket: TAsyncFD, address: string, port: Port,
proc connect*(socket: AsyncFD, address: string, port: Port,
af = AF_INET): Future[void] =
var retFuture = newFuture[void]("connect")
proc cb(fd: TAsyncFD): bool =
proc cb(fd: AsyncFD): bool =
# We have connected.
retFuture.complete()
return true
@ -1040,13 +1043,13 @@ else:
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
return retFuture
proc recv*(socket: TAsyncFD, size: int,
proc recv*(socket: AsyncFD, size: int,
flags = {SocketFlag.SafeDisconn}): Future[string] =
var retFuture = newFuture[string]("recv")
var readBuffer = newString(size)
proc cb(sock: TAsyncFD): bool =
proc cb(sock: AsyncFD): bool =
result = true
let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
flags.toOSFlags())
@ -1070,11 +1073,11 @@ else:
addRead(socket, cb)
return retFuture
proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
proc recvInto*(socket: AsyncFD, buf: cstring, size: int,
flags = {SocketFlag.SafeDisconn}): Future[int] =
var retFuture = newFuture[int]("recvInto")
proc cb(sock: TAsyncFD): bool =
proc cb(sock: AsyncFD): bool =
result = true
let res = recv(sock.SocketHandle, buf, size.cint,
flags.toOSFlags())
@ -1094,13 +1097,13 @@ else:
addRead(socket, cb)
return retFuture
proc send*(socket: TAsyncFD, data: string,
proc send*(socket: AsyncFD, data: string,
flags = {SocketFlag.SafeDisconn}): Future[void] =
var retFuture = newFuture[void]("send")
var written = 0
proc cb(sock: TAsyncFD): bool =
proc cb(sock: AsyncFD): bool =
result = true
let netSize = data.len-written
var d = data.cstring
@ -1126,11 +1129,11 @@ else:
addWrite(socket, cb)
return retFuture
proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: TAsyncFD]] =
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: AsyncFD]] =
var retFuture = newFuture[tuple[address: string,
client: TAsyncFD]]("acceptAddr")
proc cb(sock: TAsyncFD): bool =
client: AsyncFD]]("acceptAddr")
proc cb(sock: AsyncFD): bool =
result = true
var sockAddress: SockAddr_in
var addrLen = sizeof(sockAddress).Socklen
@ -1147,8 +1150,8 @@ else:
else:
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
else:
register(client.TAsyncFD)
retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.TAsyncFD))
register(client.AsyncFD)
retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.AsyncFD))
addRead(socket, cb)
return retFuture
@ -1160,15 +1163,15 @@ proc sleepAsync*(ms: int): Future[void] =
p.timers.add((epochTime() + (ms / 1000), retFuture))
return retFuture
proc accept*(socket: TAsyncFD,
flags = {SocketFlag.SafeDisconn}): Future[TAsyncFD] =
proc accept*(socket: AsyncFD,
flags = {SocketFlag.SafeDisconn}): Future[AsyncFD] =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection.
## The future will complete when the connection is successfully accepted.
var retFut = newFuture[TAsyncFD]("accept")
var retFut = newFuture[AsyncFD]("accept")
var fut = acceptAddr(socket, flags)
fut.callback =
proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
proc (future: Future[tuple[address: string, client: AsyncFD]]) =
assert future.finished
if future.failed:
retFut.fail(future.error)
@ -1495,7 +1498,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
#if prc[0].getName == "test":
# echo(toStrLit(result))
proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
proc recvLine*(socket: AsyncFD): Future[string] {.async.} =
## Reads a line of data from ``socket``. Returned future will complete once
## a full line is read or an error occurs.
##

View file

@ -31,7 +31,7 @@ else:
type
AsyncFile* = ref object
fd: TAsyncFd
fd: AsyncFd
offset: int64
when defined(windows) or defined(nimdoc):
@ -72,7 +72,7 @@ proc getFileSize(f: AsyncFile): int64 =
## Retrieves the specified file's size.
when defined(windows) or defined(nimdoc):
var high: DWord
let low = getFileSize(f.fd.THandle, addr high)
let low = getFileSize(f.fd.Handle, addr high)
if low == INVALID_FILE_SIZE:
raiseOSError(osLastError())
return (high shl 32) or low
@ -88,13 +88,13 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
when useWinUnicode:
result.fd = createFileW(newWideCString(filename), desiredAccess,
FILE_SHARE_READ,
nil, creationDisposition, flags, 0).TAsyncFd
nil, creationDisposition, flags, 0).AsyncFd
else:
result.fd = createFileA(filename, desiredAccess,
FILE_SHARE_READ,
nil, creationDisposition, flags, 0).TAsyncFd
nil, creationDisposition, flags, 0).AsyncFd
if result.fd.THandle == INVALID_HANDLE_VALUE:
if result.fd.Handle == INVALID_HANDLE_VALUE:
raiseOSError(osLastError())
register(result.fd)
@ -106,7 +106,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
let flags = getPosixFlags(mode)
# RW (Owner), RW (Group), R (Other)
let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
result.fd = open(filename, flags, perm).TAsyncFD
result.fd = open(filename, flags, perm).AsyncFD
if result.fd.cint == -1:
raiseOSError(osLastError())
@ -125,8 +125,8 @@ proc read*(f: AsyncFile, size: int): Future[string] =
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: f.fd, cb:
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
ol.data = CompletionData(fd: f.fd, cb:
proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
assert bytesCount > 0
@ -148,7 +148,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
ol.offsetHigh = DWord(f.offset shr 32)
# According to MSDN we're supposed to pass nil to lpNumberOfBytesRead.
let ret = readFile(f.fd.THandle, buffer, size.int32, nil,
let ret = readFile(f.fd.Handle, buffer, size.int32, nil,
cast[POVERLAPPED](ol))
if not ret.bool:
let err = osLastError()
@ -161,7 +161,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
else:
# Request completed immediately.
var bytesRead: DWord
let overlappedRes = getOverlappedResult(f.fd.THandle,
let overlappedRes = getOverlappedResult(f.fd.Handle,
cast[POverlapped](ol)[], bytesRead, false.WinBool)
if not overlappedRes.bool:
let err = osLastError()
@ -179,7 +179,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
else:
var readBuffer = newString(size)
proc cb(fd: TAsyncFD): bool =
proc cb(fd: AsyncFD): bool =
result = true
let res = read(fd.cint, addr readBuffer[0], size.cint)
if res < 0:
@ -251,8 +251,8 @@ proc write*(f: AsyncFile, data: string): Future[void] =
var ol = PCustomOverlapped()
GC_ref(ol)
ol.data = TCompletionData(fd: f.fd, cb:
proc (fd: TAsyncFD, bytesCount: DWord, errcode: OSErrorCode) =
ol.data = CompletionData(fd: f.fd, cb:
proc (fd: AsyncFD, bytesCount: DWord, errcode: OSErrorCode) =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
assert bytesCount == data.len.int32
@ -268,7 +268,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
ol.offsetHigh = DWord(f.offset shr 32)
# According to MSDN we're supposed to pass nil to lpNumberOfBytesWritten.
let ret = writeFile(f.fd.THandle, buffer, data.len.int32, nil,
let ret = writeFile(f.fd.Handle, buffer, data.len.int32, nil,
cast[POVERLAPPED](ol))
if not ret.bool:
let err = osLastError()
@ -281,7 +281,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
else:
# Request completed immediately.
var bytesWritten: DWord
let overlappedRes = getOverlappedResult(f.fd.THandle,
let overlappedRes = getOverlappedResult(f.fd.Handle,
cast[POverlapped](ol)[], bytesWritten, false.WinBool)
if not overlappedRes.bool:
retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
@ -292,7 +292,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
else:
var written = 0
proc cb(fd: TAsyncFD): bool =
proc cb(fd: AsyncFD): bool =
result = true
let remainderSize = data.len-written
let res = write(fd.cint, addr copy[written], remainderSize.cint)
@ -317,7 +317,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
proc close*(f: AsyncFile) =
## Closes the file specified.
when defined(windows) or defined(nimdoc):
if not closeHandle(f.fd.THandle).bool:
if not closeHandle(f.fd.Handle).bool:
raiseOSError(osLastError())
else:
if close(f.fd.cint) == -1:

View file

@ -210,6 +210,7 @@ proc processClient(client: AsyncSocket, address: string,
var contentLength = 0
if parseInt(request.headers["Content-Length"], contentLength) == 0:
await request.respond(Http400, "Bad Request. Invalid Content-Length.")
continue
else:
request.body = await client.recv(contentLength)
assert request.body.len == contentLength

View file

@ -188,8 +188,8 @@ proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
result.socket.setBlocking(false)
proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): AsyncSocket =
## Wraps an already initialized ``TSocket`` into a AsyncSocket.
## This is useful if you want to use an already connected TSocket as an
## Wraps an already initialized ``Socket`` into a AsyncSocket.
## This is useful if you want to use an already connected Socket as an
## asynchronous AsyncSocket in asyncio's event loop.
##
## ``state`` may be overriden, i.e. if ``sock`` is not connected it should be

View file

@ -91,9 +91,9 @@ type
# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
proc newAsyncSocket*(fd: TAsyncFD, isBuff: bool): AsyncSocket =
proc newAsyncSocket*(fd: AsyncFD, isBuff: bool): AsyncSocket =
## Creates a new ``AsyncSocket`` based on the supplied params.
assert fd != osInvalidSocket.TAsyncFD
assert fd != osInvalidSocket.AsyncFD
new(result)
result.fd = fd.SocketHandle
result.isBuffered = isBuff
@ -142,7 +142,7 @@ when defined(ssl):
if read < 0:
raiseSslError()
data.setLen(read)
await socket.fd.TAsyncFd.send(data, flags)
await socket.fd.AsyncFd.send(data, flags)
proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag],
sslError: cint) {.async.} =
@ -150,7 +150,7 @@ when defined(ssl):
of SSL_ERROR_WANT_WRITE:
await sendPendingSslData(socket, flags)
of SSL_ERROR_WANT_READ:
var data = await recv(socket.fd.TAsyncFD, BufferSize, flags)
var data = await recv(socket.fd.AsyncFD, BufferSize, flags)
let ret = bioWrite(socket.bioIn, addr data[0], data.len.cint)
if ret < 0:
raiseSSLError()
@ -175,7 +175,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port,
##
## Returns a ``Future`` which will complete when the connection succeeds
## or an error occurs.
await connect(socket.fd.TAsyncFD, address, port, af)
await connect(socket.fd.AsyncFD, address, port, af)
if socket.isSsl:
when defined(ssl):
let flags = {SocketFlag.SafeDisconn}
@ -194,7 +194,7 @@ template readInto(buf: cstring, size: int, socket: AsyncSocket,
sslRead(socket.sslHandle, buf, size.cint))
res = opResult
else:
var recvIntoFut = recvInto(socket.fd.TAsyncFD, buf, size, flags)
var recvIntoFut = recvInto(socket.fd.AsyncFD, buf, size, flags)
yield recvIntoFut
# Not in SSL mode.
res = recvIntoFut.read()
@ -271,7 +271,7 @@ proc send*(socket: AsyncSocket, data: string,
sslWrite(socket.sslHandle, addr copy[0], copy.len.cint))
await sendPendingSslData(socket, flags)
else:
await send(socket.fd.TAsyncFD, data, flags)
await send(socket.fd.AsyncFD, data, flags)
proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
Future[tuple[address: string, client: AsyncSocket]] =
@ -279,9 +279,9 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
## corresponding to that connection and the remote address of the client.
## The future will complete when the connection is successfully accepted.
var retFuture = newFuture[tuple[address: string, client: AsyncSocket]]("asyncnet.acceptAddr")
var fut = acceptAddr(socket.fd.TAsyncFD, flags)
var fut = acceptAddr(socket.fd.AsyncFD, flags)
fut.callback =
proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
proc (future: Future[tuple[address: string, client: AsyncFD]]) =
assert future.finished
if future.failed:
retFuture.fail(future.readError)
@ -445,7 +445,7 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
proc close*(socket: AsyncSocket) =
## Closes the socket.
defer:
socket.fd.TAsyncFD.closeSocket()
socket.fd.AsyncFD.closeSocket()
when defined(ssl):
if socket.isSSL:
let res = SslShutdown(socket.sslHandle)

View file

@ -20,20 +20,20 @@ import strutils
##
## # Create a matrix which first rotates, then scales and at last translates
##
## var m:TMatrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
## var m:Matrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
##
## # Create a 2d point at (100,0) and a vector (5,2)
##
## var pt:TPoint2d=point2d(100.0,0.0)
## var pt:Point2d=point2d(100.0,0.0)
##
## var vec:TVector2d=vector2d(5.0,2.0)
## var vec:Vector2d=vector2d(5.0,2.0)
##
##
## pt &= m # transforms pt in place
##
## var pt2:TPoint2d=pt & m #concatenates pt with m and returns a new point
## var pt2:Point2d=pt & m #concatenates pt with m and returns a new point
##
## var vec2:TVector2d=vec & m #concatenates vec with m and returns a new vector
## var vec2:Vector2d=vec & m #concatenates vec with m and returns a new vector
const
@ -57,46 +57,46 @@ const
## used internally by DegToRad and RadToDeg
type
TMatrix2d* = object
Matrix2d* = object
## Implements a row major 2d matrix, which means
## transformations are applied the order they are concatenated.
## The rightmost column of the 3x3 matrix is left out since normally
## not used for geometric transformations in 2d.
ax*,ay*,bx*,by*,tx*,ty*:float
TPoint2d* = object
Point2d* = object
## Implements a non-homegeneous 2d point stored as
## an `x` coordinate and an `y` coordinate.
x*,y*:float
TVector2d* = object
Vector2d* = object
## Implements a 2d **direction vector** stored as
## an `x` coordinate and an `y` coordinate. Direction vector means,
## that when transforming a vector with a matrix, the translational
## part of the matrix is ignored.
x*,y*:float
{.deprecated: [TMatrix2d: Matrix2d, TPoint2d: Point2d, TVector2d: Vector2d].}
# Some forward declarations...
proc matrix2d*(ax,ay,bx,by,tx,ty:float):TMatrix2d {.noInit.}
proc matrix2d*(ax,ay,bx,by,tx,ty:float):Matrix2d {.noInit.}
## Creates a new matrix.
## `ax`,`ay` is the local x axis
## `bx`,`by` is the local y axis
## `tx`,`ty` is the translation
proc vector2d*(x,y:float):TVector2d {.noInit,inline.}
proc vector2d*(x,y:float):Vector2d {.noInit,inline.}
## Returns a new vector (`x`,`y`)
proc point2d*(x,y:float):TPoint2d {.noInit,inline.}
proc point2d*(x,y:float):Point2d {.noInit,inline.}
## Returns a new point (`x`,`y`)
let
IDMATRIX*:TMatrix2d=matrix2d(1.0,0.0,0.0,1.0,0.0,0.0)
IDMATRIX*:Matrix2d=matrix2d(1.0,0.0,0.0,1.0,0.0,0.0)
## Quick access to an identity matrix
ORIGO*:TPoint2d=point2d(0.0,0.0)
ORIGO*:Point2d=point2d(0.0,0.0)
## Quick acces to point (0,0)
XAXIS*:TVector2d=vector2d(1.0,0.0)
XAXIS*:Vector2d=vector2d(1.0,0.0)
## Quick acces to an 2d x-axis unit vector
YAXIS*:TVector2d=vector2d(0.0,1.0)
YAXIS*:Vector2d=vector2d(0.0,1.0)
## Quick acces to an 2d y-axis unit vector
@ -116,21 +116,21 @@ proc safeArccos(v:float):float=
template makeBinOpVector(s:expr)=
## implements binary operators + , - , * and / for vectors
proc s*(a,b:TVector2d):TVector2d {.inline,noInit.} = vector2d(s(a.x,b.x),s(a.y,b.y))
proc s*(a:TVector2d,b:float):TVector2d {.inline,noInit.} = vector2d(s(a.x,b),s(a.y,b))
proc s*(a:float,b:TVector2d):TVector2d {.inline,noInit.} = vector2d(s(a,b.x),s(a,b.y))
proc s*(a,b:Vector2d):Vector2d {.inline,noInit.} = vector2d(s(a.x,b.x),s(a.y,b.y))
proc s*(a:Vector2d,b:float):Vector2d {.inline,noInit.} = vector2d(s(a.x,b),s(a.y,b))
proc s*(a:float,b:Vector2d):Vector2d {.inline,noInit.} = vector2d(s(a,b.x),s(a,b.y))
template makeBinOpAssignVector(s:expr)=
## implements inplace binary operators += , -= , /= and *= for vectors
proc s*(a:var TVector2d,b:TVector2d) {.inline.} = s(a.x,b.x) ; s(a.y,b.y)
proc s*(a:var TVector2d,b:float) {.inline.} = s(a.x,b) ; s(a.y,b)
proc s*(a:var Vector2d,b:Vector2d) {.inline.} = s(a.x,b.x) ; s(a.y,b.y)
proc s*(a:var Vector2d,b:float) {.inline.} = s(a.x,b) ; s(a.y,b)
# ***************************************
# TMatrix2d implementation
# Matrix2d implementation
# ***************************************
proc setElements*(t:var TMatrix2d,ax,ay,bx,by,tx,ty:float) {.inline.}=
proc setElements*(t:var Matrix2d,ax,ay,bx,by,tx,ty:float) {.inline.}=
## Sets arbitrary elements in an existing matrix.
t.ax=ax
t.ay=ay
@ -139,10 +139,10 @@ proc setElements*(t:var TMatrix2d,ax,ay,bx,by,tx,ty:float) {.inline.}=
t.tx=tx
t.ty=ty
proc matrix2d*(ax,ay,bx,by,tx,ty:float):TMatrix2d =
proc matrix2d*(ax,ay,bx,by,tx,ty:float):Matrix2d =
result.setElements(ax,ay,bx,by,tx,ty)
proc `&`*(a,b:TMatrix2d):TMatrix2d {.noInit.} = #concatenate matrices
proc `&`*(a,b:Matrix2d):Matrix2d {.noInit.} = #concatenate matrices
## Concatenates matrices returning a new matrix.
# | a.AX a.AY 0 | | b.AX b.AY 0 |
@ -157,34 +157,34 @@ proc `&`*(a,b:TMatrix2d):TMatrix2d {.noInit.} = #concatenate matrices
a.tx * b.ay + a.ty * b.by + b.ty)
proc scale*(s:float):TMatrix2d {.noInit.} =
proc scale*(s:float):Matrix2d {.noInit.} =
## Returns a new scale matrix.
result.setElements(s,0,0,s,0,0)
proc scale*(s:float,org:TPoint2d):TMatrix2d {.noInit.} =
proc scale*(s:float,org:Point2d):Matrix2d {.noInit.} =
## Returns a new scale matrix using, `org` as scale origin.
result.setElements(s,0,0,s,org.x-s*org.x,org.y-s*org.y)
proc stretch*(sx,sy:float):TMatrix2d {.noInit.} =
proc stretch*(sx,sy:float):Matrix2d {.noInit.} =
## Returns new a stretch matrix, which is a
## scale matrix with non uniform scale in x and y.
result.setElements(sx,0,0,sy,0,0)
proc stretch*(sx,sy:float,org:TPoint2d):TMatrix2d {.noInit.} =
proc stretch*(sx,sy:float,org:Point2d):Matrix2d {.noInit.} =
## Returns a new stretch matrix, which is a
## scale matrix with non uniform scale in x and y.
## `org` is used as stretch origin.
result.setElements(sx,0,0,sy,org.x-sx*org.x,org.y-sy*org.y)
proc move*(dx,dy:float):TMatrix2d {.noInit.} =
proc move*(dx,dy:float):Matrix2d {.noInit.} =
## Returns a new translation matrix.
result.setElements(1,0,0,1,dx,dy)
proc move*(v:TVector2d):TMatrix2d {.noInit.} =
proc move*(v:Vector2d):Matrix2d {.noInit.} =
## Returns a new translation matrix from a vector.
result.setElements(1,0,0,1,v.x,v.y)
proc rotate*(rad:float):TMatrix2d {.noInit.} =
proc rotate*(rad:float):Matrix2d {.noInit.} =
## Returns a new rotation matrix, which
## represents a rotation by `rad` radians
let
@ -192,7 +192,7 @@ proc rotate*(rad:float):TMatrix2d {.noInit.} =
c=cos(rad)
result.setElements(c,s,-s,c,0,0)
proc rotate*(rad:float,org:TPoint2d):TMatrix2d {.noInit.} =
proc rotate*(rad:float,org:Point2d):Matrix2d {.noInit.} =
## Returns a new rotation matrix, which
## represents a rotation by `rad` radians around
## the origin `org`
@ -201,7 +201,7 @@ proc rotate*(rad:float,org:TPoint2d):TMatrix2d {.noInit.} =
c=cos(rad)
result.setElements(c,s,-s,c,org.x+s*org.y-c*org.x,org.y-c*org.y-s*org.x)
proc mirror*(v:TVector2d):TMatrix2d {.noInit.} =
proc mirror*(v:Vector2d):Matrix2d {.noInit.} =
## Returns a new mirror matrix, mirroring
## around the line that passes through origo and
## has the direction of `v`
@ -220,7 +220,7 @@ proc mirror*(v:TVector2d):TMatrix2d {.noInit.} =
xy2,-sqd,
0.0,0.0)
proc mirror*(org:TPoint2d,v:TVector2d):TMatrix2d {.noInit.} =
proc mirror*(org:Point2d,v:Vector2d):Matrix2d {.noInit.} =
## Returns a new mirror matrix, mirroring
## around the line that passes through `org` and
## has the direction of `v`
@ -241,20 +241,20 @@ proc mirror*(org:TPoint2d,v:TVector2d):TMatrix2d {.noInit.} =
proc skew*(xskew,yskew:float):TMatrix2d {.noInit.} =
proc skew*(xskew,yskew:float):Matrix2d {.noInit.} =
## Returns a new skew matrix, which has its
## x axis rotated `xskew` radians from the local x axis, and
## y axis rotated `yskew` radians from the local y axis
result.setElements(cos(yskew),sin(yskew),-sin(xskew),cos(xskew),0,0)
proc `$`* (t:TMatrix2d):string {.noInit.} =
proc `$`* (t:Matrix2d):string {.noInit.} =
## Returns a string representation of the matrix
return rtos(t.ax) & "," & rtos(t.ay) &
"," & rtos(t.bx) & "," & rtos(t.by) &
"," & rtos(t.tx) & "," & rtos(t.ty)
proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool=
proc isUniform*(t:Matrix2d,tol=1.0e-6):bool=
## Checks if the transform is uniform, that is
## perpendicular axes of equal length, which means (for example)
## it cannot transform a circle into an ellipse.
@ -268,18 +268,18 @@ proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool=
return true
return false
proc determinant*(t:TMatrix2d):float=
proc determinant*(t:Matrix2d):float=
## Computes the determinant of the matrix.
#NOTE: equivalent with perp.dot product for two 2d vectors
return t.ax*t.by-t.bx*t.ay
proc isMirroring* (m:TMatrix2d):bool=
proc isMirroring* (m:Matrix2d):bool=
## Checks if the `m` is a mirroring matrix,
## which means it will reverse direction of a curve transformed with it
return m.determinant<0.0
proc inverse*(m:TMatrix2d):TMatrix2d {.noInit.} =
proc inverse*(m:Matrix2d):Matrix2d {.noInit.} =
## Returns a new matrix, which is the inverse of the matrix
## If the matrix is not invertible (determinant=0), an EDivByZero
## will be raised.
@ -293,7 +293,7 @@ proc inverse*(m:TMatrix2d):TMatrix2d {.noInit.} =
(m.bx*m.ty-m.by*m.tx)/d,
(m.ay*m.tx-m.ax*m.ty)/d)
proc equals*(m1:TMatrix2d,m2:TMatrix2d,tol=1.0e-6):bool=
proc equals*(m1:Matrix2d,m2:Matrix2d,tol=1.0e-6):bool=
## Checks if all elements of `m1`and `m2` is equal within
## a given tolerance `tol`.
return
@ -304,17 +304,17 @@ proc equals*(m1:TMatrix2d,m2:TMatrix2d,tol=1.0e-6):bool=
abs(m1.tx-m2.tx)<=tol and
abs(m1.ty-m2.ty)<=tol
proc `=~`*(m1,m2:TMatrix2d):bool=
proc `=~`*(m1,m2:Matrix2d):bool=
## Checks if `m1`and `m2` is approximately equal, using a
## tolerance of 1e-6.
equals(m1,m2)
proc isIdentity*(m:TMatrix2d,tol=1.0e-6):bool=
proc isIdentity*(m:Matrix2d,tol=1.0e-6):bool=
## Checks is a matrix is approximately an identity matrix,
## using `tol` as tolerance for each element.
return equals(m,IDMATRIX,tol)
proc apply*(m:TMatrix2d,x,y:var float,translate=false)=
proc apply*(m:Matrix2d,x,y:var float,translate=false)=
## Applies transformation `m` onto `x`,`y`, optionally
## using the translation part of the matrix.
if translate: # positional style transform
@ -329,29 +329,29 @@ proc apply*(m:TMatrix2d,x,y:var float,translate=false)=
# ***************************************
# TVector2d implementation
# Vector2d implementation
# ***************************************
proc vector2d*(x,y:float):TVector2d = #forward decl.
proc vector2d*(x,y:float):Vector2d = #forward decl.
result.x=x
result.y=y
proc polarVector2d*(ang:float,len:float):TVector2d {.noInit.} =
proc polarVector2d*(ang:float,len:float):Vector2d {.noInit.} =
## Returns a new vector with angle `ang` and magnitude `len`
result.x=cos(ang)*len
result.y=sin(ang)*len
proc slopeVector2d*(slope:float,len:float):TVector2d {.noInit.} =
proc slopeVector2d*(slope:float,len:float):Vector2d {.noInit.} =
## Returns a new vector having slope (dy/dx) given by
## `slope`, and a magnitude of `len`
let ang=arctan(slope)
result.x=cos(ang)*len
result.y=sin(ang)*len
proc len*(v:TVector2d):float {.inline.}=
proc len*(v:Vector2d):float {.inline.}=
## Returns the length of the vector.
sqrt(v.x*v.x+v.y*v.y)
proc `len=`*(v:var TVector2d,newlen:float) {.noInit.} =
proc `len=`*(v:var Vector2d,newlen:float) {.noInit.} =
## Sets the length of the vector, keeping its angle.
let fac=newlen/v.len
@ -369,25 +369,25 @@ proc `len=`*(v:var TVector2d,newlen:float) {.noInit.} =
v.x*=fac
v.y*=fac
proc sqrLen*(v:TVector2d):float {.inline.}=
proc sqrLen*(v:Vector2d):float {.inline.}=
## Computes the squared length of the vector, which is
## faster than computing the absolute length.
v.x*v.x+v.y*v.y
proc angle*(v:TVector2d):float=
proc angle*(v:Vector2d):float=
## Returns the angle of the vector.
## (The counter clockwise plane angle between posetive x axis and `v`)
result=arctan2(v.y,v.x)
if result<0.0: result+=DEG360
proc `$` *(v:TVector2d):string=
proc `$` *(v:Vector2d):string=
## String representation of `v`
result=rtos(v.x)
result.add(",")
result.add(rtos(v.y))
proc `&` *(v:TVector2d,m:TMatrix2d):TVector2d {.noInit.} =
proc `&` *(v:Vector2d,m:Matrix2d):Vector2d {.noInit.} =
## Concatenate vector `v` with a transformation matrix.
## Transforming a vector ignores the translational part
## of the matrix.
@ -399,7 +399,7 @@ proc `&` *(v:TVector2d,m:TMatrix2d):TVector2d {.noInit.} =
result.y=v.x*m.ay+v.y*m.by
proc `&=`*(v:var TVector2d,m:TMatrix2d) {.inline.}=
proc `&=`*(v:var Vector2d,m:Matrix2d) {.inline.}=
## Applies transformation `m` onto `v` in place.
## Transforming a vector ignores the translational part
## of the matrix.
@ -412,7 +412,7 @@ proc `&=`*(v:var TVector2d,m:TMatrix2d) {.inline.}=
v.x=newx
proc tryNormalize*(v:var TVector2d):bool=
proc tryNormalize*(v:var Vector2d):bool=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length (and thus no angle), it is left unmodified and
## false is returned, otherwise true is returned.
@ -427,13 +427,13 @@ proc tryNormalize*(v:var TVector2d):bool=
return true
proc normalize*(v:var TVector2d) {.inline.}=
proc normalize*(v:var Vector2d) {.inline.}=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length, an EDivByZero will be raised.
if not tryNormalize(v):
raise newException(DivByZeroError,"Cannot normalize zero length vector")
proc transformNorm*(v:var TVector2d,t:TMatrix2d)=
proc transformNorm*(v:var Vector2d,t:Matrix2d)=
## Applies a normal direction transformation `t` onto `v` in place.
## The resulting vector is *not* normalized. Transforming a vector ignores the
## translational part of the matrix. If the matrix is not invertible
@ -452,7 +452,7 @@ proc transformNorm*(v:var TVector2d,t:TMatrix2d)=
v.y = (t.ax*v.y-t.bx*v.x)/d
v.x = newx
proc transformInv*(v:var TVector2d,t:TMatrix2d)=
proc transformInv*(v:var Vector2d,t:Matrix2d)=
## Applies inverse of a transformation `t` to `v` in place.
## This is faster than creating an inverse matrix and apply() it.
## Transforming a vector ignores the translational part
@ -467,7 +467,7 @@ proc transformInv*(v:var TVector2d,t:TMatrix2d)=
v.y = (t.ax*v.y-t.ay*v.x)/d
v.x = newx
proc transformNormInv*(v:var TVector2d,t:TMatrix2d)=
proc transformNormInv*(v:var Vector2d,t:Matrix2d)=
## Applies an inverse normal direction transformation `t` onto `v` in place.
## This is faster than creating an inverse
## matrix and transformNorm(...) it. Transforming a vector ignores the
@ -484,25 +484,25 @@ proc transformNormInv*(v:var TVector2d,t:TMatrix2d)=
v.y=t.by*v.y+t.bx*v.x
v.x=newx
proc rotate90*(v:var TVector2d) {.inline.}=
proc rotate90*(v:var Vector2d) {.inline.}=
## Quickly rotates vector `v` 90 degrees counter clockwise,
## without using any trigonometrics.
swap(v.x,v.y)
v.x= -v.x
proc rotate180*(v:var TVector2d){.inline.}=
proc rotate180*(v:var Vector2d){.inline.}=
## Quickly rotates vector `v` 180 degrees counter clockwise,
## without using any trigonometrics.
v.x= -v.x
v.y= -v.y
proc rotate270*(v:var TVector2d) {.inline.}=
proc rotate270*(v:var Vector2d) {.inline.}=
## Quickly rotates vector `v` 270 degrees counter clockwise,
## without using any trigonometrics.
swap(v.x,v.y)
v.y= -v.y
proc rotate*(v:var TVector2d,rad:float) =
proc rotate*(v:var Vector2d,rad:float) =
## Rotates vector `v` `rad` radians in place.
let
s=sin(rad)
@ -511,18 +511,18 @@ proc rotate*(v:var TVector2d,rad:float) =
v.y=c*v.y+s*v.x
v.x=newx
proc scale*(v:var TVector2d,fac:float){.inline.}=
proc scale*(v:var Vector2d,fac:float){.inline.}=
## Scales vector `v` `rad` radians in place.
v.x*=fac
v.y*=fac
proc stretch*(v:var TVector2d,facx,facy:float){.inline.}=
proc stretch*(v:var Vector2d,facx,facy:float){.inline.}=
## Stretches vector `v` `facx` times horizontally,
## and `facy` times vertically.
v.x*=facx
v.y*=facy
proc mirror*(v:var TVector2d,mirrvec:TVector2d)=
proc mirror*(v:var Vector2d,mirrvec:Vector2d)=
## Mirrors vector `v` using `mirrvec` as mirror direction.
let
sqx=mirrvec.x*mirrvec.x
@ -539,7 +539,7 @@ proc mirror*(v:var TVector2d,mirrvec:TVector2d)=
v.x=newx
proc `-` *(v:TVector2d):TVector2d=
proc `-` *(v:Vector2d):Vector2d=
## Negates a vector
result.x= -v.x
result.y= -v.y
@ -555,27 +555,27 @@ makeBinOpAssignVector(`*=`)
makeBinOpAssignVector(`/=`)
proc dot*(v1,v2:TVector2d):float=
proc dot*(v1,v2:Vector2d):float=
## Computes the dot product of two vectors.
## Returns 0.0 if the vectors are perpendicular.
return v1.x*v2.x+v1.y*v2.y
proc cross*(v1,v2:TVector2d):float=
proc cross*(v1,v2:Vector2d):float=
## Computes the cross product of two vectors, also called
## the 'perpendicular dot product' in 2d. Returns 0.0 if the vectors
## are parallel.
return v1.x*v2.y-v1.y*v2.x
proc equals*(v1,v2:TVector2d,tol=1.0e-6):bool=
proc equals*(v1,v2:Vector2d,tol=1.0e-6):bool=
## Checks if two vectors approximately equals with a tolerance.
return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol
proc `=~` *(v1,v2:TVector2d):bool=
proc `=~` *(v1,v2:Vector2d):bool=
## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(v1,v2)
proc angleTo*(v1,v2:TVector2d):float=
proc angleTo*(v1,v2:Vector2d):float=
## Returns the smallest of the two possible angles
## between `v1` and `v2` in radians.
var
@ -585,7 +585,7 @@ proc angleTo*(v1,v2:TVector2d):float=
return 0.0 # zero length vector has zero angle to any other vector
return safeArccos(dot(nv1,nv2))
proc angleCCW*(v1,v2:TVector2d):float=
proc angleCCW*(v1,v2:Vector2d):float=
## Returns the counter clockwise plane angle from `v1` to `v2`,
## in range 0 - 2*PI
let a=v1.angleTo(v2)
@ -593,7 +593,7 @@ proc angleCCW*(v1,v2:TVector2d):float=
return a
return DEG360-a
proc angleCW*(v1,v2:TVector2d):float=
proc angleCW*(v1,v2:Vector2d):float=
## Returns the clockwise plane angle from `v1` to `v2`,
## in range 0 - 2*PI
let a=v1.angleTo(v2)
@ -601,7 +601,7 @@ proc angleCW*(v1,v2:TVector2d):float=
return a
return DEG360-a
proc turnAngle*(v1,v2:TVector2d):float=
proc turnAngle*(v1,v2:Vector2d):float=
## Returns the amount v1 should be rotated (in radians) to equal v2,
## in range -PI to PI
let a=v1.angleTo(v2)
@ -609,7 +609,7 @@ proc turnAngle*(v1,v2:TVector2d):float=
return -a
return a
proc bisect*(v1,v2:TVector2d):TVector2d {.noInit.}=
proc bisect*(v1,v2:Vector2d):Vector2d {.noInit.}=
## Computes the bisector between v1 and v2 as a normalized vector.
## If one of the input vectors has zero length, a normalized version
## of the other is returned. If both input vectors has zero length,
@ -645,24 +645,24 @@ proc bisect*(v1,v2:TVector2d):TVector2d {.noInit.}=
# ***************************************
# TPoint2d implementation
# Point2d implementation
# ***************************************
proc point2d*(x,y:float):TPoint2d =
proc point2d*(x,y:float):Point2d =
result.x=x
result.y=y
proc sqrDist*(a,b:TPoint2d):float=
proc sqrDist*(a,b:Point2d):float=
## Computes the squared distance between `a` and `b`
let dx=b.x-a.x
let dy=b.y-a.y
result=dx*dx+dy*dy
proc dist*(a,b:TPoint2d):float {.inline.}=
proc dist*(a,b:Point2d):float {.inline.}=
## Computes the absolute distance between `a` and `b`
result=sqrt(sqrDist(a,b))
proc angle*(a,b:TPoint2d):float=
proc angle*(a,b:Point2d):float=
## Computes the angle of the vector `b`-`a`
let dx=b.x-a.x
let dy=b.y-a.y
@ -670,13 +670,13 @@ proc angle*(a,b:TPoint2d):float=
if result<0:
result += DEG360
proc `$` *(p:TPoint2d):string=
proc `$` *(p:Point2d):string=
## String representation of `p`
result=rtos(p.x)
result.add(",")
result.add(rtos(p.y))
proc `&`*(p:TPoint2d,t:TMatrix2d):TPoint2d {.noInit,inline.} =
proc `&`*(p:Point2d,t:Matrix2d):Point2d {.noInit,inline.} =
## Concatenates a point `p` with a transform `t`,
## resulting in a new, transformed point.
@ -686,14 +686,14 @@ proc `&`*(p:TPoint2d,t:TMatrix2d):TPoint2d {.noInit,inline.} =
result.x=p.x*t.ax+p.y*t.bx+t.tx
result.y=p.x*t.ay+p.y*t.by+t.ty
proc `&=` *(p:var TPoint2d,t:TMatrix2d) {.inline.}=
proc `&=` *(p:var Point2d,t:Matrix2d) {.inline.}=
## Applies transformation `t` onto `p` in place.
let newx=p.x*t.ax+p.y*t.bx+t.tx
p.y=p.x*t.ay+p.y*t.by+t.ty
p.x=newx
proc transformInv*(p:var TPoint2d,t:TMatrix2d){.inline.}=
proc transformInv*(p:var Point2d,t:Matrix2d){.inline.}=
## Applies the inverse of transformation `t` onto `p` in place.
## If the matrix is not invertable (determinant=0) , EDivByZero will
## be raised.
@ -710,48 +710,48 @@ proc transformInv*(p:var TPoint2d,t:TMatrix2d){.inline.}=
p.x=newx
proc `+`*(p:TPoint2d,v:TVector2d):TPoint2d {.noInit,inline.} =
proc `+`*(p:Point2d,v:Vector2d):Point2d {.noInit,inline.} =
## Adds a vector `v` to a point `p`, resulting
## in a new point.
result.x=p.x+v.x
result.y=p.y+v.y
proc `+=`*(p:var TPoint2d,v:TVector2d) {.noInit,inline.} =
proc `+=`*(p:var Point2d,v:Vector2d) {.noInit,inline.} =
## Adds a vector `v` to a point `p` in place.
p.x+=v.x
p.y+=v.y
proc `-`*(p:TPoint2d,v:TVector2d):TPoint2d {.noInit,inline.} =
proc `-`*(p:Point2d,v:Vector2d):Point2d {.noInit,inline.} =
## Subtracts a vector `v` from a point `p`, resulting
## in a new point.
result.x=p.x-v.x
result.y=p.y-v.y
proc `-`*(p1,p2:TPoint2d):TVector2d {.noInit,inline.} =
proc `-`*(p1,p2:Point2d):Vector2d {.noInit,inline.} =
## Subtracts `p2`from `p1` resulting in a difference vector.
result.x=p1.x-p2.x
result.y=p1.y-p2.y
proc `-=`*(p:var TPoint2d,v:TVector2d) {.noInit,inline.} =
proc `-=`*(p:var Point2d,v:Vector2d) {.noInit,inline.} =
## Subtracts a vector `v` from a point `p` in place.
p.x-=v.x
p.y-=v.y
proc equals(p1,p2:TPoint2d,tol=1.0e-6):bool {.inline.}=
proc equals(p1,p2:Point2d,tol=1.0e-6):bool {.inline.}=
## Checks if two points approximately equals with a tolerance.
return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol
proc `=~`*(p1,p2:TPoint2d):bool {.inline.}=
proc `=~`*(p1,p2:Point2d):bool {.inline.}=
## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(p1,p2)
proc polar*(p:TPoint2d,ang,dist:float):TPoint2d {.noInit.} =
proc polar*(p:Point2d,ang,dist:float):Point2d {.noInit.} =
## Returns a point with a given angle and distance away from `p`
result.x=p.x+cos(ang)*dist
result.y=p.y+sin(ang)*dist
proc rotate*(p:var TPoint2d,rad:float)=
proc rotate*(p:var Point2d,rad:float)=
## Rotates a point in place `rad` radians around origo.
let
c=cos(rad)
@ -760,7 +760,7 @@ proc rotate*(p:var TPoint2d,rad:float)=
p.y=p.y*c+p.x*s
p.x=newx
proc rotate*(p:var TPoint2d,rad:float,org:TPoint2d)=
proc rotate*(p:var Point2d,rad:float,org:Point2d)=
## Rotates a point in place `rad` radians using `org` as
## center of rotation.
let
@ -770,50 +770,50 @@ proc rotate*(p:var TPoint2d,rad:float,org:TPoint2d)=
p.y=(p.y - org.y) * c + (p.x - org.x) * s + org.y
p.x=newx
proc scale*(p:var TPoint2d,fac:float) {.inline.}=
proc scale*(p:var Point2d,fac:float) {.inline.}=
## Scales a point in place `fac` times with world origo as origin.
p.x*=fac
p.y*=fac
proc scale*(p:var TPoint2d,fac:float,org:TPoint2d){.inline.}=
proc scale*(p:var Point2d,fac:float,org:Point2d){.inline.}=
## Scales the point in place `fac` times with `org` as origin.
p.x=(p.x - org.x) * fac + org.x
p.y=(p.y - org.y) * fac + org.y
proc stretch*(p:var TPoint2d,facx,facy:float){.inline.}=
proc stretch*(p:var Point2d,facx,facy:float){.inline.}=
## Scales a point in place non uniformly `facx` and `facy` times with
## world origo as origin.
p.x*=facx
p.y*=facy
proc stretch*(p:var TPoint2d,facx,facy:float,org:TPoint2d){.inline.}=
proc stretch*(p:var Point2d,facx,facy:float,org:Point2d){.inline.}=
## Scales the point in place non uniformly `facx` and `facy` times with
## `org` as origin.
p.x=(p.x - org.x) * facx + org.x
p.y=(p.y - org.y) * facy + org.y
proc move*(p:var TPoint2d,dx,dy:float){.inline.}=
proc move*(p:var Point2d,dx,dy:float){.inline.}=
## Translates a point `dx`, `dy` in place.
p.x+=dx
p.y+=dy
proc move*(p:var TPoint2d,v:TVector2d){.inline.}=
proc move*(p:var Point2d,v:Vector2d){.inline.}=
## Translates a point with vector `v` in place.
p.x+=v.x
p.y+=v.y
proc sgnArea*(a,b,c:TPoint2d):float=
proc sgnArea*(a,b,c:Point2d):float=
## Computes the signed area of the triangle thru points `a`,`b` and `c`
## result>0.0 for counter clockwise triangle
## result<0.0 for clockwise triangle
## This is commonly used to determinate side of a point with respect to a line.
return ((b.x - c.x) * (b.y - a.y)-(b.y - c.y) * (b.x - a.x))*0.5
proc area*(a,b,c:TPoint2d):float=
proc area*(a,b,c:Point2d):float=
## Computes the area of the triangle thru points `a`,`b` and `c`
return abs(sgnArea(a,b,c))
proc closestPoint*(p:TPoint2d,pts:varargs[TPoint2d]):TPoint2d=
proc closestPoint*(p:Point2d,pts:varargs[Point2d]):Point2d=
## Returns a point selected from `pts`, that has the closest
## euclidean distance to `p`
assert(pts.len>0) # must have at least one point

View file

@ -25,25 +25,25 @@ import times
##
## # Create a matrix which first rotates, then scales and at last translates
##
## var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
## var m:Matrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
##
## # Create a 3d point at (100,150,200) and a vector (5,2,3)
##
## var pt:TPoint3d=point3d(100.0,150.0,200.0)
## var pt:Point3d=point3d(100.0,150.0,200.0)
##
## var vec:TVector3d=vector3d(5.0,2.0,3.0)
## var vec:Vector3d=vector3d(5.0,2.0,3.0)
##
##
## pt &= m # transforms pt in place
##
## var pt2:TPoint3d=pt & m #concatenates pt with m and returns a new point
## var pt2:Point3d=pt & m #concatenates pt with m and returns a new point
##
## var vec2:TVector3d=vec & m #concatenates vec with m and returns a new vector
## var vec2:Vector3d=vec & m #concatenates vec with m and returns a new vector
type
TMatrix3d* =object
Matrix3d* =object
## Implements a row major 3d matrix, which means
## transformations are applied the order they are concatenated.
## This matrix is stored as an 4x4 matrix:
@ -52,31 +52,31 @@ type
## [ cx cy cz cw ]
## [ tx ty tz tw ]
ax*,ay*,az*,aw*, bx*,by*,bz*,bw*, cx*,cy*,cz*,cw*, tx*,ty*,tz*,tw*:float
TPoint3d* = object
Point3d* = object
## Implements a non-homegeneous 2d point stored as
## an `x` , `y` and `z` coordinate.
x*,y*,z*:float
TVector3d* = object
Vector3d* = object
## Implements a 3d **direction vector** stored as
## an `x` , `y` and `z` coordinate. Direction vector means,
## that when transforming a vector with a matrix, the translational
## part of the matrix is ignored.
x*,y*,z*:float
{.deprecated: [TMatrix3d: Matrix3d, TPoint3d: Point3d, TVector3d: Vector3d].}
# Some forward declarations
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d {.noInit.}
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):Matrix3d {.noInit.}
## Creates a new 4x4 3d transformation matrix.
## `ax` , `ay` , `az` is the local x axis.
## `bx` , `by` , `bz` is the local y axis.
## `cx` , `cy` , `cz` is the local z axis.
## `tx` , `ty` , `tz` is the translation.
proc vector3d*(x,y,z:float):TVector3d {.noInit,inline.}
proc vector3d*(x,y,z:float):Vector3d {.noInit,inline.}
## Returns a new 3d vector (`x`,`y`,`z`)
proc point3d*(x,y,z:float):TPoint3d {.noInit,inline.}
proc point3d*(x,y,z:float):Point3d {.noInit,inline.}
## Returns a new 4d point (`x`,`y`,`z`)
proc tryNormalize*(v:var TVector3d):bool
proc tryNormalize*(v:var Vector3d):bool
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length (and thus no angle), it is left unmodified and false is
## returned, otherwise true is returned.
@ -84,19 +84,19 @@ proc tryNormalize*(v:var TVector3d):bool
let
IDMATRIX*:TMatrix3d=matrix3d(
IDMATRIX*:Matrix3d=matrix3d(
1.0,0.0,0.0,0.0,
0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,
0.0,0.0,0.0,1.0)
## Quick access to a 3d identity matrix
ORIGO*:TPoint3d=point3d(0.0,0.0,0.0)
ORIGO*:Point3d=point3d(0.0,0.0,0.0)
## Quick access to point (0,0)
XAXIS*:TVector3d=vector3d(1.0,0.0,0.0)
XAXIS*:Vector3d=vector3d(1.0,0.0,0.0)
## Quick access to an 3d x-axis unit vector
YAXIS*:TVector3d=vector3d(0.0,1.0,0.0)
YAXIS*:Vector3d=vector3d(0.0,1.0,0.0)
## Quick access to an 3d y-axis unit vector
ZAXIS*:TVector3d=vector3d(0.0,0.0,1.0)
ZAXIS*:Vector3d=vector3d(0.0,0.0,1.0)
## Quick access to an 3d z-axis unit vector
@ -116,27 +116,27 @@ proc safeArccos(v:float):float=
template makeBinOpVector(s:expr)=
## implements binary operators + , - , * and / for vectors
proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
proc s*(a,b:Vector3d):Vector3d {.inline,noInit.} =
vector3d(s(a.x,b.x),s(a.y,b.y),s(a.z,b.z))
proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.} =
proc s*(a:Vector3d,b:float):Vector3d {.inline,noInit.} =
vector3d(s(a.x,b),s(a.y,b),s(a.z,b))
proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.} =
proc s*(a:float,b:Vector3d):Vector3d {.inline,noInit.} =
vector3d(s(a,b.x),s(a,b.y),s(a,b.z))
template makeBinOpAssignVector(s:expr)=
## implements inplace binary operators += , -= , /= and *= for vectors
proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
proc s*(a:var Vector3d,b:Vector3d) {.inline.} =
s(a.x,b.x) ; s(a.y,b.y) ; s(a.z,b.z)
proc s*(a:var TVector3d,b:float) {.inline.} =
proc s*(a:var Vector3d,b:float) {.inline.} =
s(a.x,b) ; s(a.y,b) ; s(a.z,b)
# ***************************************
# TMatrix3d implementation
# Matrix3d implementation
# ***************************************
proc setElements*(t:var TMatrix3d,ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float) {.inline.}=
proc setElements*(t:var Matrix3d,ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float) {.inline.}=
## Sets arbitrary elements in an exisitng matrix.
t.ax=ax
t.ay=ay
@ -155,10 +155,10 @@ proc setElements*(t:var TMatrix3d,ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,t
t.tz=tz
t.tw=tw
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d =
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):Matrix3d =
result.setElements(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw)
proc `&`*(a,b:TMatrix3d):TMatrix3d {.noinit.} =
proc `&`*(a,b:Matrix3d):Matrix3d {.noinit.} =
## Concatenates matrices returning a new matrix.
result.setElements(
a.aw*b.tx+a.az*b.cx+a.ay*b.bx+a.ax*b.ax,
@ -182,36 +182,36 @@ proc `&`*(a,b:TMatrix3d):TMatrix3d {.noinit.} =
a.tw*b.tw+a.tz*b.cw+a.ty*b.bw+a.tx*b.aw)
proc scale*(s:float):TMatrix3d {.noInit.} =
proc scale*(s:float):Matrix3d {.noInit.} =
## Returns a new scaling matrix.
result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0, 0,0,0,1)
proc scale*(s:float,org:TPoint3d):TMatrix3d {.noInit.} =
proc scale*(s:float,org:Point3d):Matrix3d {.noInit.} =
## Returns a new scaling matrix using, `org` as scale origin.
result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
org.x-s*org.x,org.y-s*org.y,org.z-s*org.z,1.0)
proc stretch*(sx,sy,sz:float):TMatrix3d {.noInit.} =
proc stretch*(sx,sy,sz:float):Matrix3d {.noInit.} =
## Returns new a stretch matrix, which is a
## scale matrix with non uniform scale in x,y and z.
result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1)
proc stretch*(sx,sy,sz:float,org:TPoint3d):TMatrix3d {.noInit.} =
proc stretch*(sx,sy,sz:float,org:Point3d):Matrix3d {.noInit.} =
## Returns a new stretch matrix, which is a
## scale matrix with non uniform scale in x,y and z.
## `org` is used as stretch origin.
result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, org.x-sx*org.x,org.y-sy*org.y,org.z-sz*org.z,1)
proc move*(dx,dy,dz:float):TMatrix3d {.noInit.} =
proc move*(dx,dy,dz:float):Matrix3d {.noInit.} =
## Returns a new translation matrix.
result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, dx,dy,dz,1)
proc move*(v:TVector3d):TMatrix3d {.noInit.} =
proc move*(v:Vector3d):Matrix3d {.noInit.} =
## Returns a new translation matrix from a vector.
result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, v.x,v.y,v.z,1)
proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
proc rotate*(angle:float,axis:Vector3d):Matrix3d {.noInit.}=
## Creates a rotation matrix that rotates `angle` radians over
## `axis`, which passes through origo.
@ -242,7 +242,7 @@ proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
uwomc+vsi, vwomc-usi, w2+(1.0-w2)*cs, 0.0,
0.0,0.0,0.0,1.0)
proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
proc rotate*(angle:float,org:Point3d,axis:Vector3d):Matrix3d {.noInit.}=
## Creates a rotation matrix that rotates `angle` radians over
## `axis`, which passes through `org`.
@ -282,7 +282,7 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
(c*(u2+v2)-w*(a*u+b*v))*omc+(a*v-b*u)*si,1.0)
proc rotateX*(angle:float):TMatrix3d {.noInit.}=
proc rotateX*(angle:float):Matrix3d {.noInit.}=
## Creates a matrix that rotates around the x-axis with `angle` radians,
## which is also called a 'roll' matrix.
let
@ -294,7 +294,7 @@ proc rotateX*(angle:float):TMatrix3d {.noInit.}=
0,-s,c,0,
0,0,0,1)
proc rotateY*(angle:float):TMatrix3d {.noInit.}=
proc rotateY*(angle:float):Matrix3d {.noInit.}=
## Creates a matrix that rotates around the y-axis with `angle` radians,
## which is also called a 'pitch' matrix.
let
@ -306,7 +306,7 @@ proc rotateY*(angle:float):TMatrix3d {.noInit.}=
s,0,c,0,
0,0,0,1)
proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
proc rotateZ*(angle:float):Matrix3d {.noInit.}=
## Creates a matrix that rotates around the z-axis with `angle` radians,
## which is also called a 'yaw' matrix.
let
@ -318,7 +318,7 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
0,0,1,0,
0,0,0,1)
proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
proc isUniform*(m:Matrix3d,tol=1.0e-6):bool=
## Checks if the transform is uniform, that is
## perpendicular axes of equal length, which means (for example)
## it cannot transform a sphere into an ellipsoid.
@ -341,7 +341,7 @@ proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
proc mirror*(planeperp:Vector3d):Matrix3d {.noInit.}=
## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
## and passes through origo. `planeperp` does not need to be normalized.
@ -365,7 +365,7 @@ proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
0,0,0,1)
proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
proc mirror*(org:Point3d,planeperp:Vector3d):Matrix3d {.noInit.}=
## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
## and passes through `org`. `planeperp` does not need to be normalized.
@ -400,7 +400,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
2*(cc*tz+bc*ty+ac*tx) ,1)
proc determinant*(m:TMatrix3d):float=
proc determinant*(m:Matrix3d):float=
## Computes the determinant of matrix `m`.
# This computation is gotten from ratsimp(optimize(determinant(m)))
@ -419,7 +419,7 @@ proc determinant*(m:TMatrix3d):float=
(O3*m.az-O5*m.ay+O6*m.ax)*m.bw
proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
proc inverse*(m:Matrix3d):Matrix3d {.noInit.}=
## Computes the inverse of matrix `m`. If the matrix
## determinant is zero, thus not invertible, a EDivByZero
## will be raised.
@ -461,7 +461,7 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
(-m.ax*O7+m.ay*O14-m.az*O18)/det , (m.ax*O10-m.ay*O16+m.az*O19)/det)
proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
proc equals*(m1:Matrix3d,m2:Matrix3d,tol=1.0e-6):bool=
## Checks if all elements of `m1`and `m2` is equal within
## a given tolerance `tol`.
return
@ -482,42 +482,42 @@ proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
abs(m1.tz-m2.tz)<=tol and
abs(m1.tw-m2.tw)<=tol
proc `=~`*(m1,m2:TMatrix3d):bool=
proc `=~`*(m1,m2:Matrix3d):bool=
## Checks if `m1` and `m2` is approximately equal, using a
## tolerance of 1e-6.
equals(m1,m2)
proc transpose*(m:TMatrix3d):TMatrix3d {.noInit.}=
proc transpose*(m:Matrix3d):Matrix3d {.noInit.}=
## Returns the transpose of `m`
result.setElements(m.ax,m.bx,m.cx,m.tx,m.ay,m.by,m.cy,m.ty,m.az,m.bz,m.cz,m.tz,m.aw,m.bw,m.cw,m.tw)
proc getXAxis*(m:TMatrix3d):TVector3d {.noInit.}=
proc getXAxis*(m:Matrix3d):Vector3d {.noInit.}=
## Gets the local x axis of `m`
result.x=m.ax
result.y=m.ay
result.z=m.az
proc getYAxis*(m:TMatrix3d):TVector3d {.noInit.}=
proc getYAxis*(m:Matrix3d):Vector3d {.noInit.}=
## Gets the local y axis of `m`
result.x=m.bx
result.y=m.by
result.z=m.bz
proc getZAxis*(m:TMatrix3d):TVector3d {.noInit.}=
proc getZAxis*(m:Matrix3d):Vector3d {.noInit.}=
## Gets the local y axis of `m`
result.x=m.cx
result.y=m.cy
result.z=m.cz
proc `$`*(m:TMatrix3d):string=
proc `$`*(m:Matrix3d):string=
## String representation of `m`
return rtos(m.ax) & "," & rtos(m.ay) & "," & rtos(m.az) & "," & rtos(m.aw) &
"\n" & rtos(m.bx) & "," & rtos(m.by) & "," & rtos(m.bz) & "," & rtos(m.bw) &
"\n" & rtos(m.cx) & "," & rtos(m.cy) & "," & rtos(m.cz) & "," & rtos(m.cw) &
"\n" & rtos(m.tx) & "," & rtos(m.ty) & "," & rtos(m.tz) & "," & rtos(m.tw)
proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
proc apply*(m:Matrix3d, x,y,z:var float, translate=false)=
## Applies transformation `m` onto `x` , `y` , `z` , optionally
## using the translation part of the matrix.
let
@ -535,18 +535,18 @@ proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
z+=m.tz
# ***************************************
# TVector3d implementation
# Vector3d implementation
# ***************************************
proc vector3d*(x,y,z:float):TVector3d=
proc vector3d*(x,y,z:float):Vector3d=
result.x=x
result.y=y
result.z=z
proc len*(v:TVector3d):float=
proc len*(v:Vector3d):float=
## Returns the length of the vector `v`.
sqrt(v.x*v.x+v.y*v.y+v.z*v.z)
proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
proc `len=`*(v:var Vector3d,newlen:float) {.noInit.} =
## Sets the length of the vector, keeping its direction.
## If the vector has zero length before changing it's length,
## an arbitrary vector of the requested length is returned.
@ -571,12 +571,12 @@ proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
v.z*=fac
proc sqrLen*(v:TVector3d):float {.inline.}=
proc sqrLen*(v:Vector3d):float {.inline.}=
## Computes the squared length of the vector, which is
## faster than computing the absolute length.
return v.x*v.x+v.y*v.y+v.z*v.z
proc `$` *(v:TVector3d):string=
proc `$` *(v:Vector3d):string=
## String representation of `v`
result=rtos(v.x)
result.add(",")
@ -584,7 +584,7 @@ proc `$` *(v:TVector3d):string=
result.add(",")
result.add(rtos(v.z))
proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
proc `&` *(v:Vector3d,m:Matrix3d):Vector3d {.noInit.} =
## Concatenate vector `v` with a transformation matrix.
## Transforming a vector ignores the translational part
## of the matrix.
@ -601,7 +601,7 @@ proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
result.x=newx
proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
proc `&=` *(v:var Vector3d,m:Matrix3d) {.noInit.} =
## Applies transformation `m` onto `v` in place.
## Transforming a vector ignores the translational part
## of the matrix.
@ -618,7 +618,7 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
v.y=newy
v.x=newx
proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
proc transformNorm*(v:var Vector3d,m:Matrix3d)=
## Applies a normal direction transformation `m` onto `v` in place.
## The resulting vector is *not* normalized. Transforming a vector ignores the
## translational part of the matrix. If the matrix is not invertible
@ -631,7 +631,7 @@ proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
# (possibly by hardware) as well as having a consistent API with the 2d version.
v&=transpose(inverse(m))
proc transformInv*(v:var TVector3d,m:TMatrix3d)=
proc transformInv*(v:var Vector3d,m:Matrix3d)=
## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
## the translational part of the matrix. Transforming a vector ignores the
## translational part of the matrix.
@ -642,7 +642,7 @@ proc transformInv*(v:var TVector3d,m:TMatrix3d)=
# (possibly by hardware) as well as having a consistent API with the 2d version.
v&=m.inverse
proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
proc transformNormInv*(vec:var Vector3d,m:Matrix3d)=
## Applies an inverse normal direction transformation `m` onto `v` in place.
## This is faster than creating an inverse
## matrix and transformNorm(...) it. Transforming a vector ignores the
@ -651,7 +651,7 @@ proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
# see vector2d:s equivalent for a deeper look how/why this works
vec&=m.transpose
proc tryNormalize*(v:var TVector3d):bool=
proc tryNormalize*(v:var Vector3d):bool=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length (and thus no angle), it is left unmodified and false is
## returned, otherwise true is returned.
@ -666,13 +666,13 @@ proc tryNormalize*(v:var TVector3d):bool=
return true
proc normalize*(v:var TVector3d) {.inline.}=
proc normalize*(v:var Vector3d) {.inline.}=
## Modifies `v` to have a length of 1.0, keeping its angle.
## If `v` has zero length, an EDivByZero will be raised.
if not tryNormalize(v):
raise newException(DivByZeroError,"Cannot normalize zero length vector")
proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
proc rotate*(vec:var Vector3d,angle:float,axis:Vector3d)=
## Rotates `vec` in place, with `angle` radians over `axis`, which passes
## through origo.
@ -699,19 +699,19 @@ proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
vec.y=v*uxyzomc+y*cs+(w*x-u*z)*si
vec.z=w*uxyzomc+z*cs+(u*y-v*x)*si
proc scale*(v:var TVector3d,s:float)=
proc scale*(v:var Vector3d,s:float)=
## Scales the vector in place with factor `s`
v.x*=s
v.y*=s
v.z*=s
proc stretch*(v:var TVector3d,sx,sy,sz:float)=
proc stretch*(v:var Vector3d,sx,sy,sz:float)=
## Scales the vector non uniformly with factors `sx` , `sy` , `sz`
v.x*=sx
v.y*=sy
v.z*=sz
proc mirror*(v:var TVector3d,planeperp:TVector3d)=
proc mirror*(v:var Vector3d,planeperp:Vector3d)=
## Computes the mirrored vector of `v` over the plane
## that has `planeperp` as normal direction.
## `planeperp` does not need to be normalized.
@ -735,7 +735,7 @@ proc mirror*(v:var TVector3d,planeperp:TVector3d)=
v.z= -2*(c*c*z+bc*y+ac*x)+z
proc `-` *(v:TVector3d):TVector3d=
proc `-` *(v:Vector3d):Vector3d=
## Negates a vector
result.x= -v.x
result.y= -v.y
@ -751,12 +751,12 @@ makeBinOpAssignVector(`-=`)
makeBinOpAssignVector(`*=`)
makeBinOpAssignVector(`/=`)
proc dot*(v1,v2:TVector3d):float {.inline.}=
proc dot*(v1,v2:Vector3d):float {.inline.}=
## Computes the dot product of two vectors.
## Returns 0.0 if the vectors are perpendicular.
return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
proc cross*(v1,v2:Vector3d):Vector3d {.inline.}=
## Computes the cross product of two vectors.
## The result is a vector which is perpendicular
## to the plane of `v1` and `v2`, which means
@ -766,16 +766,16 @@ proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
result.y = (v1.z * v2.x) - (v2.z * v1.x)
result.z = (v1.x * v2.y) - (v2.x * v1.y)
proc equals*(v1,v2:TVector3d,tol=1.0e-6):bool=
proc equals*(v1,v2:Vector3d,tol=1.0e-6):bool=
## Checks if two vectors approximately equals with a tolerance.
return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol and abs(v2.z-v1.z)<=tol
proc `=~` *(v1,v2:TVector3d):bool=
proc `=~` *(v1,v2:Vector3d):bool=
## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(v1,v2)
proc angleTo*(v1,v2:TVector3d):float=
proc angleTo*(v1,v2:Vector3d):float=
## Returns the smallest angle between v1 and v2,
## which is in range 0-PI
var
@ -785,13 +785,13 @@ proc angleTo*(v1,v2:TVector3d):float=
return 0.0 # zero length vector has zero angle to any other vector
return safeArccos(dot(nv1,nv2))
proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
proc arbitraryAxis*(norm:Vector3d):Matrix3d {.noInit.}=
## Computes the rotation matrix that would transform
## world z vector into `norm`. The inverse of this matrix
## is useful to transform a planar 3d object to 2d space.
## This is the same algorithm used to interpret DXF and DWG files.
const lim=1.0/64.0
var ax,ay,az:TVector3d
var ax,ay,az:Vector3d
if abs(norm.x)<lim and abs(norm.y)<lim:
ax=cross(YAXIS,norm)
else:
@ -808,7 +808,7 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
az.x,az.y,az.z,0.0,
0.0,0.0,0.0,1.0)
proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
proc bisect*(v1,v2:Vector3d):Vector3d {.noInit.}=
## Computes the bisector between v1 and v2 as a normalized vector.
## If one of the input vectors has zero length, a normalized version
## of the other is returned. If both input vectors has zero length,
@ -851,25 +851,25 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
# ***************************************
# TPoint3d implementation
# Point3d implementation
# ***************************************
proc point3d*(x,y,z:float):TPoint3d=
proc point3d*(x,y,z:float):Point3d=
result.x=x
result.y=y
result.z=z
proc sqrDist*(a,b:TPoint3d):float=
proc sqrDist*(a,b:Point3d):float=
## Computes the squared distance between `a`and `b`
let dx=b.x-a.x
let dy=b.y-a.y
let dz=b.z-a.z
result=dx*dx+dy*dy+dz*dz
proc dist*(a,b:TPoint3d):float {.inline.}=
proc dist*(a,b:Point3d):float {.inline.}=
## Computes the absolute distance between `a`and `b`
result=sqrt(sqrDist(a,b))
proc `$` *(p:TPoint3d):string=
proc `$` *(p:Point3d):string=
## String representation of `p`
result=rtos(p.x)
result.add(",")
@ -877,14 +877,14 @@ proc `$` *(p:TPoint3d):string=
result.add(",")
result.add(rtos(p.z))
proc `&`*(p:TPoint3d,m:TMatrix3d):TPoint3d=
proc `&`*(p:Point3d,m:Matrix3d):Point3d=
## Concatenates a point `p` with a transform `m`,
## resulting in a new, transformed point.
result.z=m.cz*p.z+m.bz*p.y+m.az*p.x+m.tz
result.y=m.cy*p.z+m.by*p.y+m.ay*p.x+m.ty
result.x=m.cx*p.z+m.bx*p.y+m.ax*p.x+m.tx
proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
proc `&=` *(p:var Point3d,m:Matrix3d)=
## Applies transformation `m` onto `p` in place.
let
x=p.x
@ -894,7 +894,7 @@ proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
p.y=m.cy*z+m.by*y+m.ay*x+m.ty
p.z=m.cz*z+m.bz*y+m.az*x+m.tz
proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
proc transformInv*(p:var Point3d,m:Matrix3d)=
## Applies the inverse of transformation `m` onto `p` in place.
## If the matrix is not invertable (determinant=0) , EDivByZero will
## be raised.
@ -903,48 +903,48 @@ proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
p&=inverse(m)
proc `+`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
proc `+`*(p:Point3d,v:Vector3d):Point3d {.noInit,inline.} =
## Adds a vector `v` to a point `p`, resulting
## in a new point.
result.x=p.x+v.x
result.y=p.y+v.y
result.z=p.z+v.z
proc `+=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
proc `+=`*(p:var Point3d,v:Vector3d) {.noInit,inline.} =
## Adds a vector `v` to a point `p` in place.
p.x+=v.x
p.y+=v.y
p.z+=v.z
proc `-`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
proc `-`*(p:Point3d,v:Vector3d):Point3d {.noInit,inline.} =
## Subtracts a vector `v` from a point `p`, resulting
## in a new point.
result.x=p.x-v.x
result.y=p.y-v.y
result.z=p.z-v.z
proc `-`*(p1,p2:TPoint3d):TVector3d {.noInit,inline.} =
proc `-`*(p1,p2:Point3d):Vector3d {.noInit,inline.} =
## Subtracts `p2`from `p1` resulting in a difference vector.
result.x=p1.x-p2.x
result.y=p1.y-p2.y
result.z=p1.z-p2.z
proc `-=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
proc `-=`*(p:var Point3d,v:Vector3d) {.noInit,inline.} =
## Subtracts a vector `v` from a point `p` in place.
p.x-=v.x
p.y-=v.y
p.z-=v.z
proc equals(p1,p2:TPoint3d,tol=1.0e-6):bool {.inline.}=
proc equals(p1,p2:Point3d,tol=1.0e-6):bool {.inline.}=
## Checks if two points approximately equals with a tolerance.
return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol and abs(p2.z-p1.z)<=tol
proc `=~`*(p1,p2:TPoint3d):bool {.inline.}=
proc `=~`*(p1,p2:Point3d):bool {.inline.}=
## Checks if two vectors approximately equals with a
## hardcoded tolerance 1e-6
equals(p1,p2)
proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
proc rotate*(p:var Point3d,rad:float,axis:Vector3d)=
## Rotates point `p` in place `rad` radians about an axis
## passing through origo.
@ -954,7 +954,7 @@ proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
p.y=v.y
p.z=v.z
proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
proc rotate*(p:var Point3d,angle:float,org:Point3d,axis:Vector3d)=
## Rotates point `p` in place `rad` radians about an axis
## passing through `org`
@ -992,26 +992,26 @@ proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
p.y=(b*(uu+ww)-v*(au+cw-uxmvymwz))*omc + y*cs + (c*u-a*w+w*x-u*z)*si
p.z=(c*(uu+vv)-w*(au+bv-uxmvymwz))*omc + z*cs + (a*v+u*y-b*u-v*x)*si
proc scale*(p:var TPoint3d,fac:float) {.inline.}=
proc scale*(p:var Point3d,fac:float) {.inline.}=
## Scales a point in place `fac` times with world origo as origin.
p.x*=fac
p.y*=fac
p.z*=fac
proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
proc scale*(p:var Point3d,fac:float,org:Point3d){.inline.}=
## Scales the point in place `fac` times with `org` as origin.
p.x=(p.x - org.x) * fac + org.x
p.y=(p.y - org.y) * fac + org.y
p.z=(p.z - org.z) * fac + org.z
proc stretch*(p:var TPoint3d,facx,facy,facz:float){.inline.}=
proc stretch*(p:var Point3d,facx,facy,facz:float){.inline.}=
## Scales a point in place non uniformly `facx` , `facy` , `facz` times
## with world origo as origin.
p.x*=facx
p.y*=facy
p.z*=facz
proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
proc stretch*(p:var Point3d,facx,facy,facz:float,org:Point3d){.inline.}=
## Scales the point in place non uniformly `facx` , `facy` , `facz` times
## with `org` as origin.
p.x=(p.x - org.x) * facx + org.x
@ -1019,19 +1019,19 @@ proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
p.z=(p.z - org.z) * facz + org.z
proc move*(p:var TPoint3d,dx,dy,dz:float){.inline.}=
proc move*(p:var Point3d,dx,dy,dz:float){.inline.}=
## Translates a point `dx` , `dy` , `dz` in place.
p.x+=dx
p.y+=dy
p.z+=dz
proc move*(p:var TPoint3d,v:TVector3d){.inline.}=
proc move*(p:var Point3d,v:Vector3d){.inline.}=
## Translates a point with vector `v` in place.
p.x+=v.x
p.y+=v.y
p.z+=v.z
proc area*(a,b,c:TPoint3d):float {.inline.}=
proc area*(a,b,c:Point3d):float {.inline.}=
## Computes the area of the triangle thru points `a` , `b` and `c`
# The area of a planar 3d quadliteral is the magnitude of the cross

View file

@ -46,24 +46,25 @@ const
when sizeof(int) == 4: # 32bit
type
TRaw = range[0..1073741823]
Raw = range[0..1073741823]
## The range of uint values that can be stored directly in a value slot
## when on a 32 bit platform
{.deprecated: [TRaw: Raw].}
elif sizeof(int) == 8: # 64bit
type
TRaw = range[0..4611686018427387903]
Raw = range[0..4611686018427387903]
## The range of uint values that can be stored directly in a value slot
## when on a 64 bit platform
{.deprecated: [TRaw: Raw].}
else:
{.error: "unsupported platform".}
type
TEntry = tuple
Entry = tuple
key: int
value: int
TEntryArr = ptr array[0..10_000_000, TEntry]
EntryArr = ptr array[0..10_000_000, Entry]
PConcTable[K,V] = ptr object {.pure.}
len: int
@ -72,8 +73,8 @@ type
copyIdx: int
copyDone: int
next: PConcTable[K,V]
data: TEntryArr
data: EntryArr
{.deprecated: [TEntry: Entry, TEntryArr: EntryArr.}
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int
@ -84,7 +85,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
let
dataLen = max(nextPowerOfTwo(size), minTableSize)
dataSize = dataLen*sizeof(TEntry)
dataSize = dataLen*sizeof(Entry)
dataMem = allocShared0(dataSize)
tableSize = 7 * intSize
tableMem = allocShared0(tableSize)
@ -95,7 +96,7 @@ proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
table.copyIdx = 0
table.copyDone = 0
table.next = nil
table.data = cast[TEntryArr](dataMem)
table.data = cast[EntryArr](dataMem)
result = table
#------------------------------------------------------------------------------
@ -107,7 +108,7 @@ proc deleteConcTable[K,V](tbl: PConcTable[K,V]) =
#------------------------------------------------------------------------------
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var TEntry {.inline.} =
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var Entry {.inline.} =
table.data[i]
#------------------------------------------------------------------------------
@ -191,7 +192,7 @@ proc resize[K,V](self: PConcTable[K,V]): PConcTable[K,V] =
#proc keyEQ[K](key1: ptr K, key2: ptr K): bool {.inline.} =
proc keyEQ[K](key1: int, key2: int): bool {.inline.} =
result = false
when K is TRaw:
when K is Raw:
if key1 == key2:
result = true
else:
@ -236,7 +237,7 @@ proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable
break
#echo("oldVal was = ", oldVal, " set it to prime ", box)
if isPrime(oldVal) and isTomb(oldVal):
#when not (K is TRaw):
#when not (K is Raw):
# deallocShared(popPtr[K](oldKey))
return false
if isTomb(oldVal):
@ -343,7 +344,7 @@ proc helpCopy[K,V](table: var PConcTable[K,V]): PConcTable[K,V] =
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int =
#echo("-try set- in table ", " key = ", (popPtr[K](key)[]), " val = ", val)
when K is TRaw:
when K is Raw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
@ -428,7 +429,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
#echo("-try get- key = " & $key)
when K is TRaw:
when K is Raw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
@ -468,37 +469,37 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
#------------------------------------------------------------------------------
#proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) =
#proc set*(table: var PConcTable[Raw,Raw], key: Raw, val: Raw) =
# discard setVal(table, pack(key), pack(key), 0, false)
#proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) =
#proc set*[V](table: var PConcTable[Raw,V], key: Raw, val: ptr V) =
# discard setVal(table, pack(key), cast[int](val), 0, false)
proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
when not (K is TRaw):
when not (K is Raw):
var newKey = cast[int](copyShared(key))
else:
var newKey = pack(key)
when not (V is TRaw):
when not (V is Raw):
var newVal = cast[int](copyShared(val))
else:
var newVal = pack(val)
var oldPtr = pop(setVal(table, newKey, newVal, 0, false))
#echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
when not (V is TRaw):
when not (V is Raw):
if newVal != oldPtr and oldPtr != 0:
deallocShared(cast[ptr V](oldPtr))
proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
when not (V is TRaw):
when not (K is TRaw):
when not (V is Raw):
when not (K is Raw):
return popPtr[V](getVal(table, cast[int](key.addr)))[]
else:
return popPtr[V](getVal(table, pack(key)))[]
else:
when not (K is TRaw):
when not (K is Raw):
return popRaw(getVal(table, cast[int](key.addr)))
else:
return popRaw(getVal(table, pack(key)))
@ -535,23 +536,24 @@ when not defined(testing) and isMainModule:
type
TTestObj = tuple
TestObj = tuple
thr: int
f0: int
f1: int
TData = tuple[k: string,v: TTestObj]
PDataArr = array[0..numTests-1, TData]
Dict = PConcTable[string,TTestObj]
Data = tuple[k: string,v: TestObj]
PDataArr = array[0..numTests-1, Data]
Dict = PConcTable[string,TestObj]
{.deprecated: [TTestObj: TestObj, TData: Data].}
var
thr: array[0..numThreads-1, TThread[Dict]]
thr: array[0..numThreads-1, Thread[Dict]]
table = newLFTable[string,TTestObj](8)
table = newLFTable[string,TestObj](8)
rand = newMersenneTwister(2525)
proc createSampleData(len: int): PDataArr =
#result = cast[PDataArr](allocShared0(sizeof(TData)*numTests))
#result = cast[PDataArr](allocShared0(sizeof(Data)*numTests))
for i in 0..len-1:
result[i].k = "mark" & $(i+1)
#echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))

View file

@ -30,25 +30,25 @@ const
IntMask = 1 shl IntShift - 1
type
PTrunk = ref TTrunk
TTrunk {.final.} = object
PTrunk = ref Trunk
Trunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0
bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
TTrunkSeq = seq[PTrunk]
TrunkSeq = seq[PTrunk]
IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
counter, max: int
head: PTrunk
data: TTrunkSeq
data: TrunkSeq
{.deprecated: [TIntSet: IntSet].}
{.deprecated: [TIntSet: IntSet, TTrunk: Trunk, TTrunkSeq: TrunkSeq].}
proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc intSetGet(t: IntSet, key: int): PTrunk =
@ -59,7 +59,7 @@ proc intSetGet(t: IntSet, key: int): PTrunk =
h = nextTry(h, t.max)
result = nil
proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
proc intSetRawInsert(t: IntSet, data: var TrunkSeq, desc: PTrunk) =
var h = desc.key and t.max
while data[h] != nil:
assert(data[h] != desc)
@ -68,7 +68,7 @@ proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
data[h] = desc
proc intSetEnlarge(t: var IntSet) =
var n: TTrunkSeq
var n: TrunkSeq
var oldMax = t.max
t.max = ((t.max + 1) * 2) - 1
newSeq(n, t.max + 1)

View file

@ -29,7 +29,7 @@ when not defined(nimhygiene):
# codes should never be needed, and this can pack more entries per cache-line.
# Losing hcode entirely is also possible - if some element value is forbidden.
type
KeyValuePair[A] = tuple[hcode: THash, key: A]
KeyValuePair[A] = tuple[hcode: Hash, key: A]
KeyValuePairSeq[A] = seq[KeyValuePair[A]]
HashSet* {.myShallow.}[A] = object ## \
## A generic hash set.
@ -43,10 +43,10 @@ type
# hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These
# two procs retain clarity of that encoding without the space cost of an enum.
proc isEmpty(hcode: THash): bool {.inline.} =
proc isEmpty(hcode: Hash): bool {.inline.} =
result = hcode == 0
proc isFilled(hcode: THash): bool {.inline.} =
proc isFilled(hcode: Hash): bool {.inline.} =
result = hcode != 0
proc isValid*[A](s: HashSet[A]): bool =
@ -58,7 +58,7 @@ proc isValid*[A](s: HashSet[A]): bool =
## initialized. Example:
##
## .. code-block ::
## proc savePreferences(options: TSet[string]) =
## proc savePreferences(options: Set[string]) =
## assert options.isValid, "Pass an initialized set!"
## # Do stuff here, may crash in release builds!
result = not s.data.isNil
@ -72,7 +72,7 @@ proc len*[A](s: HashSet[A]): int =
##
## .. code-block::
##
## var values: TSet[int]
## var values: Set[int]
## assert(not values.isValid)
## assert values.len == 0
result = s.counter
@ -123,15 +123,15 @@ proc rightSize*(count: Natural): int {.inline.} =
## Internally, we want mustRehash(rightSize(x), x) == false.
result = nextPowerOfTwo(count * 3 div 2 + 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash
template rawGetKnownHCImpl() {.dirty.} =
var h: THash = hc and high(s.data) # start with real hash value
var h: Hash = hc and high(s.data) # start with real hash value
while isFilled(s.data[h].hcode):
# Compare hc THEN key with boolean short circuit. This makes the common case
# zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
# It does slow down succeeding lookups by one extra THash cmp&and..usually
# It does slow down succeeding lookups by one extra Hash cmp&and..usually
# just a few clock cycles, generally worth it for any non-integer-like A.
if s.data[h].hcode == hc and s.data[h].key == key: # compare hc THEN key
return h
@ -148,10 +148,10 @@ template rawInsertImpl() {.dirty.} =
data[h].key = key
data[h].hcode = hc
proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} =
proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: Hash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} =
proc rawGet[A](s: HashSet[A], key: A, hc: var Hash): int {.inline.} =
rawGetImpl()
proc mget*[A](s: var HashSet[A], key: A): var A =
@ -160,7 +160,7 @@ proc mget*[A](s: var HashSet[A], key: A): var A =
## when one overloaded 'hash' and '==' but still needs reference semantics
## for sharing.
assert s.isValid, "The set needs to be initialized."
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
if index >= 0: result = s.data[index].key
else: raise newException(KeyError, "key not found: " & $key)
@ -178,12 +178,12 @@ proc contains*[A](s: HashSet[A], key: A): bool =
## values.excl(2)
## assert(not values.contains(2))
assert s.isValid, "The set needs to be initialized."
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
result = index >= 0
proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A,
hc: THash, h: THash) =
hc: Hash, h: Hash) =
rawInsertImpl()
proc enlarge[A](s: var HashSet[A]) =
@ -196,7 +196,7 @@ proc enlarge[A](s: var HashSet[A]) =
rawInsert(s, s.data, n[i].key, n[i].hcode, j)
template inclImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
if index < 0:
if mustRehash(len(s.data), s.counter):
@ -206,7 +206,7 @@ template inclImpl() {.dirty.} =
inc(s.counter)
template containsOrInclImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
if index >= 0:
result = true
@ -261,7 +261,7 @@ proc excl*[A](s: var HashSet[A], key: A) =
## s.excl(2)
## assert s.len == 3
assert s.isValid, "The set needs to be initialized."
var hc: THash
var hc: Hash
var i = rawGet(s, key, hc)
var msk = high(s.data)
if i >= 0:
@ -323,7 +323,7 @@ proc init*[A](s: var HashSet[A], initialSize=64) =
## existing values and calling `excl() <#excl,TSet[A],A>`_ on them. Example:
##
## .. code-block ::
## var a: TSet[int]
## var a: Set[int]
## a.init(4)
## a.incl(2)
## a.init
@ -552,7 +552,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] =
type
OrderedKeyValuePair[A] = tuple[
hcode: THash, next: int, key: A]
hcode: Hash, next: int, key: A]
OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
OrderedSet* {.myShallow.}[A] = object ## \
## A generic hash set that remembers insertion order.
@ -574,7 +574,7 @@ proc isValid*[A](s: OrderedSet[A]): bool =
## correctly initialized. Example:
##
## .. code-block::
## proc saveTarotCards(cards: TOrderedSet[int]) =
## proc saveTarotCards(cards: OrderedSet[int]) =
## assert cards.isValid, "Pass an initialized set!"
## # Do stuff here, may crash in release builds!
result = not s.data.isNil
@ -588,7 +588,7 @@ proc len*[A](s: OrderedSet[A]): int {.inline.} =
##
## .. code-block::
##
## var values: TOrderedSet[int]
## var values: OrderedSet[int]
## assert(not values.isValid)
## assert values.len == 0
result = s.counter
@ -629,10 +629,10 @@ iterator items*[A](s: OrderedSet[A]): A =
forAllOrderedPairs:
yield s.data[h].key
proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: THash): int {.inline.} =
proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: Hash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGet[A](s: OrderedSet[A], key: A, hc: var THash): int {.inline.} =
proc rawGet[A](s: OrderedSet[A], key: A, hc: var Hash): int {.inline.} =
rawGetImpl()
proc contains*[A](s: OrderedSet[A], key: A): bool =
@ -646,12 +646,12 @@ proc contains*[A](s: OrderedSet[A], key: A): bool =
## values.incl(2)
## assert values.contains(2)
assert s.isValid, "The set needs to be initialized."
var hc: THash
var hc: Hash
var index = rawGet(s, key, hc)
result = index >= 0
proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A],
key: A, hc: THash, h: THash) =
key: A, hc: Hash, h: Hash) =
rawInsertImpl()
data[h].next = -1
if s.first < 0: s.first = h
@ -729,7 +729,7 @@ proc init*[A](s: var OrderedSet[A], initialSize=64) =
## from an ordered hash set. Example:
##
## .. code-block ::
## var a: TOrderedSet[int]
## var a: OrderedSet[int]
## a.init(4)
## a.incl(2)
## a.init

View file

@ -24,13 +24,13 @@
##
## Error: type mismatch: got (Person)
## but expected one of:
## hashes.hash(x: openarray[A]): THash
## hashes.hash(x: int): THash
## hashes.hash(x: float): THash
## hashes.hash(x: openarray[A]): Hash
## hashes.hash(x: int): Hash
## hashes.hash(x: float): Hash
## …
##
## What is happening here is that the types used for table keys require to have
## a ``hash()`` proc which will convert them to a `THash <hashes.html#THash>`_
## a ``hash()`` proc which will convert them to a `Hash <hashes.html#Hash>`_
## value, and the compiler is listing all the hash functions it knows.
## Additionally there has to be a ``==`` operator that provides the same
## semantics as its corresponding ``hash`` proc.
@ -46,7 +46,7 @@
## Person = object
## firstName, lastName: string
##
## proc hash(x: Person): THash =
## proc hash(x: Person): Hash =
## ## Piggyback on the already available string hash proc.
## ##
## ## Without this proc nothing works!
@ -71,7 +71,7 @@ import
{.pragma: myShallow.}
type
KeyValuePair[A, B] = tuple[hcode: THash, key: A, val: B]
KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B]
KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
Table* {.myShallow.}[A, B] = object ## generic hash table
data: KeyValuePairSeq[A, B]
@ -85,10 +85,10 @@ when not defined(nimhygiene):
# hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These
# two procs retain clarity of that encoding without the space cost of an enum.
proc isEmpty(hcode: THash): bool {.inline.} =
proc isEmpty(hcode: Hash): bool {.inline.} =
result = hcode == 0
proc isFilled(hcode: THash): bool {.inline.} =
proc isFilled(hcode: Hash): bool {.inline.} =
result = hcode != 0
proc len*[A, B](t: Table[A, B]): int =
@ -137,15 +137,15 @@ proc rightSize*(count: Natural): int {.inline.} =
## Internally, we want mustRehash(rightSize(x), x) == false.
result = nextPowerOfTwo(count * 3 div 2 + 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash
template rawGetKnownHCImpl() {.dirty.} =
var h: THash = hc and high(t.data) # start with real hash value
var h: Hash = hc and high(t.data) # start with real hash value
while isFilled(t.data[h].hcode):
# Compare hc THEN key with boolean short circuit. This makes the common case
# zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
# It does slow down succeeding lookups by one extra THash cmp&and..usually
# It does slow down succeeding lookups by one extra Hash cmp&and..usually
# just a few clock cycles, generally worth it for any non-integer-like A.
if t.data[h].hcode == hc and t.data[h].key == key:
return h
@ -162,7 +162,7 @@ template rawGetDeepImpl() {.dirty.} = # Search algo for unconditional add
hc = hash(key)
if hc == 0:
hc = 314159265
var h: THash = hc and high(t.data)
var h: Hash = hc and high(t.data)
while isFilled(t.data[h].hcode):
h = nextTry(h, high(t.data))
result = h
@ -172,13 +172,13 @@ template rawInsertImpl() {.dirty.} =
data[h].val = val
data[h].hcode = hc
proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: THash): int {.inline.} =
proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: Hash): int {.inline.} =
rawGetKnownHCImpl()
proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var Hash): int {.inline.} =
rawGetDeepImpl()
proc rawGet[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
proc rawGet[A, B](t: Table[A, B], key: A, hc: var Hash): int {.inline.} =
rawGetImpl()
proc `[]`*[A, B](t: Table[A, B], key: A): B =
@ -186,14 +186,14 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B =
## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var Table[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``KeyError`` exception is raised.
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val
else:
@ -204,7 +204,7 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
iterator allValues*[A, B](t: Table[A, B]; key: A): B =
## iterates over any value in the table `t` that belongs to the given `key`.
var h: THash = hash(key) and high(t.data)
var h: Hash = hash(key) and high(t.data)
while isFilled(t.data[h].hcode):
if t.data[h].key == key:
yield t.data[h].val
@ -212,7 +212,7 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B =
proc hasKey*[A, B](t: Table[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
var hc: THash
var hc: Hash
result = rawGet(t, key, hc) >= 0
proc contains*[A, B](t: Table[A, B], key: A): bool =
@ -220,7 +220,7 @@ proc contains*[A, B](t: Table[A, B], key: A): bool =
return hasKey[A, B](t, key)
proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
key: A, val: B, hc: THash, h: THash) =
key: A, val: B, hc: Hash, h: Hash) =
rawInsertImpl()
proc enlarge[A, B](t: var Table[A, B]) =
@ -234,7 +234,7 @@ proc enlarge[A, B](t: var Table[A, B]) =
template addImpl() {.dirty.} =
if mustRehash(len(t.data), t.counter): enlarge(t)
var hc: THash
var hc: Hash
var j = rawGetDeep(t, key, hc)
rawInsert(t, t.data, key, val, hc, j)
inc(t.counter)
@ -248,19 +248,19 @@ template maybeRehashPutImpl() {.dirty.} =
inc(t.counter)
template putImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: t.data[index].val = val
else: maybeRehashPutImpl()
template mgetOrPutImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index < 0: maybeRehashPutImpl() # not present: insert (flipping index)
result = t.data[index].val # either way return modifiable val
template hasKeyOrPutImpl() {.dirty.} =
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index < 0:
result = false
@ -291,7 +291,7 @@ template doWhile(a: expr, b: stmt): stmt =
proc del*[A, B](t: var Table[A, B], key: A) =
## deletes `key` from hash table `t`.
var hc: THash
var hc: Hash
var i = rawGet(t, key, hc)
let msk = high(t.data)
if i >= 0:
@ -460,7 +460,7 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B]
type
OrderedKeyValuePair[A, B] = tuple[
hcode: THash, next: int, key: A, val: B]
hcode: Hash, next: int, key: A, val: B]
OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
OrderedTable* {.
myShallow.}[A, B] = object ## table that remembers insertion order
@ -509,13 +509,13 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
forAllOrderedPairs:
yield t.data[h].val
proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: THash): int =
proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: Hash): int =
rawGetKnownHCImpl()
proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int {.inline.} =
proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int {.inline.} =
rawGetDeepImpl()
proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int =
proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
rawGetImpl()
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
@ -523,21 +523,21 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var hc: THash
var hc: Hash
var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val
else: raise newException(KeyError, "key not found: " & $key)
proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
var hc: THash
var hc: Hash
result = rawGet(t, key, hc) >= 0
proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
@ -546,7 +546,7 @@ proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
proc rawInsert[A, B](t: var OrderedTable[A, B],
data: var OrderedKeyValuePairSeq[A, B],
key: A, val: B, hc: THash, h: THash) =
key: A, val: B, hc: Hash, h: Hash) =
rawInsertImpl()
data[h].next = -1
if t.first < 0: t.first = h
@ -796,7 +796,7 @@ iterator mvalues*[A](t: CountTable[A]): var int =
if t.data[h].val != 0: yield t.data[h].val
proc rawGet[A](t: CountTable[A], key: A): int =
var h: THash = hash(key) and high(t.data) # start with real hash value
var h: Hash = hash(key) and high(t.data) # start with real hash value
while t.data[h].val != 0:
if t.data[h].key == key: return h
h = nextTry(h, high(t.data))
@ -826,7 +826,7 @@ proc contains*[A](t: CountTable[A], key: A): bool =
proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
key: A, val: int) =
var h: THash = hash(key) and high(data)
var h: Hash = hash(key) and high(data)
while data[h].val != 0: h = nextTry(h, high(data))
data[h].key = key
data[h].val = val
@ -1032,7 +1032,7 @@ when isMainModule:
Person = object
firstName, lastName: string
proc hash(x: Person): THash =
proc hash(x: Person): Hash =
## Piggyback on the already available string hash proc.
##
## Without this proc nothing works!

View file

@ -34,7 +34,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
sysIdle, sysKernel, sysUser,
procCreation, procExit, procKernel, procUser: TFILETIME
if getSystemTimes(sysIdle, sysKernel, sysUser) == 0 or
getProcessTimes(THandle(-1), procCreation, procExit,
getProcessTimes(Handle(-1), procCreation, procExit,
procKernel, procUser) == 0:
return doNothing
if s.calls > 0:

View file

@ -18,8 +18,8 @@ import cpuinfo, cpuload, locks
type
Semaphore = object
c: TCond
L: TLock
c: Cond
L: Lock
counter: int
proc createSemaphore(): Semaphore =
@ -113,7 +113,7 @@ type
ToFreeQueue = object
len: int
lock: TLock
lock: Lock
empty: Semaphore
data: array[128, pointer]
@ -221,11 +221,17 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
action(fv.blob)
finished(fv)
proc `^`*[T](fv: FlowVar[ref T]): foreign ptr T =
proc unsafeRead*[T](fv: FlowVar[ref T]): foreign ptr T =
## blocks until the value is available and then returns this value.
await(fv)
result = cast[foreign ptr T](fv.data)
proc `^`*[T](fv: FlowVar[ref T]): ref T =
## blocks until the value is available and then returns this value.
await(fv)
let src = cast[ref T](fv.data)
deepCopy result, src
proc `^`*[T](fv: FlowVar[T]): T =
## blocks until the value is available and then returns this value.
await(fv)
@ -349,7 +355,7 @@ proc parallel*(body: stmt) {.magic: "Parallel".}
var
state: ThreadPoolState
stateLock: TLock
stateLock: Lock
initLock stateLock

View file

@ -211,12 +211,13 @@ when defined(windows):
when false:
# not needed yet:
type
TCpInfo = object
CpInfo = object
maxCharSize: int32
defaultChar: array[0..1, char]
leadByte: array[0..12-1, char]
{.deprecated: [TCpInfo: CpInfo].}
proc getCPInfo(codePage: CodePage, lpCPInfo: var TCpInfo): int32 {.
proc getCPInfo(codePage: CodePage, lpCPInfo: var CpInfo): int32 {.
stdcall, importc: "GetCPInfo", dynlib: "kernel32".}
proc nameToCodePage(name: string): CodePage =

23
lib/pure/etcpriv.nim Normal file
View file

@ -0,0 +1,23 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2015 Nim Authors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains utils that are less then easy to categorize and
## don't really warrant a specific module. They are private to compiler
## and stdlib usage, and should not be used outside of that - they may
## change or disappear at any time.
# Used by pure/hashes.nim, and the compiler parsing
const magicIdentSeparatorRuneByteWidth* = 3
# Used by pure/hashes.nim, and the compiler parsing
proc isMagicIdentSeparatorRune*(cs: cstring, i: int): bool {. inline } =
result = cs[i] == '\226' and
cs[i + 1] == '\128' and
cs[i + 2] == '\147' # en-dash # 145 = nb-hyphen

View file

@ -18,20 +18,22 @@ import
os, hashes, strutils
type
TGenTableMode* = enum ## describes the table's key matching mode
GenTableMode* = enum ## describes the table's key matching mode
modeCaseSensitive, ## case sensitive matching of keys
modeCaseInsensitive, ## case insensitive matching of keys
modeStyleInsensitive ## style sensitive matching of keys
TGenKeyValuePair[T] = tuple[key: string, val: T]
TGenKeyValuePairSeq[T] = seq[TGenKeyValuePair[T]]
TGenTable*[T] = object of RootObj
GenKeyValuePair[T] = tuple[key: string, val: T]
GenKeyValuePairSeq[T] = seq[GenKeyValuePair[T]]
GenTable*[T] = object of RootObj
counter: int
data: TGenKeyValuePairSeq[T]
mode: TGenTableMode
data: GenKeyValuePairSeq[T]
mode: GenTableMode
PGenTable*[T] = ref TGenTable[T] ## use this type to declare hash tables
PGenTable*[T] = ref GenTable[T] ## use this type to declare hash tables
{.deprecated: [TGenTableMode: GenTableMode, TGenKeyValuePair: GenKeyValuePair,
TGenKeyValuePairSeq: GenKeyValuePairSeq, TGenTable: GenTable].}
const
growthFactor = 2
@ -48,7 +50,7 @@ iterator pairs*[T](tbl: PGenTable[T]): tuple[key: string, value: T] =
if not isNil(tbl.data[h].key):
yield (tbl.data[h].key, tbl.data[h].val)
proc myhash[T](tbl: PGenTable[T], key: string): THash =
proc myhash[T](tbl: PGenTable[T], key: string): Hash =
case tbl.mode
of modeCaseSensitive: result = hashes.hash(key)
of modeCaseInsensitive: result = hashes.hashIgnoreCase(key)
@ -64,18 +66,18 @@ proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc newGenTable*[T](mode: TGenTableMode): PGenTable[T] =
proc newGenTable*[T](mode: GenTableMode): PGenTable[T] =
## creates a new generic hash table that is empty.
new(result)
result.mode = mode
result.counter = 0
newSeq(result.data, startSize)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc rawGet[T](tbl: PGenTable[T], key: string): int =
var h: THash
var h: Hash
h = myhash(tbl, key) and high(tbl.data) # start with real hash value
while not isNil(tbl.data[h].key):
if myCmp(tbl, tbl.data[h].key, key):
@ -83,9 +85,9 @@ proc rawGet[T](tbl: PGenTable[T], key: string): int =
h = nextTry(h, high(tbl.data))
result = - 1
proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
proc rawInsert[T](tbl: PGenTable[T], data: var GenKeyValuePairSeq[T],
key: string, val: T) =
var h: THash
var h: Hash
h = myhash(tbl, key) and high(data)
while not isNil(data[h].key):
h = nextTry(h, high(data))
@ -93,7 +95,7 @@ proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
data[h].val = val
proc enlarge[T](tbl: PGenTable[T]) =
var n: TGenKeyValuePairSeq[T]
var n: GenKeyValuePairSeq[T]
newSeq(n, len(tbl.data) * growthFactor)
for i in countup(0, high(tbl.data)):
if not isNil(tbl.data[i].key):
@ -146,19 +148,20 @@ when isMainModule:
# Verify a table of user-defined types
#
type
TMyType = tuple[first, second: string] # a pair of strings
MyType = tuple[first, second: string] # a pair of strings
{.deprecated: [TMyType: MyType].}
var y = newGenTable[TMyType](modeCaseInsensitive) # hash table where each
# value is TMyType tuple
var y = newGenTable[MyType](modeCaseInsensitive) # hash table where each
# value is MyType tuple
#var junk: TMyType = ("OK", "Here")
#var junk: MyType = ("OK", "Here")
#echo junk.first, " ", junk.second
y["Hello"] = ("Hello", "World")
y["Goodbye"] = ("Goodbye", "Everyone")
#y["Hello"] = TMyType( ("Hello", "World") )
#y["Goodbye"] = TMyType( ("Goodbye", "Everyone") )
#y["Hello"] = MyType( ("Hello", "World") )
#y["Goodbye"] = MyType( ("Goodbye", "Everyone") )
assert( not isNil(y["Hello"].first) )
assert( y["Hello"].first == "Hello" )

View file

@ -15,9 +15,9 @@
## code:
##
## .. code-block:: Nim
## proc hash(x: Something): THash =
## ## Computes a THash from `x`.
## var h: THash = 0
## proc hash(x: Something): Hash =
## ## Computes a Hash from `x`.
## var h: Hash = 0
## # Iterate over parts of `x`.
## for xAtom in x:
## # Mix the atom with the partial hash.
@ -30,38 +30,39 @@
## together the hash value of the individual fields:
##
## .. code-block:: Nim
## proc hash(x: Something): THash =
## ## Computes a THash from `x`.
## var h: THash = 0
## proc hash(x: Something): Hash =
## ## Computes a Hash from `x`.
## var h: Hash = 0
## h = h !& hash(x.foo)
## h = h !& hash(x.bar)
## result = !$h
import
strutils
strutils, etcpriv
type
THash* = int ## a hash value; hash tables using these values should
Hash* = int ## a hash value; hash tables using these values should
## always have a size of a power of two and can use the ``and``
## operator instead of ``mod`` for truncation of the hash value.
{.deprecated: [THash: Hash].}
proc `!&`*(h: THash, val: int): THash {.inline.} =
proc `!&`*(h: Hash, val: int): Hash {.inline.} =
## mixes a hash value `h` with `val` to produce a new hash value. This is
## only needed if you need to implement a hash proc for a new datatype.
result = h +% val
result = result +% result shl 10
result = result xor (result shr 6)
proc `!$`*(h: THash): THash {.inline.} =
proc `!$`*(h: Hash): Hash {.inline.} =
## finishes the computation of the hash value. This is
## only needed if you need to implement a hash proc for a new datatype.
result = h +% h shl 3
result = result xor (result shr 11)
result = result +% result shl 15
proc hashData*(data: pointer, size: int): THash =
proc hashData*(data: pointer, size: int): Hash =
## hashes an array of bytes of size `size`
var h: THash = 0
var h: Hash = 0
when defined(js):
var p: cstring
asm """`p` = `Data`;"""
@ -78,7 +79,7 @@ proc hashData*(data: pointer, size: int): THash =
when defined(js):
var objectID = 0
proc hash*(x: pointer): THash {.inline.} =
proc hash*(x: pointer): Hash {.inline.} =
## efficient hashing of pointers
when defined(js):
asm """
@ -92,50 +93,57 @@ proc hash*(x: pointer): THash {.inline.} =
}
"""
else:
result = (cast[THash](x)) shr 3 # skip the alignment
result = (cast[Hash](x)) shr 3 # skip the alignment
when not defined(booting):
proc hash*[T: proc](x: T): THash {.inline.} =
proc hash*[T: proc](x: T): Hash {.inline.} =
## efficient hashing of proc vars; closures are supported too.
when T is "closure":
result = hash(rawProc(x)) !& hash(rawEnv(x))
else:
result = hash(pointer(x))
proc hash*(x: int): THash {.inline.} =
proc hash*(x: int): Hash {.inline.} =
## efficient hashing of integers
result = x
proc hash*(x: int64): THash {.inline.} =
proc hash*(x: int64): Hash {.inline.} =
## efficient hashing of integers
result = toU32(x)
proc hash*(x: char): THash {.inline.} =
proc hash*(x: char): Hash {.inline.} =
## efficient hashing of characters
result = ord(x)
proc hash*(x: string): THash =
proc hash*(x: string): Hash =
## efficient hashing of strings
var h: THash = 0
var h: Hash = 0
for i in 0..x.len-1:
h = h !& ord(x[i])
result = !$h
proc hashIgnoreStyle*(x: string): THash =
proc hashIgnoreStyle*(x: string): Hash =
## efficient hashing of strings; style is ignored
var h: THash = 0
for i in 0..x.len-1:
var h: Hash = 0
var i = 0
let xLen = x.len
while i < xLen:
var c = x[i]
if c == '_':
continue # skip _
if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h !& ord(c)
inc(i)
elif isMagicIdentSeparatorRune(cstring(x), i):
inc(i, magicIdentSeparatorRuneByteWidth)
else:
if c in {'A'..'Z'}:
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
h = h !& ord(c)
inc(i)
result = !$h
proc hashIgnoreCase*(x: string): THash =
proc hashIgnoreCase*(x: string): Hash =
## efficient hashing of strings; case is ignored
var h: THash = 0
var h: Hash = 0
for i in 0..x.len-1:
var c = x[i]
if c in {'A'..'Z'}:
@ -143,28 +151,28 @@ proc hashIgnoreCase*(x: string): THash =
h = h !& ord(c)
result = !$h
proc hash*(x: float): THash {.inline.} =
proc hash*(x: float): Hash {.inline.} =
var y = x + 1.0
result = cast[ptr THash](addr(y))[]
result = cast[ptr Hash](addr(y))[]
# Forward declarations before methods that hash containers. This allows
# containers to contain other containers
proc hash*[A](x: openArray[A]): THash
proc hash*[A](x: set[A]): THash
proc hash*[A](x: openArray[A]): Hash
proc hash*[A](x: set[A]): Hash
proc hash*[T: tuple](x: T): THash =
proc hash*[T: tuple](x: T): Hash =
## efficient hashing of tuples.
for f in fields(x):
result = result !& hash(f)
result = !$result
proc hash*[A](x: openArray[A]): THash =
proc hash*[A](x: openArray[A]): Hash =
for it in items(x): result = result !& hash(it)
result = !$result
proc hash*[A](x: set[A]): THash =
proc hash*[A](x: set[A]): Hash =
for it in items(x): result = result !& hash(it)
result = !$result

View file

@ -52,7 +52,7 @@
import strutils, streams, parsexml, xmltree, unicode, strtabs
type
THtmlTag* = enum ## list of all supported HTML tags; order will always be
HtmlTag* = enum ## list of all supported HTML tags; order will always be
## alphabetically
tagUnknown, ## unknown HTML element
tagA, ## the HTML ``a`` element
@ -178,6 +178,7 @@ type
tagVar, ## the HTML ``var`` element
tagVideo, ## the HTML ``video`` element
tagWbr ## the HTML ``wbr`` element
{.deprecated: [THtmlTag: HtmlTag].}
const
tagToStr* = [
@ -295,7 +296,7 @@ proc allLower(s: string): bool =
if c < 'a' or c > 'z': return false
return true
proc toHtmlTag(s: string): THtmlTag =
proc toHtmlTag(s: string): HtmlTag =
case s
of "a": tagA
of "abbr": tagAbbr
@ -422,14 +423,14 @@ proc toHtmlTag(s: string): THtmlTag =
of "wbr": tagWbr
else: tagUnknown
proc htmlTag*(n: XmlNode): THtmlTag =
## gets `n`'s tag as a ``THtmlTag``.
proc htmlTag*(n: XmlNode): HtmlTag =
## gets `n`'s tag as a ``HtmlTag``.
if n.clientData == 0:
n.clientData = toHtmlTag(n.tag).ord
result = THtmlTag(n.clientData)
result = HtmlTag(n.clientData)
proc htmlTag*(s: string): THtmlTag =
## converts `s` to a ``THtmlTag``. If `s` is no HTML tag, ``tagUnknown`` is
proc htmlTag*(s: string): HtmlTag =
## converts `s` to a ``HtmlTag``. If `s` is no HTML tag, ``tagUnknown`` is
## returned.
let s = if allLower(s): s else: s.toLower
result = toHtmlTag(s)

View file

@ -106,9 +106,10 @@ proc serveFile*(client: Socket, filename: string) =
when false:
# TODO: Fix this, or get rid of it.
type
TRequestMethod = enum reqGet, reqPost
RequestMethod = enum reqGet, reqPost
{.deprecated: [TRequestMethod: RequestMethod].}
proc executeCgi(client: Socket, path, query: string, meth: TRequestMethod) =
proc executeCgi(client: Socket, path, query: string, meth: RequestMethod) =
var env = newStringTable(modeCaseInsensitive)
var contentLength = -1
case meth
@ -208,7 +209,7 @@ when false:
executeCgi(client, path, query, meth)
type
TServer* = object of RootObj ## contains the current server state
Server* = object of RootObj ## contains the current server state
socket: Socket
port: Port
client*: Socket ## the socket to write the file data to
@ -218,11 +219,12 @@ type
body*: string ## only set with POST requests
ip*: string ## ip address of the requesting client
PAsyncHTTPServer* = ref TAsyncHTTPServer
TAsyncHTTPServer = object of TServer
PAsyncHTTPServer* = ref AsyncHTTPServer
AsyncHTTPServer = object of Server
asyncSocket: AsyncSocket
{.deprecated: [TAsyncHTTPServer: AsyncHTTPServer, TServer: Server].}
proc open*(s: var TServer, port = Port(80), reuseAddr = false) =
proc open*(s: var Server, port = Port(80), reuseAddr = false) =
## creates a new server at port `port`. If ``port == 0`` a free port is
## acquired that can be accessed later by the ``port`` proc.
s.socket = socket(AF_INET)
@ -243,11 +245,11 @@ proc open*(s: var TServer, port = Port(80), reuseAddr = false) =
s.query = ""
s.headers = {:}.newStringTable()
proc port*(s: var TServer): Port =
proc port*(s: var Server): Port =
## get the port number the server has acquired.
result = s.port
proc next*(s: var TServer) =
proc next*(s: var Server) =
## proceed to the first/next request.
var client: Socket
new(client)
@ -354,7 +356,7 @@ proc next*(s: var TServer) =
s.query = ""
s.path = data.substr(i, last-1)
proc close*(s: TServer) =
proc close*(s: Server) =
## closes the server (and the socket the server uses).
close(s.socket)
@ -362,7 +364,7 @@ proc run*(handleRequest: proc (client: Socket,
path, query: string): bool {.closure.},
port = Port(80)) =
## encapsulates the server object and main loop
var s: TServer
var s: Server
open(s, port, reuseAddr = true)
#echo("httpserver running on port ", s.port)
while true:
@ -517,7 +519,7 @@ proc close*(h: PAsyncHTTPServer) =
when not defined(testing) and isMainModule:
var counter = 0
var s: TServer
var s: Server
open(s, Port(0))
echo("httpserver running on port ", s.port)
while true:

View file

@ -68,7 +68,7 @@ type
jsonArrayStart, ## start of an array: the ``[`` token
jsonArrayEnd ## start of an array: the ``]`` token
TTokKind = enum # must be synchronized with TJsonEventKind!
TokKind = enum # must be synchronized with TJsonEventKind!
tkError,
tkEof,
tkString,
@ -103,14 +103,14 @@ type
JsonParser* = object of BaseLexer ## the parser object.
a: string
tok: TTokKind
tok: TokKind
kind: JsonEventKind
err: JsonError
state: seq[ParserState]
filename: string
{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError,
TJsonParser: JsonParser].}
TJsonParser: JsonParser, TTokKind: TokKind].}
const
errorMessages: array [JsonError, string] = [
@ -126,7 +126,7 @@ const
"EOF expected",
"expression expected"
]
tokToStr: array [TTokKind, string] = [
tokToStr: array [TokKind, string] = [
"invalid token",
"EOF",
"string literal",
@ -203,7 +203,7 @@ proc handleHexChar(c: char, x: var int): bool =
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: result = false # error
proc parseString(my: var JsonParser): TTokKind =
proc parseString(my: var JsonParser): TokKind =
result = tkString
var pos = my.bufpos + 1
var buf = my.buf
@ -359,7 +359,7 @@ proc parseName(my: var JsonParser) =
inc(pos)
my.bufpos = pos
proc getTok(my: var JsonParser): TTokKind =
proc getTok(my: var JsonParser): TokKind =
setLen(my.a, 0)
skip(my) # skip whitespace, comments
case my.buf[my.bufpos]
@ -734,7 +734,7 @@ proc `==`* (a,b: JsonNode): bool =
of JObject:
a.fields == b.fields
proc hash* (n:JsonNode): THash =
proc hash* (n:JsonNode): Hash =
## Compute the hash for a JSON node
case n.kind
of JArray:
@ -1016,7 +1016,7 @@ iterator mpairs*(node: var JsonNode): var tuple[key: string, val: JsonNode] =
for keyVal in mitems(node.fields):
yield keyVal
proc eat(p: var JsonParser, tok: TTokKind) =
proc eat(p: var JsonParser, tok: TokKind) =
if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok])
@ -1091,8 +1091,10 @@ when not defined(js):
else:
from math import `mod`
type
TJSObject = object
proc parseNativeJson(x: cstring): TJSObject {.importc: "JSON.parse".}
JSObject = object
{.deprecated: [TJSObject: JSObject].}
proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".}
proc getVarType(x): JsonNodeKind =
result = JNull
@ -1111,25 +1113,25 @@ else:
of "[object String]": return JString
else: assert false
proc len(x: TJSObject): int =
proc len(x: JSObject): int =
assert x.getVarType == JArray
asm """
return `x`.length;
"""
proc `[]`(x: TJSObject, y: string): TJSObject =
proc `[]`(x: JSObject, y: string): JSObject =
assert x.getVarType == JObject
asm """
return `x`[`y`];
"""
proc `[]`(x: TJSObject, y: int): TJSObject =
proc `[]`(x: JSObject, y: int): JSObject =
assert x.getVarType == JArray
asm """
return `x`[`y`];
"""
proc convertObject(x: TJSObject): JsonNode =
proc convertObject(x: JSObject): JsonNode =
case getVarType(x)
of JArray:
result = newJArray()
@ -1141,7 +1143,7 @@ else:
if (`x`.hasOwnProperty(property)) {
"""
var nimProperty: cstring
var nimValue: TJSObject
var nimValue: JSObject
asm "`nimProperty` = property; `nimValue` = `x`[property];"
result[$nimProperty] = nimValue.convertObject()
asm "}}"

View file

@ -39,7 +39,7 @@ type
{.deprecated: [TBaseLexer: BaseLexer].}
proc open*(L: var BaseLexer, input: Stream, bufLen: int = 8192)
## inits the TBaseLexer with a stream to read from
## inits the BaseLexer with a stream to read from
proc close*(L: var BaseLexer)
## closes the base lexer. This closes `L`'s associated stream too.

View file

@ -82,6 +82,7 @@ type
baseName: string # initial filename
baseMode: FileMode # initial file mode
logFiles: int # how many log files already created, e.g. basename.1, basename.2...
bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size)
{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
@ -112,27 +113,22 @@ proc substituteLog(frmt: string): string =
of "appname": result.add(app.splitFile.name)
else: discard
method log*(logger: Logger, level: Level,
frmt: string, args: varargs[string, `$`]) {.
method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
raises: [Exception],
tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} =
## Override this method in custom loggers. Default implementation does
## nothing.
discard
method log*(logger: ConsoleLogger, level: Level,
frmt: string, args: varargs[string, `$`]) =
method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
## Logs to the console using ``logger`` only.
if level >= logger.levelThreshold:
writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr),
frmt % args)
writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr), args)
method log*(logger: FileLogger, level: Level,
frmt: string, args: varargs[string, `$`]) =
method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
## Logs to a file using ``logger`` only.
if level >= logger.levelThreshold:
writeln(logger.f, LevelNames[level], " ",
substituteLog(logger.fmtStr), frmt % args)
writeln(logger.f, LevelNames[level], " ", substituteLog(logger.fmtStr), args)
proc defaultFilename*(): string =
## Returns the default filename for a logger.
@ -148,11 +144,14 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): Console
proc newFileLogger*(filename = defaultFilename(),
mode: FileMode = fmAppend,
levelThreshold = lvlAll,
fmtStr = defaultFmtStr): FileLogger =
fmtStr = defaultFmtStr,
bufSize: int = -1): FileLogger =
## Creates a new file logger. This logger logs to a file.
## Use ``bufSize`` as size of the output buffer when writing the file
## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
new(result)
result.levelThreshold = levelThreshold
result.f = open(filename, mode)
result.f = open(filename, mode, bufSize = bufSize)
result.fmtStr = fmtStr
# ------
@ -181,14 +180,18 @@ proc newRollingFileLogger*(filename = defaultFilename(),
mode: FileMode = fmReadWrite,
levelThreshold = lvlAll,
fmtStr = defaultFmtStr,
maxLines = 1000): RollingFileLogger =
maxLines = 1000,
bufSize: int = -1): RollingFileLogger =
## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines
## a new log file will be started and the old will be renamed.
## Use ``bufSize`` as size of the output buffer when writing the file
## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
new(result)
result.levelThreshold = levelThreshold
result.fmtStr = fmtStr
result.maxLines = maxLines
result.f = open(filename, mode)
result.bufSize = bufSize
result.f = open(filename, mode, bufSize=result.bufSize)
result.curLine = 0
result.baseName = filename
result.baseMode = mode
@ -206,8 +209,7 @@ proc rotate(logger: RollingFileLogger) =
moveFile(dir / (name & ext & srcSuff),
dir / (name & ext & ExtSep & $(i+1)))
method log*(logger: RollingFileLogger, level: Level,
frmt: string, args: varargs[string, `$`]) =
method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
## Logs to a file using rolling ``logger`` only.
if level >= logger.levelThreshold:
if logger.curLine >= logger.maxLines:
@ -215,9 +217,9 @@ method log*(logger: RollingFileLogger, level: Level,
rotate(logger)
logger.logFiles.inc
logger.curLine = 0
logger.f = open(logger.baseName, logger.baseMode)
logger.f = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
writeln(logger.f, LevelNames[level], " ",substituteLog(logger.fmtStr), frmt % args)
writeln(logger.f, LevelNames[level], " ", substituteLog(logger.fmtStr), args)
logger.curLine.inc
# --------
@ -225,39 +227,39 @@ method log*(logger: RollingFileLogger, level: Level,
var level {.threadvar.}: Level ## global log filter
var handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
proc logLoop(level: Level, frmt: string, args: varargs[string, `$`]) =
proc logLoop(level: Level, args: varargs[string, `$`]) =
for logger in items(handlers):
if level >= logger.levelThreshold:
log(logger, level, frmt, args)
log(logger, level, args)
template log*(level: Level, frmt: string, args: varargs[string, `$`]) =
template log*(level: Level, args: varargs[string, `$`]) =
## Logs a message to all registered handlers at the given level.
bind logLoop
bind `%`
bind logging.level
if level >= logging.level:
logLoop(level, frmt, args)
logLoop(level, args)
template debug*(frmt: string, args: varargs[string, `$`]) =
template debug*(args: varargs[string, `$`]) =
## Logs a debug message to all registered handlers.
log(lvlDebug, frmt, args)
log(lvlDebug, args)
template info*(frmt: string, args: varargs[string, `$`]) =
template info*(args: varargs[string, `$`]) =
## Logs an info message to all registered handlers.
log(lvlInfo, frmt, args)
log(lvlInfo, args)
template warn*(frmt: string, args: varargs[string, `$`]) =
template warn*(args: varargs[string, `$`]) =
## Logs a warning message to all registered handlers.
log(lvlWarn, frmt, args)
log(lvlWarn, args)
template error*(frmt: string, args: varargs[string, `$`]) =
template error*(args: varargs[string, `$`]) =
## Logs an error message to all registered handlers.
log(lvlError, frmt, args)
log(lvlError, args)
template fatal*(frmt: string, args: varargs[string, `$`]) =
template fatal*(args: varargs[string, `$`]) =
## Logs a fatal error message to all registered handlers.
log(lvlFatal, frmt, args)
log(lvlFatal, args)
proc addHandler*(handler: Logger) =
## Adds ``handler`` to the list of handlers.
@ -286,6 +288,4 @@ when not defined(testing) and isMainModule:
addHandler(fL)
addHandler(rL)
for i in 0 .. 25:
info("hello" & $i, [])
info("hello", i)

View file

@ -17,13 +17,13 @@
## .. code-block:: nim
##
## type
## TA = object
## TB = object of TA
## A = object
## B = object of A
## f: int
##
## var
## a: ref TA
## b: ref TB
## a: ref A
## b: ref B
##
## new(b)
## a = b
@ -36,7 +36,7 @@ import streams, typeinfo, json, intsets, tables
proc ptrToInt(x: pointer): int {.inline.} =
result = cast[int](x) # don't skip alignment
proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
proc storeAny(s: Stream, a: Any, stored: var IntSet) =
case a.kind
of akNone: assert false
of akBool: s.write($getBool(a))
@ -96,7 +96,7 @@ proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
of akInt..akInt64, akUInt..akUInt64: s.write($getBiggestInt(a))
of akFloat..akFloat128: s.write($getBiggestFloat(a))
proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) =
case a.kind
of akNone: assert false
of akBool:
@ -222,7 +222,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
raiseParseErr(p, "float expected")
of akRange: loadAny(p, a.skipRange, t)
proc loadAny(s: Stream, a: TAny, t: var Table[BiggestInt, pointer]) =
proc loadAny(s: Stream, a: Any, t: var Table[BiggestInt, pointer]) =
var p: JsonParser
open(p, s, "unknown file")
next(p)
@ -278,10 +278,11 @@ when not defined(testing) and isMainModule:
else:
nil
PNode = ref TNode
TNode = object
PNode = ref Node
Node = object
next, prev: PNode
data: string
{.deprecated: [TNode: Node].}
proc buildList(): PNode =
new(result)
@ -317,14 +318,15 @@ when not defined(testing) and isMainModule:
testit(test7)
type
TA {.inheritable.} = object
TB = object of TA
A {.inheritable.} = object
B = object of A
f: int
var
a: ref TA
b: ref TB
a: ref A
b: ref B
new(b)
a = b
echo($$a[]) # produces "{}", not "{f: 0}"

View file

@ -196,7 +196,7 @@ proc open*(filename: string, mode: FileMode = fmRead,
if mappedSize != -1:
result.size = mappedSize
else:
var stat: TStat
var stat: Stat
if fstat(result.handle, stat) != -1:
# XXX: Hmm, this could be unsafe
# Why is mmap taking int anyway?

View file

@ -86,7 +86,7 @@ type
IPv6, ## IPv6 address
IPv4 ## IPv4 address
TIpAddress* = object ## stores an arbitrary IP address
IpAddress* = object ## stores an arbitrary IP address
case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
of IpAddressFamily.IPv6:
address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
@ -94,9 +94,10 @@ type
of IpAddressFamily.IPv4:
address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
## case of IPv4
{.deprecated: [TIpAddress: IpAddress].}
proc isIpAddress*(address_str: string): bool {.tags: [].}
proc parseIpAddress*(address_str: string): TIpAddress
proc parseIpAddress*(address_str: string): IpAddress
proc isDisconnectionError*(flags: set[SocketFlag],
lastError: OSErrorCode): bool =
@ -395,7 +396,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
when false: #defined(ssl):
proc acceptAddrSSL*(server: Socket, client: var Socket,
address: var string): TSSLAcceptResult {.
address: var string): SSLAcceptResult {.
tags: [ReadIOEffect].} =
## This procedure should only be used for non-blocking **SSL** sockets.
## It will immediately return with one of the following values:
@ -992,39 +993,39 @@ proc isSsl*(socket: Socket): bool =
proc getFd*(socket: Socket): SocketHandle = return socket.fd
## Returns the socket's file descriptor
proc IPv4_any*(): TIpAddress =
proc IPv4_any*(): IpAddress =
## Returns the IPv4 any address, which can be used to listen on all available
## network adapters
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv4,
address_v4: [0'u8, 0, 0, 0])
proc IPv4_loopback*(): TIpAddress =
proc IPv4_loopback*(): IpAddress =
## Returns the IPv4 loopback address (127.0.0.1)
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv4,
address_v4: [127'u8, 0, 0, 1])
proc IPv4_broadcast*(): TIpAddress =
proc IPv4_broadcast*(): IpAddress =
## Returns the IPv4 broadcast address (255.255.255.255)
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv4,
address_v4: [255'u8, 255, 255, 255])
proc IPv6_any*(): TIpAddress =
proc IPv6_any*(): IpAddress =
## Returns the IPv6 any address (::0), which can be used
## to listen on all available network adapters
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv6,
address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
proc IPv6_loopback*(): TIpAddress =
proc IPv6_loopback*(): IpAddress =
## Returns the IPv6 loopback address (::1)
result = TIpAddress(
result = IpAddress(
family: IpAddressFamily.IPv6,
address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
proc `==`*(lhs, rhs: TIpAddress): bool =
proc `==`*(lhs, rhs: IpAddress): bool =
## Compares two IpAddresses for Equality. Returns two if the addresses are equal
if lhs.family != rhs.family: return false
if lhs.family == IpAddressFamily.IPv4:
@ -1035,8 +1036,8 @@ proc `==`*(lhs, rhs: TIpAddress): bool =
if lhs.address_v6[i] != rhs.address_v6[i]: return false
return true
proc `$`*(address: TIpAddress): string =
## Converts an TIpAddress into the textual representation
proc `$`*(address: IpAddress): string =
## Converts an IpAddress into the textual representation
result = ""
case address.family
of IpAddressFamily.IPv4:
@ -1095,7 +1096,7 @@ proc `$`*(address: TIpAddress): string =
mask = mask shr 4
printedLastGroup = true
proc parseIPv4Address(address_str: string): TIpAddress =
proc parseIPv4Address(address_str: string): IpAddress =
## Parses IPv4 adresses
## Raises EInvalidValue on errors
var
@ -1129,7 +1130,7 @@ proc parseIPv4Address(address_str: string): TIpAddress =
raise newException(ValueError, "Invalid IP Address")
result.address_v4[byteCount] = cast[uint8](currentByte)
proc parseIPv6Address(address_str: string): TIpAddress =
proc parseIPv6Address(address_str: string): IpAddress =
## Parses IPv6 adresses
## Raises EInvalidValue on errors
result.family = IpAddressFamily.IPv6
@ -1250,7 +1251,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
raise newException(ValueError,
"Invalid IP Address. The address consists of too many groups")
proc parseIpAddress(address_str: string): TIpAddress =
proc parseIpAddress(address_str: string): IpAddress =
## Parses an IP address
## Raises EInvalidValue on error
if address_str == nil:

View file

@ -26,17 +26,19 @@ const
withThreads = compileOption("threads")
tickCountCorrection = 50_000
when not declared(system.TStackTrace):
type TStackTrace = array [0..20, cstring]
when not declared(system.StackTrace):
type StackTrace = array [0..20, cstring]
{.deprecated: [TStackTrace: StackTrace].}
# We use a simple hash table of bounded size to keep track of the stack traces:
type
TProfileEntry = object
ProfileEntry = object
total: int
st: TStackTrace
TProfileData = array [0..64*1024-1, ptr TProfileEntry]
st: StackTrace
ProfileData = array [0..64*1024-1, ptr ProfileEntry]
{.deprecated: [TProfileEntry: ProfileEntry, TProfileData: ProfileData].}
proc `==`(a, b: TStackTrace): bool =
proc `==`(a, b: StackTrace): bool =
for i in 0 .. high(a):
if a[i] != b[i]: return false
result = true
@ -44,13 +46,13 @@ proc `==`(a, b: TStackTrace): bool =
# XXX extract this data structure; it is generally useful ;-)
# However a chain length of over 3000 is suspicious...
var
profileData: TProfileData
profileData: ProfileData
emptySlots = profileData.len * 3 div 2
maxChainLen = 0
totalCalls = 0
when not defined(memProfiler):
var interval: TNanos = 5_000_000 - tickCountCorrection # 5ms
var interval: Nanos = 5_000_000 - tickCountCorrection # 5ms
proc setSamplingFrequency*(intervalInUs: int) =
## set this to change the sampling frequency. Default value is 5ms.
@ -62,11 +64,11 @@ when not defined(memProfiler):
when withThreads:
import locks
var
profilingLock: TLock
profilingLock: Lock
initLock profilingLock
proc hookAux(st: TStackTrace, costs: int) =
proc hookAux(st: StackTrace, costs: int) =
# this is quite performance sensitive!
when withThreads: acquire profilingLock
inc totalCalls
@ -94,8 +96,8 @@ proc hookAux(st: TStackTrace, costs: int) =
var chain = 0
while true:
if profileData[h] == nil:
profileData[h] = cast[ptr TProfileEntry](
allocShared0(sizeof(TProfileEntry)))
profileData[h] = cast[ptr ProfileEntry](
allocShared0(sizeof(ProfileEntry)))
profileData[h].total = costs
profileData[h].st = st
dec emptySlots
@ -115,7 +117,7 @@ when defined(memProfiler):
var
gTicker {.threadvar.}: int
proc hook(st: TStackTrace, size: int) {.nimcall.} =
proc hook(st: StackTrace, size: int) {.nimcall.} =
if gTicker == 0:
gTicker = -1
when defined(ignoreAllocationSize):
@ -127,26 +129,26 @@ when defined(memProfiler):
else:
var
t0 {.threadvar.}: TTicks
t0 {.threadvar.}: Ticks
proc hook(st: TStackTrace) {.nimcall.} =
proc hook(st: StackTrace) {.nimcall.} =
if interval == 0:
hookAux(st, 1)
elif int64(t0) == 0 or getTicks() - t0 > interval:
hookAux(st, 1)
t0 = getTicks()
proc getTotal(x: ptr TProfileEntry): int =
proc getTotal(x: ptr ProfileEntry): int =
result = if isNil(x): 0 else: x.total
proc cmpEntries(a, b: ptr TProfileEntry): int =
proc cmpEntries(a, b: ptr ProfileEntry): int =
result = b.getTotal - a.getTotal
proc `//`(a, b: int): string =
result = format("$1/$2 = $3%", a, b, formatFloat(a / b * 100.0, ffDefault, 2))
proc writeProfile() {.noconv.} =
when declared(system.TStackTrace):
when declared(system.StackTrace):
system.profilerHook = nil
const filename = "profile_results.txt"
echo "writing " & filename & "..."
@ -161,7 +163,7 @@ proc writeProfile() {.noconv.} =
var perProc = initCountTable[string]()
for i in 0..entries-1:
var dups = initSet[string]()
for ii in 0..high(TStackTrace):
for ii in 0..high(StackTrace):
let procname = profileData[i].st[ii]
if isNil(procname): break
let p = $procname
@ -176,7 +178,7 @@ proc writeProfile() {.noconv.} =
writeln(f, "Entry: ", i+1, "/", entries, " Calls: ",
profileData[i].total // totalCalls, " [sum: ", sum, "; ",
sum // totalCalls, "]")
for ii in 0..high(TStackTrace):
for ii in 0..high(StackTrace):
let procname = profileData[i].st[ii]
if isNil(procname): break
writeln(f, " ", procname, " ", perProc[$procname] // totalCalls)
@ -189,16 +191,16 @@ var
disabled: int
proc disableProfiling*() =
when declared(system.TStackTrace):
when declared(system.StackTrace):
atomicDec disabled
system.profilerHook = nil
proc enableProfiling*() =
when declared(system.TStackTrace):
when declared(system.StackTrace):
if atomicInc(disabled) >= 0:
system.profilerHook = hook
when declared(system.TStackTrace):
when declared(system.StackTrace):
system.profilerHook = hook
addQuitProc(writeProfile)

View file

@ -41,7 +41,7 @@ type
OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect,
{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect,
FReadDir: ReadDirEffect,
FWriteDir: WriteDirEffect,
TOSErrorCode: OSErrorCode
@ -359,7 +359,7 @@ when defined(windows):
template wrapBinary(varname, winApiProc, arg, arg2: expr) {.immediate.} =
var varname = winApiProc(newWideCString(arg), arg2)
proc findFirstFile(a: string, b: var TWIN32_FIND_DATA): THandle =
proc findFirstFile(a: string, b: var WIN32_FIND_DATA): Handle =
result = findFirstFileW(newWideCString(a), b)
template findNextFile(a, b: expr): expr = findNextFileW(a, b)
template getCommandLine(): expr = getCommandLineW()
@ -373,7 +373,7 @@ when defined(windows):
template getFilename(f: expr): expr = $f.cFilename
proc skipFindData(f: TWIN32_FIND_DATA): bool {.inline.} =
proc skipFindData(f: WIN32_FIND_DATA): bool {.inline.} =
# Note - takes advantage of null delimiter in the cstring
const dot = ord('.')
result = f.cFileName[0].int == dot and (f.cFileName[1].int == 0 or
@ -390,7 +390,7 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1",
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32
else:
var res: TStat
var res: Stat
return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect].} =
@ -404,7 +404,7 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect]
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
else:
var res: TStat
var res: Stat
return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
@ -419,7 +419,7 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
if a != -1'i32:
result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32
else:
var res: TStat
var res: Stat
return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)
proc fileExists*(filename: string): bool {.inline.} =
@ -433,11 +433,11 @@ proc dirExists*(dir: string): bool {.inline.} =
proc getLastModificationTime*(file: string): Time {.rtl, extern: "nos$1".} =
## Returns the `file`'s last modification time.
when defined(posix):
var res: TStat
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return res.st_mtime
else:
var f: TWIN32_FIND_DATA
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError())
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
@ -446,11 +446,11 @@ proc getLastModificationTime*(file: string): Time {.rtl, extern: "nos$1".} =
proc getLastAccessTime*(file: string): Time {.rtl, extern: "nos$1".} =
## Returns the `file`'s last read or write access time.
when defined(posix):
var res: TStat
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return res.st_atime
else:
var f: TWIN32_FIND_DATA
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError())
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
@ -461,11 +461,11 @@ proc getCreationTime*(file: string): Time {.rtl, extern: "nos$1".} =
## Note that under posix OS's, the returned time may actually be the time at
## which the file's attribute's were last modified.
when defined(posix):
var res: TStat
var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError())
return res.st_ctime
else:
var f: TWIN32_FIND_DATA
var f: WIN32_FIND_DATA
var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError())
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
@ -794,20 +794,20 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
result = path[0] == '/'
when defined(Windows):
proc openHandle(path: string, followSymlink=true): THandle =
proc openHandle(path: string, followSymlink=true): Handle =
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
if not followSymlink:
flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
when useWinUnicode:
result = createFileW(
newWideCString(path), 0'i32,
newWideCString(path), 0'i32,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)
else:
result = createFileA(
path, 0'i32,
path, 0'i32,
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, flags, 0
)
@ -827,7 +827,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
var lastErr: OSErrorCode
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
var fi1, fi2: BY_HANDLE_FILE_INFORMATION
if getFileInformationByHandle(f1, addr(fi1)) != 0 and
getFileInformationByHandle(f2, addr(fi2)) != 0:
@ -846,7 +846,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
if not success: raiseOSError(lastErr)
else:
var a, b: TStat
var a, b: Stat
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
raiseOSError(osLastError())
else:
@ -903,7 +903,7 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
## an error. On Windows, only the ``readonly`` flag is checked, every other
## permission is available in any case.
when defined(posix):
var a: TStat
var a: Stat
if stat(filename, a) < 0'i32: raiseOSError(osLastError())
result = {}
if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
@ -924,11 +924,11 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
var res = getFileAttributesA(filename)
if res == -1'i32: raiseOSError(osLastError())
if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
fpOthersExec, fpOthersRead}
else:
result = {fpUserExec..fpOthersRead}
proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
rtl, extern: "nos$1", tags: [WriteDirEffect].} =
## sets the file permissions for `filename`. `OSError` is raised in case of
@ -939,15 +939,15 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
if fpUserRead in permissions: p = p or S_IRUSR
if fpUserWrite in permissions: p = p or S_IWUSR
if fpUserExec in permissions: p = p or S_IXUSR
if fpGroupRead in permissions: p = p or S_IRGRP
if fpGroupWrite in permissions: p = p or S_IWGRP
if fpGroupExec in permissions: p = p or S_IXGRP
if fpOthersRead in permissions: p = p or S_IROTH
if fpOthersWrite in permissions: p = p or S_IWOTH
if fpOthersExec in permissions: p = p or S_IXOTH
if chmod(filename, p) != 0: raiseOSError(osLastError())
else:
when useWinUnicode:
@ -955,7 +955,7 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
else:
var res = getFileAttributesA(filename)
if res == -1'i32: raiseOSError(osLastError())
if fpUserWrite in permissions:
if fpUserWrite in permissions:
res = res and not FILE_ATTRIBUTE_READONLY
else:
res = res or FILE_ATTRIBUTE_READONLY
@ -1030,11 +1030,11 @@ when not declared(ENOENT) and not defined(Windows):
when defined(Windows):
when useWinUnicode:
template deleteFile(file: expr): expr {.immediate.} = deleteFileW(file)
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
setFileAttributesW(file, attrs)
else:
template deleteFile(file: expr): expr {.immediate.} = deleteFileA(file)
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
template setFileAttributes(file, attrs: expr): expr {.immediate.} =
setFileAttributesA(file, attrs)
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
@ -1047,7 +1047,7 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].}
else:
let f = file
if deleteFile(f) == 0:
if getLastError() == ERROR_ACCESS_DENIED:
if getLastError() == ERROR_ACCESS_DENIED:
if setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0:
raiseOSError(osLastError())
if deleteFile(f) == 0:
@ -1220,7 +1220,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
## notation is supported.
when defined(windows):
var
f: TWIN32_FIND_DATA
f: WIN32_FIND_DATA
res: int
res = findFirstFile(pattern, f)
if res != -1:
@ -1232,7 +1232,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
findClose(res)
else: # here we use glob
var
f: TGlob
f: Glob
res: int
f.gl_offs = 0
f.gl_pathc = 0
@ -1276,7 +1276,7 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
## dirA/fileA1.txt
## dirA/fileA2.txt
when defined(windows):
var f: TWIN32_FIND_DATA
var f: WIN32_FIND_DATA
var h = findFirstFile(dir / "*", f)
if h != -1:
while true:
@ -1297,7 +1297,7 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
if x == nil: break
var y = $x.d_name
if y != "." and y != "..":
var s: TStat
var s: Stat
y = dir / y
var k = pcFile
@ -1319,9 +1319,9 @@ iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
## walks over the directory `dir` and yields for each file in `dir`. The
## full path for each file is returned.
## **Warning**:
## Modifying the directory structure while the iterator
## is traversing may result in undefined behavior!
##
## Modifying the directory structure while the iterator
## is traversing may result in undefined behavior!
##
## Walking is recursive. `filter` controls the behaviour of the iterator:
##
## --------------------- ---------------------------------------------
@ -1424,7 +1424,7 @@ proc createSymlink*(src, dest: string) =
## by `src`. On most operating systems, will fail if a lonk
##
## **Warning**:
## Some OS's (such as Microsoft Windows) restrict the creation
## Some OS's (such as Microsoft Windows) restrict the creation
## of symlinks to root users (administrators).
when defined(Windows):
let flag = dirExists(src).int32
@ -1444,7 +1444,7 @@ proc createHardlink*(src, dest: string) =
## Create a hard link at `dest` which points to the item specified
## by `src`.
##
## **Warning**: Most OS's restrict the creation of hard links to
## **Warning**: Most OS's restrict the creation of hard links to
## root users (administrators) .
when defined(Windows):
when useWinUnicode:
@ -1548,7 +1548,7 @@ proc parseCmdLine*(c: string): seq[string] {.
add(a, c[i])
inc(i)
add(result, a)
proc copyFileWithPermissions*(source, dest: string,
ignorePermissionErrors = true) =
## Copies a file from `source` to `dest` preserving file permissions.
@ -1842,7 +1842,7 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
when defined(windows):
winlean.sleep(int32(milsecs))
else:
var a, b: Ttimespec
var a, b: Timespec
a.tv_sec = Time(milsecs div 1000)
a.tv_nsec = (milsecs mod 1000) * 1000 * 1000
discard posix.nanosleep(a, b)
@ -1851,7 +1851,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
tags: [ReadIOEffect].} =
## returns the file size of `file`. Can raise ``OSError``.
when defined(windows):
var a: TWIN32_FIND_DATA
var a: WIN32_FIND_DATA
var resA = findFirstFile(file, a)
if resA == -1: raiseOSError(osLastError())
result = rdFileSize(a)
@ -1907,8 +1907,8 @@ when defined(Windows):
FileId* = int64
else:
type
DeviceId* = TDev
FileId* = Tino
DeviceId* = Dev
FileId* = Ino
type
FileInfo* = object
@ -1925,7 +1925,7 @@ type
template rawToFormalFileInfo(rawInfo, formalInfo): expr =
## Transforms the native file info structure into the one nim uses.
## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
## or a 'TStat' structure on posix
## or a 'Stat' structure on posix
when defined(Windows):
template toTime(e): expr = winTimeToUnixTime(rdFileTime(e))
template merge(a, b): expr = a or (b shl 32)
@ -1936,10 +1936,10 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr =
formalInfo.lastAccessTime = toTime(rawInfo.ftLastAccessTime)
formalInfo.lastWriteTime = toTime(rawInfo.ftLastWriteTime)
formalInfo.creationTime = toTime(rawInfo.ftCreationTime)
# Retrieve basic permissions
if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec,
formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec,
fpGroupRead, fpOthersExec, fpOthersRead}
else:
result.permissions = {fpUserExec..fpOthersRead}
@ -1953,7 +1953,7 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr =
else:
template checkAndIncludeMode(rawMode, formalMode: expr) =
template checkAndIncludeMode(rawMode, formalMode: expr) =
if (rawInfo.st_mode and rawMode) != 0'i32:
formalInfo.permissions.incl(formalMode)
formalInfo.id = (rawInfo.st_dev, rawInfo.st_ino)
@ -1988,7 +1988,7 @@ proc getFileInfo*(handle: FileHandle): FileInfo =
## is invalid, an error will be thrown.
# Done: ID, Kind, Size, Permissions, Link Count
when defined(Windows):
var rawInfo: TBY_HANDLE_FILE_INFORMATION
var rawInfo: BY_HANDLE_FILE_INFORMATION
# We have to use the super special '_get_osfhandle' call (wrapped above)
# To transform the C file descripter to a native file handle.
var realHandle = get_osfhandle(handle)
@ -1996,7 +1996,7 @@ proc getFileInfo*(handle: FileHandle): FileInfo =
raiseOSError(osLastError())
rawToFormalFileInfo(rawInfo, result)
else:
var rawInfo: TStat
var rawInfo: Stat
if fstat(handle, rawInfo) < 0'i32:
raiseOSError(osLastError())
rawToFormalFileInfo(rawInfo, result)
@ -2008,22 +2008,22 @@ proc getFileInfo*(file: File): FileInfo =
proc getFileInfo*(path: string, followSymlink = true): FileInfo =
## Retrieves file information for the file object pointed to by `path`.
##
##
## Due to intrinsic differences between operating systems, the information
## contained by the returned `FileInfo` structure will be slightly different
## across platforms, and in some cases, incomplete or inaccurate.
##
##
## When `followSymlink` is true, symlinks are followed and the information
## retrieved is information related to the symlink's target. Otherwise,
## information on the symlink itself is retrieved.
##
##
## If the information cannot be retrieved, such as when the path doesn't
## exist, or when permission restrictions prevent the program from retrieving
## file information, an error will be thrown.
when defined(Windows):
var
var
handle = openHandle(path, followSymlink)
rawInfo: TBY_HANDLE_FILE_INFORMATION
rawInfo: BY_HANDLE_FILE_INFORMATION
if handle == INVALID_HANDLE_VALUE:
raiseOSError(osLastError())
if getFileInformationByHandle(handle, addr rawInfo) == 0:
@ -2031,7 +2031,7 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo =
rawToFormalFileInfo(rawInfo, result)
discard closeHandle(handle)
else:
var rawInfo: TStat
var rawInfo: Stat
if followSymlink:
if stat(path, rawInfo) < 0'i32:
raiseOSError(osLastError())
@ -2044,7 +2044,7 @@ proc isHidden*(path: string): bool =
## Determines whether a given path is hidden or not. Returns false if the
## file doesn't exist. The given path must be accessible from the current
## working directory of the program.
##
##
## On Windows, a file is hidden if the file's 'hidden' attribute is set.
## On Unix-like systems, a file is hidden if it starts with a '.' (period)
## and is not *just* '.' or '..' ' ."

View file

@ -26,13 +26,13 @@ when defined(linux):
type
ProcessObj = object of RootObj
when defined(windows):
fProcessHandle: THandle
fProcessHandle: Handle
inHandle, outHandle, errHandle: FileHandle
id: THandle
id: Handle
else:
inHandle, outHandle, errHandle: FileHandle
inStream, outStream, errStream: Stream
id: TPid
id: Pid
exitCode: cint
Process* = ref ProcessObj ## represents an operating system process
@ -334,10 +334,11 @@ when not defined(useNimRtl):
when defined(Windows) and not defined(useNimRtl):
# We need to implement a handle stream for Windows:
type
PFileHandleStream = ref TFileHandleStream
TFileHandleStream = object of StreamObj
handle: THandle
PFileHandleStream = ref FileHandleStream
FileHandleStream = object of StreamObj
handle: Handle
atTheEnd: bool
{.deprecated: [TFileHandleStream: FileHandleStream].}
proc hsClose(s: Stream) = discard # nothing to do here
proc hsAtEnd(s: Stream): bool = return PFileHandleStream(s).atTheEnd
@ -361,7 +362,7 @@ when defined(Windows) and not defined(useNimRtl):
addr bytesWritten, nil)
if a == 0: raiseOSError(osLastError())
proc newFileHandleStream(handle: THandle): PFileHandleStream =
proc newFileHandleStream(handle: Handle): PFileHandleStream =
new(result)
result.handle = handle
result.closeImpl = hsClose
@ -387,22 +388,22 @@ when defined(Windows) and not defined(useNimRtl):
copyMem(addr(result[L]), cstring(x), x.len+1) # copy \0
inc(L, x.len+1)
#proc open_osfhandle(osh: THandle, mode: int): int {.
#proc open_osfhandle(osh: Handle, mode: int): int {.
# importc: "_open_osfhandle", header: "<fcntl.h>".}
#var
# O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
# O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int
proc createPipeHandles(rdHandle, wrHandle: var THandle) =
var piInheritablePipe: TSECURITY_ATTRIBUTES
piInheritablePipe.nLength = sizeof(TSECURITY_ATTRIBUTES).cint
proc createPipeHandles(rdHandle, wrHandle: var Handle) =
var piInheritablePipe: SECURITY_ATTRIBUTES
piInheritablePipe.nLength = sizeof(SECURITY_ATTRIBUTES).cint
piInheritablePipe.lpSecurityDescriptor = nil
piInheritablePipe.bInheritHandle = 1
if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32:
raiseOSError(osLastError())
proc fileClose(h: THandle) {.inline.} =
proc fileClose(h: Handle) {.inline.} =
if h > 4: discard closeHandle(h)
proc startProcess(command: string,
@ -411,10 +412,10 @@ when defined(Windows) and not defined(useNimRtl):
env: StringTableRef = nil,
options: set[ProcessOption] = {poStdErrToStdOut}): Process =
var
si: TSTARTUPINFO
procInfo: TPROCESS_INFORMATION
si: STARTUPINFO
procInfo: PROCESS_INFORMATION
success: int
hi, ho, he: THandle
hi, ho, he: Handle
new(result)
si.cb = sizeof(si).cint
if poParentStreams notin options:
@ -525,9 +526,9 @@ when defined(Windows) and not defined(useNimRtl):
proc execCmd(command: string): int =
var
si: TSTARTUPINFO
procInfo: TPROCESS_INFORMATION
process: THandle
si: STARTUPINFO
procInfo: PROCESS_INFORMATION
process: Handle
L: int32
si.cb = sizeof(si).cint
si.hStdError = getStdHandle(STD_ERROR_HANDLE)
@ -554,7 +555,7 @@ when defined(Windows) and not defined(useNimRtl):
proc select(readfds: var seq[Process], timeout = 500): int =
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
var rfds: TWOHandleArray
var rfds: WOHandleArray
for i in 0..readfds.len()-1:
rfds[i] = readfds[i].fProcessHandle
@ -595,7 +596,7 @@ elif not defined(useNimRtl):
copyMem(result[i], addr(x[0]), x.len+1)
inc(i)
type TStartProcessData = object
type StartProcessData = object
sysCommand: cstring
sysArgs: cstringArray
sysEnv: cstringArray
@ -604,14 +605,15 @@ elif not defined(useNimRtl):
optionPoUsePath: bool
optionPoParentStreams: bool
optionPoStdErrToStdOut: bool
{.deprecated: [TStartProcessData: StartProcessData].}
when not defined(useFork):
proc startProcessAuxSpawn(data: TStartProcessData): TPid {.
proc startProcessAuxSpawn(data: StartProcessData): Pid {.
tags: [ExecIOEffect, ReadEnvEffect], gcsafe.}
proc startProcessAuxFork(data: TStartProcessData): TPid {.
proc startProcessAuxFork(data: StartProcessData): Pid {.
tags: [ExecIOEffect, ReadEnvEffect], gcsafe.}
{.push stacktrace: off, profiler: off.}
proc startProcessAfterFork(data: ptr TStartProcessData) {.
proc startProcessAfterFork(data: ptr StartProcessData) {.
tags: [ExecIOEffect, ReadEnvEffect], cdecl, gcsafe.}
{.pop.}
@ -641,7 +643,7 @@ elif not defined(useNimRtl):
for arg in args.items:
sysArgsRaw.add arg
var pid: TPid
var pid: Pid
var sysArgs = allocCStringArray(sysArgsRaw)
defer: deallocCStringArray(sysArgs)
@ -653,7 +655,7 @@ elif not defined(useNimRtl):
defer: deallocCStringArray(sysEnv)
var data: TStartProcessData
var data: StartProcessData
data.sysCommand = sysCommand
data.sysArgs = sysArgs
data.sysEnv = sysEnv
@ -698,7 +700,7 @@ elif not defined(useNimRtl):
discard close(pStdout[writeIdx])
when not defined(useFork):
proc startProcessAuxSpawn(data: TStartProcessData): TPid =
proc startProcessAuxSpawn(data: StartProcessData): Pid =
var attr: Tposix_spawnattr
var fops: Tposix_spawn_file_actions
@ -708,7 +710,7 @@ elif not defined(useNimRtl):
chck posix_spawn_file_actions_init(fops)
chck posix_spawnattr_init(attr)
var mask: Tsigset
var mask: Sigset
chck sigemptyset(mask)
chck posix_spawnattr_setsigmask(attr, mask)
chck posix_spawnattr_setpgroup(attr, 0'i32)
@ -732,7 +734,7 @@ elif not defined(useNimRtl):
# FIXME: chdir is global to process
if data.workingDir.len > 0:
setCurrentDir($data.workingDir)
var pid: TPid
var pid: Pid
if data.optionPoUsePath:
res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
@ -744,14 +746,14 @@ elif not defined(useNimRtl):
chck res
return pid
proc startProcessAuxFork(data: TStartProcessData): TPid =
proc startProcessAuxFork(data: StartProcessData): Pid =
if pipe(data.pErrorPipe) != 0:
raiseOSError(osLastError())
defer:
discard close(data.pErrorPipe[readIdx])
var pid: TPid
var pid: Pid
var dataCopy = data
when defined(useClone):
@ -781,7 +783,7 @@ elif not defined(useNimRtl):
return pid
{.push stacktrace: off, profiler: off.}
proc startProcessFail(data: ptr TStartProcessData) =
proc startProcessFail(data: ptr StartProcessData) =
var error: cint = errno
discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error))
exitnow(1)
@ -789,7 +791,7 @@ elif not defined(useNimRtl):
when defined(macosx) or defined(freebsd):
var environ {.importc.}: cstringArray
proc startProcessAfterFork(data: ptr TStartProcessData) =
proc startProcessAfterFork(data: ptr StartProcessData) =
# Warning: no GC here!
# Or anything that touches global structures - all called nim procs
# must be marked with stackTrace:off. Inspect C code after making changes.

View file

@ -133,7 +133,7 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
when declared(initOptParser):
iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
## This is an convenience iterator for iterating over the command line.
## This uses the TOptParser object. Example:
## This uses the OptParser object. Example:
##
## .. code-block:: nim
## var

View file

@ -74,8 +74,8 @@ type
line: int ## line the symbol has been declared/used in
col: int ## column the symbol has been declared/used in
flags: set[NonTerminalFlag] ## the nonterminal's flags
rule: TNode ## the rule that the symbol refers to
TNode {.shallow.} = object
rule: Node ## the rule that the symbol refers to
Node {.shallow.} = object
case kind: PegKind
of pkEmpty..pkWhitespace: nil
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
@ -83,12 +83,12 @@ type
of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
of pkNonTerminal: nt: NonTerminal
of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
else: sons: seq[TNode]
else: sons: seq[Node]
NonTerminal* = ref NonTerminalObj
Peg* = TNode ## type that represents a PEG
Peg* = Node ## type that represents a PEG
{.deprecated: [TPeg: Peg].}
{.deprecated: [TPeg: Peg, TNode: Node].}
proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
## constructs a PEG from a terminal string
@ -1014,12 +1014,12 @@ proc split*(s: string, sep: Peg): seq[string] {.
# ------------------- scanner -------------------------------------------------
type
TModifier = enum
Modifier = enum
modNone,
modVerbatim,
modIgnoreCase,
modIgnoreStyle
TTokKind = enum ## enumeration of all tokens
TokKind = enum ## enumeration of all tokens
tkInvalid, ## invalid token
tkEof, ## end of file reached
tkAny, ## .
@ -1046,9 +1046,9 @@ type
tkDollar, ## '$'
tkHat ## '^'
TToken {.final.} = object ## a token
kind: TTokKind ## the type of the token
modifier: TModifier
Token {.final.} = object ## a token
kind: TokKind ## the type of the token
modifier: Modifier
literal: string ## the parsed (string) literal
charset: set[char] ## if kind == tkCharSet
index: int ## if kind == tkBackref
@ -1060,9 +1060,10 @@ type
lineStart: int ## index of last line start in buffer
colOffset: int ## column to add
filename: string
{.deprecated: [TTokKind: TokKind, TToken: Token, TModifier: Modifier].}
const
tokKindToStr: array[TTokKind, string] = [
tokKindToStr: array[TokKind, string] = [
"invalid", "[EOF]", ".", "_", "identifier", "string literal",
"character set", "(", ")", "{", "}", "{@}",
"<-", "/", "*", "+", "&", "!", "?",
@ -1114,7 +1115,7 @@ proc handleHexChar(c: var PegLexer, xi: var int) =
inc(c.bufpos)
else: discard
proc getEscapedChar(c: var PegLexer, tok: var TToken) =
proc getEscapedChar(c: var PegLexer, tok: var Token) =
inc(c.bufpos)
case c.buf[c.bufpos]
of 'r', 'R', 'c', 'C':
@ -1185,7 +1186,7 @@ proc skip(c: var PegLexer) =
break # EndOfFile also leaves the loop
c.bufpos = pos
proc getString(c: var PegLexer, tok: var TToken) =
proc getString(c: var PegLexer, tok: var Token) =
tok.kind = tkStringLit
var pos = c.bufpos + 1
var buf = c.buf
@ -1207,7 +1208,7 @@ proc getString(c: var PegLexer, tok: var TToken) =
inc(pos)
c.bufpos = pos
proc getDollar(c: var PegLexer, tok: var TToken) =
proc getDollar(c: var PegLexer, tok: var Token) =
var pos = c.bufpos + 1
var buf = c.buf
if buf[pos] in {'0'..'9'}:
@ -1220,7 +1221,7 @@ proc getDollar(c: var PegLexer, tok: var TToken) =
tok.kind = tkDollar
c.bufpos = pos
proc getCharSet(c: var PegLexer, tok: var TToken) =
proc getCharSet(c: var PegLexer, tok: var Token) =
tok.kind = tkCharSet
tok.charset = {}
var pos = c.bufpos + 1
@ -1271,7 +1272,7 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
c.bufpos = pos
if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
proc getSymbol(c: var PegLexer, tok: var TToken) =
proc getSymbol(c: var PegLexer, tok: var Token) =
var pos = c.bufpos
var buf = c.buf
while true:
@ -1281,7 +1282,7 @@ proc getSymbol(c: var PegLexer, tok: var TToken) =
c.bufpos = pos
tok.kind = tkIdentifier
proc getBuiltin(c: var PegLexer, tok: var TToken) =
proc getBuiltin(c: var PegLexer, tok: var Token) =
if c.buf[c.bufpos+1] in strutils.Letters:
inc(c.bufpos)
getSymbol(c, tok)
@ -1290,7 +1291,7 @@ proc getBuiltin(c: var PegLexer, tok: var TToken) =
tok.kind = tkEscaped
getEscapedChar(c, tok) # may set tok.kind to tkInvalid
proc getTok(c: var PegLexer, tok: var TToken) =
proc getTok(c: var PegLexer, tok: var Token) =
tok.kind = tkInvalid
tok.modifier = modNone
setLen(tok.literal, 0)
@ -1408,9 +1409,9 @@ type
EInvalidPeg* = object of ValueError ## raised if an invalid
## PEG has been detected
PegParser = object of PegLexer ## the PEG parser object
tok: TToken
tok: Token
nonterms: seq[NonTerminal]
modifier: TModifier
modifier: Modifier
captures: int
identIsVerbatim: bool
skip: Peg
@ -1425,7 +1426,7 @@ proc getTok(p: var PegParser) =
getTok(p, p.tok)
if p.tok.kind == tkInvalid: pegError(p, "invalid token")
proc eat(p: var PegParser, kind: TTokKind) =
proc eat(p: var PegParser, kind: TokKind) =
if p.tok.kind == kind: getTok(p)
else: pegError(p, tokKindToStr[kind] & " expected")
@ -1439,13 +1440,13 @@ proc getNonTerminal(p: var PegParser, name: string): NonTerminal =
result = newNonTerminal(name, getLine(p), getColumn(p))
add(p.nonterms, result)
proc modifiedTerm(s: string, m: TModifier): Peg =
proc modifiedTerm(s: string, m: Modifier): Peg =
case m
of modNone, modVerbatim: result = term(s)
of modIgnoreCase: result = termIgnoreCase(s)
of modIgnoreStyle: result = termIgnoreStyle(s)
proc modifiedBackref(s: int, m: TModifier): Peg =
proc modifiedBackref(s: int, m: Modifier): Peg =
case m
of modNone, modVerbatim: result = backref(s)
of modIgnoreCase: result = backrefIgnoreCase(s)

View file

@ -206,13 +206,13 @@ proc abs*[T](x: Rational[T]): Rational[T] =
result.num = abs x.num
result.den = abs x.den
proc hash*[T](x: Rational[T]): THash =
proc hash*[T](x: Rational[T]): Hash =
## Computes hash for rational `x`
# reduce first so that hash(x) == hash(y) for x == y
var copy = x
reduce(copy)
var h: THash = 0
var h: Hash = 0
h = h !& hash(copy.num)
h = h !& hash(copy.den)
result = !$h

View file

@ -106,13 +106,13 @@ proc `$`*(p: Port): string {.borrow.}
## returns the port number as a string
proc toInt*(domain: Domain): cint
## Converts the TDomain enum to a platform-dependent ``cint``.
## Converts the Domain enum to a platform-dependent ``cint``.
proc toInt*(typ: SockType): cint
## Converts the TType enum to a platform-dependent ``cint``.
## Converts the SockType enum to a platform-dependent ``cint``.
proc toInt*(p: Protocol): cint
## Converts the TProtocol enum to a platform-dependent ``cint``.
## Converts the Protocol enum to a platform-dependent ``cint``.
when not useWinVersion:
proc toInt(domain: Domain): cint =

View file

@ -10,8 +10,8 @@
## This module implements a redis client. It allows you to connect to a
## redis-server instance, send commands and receive replies.
##
## **Beware**: Most (if not all) functions that return a ``TRedisString`` may
## return ``redisNil``, and functions which return a ``TRedisList``
## **Beware**: Most (if not all) functions that return a ``RedisString`` may
## return ``redisNil``, and functions which return a ``RedisList``
## may return ``nil``.
import sockets, os, strutils, parseutils
@ -843,27 +843,27 @@ proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
# TODO: pub/sub -- I don't think this will work synchronously.
discard """
proc psubscribe*(r: TRedis, pattern: openarray[string]): ???? =
proc psubscribe*(r: Redis, pattern: openarray[string]): ???? =
## Listen for messages published to channels matching the given patterns
r.socket.send("PSUBSCRIBE $#\c\L" % pattern)
return ???
proc publish*(r: TRedis, channel: string, message: string): TRedisInteger =
proc publish*(r: Redis, channel: string, message: string): RedisInteger =
## Post a message to a channel
r.socket.send("PUBLISH $# $#\c\L" % [channel, message])
return r.readInteger()
proc punsubscribe*(r: TRedis, [pattern: openarray[string], : string): ???? =
proc punsubscribe*(r: Redis, [pattern: openarray[string], : string): ???? =
## Stop listening for messages posted to channels matching the given patterns
r.socket.send("PUNSUBSCRIBE $# $#\c\L" % [[pattern.join(), ])
return ???
proc subscribe*(r: TRedis, channel: openarray[string]): ???? =
proc subscribe*(r: Redis, channel: openarray[string]): ???? =
## Listen for messages published to the given channels
r.socket.send("SUBSCRIBE $#\c\L" % channel.join)
return ???
proc unsubscribe*(r: TRedis, [channel: openarray[string], : string): ???? =
proc unsubscribe*(r: Redis, [channel: openarray[string], : string): ???? =
## Stop listening for messages posted to the given channels
r.socket.send("UNSUBSCRIBE $# $#\c\L" % [[channel.join(), ])
return ???
@ -991,7 +991,7 @@ proc lastsave*(r: Redis): RedisInteger =
return r.readInteger()
discard """
proc monitor*(r: TRedis) =
proc monitor*(r: Redis) =
## Listen for all requests received by the server in real time
r.socket.send("MONITOR\c\L")
raiseNoOK(r.readStatus(), r.pipeline.enabled)

View file

@ -18,7 +18,7 @@ elif defined(windows):
else:
import posix
proc hash*(x: SocketHandle): THash {.borrow.}
proc hash*(x: SocketHandle): Hash {.borrow.}
proc `$`*(x: SocketHandle): string {.borrow.}
type
@ -41,7 +41,7 @@ when defined(nimdoc):
proc register*(s: Selector, fd: SocketHandle, events: set[Event],
data: RootRef): SelectorKey {.discardable.} =
## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
## Registers file descriptor ``fd`` to selector ``s`` with a set of Event
## ``events``.
proc update*(s: Selector, fd: SocketHandle,

View file

@ -23,7 +23,7 @@ type
sexpListStart, ## start of a list: the ``(`` token
sexpListEnd, ## end of a list: the ``)`` token
TTokKind = enum # must be synchronized with SexpEventKind!
TokKind = enum # must be synchronized with SexpEventKind!
tkError,
tkEof,
tkString,
@ -45,9 +45,10 @@ type
SexpParser* = object of BaseLexer ## the parser object.
a: string
tok: TTokKind
tok: TokKind
kind: SexpEventKind
err: SexpError
{.deprecated: [TTokKind: TokKind].}
const
errorMessages: array [SexpError, string] = [
@ -57,7 +58,7 @@ const
"'\"' or \"'\" expected",
"EOF expected",
]
tokToStr: array [TTokKind, string] = [
tokToStr: array [TokKind, string] = [
"invalid token",
"EOF",
"string literal",
@ -119,7 +120,7 @@ proc handleHexChar(c: char, x: var int): bool =
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
else: result = false # error
proc parseString(my: var SexpParser): TTokKind =
proc parseString(my: var SexpParser): TokKind =
result = tkString
var pos = my.bufpos + 1
var buf = my.buf
@ -217,7 +218,7 @@ proc parseSymbol(my: var SexpParser) =
inc(pos)
my.bufpos = pos
proc getTok(my: var SexpParser): TTokKind =
proc getTok(my: var SexpParser): TokKind =
setLen(my.a, 0)
case my.buf[my.bufpos]
of '-', '0'..'9': # numbers that start with a . are not parsed
@ -466,7 +467,7 @@ proc `==`* (a,b: SexpNode): bool =
of SCons:
a.car == b.car and a.cdr == b.cdr
proc hash* (n:SexpNode): THash =
proc hash* (n:SexpNode): Hash =
## Compute the hash for a SEXP node
case n.kind
of SList:
@ -620,7 +621,7 @@ iterator mitems*(node: var SexpNode): var SexpNode =
for i in mitems(node.elems):
yield i
proc eat(p: var SexpParser, tok: TTokKind) =
proc eat(p: var SexpParser, tok: TokKind) =
if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok])

View file

@ -75,7 +75,7 @@ const
BufferSize*: int = 4000 ## size of a buffered socket's buffer
type
TSocketImpl = object ## socket type
SocketImpl = object ## socket type
fd: SocketHandle
case isBuffered: bool # determines whether this socket is buffered.
of true:
@ -94,7 +94,7 @@ type
of false: nil
nonblocking: bool
Socket* = ref TSocketImpl
Socket* = ref SocketImpl
Port* = distinct uint16 ## port type
@ -146,8 +146,9 @@ type
{.deprecated: [TSocket: Socket, TType: SockType, TPort: Port, TDomain: Domain,
TProtocol: Protocol, TServent: Servent, THostent: Hostent,
TSOBool: SOBool, TRecvLineResult: RecvLineResult,
TReadLineResult: ReadLineResult, ETimeout: TimeoutError].}
TSOBool: SOBool, TRecvLineResult: RecvLineResult,
TReadLineResult: ReadLineResult, ETimeout: TimeoutError,
TSocketImpl: SocketImpl].}
when defined(booting):
let invalidSocket*: Socket = nil ## invalid socket

View file

@ -327,7 +327,7 @@ proc newStringStream*(s: string = ""): StringStream =
when not defined(js):
type
FileStream* = ref FileStreamObj ## a stream that encapsulates a `TFile`
FileStream* = ref FileStreamObj ## a stream that encapsulates a `File`
FileStreamObj* = object of Stream
f: File
{.deprecated: [PFileStream: FileStream, TFileStream: FileStreamObj].}

View file

@ -74,7 +74,7 @@ const
growthFactor = 2
startSize = 64
proc myhash(t: StringTableRef, key: string): THash =
proc myhash(t: StringTableRef, key: string): Hash =
case t.mode
of modeCaseSensitive: result = hashes.hash(key)
of modeCaseInsensitive: result = hashes.hashIgnoreCase(key)
@ -90,11 +90,11 @@ proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc rawGet(t: StringTableRef, key: string): int =
var h: THash = myhash(t, key) and high(t.data) # start with real hash value
var h: Hash = myhash(t, key) and high(t.data) # start with real hash value
while not isNil(t.data[h].key):
if myCmp(t, t.data[h].key, key):
return h
@ -122,7 +122,7 @@ proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} =
result = rawGet(t, key) >= 0
proc rawInsert(t: StringTableRef, data: var KeyValuePairSeq, key, val: string) =
var h: THash = myhash(t, key) and high(data)
var h: Hash = myhash(t, key) and high(data)
while not isNil(data[h].key):
h = nextTry(h, high(data))
data[h].key = key

View file

@ -23,7 +23,8 @@ import parseutils
include "system/inclrtl"
type
TCharSet* {.deprecated.} = set[char] # for compatibility with Nim
CharSet* {.deprecated.} = set[char] # for compatibility with Nim
{.deprecated: [TCharSet: CharSet].}
const
Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'}

View file

@ -37,13 +37,14 @@ proc raiseInvalidFormat(msg: string) {.noinline.} =
raise newException(SubexError, "invalid format string: " & msg)
type
TFormatParser = object {.pure, final.}
FormatParser = object {.pure, final.}
when defined(js):
f: string # we rely on the '\0' terminator
# which JS's native string doesn't have
else:
f: cstring
num, i, lineLen: int
{.deprecated: [TFormatParser: FormatParser].}
template call(x: stmt) {.immediate.} =
p.i = i
@ -57,7 +58,7 @@ template callNoLineLenTracking(x: stmt) {.immediate.} =
i = p.i
p.lineLen = oldLineLen
proc getFormatArg(p: var TFormatParser, a: openArray[string]): int =
proc getFormatArg(p: var FormatParser, a: openArray[string]): int =
const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}
var i = p.i
var f = p.f
@ -90,22 +91,22 @@ proc getFormatArg(p: var TFormatParser, a: openArray[string]): int =
if result >=% a.len: raiseInvalidFormat("index out of bounds: " & $result)
p.i = i
proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) {.
proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) {.
noSideEffect.}
proc emitChar(p: var TFormatParser, x: var string, ch: char) {.inline.} =
proc emitChar(p: var FormatParser, x: var string, ch: char) {.inline.} =
x.add(ch)
if ch == '\L': p.lineLen = 0
else: inc p.lineLen
proc emitStrLinear(p: var TFormatParser, x: var string, y: string) {.inline.} =
proc emitStrLinear(p: var FormatParser, x: var string, y: string) {.inline.} =
for ch in items(y): emitChar(p, x, ch)
proc emitStr(p: var TFormatParser, x: var string, y: string) {.inline.} =
proc emitStr(p: var FormatParser, x: var string, y: string) {.inline.} =
x.add(y)
inc p.lineLen, y.len
proc scanQuote(p: var TFormatParser, x: var string, toAdd: bool) =
proc scanQuote(p: var FormatParser, x: var string, toAdd: bool) =
var i = p.i+1
var f = p.f
while true:
@ -120,7 +121,7 @@ proc scanQuote(p: var TFormatParser, x: var string, toAdd: bool) =
inc i
p.i = i
proc scanBranch(p: var TFormatParser, a: openArray[string],
proc scanBranch(p: var FormatParser, a: openArray[string],
x: var string, choice: int) =
var i = p.i
var f = p.f
@ -167,7 +168,7 @@ proc scanBranch(p: var TFormatParser, a: openArray[string],
i = last
p.i = i+1
proc scanSlice(p: var TFormatParser, a: openarray[string]): tuple[x, y: int] =
proc scanSlice(p: var FormatParser, a: openarray[string]): tuple[x, y: int] =
var slice = false
var i = p.i
var f = p.f
@ -193,7 +194,7 @@ proc scanSlice(p: var TFormatParser, a: openarray[string]): tuple[x, y: int] =
inc i
p.i = i
proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) =
proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) =
var i = p.i
var f = p.f
case f[i]
@ -312,7 +313,7 @@ proc subex*(s: string): Subex =
proc addf*(s: var string, formatstr: Subex, a: varargs[string, `$`]) {.
noSideEffect, rtl, extern: "nfrmtAddf".} =
## The same as ``add(s, formatstr % a)``, but more efficient.
var p: TFormatParser
var p: FormatParser
p.f = formatstr.string
var i = 0
while i < len(formatstr.string):
@ -386,10 +387,10 @@ when isMainModule:
longishA,
longish)"""
assert "type TMyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
assert "type MyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
"fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
strutils.unindent """
type TMyEnum* = enum
type MyEnum* = enum
fieldA, fieldB,
FiledClkad, fieldD,
fieldE, longishFieldName"""
@ -400,11 +401,11 @@ when isMainModule:
doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
assert subex("type\n TEnum = enum\n $', '40c'\n '{..}") % [
assert subex("type\n Enum = enum\n $', '40c'\n '{..}") % [
"fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
strutils.unindent """
type
TEnum = enum
Enum = enum
fieldNameA, fieldNameB, fieldNameC,
fieldNameD"""

View file

@ -20,7 +20,7 @@ when defined(windows):
import windows, os
var
conHandle: THandle
conHandle: Handle
# = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0)
block:
@ -30,13 +30,13 @@ when defined(windows):
raiseOSError(osLastError())
proc getCursorPos(): tuple [x,y: int] =
var c: TCONSOLESCREENBUFFERINFO
var c: CONSOLESCREENBUFFERINFO
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0:
raiseOSError(osLastError())
return (int(c.dwCursorPosition.X), int(c.dwCursorPosition.Y))
proc getAttributes(): int16 =
var c: TCONSOLESCREENBUFFERINFO
var c: CONSOLESCREENBUFFERINFO
# workaround Windows bugs: try several times
if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
return c.wAttributes
@ -51,11 +51,11 @@ else:
proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
var mode: Termios
discard fd.tcgetattr(addr mode)
mode.c_iflag = mode.c_iflag and not Tcflag(BRKINT or ICRNL or INPCK or
mode.c_iflag = mode.c_iflag and not Cflag(BRKINT or ICRNL or INPCK or
ISTRIP or IXON)
mode.c_oflag = mode.c_oflag and not Tcflag(OPOST)
mode.c_cflag = (mode.c_cflag and not Tcflag(CSIZE or PARENB)) or CS8
mode.c_lflag = mode.c_lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
mode.c_oflag = mode.c_oflag and not Cflag(OPOST)
mode.c_cflag = (mode.c_cflag and not Cflag(CSIZE or PARENB)) or CS8
mode.c_lflag = mode.c_lflag and not Cflag(ECHO or ICANON or IEXTEN or ISIG)
mode.c_cc[VMIN] = 1.cuchar
mode.c_cc[VTIME] = 0.cuchar
discard fd.tcsetattr(time, addr mode)
@ -64,7 +64,7 @@ proc setCursorPos*(x, y: int) =
## sets the terminal's cursor to the (x,y) position. (0,0) is the
## upper left of the screen.
when defined(windows):
var c: TCOORD
var c: COORD
c.X = int16(x)
c.Y = int16(y)
if SetConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError())
@ -75,7 +75,7 @@ proc setCursorXPos*(x: int) =
## sets the terminal's cursor to the x position. The y position is
## not changed.
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var scrbuf: CONSOLESCREENBUFFERINFO
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
raiseOSError(osLastError())
@ -91,7 +91,7 @@ when defined(windows):
## sets the terminal's cursor to the y position. The x position is
## not changed. **Warning**: This is not supported on UNIX!
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var scrbuf: CONSOLESCREENBUFFERINFO
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
raiseOSError(osLastError())
@ -172,7 +172,7 @@ else:
proc eraseLine* =
## Erases the entire current line.
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var scrbuf: CONSOLESCREENBUFFERINFO
var numwrote: DWORD
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
@ -196,9 +196,9 @@ proc eraseLine* =
proc eraseScreen* =
## Erases the screen with the background colour and moves the cursor to home.
when defined(windows):
var scrbuf: TCONSOLESCREENBUFFERINFO
var scrbuf: CONSOLESCREENBUFFERINFO
var numwrote: DWORD
var origin: TCOORD # is inititalized to 0, 0
var origin: COORD # is inititalized to 0, 0
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:

View file

@ -470,7 +470,7 @@ when not defined(JS):
posix_gettimeofday(a)
result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
elif defined(windows):
var f: winlean.TFILETIME
var f: winlean.FILETIME
getSystemTimeAsFileTime(f)
var i64 = rdFileTime(f) - epochDiff
var secs = i64 div rateDiff

View file

@ -249,7 +249,7 @@ when defined(nimNewShared):
guarded* {.magic: "Guarded".}
# comparison operators:
proc `==` *[TEnum: enum](x, y: TEnum): bool {.magic: "EqEnum", noSideEffect.}
proc `==` *[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.}
proc `==` *(x, y: pointer): bool {.magic: "EqRef", noSideEffect.}
proc `==` *(x, y: string): bool {.magic: "EqStr", noSideEffect.}
proc `==` *(x, y: cstring): bool {.magic: "EqCString", noSideEffect.}
@ -260,7 +260,7 @@ proc `==` *[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.}
proc `==` *[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.}
proc `==` *[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.}
proc `<=` *[TEnum: enum](x, y: TEnum): bool {.magic: "LeEnum", noSideEffect.}
proc `<=` *[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.}
proc `<=` *(x, y: string): bool {.magic: "LeStr", noSideEffect.}
proc `<=` *(x, y: char): bool {.magic: "LeCh", noSideEffect.}
proc `<=` *[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.}
@ -268,7 +268,7 @@ proc `<=` *(x, y: bool): bool {.magic: "LeB", noSideEffect.}
proc `<=` *[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.}
proc `<=` *(x, y: pointer): bool {.magic: "LePtr", noSideEffect.}
proc `<` *[TEnum: enum](x, y: TEnum): bool {.magic: "LtEnum", noSideEffect.}
proc `<` *[Enum: enum](x, y: Enum): bool {.magic: "LtEnum", noSideEffect.}
proc `<` *(x, y: string): bool {.magic: "LtStr", noSideEffect.}
proc `<` *(x, y: char): bool {.magic: "LtCh", noSideEffect.}
proc `<` *[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.}
@ -332,7 +332,7 @@ type
RootObj* {.exportc: "TNimObject", inheritable.} =
object ## the root of Nim's object hierarchy. Objects should
## inherit from TObject or one of its descendants. However,
## inherit from RootObj or one of its descendants. However,
## objects that have no ancestor are allowed.
RootRef* = ref RootObj ## reference to RootObj
@ -1505,7 +1505,7 @@ proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
## as it is. This operator is useful for generic code, so
## that ``$expr`` also works if ``expr`` is already a string.
proc `$` *[TEnum: enum](x: TEnum): string {.magic: "EnumToStr", noSideEffect.}
proc `$` *[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.}
## The stringify operator for an enumeration argument. This works for
## any enumeration type thanks to compiler magic. If
## a ``$`` operator for a concrete enumeration is provided, this is
@ -1578,7 +1578,7 @@ else:
type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum
iterator countdown*[T](a, b: T, step = 1): T {.inline.} =
## Counts from ordinal value `a` down to `b` with the given
## Counts from ordinal value `a` down to `b` (inclusive) with the given
## step count. `T` may be any ordinal type, `step` may only
## be positive. **Note**: This fails to count to ``low(int)`` if T = int for
## efficiency reasons.
@ -1606,7 +1606,7 @@ template countupImpl(incr: stmt) {.immediate, dirty.} =
incr
iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} =
## Counts from ordinal value `a` up to `b` with the given
## Counts from ordinal value `a` up to `b` (inclusive) with the given
## step count. `S`, `T` may be any ordinal type, `step` may only
## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
## efficiency reasons.
@ -2213,6 +2213,7 @@ type
filename*: cstring ## filename of the proc that is currently executing
len*: int16 ## length of the inspectable slots
calldepth*: int16 ## used for max call depth checking
#{.deprecated: [TFrame: Frame].}
when defined(JS):
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
@ -2414,7 +2415,7 @@ when not defined(JS): #and not defined(NimrodVM):
proc open*(f: var File, filehandle: FileHandle,
mode: FileMode = fmRead): bool {.tags: [], benign.}
## Creates a ``TFile`` from a `filehandle` with given `mode`.
## Creates a ``File`` from a `filehandle` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
@ -2604,6 +2605,8 @@ when not defined(JS): #and not defined(NimrodVM):
context: C_JmpBuf
hasRaiseAction: bool
raiseAction: proc (e: ref Exception): bool {.closure.}
SafePoint = TSafePoint
# {.deprecated: [TSafePoint: SafePoint].}
when declared(initAllocator):
initAllocator()
@ -3054,9 +3057,10 @@ proc raiseAssert*(msg: string) {.noinline.} =
proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
# trick the compiler to not list ``AssertionError`` when called
# by ``assert``.
type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect,
tags: [].}
THide(raiseAssert)(msg)
{.deprecated: [THide: Hide].}
Hide(raiseAssert)(msg)
template assert*(cond: bool, msg = "") =
## Raises ``AssertionError`` with `msg` if `cond` is false. Note

View file

@ -98,46 +98,49 @@ const
SmallChunkSize = PageSize
type
PTrunk = ptr TTrunk
TTrunk {.final.} = object
PTrunk = ptr Trunk
Trunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0
bits: array[0..IntsPerTrunk-1, int] # a bit vector
TTrunkBuckets = array[0..255, PTrunk]
TIntSet {.final.} = object
data: TTrunkBuckets
TrunkBuckets = array[0..255, PTrunk]
IntSet {.final.} = object
data: TrunkBuckets
{.deprecated: [TIntSet: IntSet, TTrunk: Trunk, TTrunkBuckets: TrunkBuckets].}
type
TAlignType = BiggestFloat
TFreeCell {.final, pure.} = object
next: ptr TFreeCell # next free cell in chunk (overlaid with refcount)
AlignType = BiggestFloat
FreeCell {.final, pure.} = object
next: ptr FreeCell # next free cell in chunk (overlaid with refcount)
zeroField: int # 0 means cell is not used (overlaid with typ field)
# 1 means cell is manually managed pointer
# otherwise a PNimType is stored in there
PChunk = ptr TBaseChunk
PBigChunk = ptr TBigChunk
PSmallChunk = ptr TSmallChunk
TBaseChunk {.pure, inheritable.} = object
PChunk = ptr BaseChunk
PBigChunk = ptr BigChunk
PSmallChunk = ptr SmallChunk
BaseChunk {.pure, inheritable.} = object
prevSize: int # size of previous chunk; for coalescing
size: int # if < PageSize it is a small chunk
used: bool # later will be optimized into prevSize...
TSmallChunk = object of TBaseChunk
SmallChunk = object of BaseChunk
next, prev: PSmallChunk # chunks of the same size
freeList: ptr TFreeCell
freeList: ptr FreeCell
free: int # how many bytes remain
acc: int # accumulator for small object allocation
data: TAlignType # start of usable memory
data: AlignType # start of usable memory
TBigChunk = object of TBaseChunk # not necessarily > PageSize!
BigChunk = object of BaseChunk # not necessarily > PageSize!
next, prev: PBigChunk # chunks of the same (or bigger) size
align: int
data: TAlignType # start of usable memory
data: AlignType # start of usable memory
{.deprecated: [TAlignType: AlignType, TFreeCell: FreeCell, TBaseChunk: BaseChunk,
TBigChunk: BigChunk, TSmallChunk: SmallChunk].}
template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
template smallChunkOverhead(): expr = sizeof(SmallChunk)-sizeof(AlignType)
template bigChunkOverhead(): expr = sizeof(BigChunk)-sizeof(AlignType)
proc roundup(x, v: int): int {.inline.} =
result = (x + (v-1)) and not (v-1)
@ -156,31 +159,32 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
# to the OS), a fixed size array can be used.
type
PLLChunk = ptr TLLChunk
TLLChunk {.pure.} = object ## *low-level* chunk
PLLChunk = ptr LLChunk
LLChunk {.pure.} = object ## *low-level* chunk
size: int # remaining size
acc: int # accumulator
next: PLLChunk # next low-level chunk; only needed for dealloc
PAvlNode = ptr TAvlNode
TAvlNode {.pure, final.} = object
PAvlNode = ptr AvlNode
AvlNode {.pure, final.} = object
link: array[0..1, PAvlNode] # Left (0) and right (1) links
key, upperBound: int
level: int
TMemRegion {.final, pure.} = object
MemRegion {.final, pure.} = object
minLargeObj, maxLargeObj: int
freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
llmem: PLLChunk
currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
lastSize: int # needed for the case that OS gives us pages linearly
freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
chunkStarts: TIntSet
chunkStarts: IntSet
root, deleted, last, freeAvlNodes: PAvlNode
{.deprecated: [TLLChunk: LLChunk, TAvlNode: AvlNode, TMemRegion: MemRegion].}
# shared:
var
bottomData: TAvlNode
bottomData: AvlNode
bottom: PAvlNode
{.push stack_trace: off.}
@ -191,44 +195,44 @@ proc initAllocator() =
bottom.link[1] = bottom
{.pop.}
proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
proc incCurrMem(a: var MemRegion, bytes: int) {.inline.} =
inc(a.currMem, bytes)
proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
proc decCurrMem(a: var MemRegion, bytes: int) {.inline.} =
a.maxMem = max(a.maxMem, a.currMem)
dec(a.currMem, bytes)
proc getMaxMem(a: var TMemRegion): int =
proc getMaxMem(a: var MemRegion): int =
# Since we update maxPagesCount only when freeing pages,
# maxPagesCount may not be up to date. Thus we use the
# maximum of these both values here:
result = max(a.currMem, a.maxMem)
proc llAlloc(a: var TMemRegion, size: int): pointer =
proc llAlloc(a: var MemRegion, size: int): pointer =
# *low-level* alloc for the memory managers data structures. Deallocation
# is done at he end of the allocator's life time.
if a.llmem == nil or size > a.llmem.size:
# the requested size is ``roundup(size+sizeof(TLLChunk), PageSize)``, but
# the requested size is ``roundup(size+sizeof(LLChunk), PageSize)``, but
# since we know ``size`` is a (small) constant, we know the requested size
# is one page:
sysAssert roundup(size+sizeof(TLLChunk), PageSize) == PageSize, "roundup 6"
sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6"
var old = a.llmem # can be nil and is correct with nil
a.llmem = cast[PLLChunk](osAllocPages(PageSize))
incCurrMem(a, PageSize)
a.llmem.size = PageSize - sizeof(TLLChunk)
a.llmem.acc = sizeof(TLLChunk)
a.llmem.size = PageSize - sizeof(LLChunk)
a.llmem.acc = sizeof(LLChunk)
a.llmem.next = old
result = cast[pointer](cast[ByteAddress](a.llmem) + a.llmem.acc)
dec(a.llmem.size, size)
inc(a.llmem.acc, size)
zeroMem(result, size)
proc allocAvlNode(a: var TMemRegion, key, upperBound: int): PAvlNode =
proc allocAvlNode(a: var MemRegion, key, upperBound: int): PAvlNode =
if a.freeAvlNodes != nil:
result = a.freeAvlNodes
a.freeAvlNodes = a.freeAvlNodes.link[0]
else:
result = cast[PAvlNode](llAlloc(a, sizeof(TAvlNode)))
result = cast[PAvlNode](llAlloc(a, sizeof(AvlNode)))
result.key = key
result.upperBound = upperBound
result.link[0] = bottom
@ -238,13 +242,13 @@ proc allocAvlNode(a: var TMemRegion, key, upperBound: int): PAvlNode =
sysAssert(bottom.link[0] == bottom, "bottom link[0]")
sysAssert(bottom.link[1] == bottom, "bottom link[1]")
proc deallocAvlNode(a: var TMemRegion, n: PAvlNode) {.inline.} =
proc deallocAvlNode(a: var MemRegion, n: PAvlNode) {.inline.} =
n.link[0] = a.freeAvlNodes
a.freeAvlNodes = n
include "system/avltree"
proc llDeallocAll(a: var TMemRegion) =
proc llDeallocAll(a: var MemRegion) =
var it = a.llmem
while it != nil:
# we know each block in the list has the size of 1 page:
@ -252,14 +256,14 @@ proc llDeallocAll(a: var TMemRegion) =
osDeallocPages(it, PageSize)
it = next
proc intSetGet(t: TIntSet, key: int): PTrunk =
proc intSetGet(t: IntSet, key: int): PTrunk =
var it = t.data[key and high(t.data)]
while it != nil:
if it.key == key: return it
it = it.next
result = nil
proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
proc intSetPut(a: var MemRegion, t: var IntSet, key: int): PTrunk =
result = intSetGet(t, key)
if result == nil:
result = cast[PTrunk](llAlloc(a, sizeof(result[])))
@ -267,7 +271,7 @@ proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
t.data[key and high(t.data)] = result
result.key = key
proc contains(s: TIntSet, key: int): bool =
proc contains(s: IntSet, key: int): bool =
var t = intSetGet(s, key shr TrunkShift)
if t != nil:
var u = key and TrunkMask
@ -275,19 +279,19 @@ proc contains(s: TIntSet, key: int): bool =
else:
result = false
proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
proc incl(a: var MemRegion, s: var IntSet, key: int) =
var t = intSetPut(a, s, key shr TrunkShift)
var u = key and TrunkMask
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 IntSet, key: int) =
var t = intSetGet(s, key shr TrunkShift)
if t != nil:
var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] and not
(1 shl (u and IntMask))
iterator elements(t: TIntSet): int {.inline.} =
iterator elements(t: IntSet): int {.inline.} =
# while traversing it is forbidden to change the set!
for h in 0..high(t.data):
var r = t.data[h]
@ -311,7 +315,7 @@ proc isSmallChunk(c: PChunk): bool {.inline.} =
proc chunkUnused(c: PChunk): bool {.inline.} =
result = not c.used
iterator allObjects(m: TMemRegion): pointer {.inline.} =
iterator allObjects(m: MemRegion): pointer {.inline.} =
for s in elements(m.chunkStarts):
# we need to check here again as it could have been modified:
if s in m.chunkStarts:
@ -331,7 +335,7 @@ iterator allObjects(m: TMemRegion): pointer {.inline.} =
yield addr(c.data)
proc isCell(p: pointer): bool {.inline.} =
result = cast[ptr TFreeCell](p).zeroField >% 1
result = cast[ptr FreeCell](p).zeroField >% 1
# ------------- chunk management ----------------------------------------------
proc pageIndex(c: PChunk): int {.inline.} =
@ -344,7 +348,7 @@ proc pageAddr(p: pointer): PChunk {.inline.} =
result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
#sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
incCurrMem(a, size)
inc(a.freeMem, size)
result = cast[PBigChunk](osAllocPages(size))
@ -373,7 +377,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
result.prevSize = 0 # unknown
a.lastSize = size # for next request
proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
proc freeOsChunks(a: var MemRegion, p: pointer, size: int) =
# update next.prevSize:
var c = cast[PChunk](p)
var nxt = cast[ByteAddress](p) +% c.size
@ -387,7 +391,7 @@ proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
dec(a.freeMem, size)
#c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
proc isAccessible(a: MemRegion, p: pointer): bool {.inline.} =
result = contains(a.chunkStarts, pageIndex(p))
proc contains[T](list, x: T): bool =
@ -396,7 +400,7 @@ proc contains[T](list, x: T): bool =
if it == x: return true
it = it.next
proc writeFreeList(a: TMemRegion) =
proc writeFreeList(a: MemRegion) =
var it = a.freeChunksList
c_fprintf(c_stdout, "freeChunksList: %p\n", it)
while it != nil:
@ -427,14 +431,14 @@ proc listRemove[T](head: var T, c: T) {.inline.} =
c.next = nil
c.prev = nil
proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
proc updatePrevSize(a: var MemRegion, c: PBigChunk,
prevSize: int) {.inline.} =
var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize")
if isAccessible(a, ri):
ri.prevSize = prevSize
proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
proc freeBigChunk(a: var MemRegion, c: PBigChunk) =
var c = c
sysAssert(c.size >= PageSize, "freeBigChunk")
inc(a.freeMem, c.size)
@ -467,7 +471,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
else:
freeOsChunks(a, c, c.size)
proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
proc splitChunk(a: var MemRegion, c: PBigChunk, size: int) =
var rest = cast[PBigChunk](cast[ByteAddress](c) +% size)
sysAssert(rest notin a.freeChunksList, "splitChunk")
rest.size = c.size - size
@ -480,7 +484,7 @@ proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
incl(a, a.chunkStarts, pageIndex(rest))
listAdd(a.freeChunksList, rest)
proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
# use first fit for now:
sysAssert((size and PageMask) == 0, "getBigChunk 1")
sysAssert(size > 0, "getBigChunk 2")
@ -507,16 +511,16 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
incl(a, a.chunkStarts, pageIndex(result))
dec(a.freeMem, size)
proc getSmallChunk(a: var TMemRegion): PSmallChunk =
proc getSmallChunk(a: var MemRegion): PSmallChunk =
var res = getBigChunk(a, PageSize)
sysAssert res.prev == nil, "getSmallChunk 1"
sysAssert res.next == nil, "getSmallChunk 2"
result = cast[PSmallChunk](res)
# -----------------------------------------------------------------------------
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool {.benign.}
proc isAllocatedPtr(a: MemRegion, p: pointer): bool {.benign.}
proc allocInv(a: TMemRegion): bool =
proc allocInv(a: MemRegion): bool =
## checks some (not all yet) invariants of the allocator's data structures.
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
var c = a.freeSmallChunks[s]
@ -537,10 +541,10 @@ proc allocInv(a: TMemRegion): bool =
c = c.next
result = true
proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: begin")
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
sysAssert(requestedSize >= sizeof(TFreeCell), "rawAlloc: requested size too small")
sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small")
var size = roundup(requestedSize, MemAlign)
sysAssert(size >= requestedSize, "insufficient allocated size!")
#c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
@ -601,11 +605,11 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: end")
when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result)
proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer =
proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
result = rawAlloc(a, requestedSize)
zeroMem(result, requestedSize)
proc rawDealloc(a: var TMemRegion, p: pointer) =
proc rawDealloc(a: var MemRegion, p: pointer) =
#sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer")
sysAssert(allocInv(a), "rawDealloc: begin")
var c = pageAddr(p)
@ -615,7 +619,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
var s = c.size
sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
s == 0, "rawDealloc 3")
var f = cast[ptr TFreeCell](p)
var f = cast[ptr FreeCell](p)
#echo("setting to nil: ", $cast[TAddress](addr(f.zeroField)))
sysAssert(f.zeroField != 0, "rawDealloc 1")
f.zeroField = 0
@ -623,8 +627,8 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
c.freeList = f
when overwriteFree:
# set to 0xff to check for usage after free bugs:
c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32,
s -% sizeof(TFreeCell))
c_memset(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32,
s -% sizeof(FreeCell))
# check if it is not in the freeSmallChunks[s] list:
if c.free < s:
# add it to the freeSmallChunks[s] array:
@ -649,7 +653,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
sysAssert(allocInv(a), "rawDealloc: end")
when logAlloc: cprintf("rawDealloc: %p\n", p)
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
proc isAllocatedPtr(a: MemRegion, p: pointer): bool =
if isAccessible(a, p):
var c = pageAddr(p)
if not chunkUnused(c):
@ -658,16 +662,16 @@ proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead()
result = (c.acc >% offset) and (offset %% c.size == 0) and
(cast[ptr TFreeCell](p).zeroField >% 1)
(cast[ptr FreeCell](p).zeroField >% 1)
else:
var c = cast[PBigChunk](c)
result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1
result = p == addr(c.data) and cast[ptr FreeCell](p).zeroField >% 1
proc prepareForInteriorPointerChecking(a: var TMemRegion) {.inline.} =
proc prepareForInteriorPointerChecking(a: var MemRegion) {.inline.} =
a.minLargeObj = lowGauge(a.root)
a.maxLargeObj = highGauge(a.root)
proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
proc interiorAllocatedPtr(a: MemRegion, p: pointer): pointer =
if isAccessible(a, p):
var c = pageAddr(p)
if not chunkUnused(c):
@ -678,7 +682,7 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
if c.acc >% offset:
sysAssert(cast[ByteAddress](addr(c.data)) +% offset ==
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 FreeCell](cast[ByteAddress](addr(c.data)) +%
offset -% (offset %% c.size))
if d.zeroField >% 1:
result = d
@ -686,7 +690,7 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
else:
var c = cast[PBigChunk](c)
var d = addr(c.data)
if p >= d and cast[ptr TFreeCell](d).zeroField >% 1:
if p >= d and cast[ptr FreeCell](d).zeroField >% 1:
result = d
sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
else:
@ -699,38 +703,38 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
var k = cast[pointer](avlNode.key)
var c = cast[PBigChunk](pageAddr(k))
sysAssert(addr(c.data) == k, " k is not the same as addr(c.data)!")
if cast[ptr TFreeCell](k).zeroField >% 1:
if cast[ptr FreeCell](k).zeroField >% 1:
result = k
sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
proc ptrSize(p: pointer): int =
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell))
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell))
var c = pageAddr(p)
sysAssert(not chunkUnused(c), "ptrSize")
result = c.size -% sizeof(TFreeCell)
result = c.size -% sizeof(FreeCell)
if not isSmallChunk(c):
dec result, bigChunkOverhead()
proc alloc(allocator: var TMemRegion, size: Natural): pointer =
result = rawAlloc(allocator, size+sizeof(TFreeCell))
cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
proc alloc(allocator: var MemRegion, size: Natural): pointer =
result = rawAlloc(allocator, size+sizeof(FreeCell))
cast[ptr FreeCell](result).zeroField = 1 # mark it as used
sysAssert(not isAllocatedPtr(allocator, result), "alloc")
result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell))
result = cast[pointer](cast[ByteAddress](result) +% sizeof(FreeCell))
proc alloc0(allocator: var TMemRegion, size: Natural): pointer =
proc alloc0(allocator: var MemRegion, size: Natural): pointer =
result = alloc(allocator, size)
zeroMem(result, size)
proc dealloc(allocator: var TMemRegion, p: pointer) =
proc dealloc(allocator: var MemRegion, p: pointer) =
sysAssert(p != nil, "dealloc 0")
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell))
var x = cast[pointer](cast[ByteAddress](p) -% sizeof(FreeCell))
sysAssert(x != nil, "dealloc 1")
sysAssert(isAccessible(allocator, x), "is not accessible")
sysAssert(cast[ptr TFreeCell](x).zeroField == 1, "dealloc 2")
sysAssert(cast[ptr FreeCell](x).zeroField == 1, "dealloc 2")
rawDealloc(allocator, x)
sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
proc realloc(allocator: var MemRegion, p: pointer, newsize: Natural): pointer =
if newsize > 0:
result = alloc0(allocator, newsize)
if p != nil:
@ -739,7 +743,7 @@ proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
elif p != nil:
dealloc(allocator, p)
proc deallocOsPages(a: var TMemRegion) =
proc deallocOsPages(a: var MemRegion) =
# we free every 'ordinarily' allocated page by iterating over the page bits:
for p in elements(a.chunkStarts):
var page = cast[PChunk](p shl PageShift)
@ -756,9 +760,9 @@ proc deallocOsPages(a: var TMemRegion) =
# And then we free the pages that are in use for the page bits:
llDeallocAll(a)
proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem
proc getOccupiedMem(a: TMemRegion): int {.inline.} =
proc getFreeMem(a: MemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: MemRegion): int {.inline.} = result = a.currMem
proc getOccupiedMem(a: MemRegion): int {.inline.} =
result = a.currMem - a.freeMem
# ---------------------- thread memory region -------------------------------
@ -769,7 +773,7 @@ template instantiateForRegion(allocator: expr) =
result = interiorAllocatedPtr(allocator, p)
proc isAllocatedPtr*(p: pointer): bool =
let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(TCell)))
let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(Cell)))
result = isAllocatedPtr(allocator, p)
proc deallocOsPages = deallocOsPages(allocator)
@ -803,8 +807,8 @@ template instantiateForRegion(allocator: expr) =
# -------------------- shared heap region ----------------------------------
when hasThreadSupport:
var sharedHeap: TMemRegion
var heapLock: TSysLock
var sharedHeap: MemRegion
var heapLock: SysLock
initSysLock(heapLock)
proc allocShared(size: Natural): pointer =

View file

@ -37,39 +37,40 @@ when someGcc and hasThreadSupport:
## and release stores in all threads.
type
TAtomType* = SomeNumber|pointer|ptr|char|bool
AtomType* = SomeNumber|pointer|ptr|char|bool
## Type Class representing valid types for use with atomic procs
{.deprecated: [TAtomType: AtomType].}
proc atomicLoadN*[T: TAtomType](p: ptr T, mem: AtomMemModel): T {.
proc atomicLoadN*[T: AtomType](p: ptr T, mem: AtomMemModel): T {.
importc: "__atomic_load_n", nodecl.}
## This proc implements an atomic load operation. It returns the contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME.
proc atomicLoad*[T: TAtomType](p, ret: ptr T, mem: AtomMemModel) {.
proc atomicLoad*[T: AtomType](p, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_load", nodecl.}
## This is the generic version of an atomic load. It returns the contents at p in ret.
proc atomicStoreN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel) {.
proc atomicStoreN*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel) {.
importc: "__atomic_store_n", nodecl.}
## This proc implements an atomic store operation. It writes val at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE.
proc atomicStore*[T: TAtomType](p, val: ptr T, mem: AtomMemModel) {.
proc atomicStore*[T: AtomType](p, val: ptr T, mem: AtomMemModel) {.
importc: "__atomic_store", nodecl.}
## This is the generic version of an atomic store. It stores the value of val at p
proc atomicExchangeN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicExchangeN*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_exchange_n", nodecl.}
## This proc implements an atomic exchange operation. It writes val at p,
## and returns the previous contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL
proc atomicExchange*[T: TAtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
proc atomicExchange*[T: AtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_exchange", nodecl.}
## This is the generic version of an atomic exchange. It stores the contents at val at p.
## The original value at p is copied into ret.
proc atomicCompareExchangeN*[T: TAtomType](p, expected: ptr T, desired: T,
proc atomicCompareExchangeN*[T: AtomType](p, expected: ptr T, desired: T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange_n ", nodecl.}
## This proc implements an atomic compare and exchange operation. This compares the
@ -85,7 +86,7 @@ when someGcc and hasThreadSupport:
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
## than that specified by success_memmodel.
proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
proc atomicCompareExchange*[T: AtomType](p, expected, desired: ptr T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange", nodecl.}
## This proc implements the generic version of atomic_compare_exchange.
@ -93,31 +94,31 @@ when someGcc and hasThreadSupport:
## value is also a pointer.
## Perform the operation return the new value, all memory models are valid
proc atomicAddFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicAddFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_add_fetch", nodecl.}
proc atomicSubFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicSubFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_sub_fetch", nodecl.}
proc atomicOrFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicOrFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_or_fetch ", nodecl.}
proc atomicAndFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicAndFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_and_fetch", nodecl.}
proc atomicXorFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicXorFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_xor_fetch", nodecl.}
proc atomicNandFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicNandFetch*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_nand_fetch ", nodecl.}
## Perform the operation return the old value, all memory models are valid
proc atomicFetchAdd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchAdd*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_add", nodecl.}
proc atomicFetchSub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchSub*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_sub", nodecl.}
proc atomicFetchOr*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchOr*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_or", nodecl.}
proc atomicFetchAnd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchAnd*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_and", nodecl.}
proc atomicFetchXor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchXor*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_xor", nodecl.}
proc atomicFetchNand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicFetchNand*[T: AtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_nand", nodecl.}
proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {.

View file

@ -51,7 +51,7 @@ proc split(t: var PAvlNode) =
t.link[0] = temp
inc t.level
proc add(a: var TMemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
proc add(a: var MemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
if t == bottom:
t = allocAvlNode(a, key, upperBound)
else:
@ -64,7 +64,7 @@ proc add(a: var TMemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
skew(t)
split(t)
proc del(a: var TMemRegion, t: var PAvlNode, x: int) {.benign.} =
proc del(a: var MemRegion, t: var PAvlNode, x: int) {.benign.} =
if t == bottom: return
a.last = t
if x <% t.key:

View file

@ -10,10 +10,10 @@
# Efficient set of pointers for the GC (and repr)
type
TRefCount = int
RefCount = int
TCell {.pure.} = object
refcount: TRefCount # the refcount and some flags
Cell {.pure.} = object
refcount: RefCount # the refcount and some flags
typ: PNimType
when trackAllocationSource:
filename: cstring
@ -21,34 +21,35 @@ type
when useCellIds:
id: int
PCell = ptr TCell
PCell = ptr Cell
PPageDesc = ptr TPageDesc
TBitIndex = range[0..UnitsPerPage-1]
TPageDesc {.final, pure.} = object
PPageDesc = ptr PageDesc
BitIndex = range[0..UnitsPerPage-1]
PageDesc {.final, pure.} = object
next: PPageDesc # all nodes are connected with this pointer
key: ByteAddress # start address at bit 0
bits: array[TBitIndex, int] # a bit vector
bits: array[BitIndex, int] # a bit vector
PPageDescArray = ptr array[0..1000_000, PPageDesc]
TCellSet {.final, pure.} = object
CellSet {.final, pure.} = object
counter, max: int
head: PPageDesc
data: PPageDescArray
PCellArray = ptr array[0..100_000_000, PCell]
TCellSeq {.final, pure.} = object
CellSeq {.final, pure.} = object
len, cap: int
d: PCellArray
{.deprecated: [TCell: Cell, TBitIndex: BitIndex, TPageDesc: PageDesc,
TRefCount: RefCount, TCellSet: CellSet, TCellSeq: CellSeq].}
# ------------------- cell seq handling ---------------------------------------
proc contains(s: TCellSeq, c: PCell): bool {.inline.} =
proc contains(s: CellSeq, c: PCell): bool {.inline.} =
for i in 0 .. s.len-1:
if s.d[i] == c: return true
return false
proc add(s: var TCellSeq, c: PCell) {.inline.} =
proc add(s: var CellSeq, c: PCell) {.inline.} =
if s.len >= s.cap:
s.cap = s.cap * 3 div 2
var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
@ -59,12 +60,12 @@ proc add(s: var TCellSeq, c: PCell) {.inline.} =
s.d[s.len] = c
inc(s.len)
proc init(s: var TCellSeq, cap: int = 1024) =
proc init(s: var CellSeq, cap: int = 1024) =
s.len = 0
s.cap = cap
s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
proc deinit(s: var TCellSeq) =
proc deinit(s: var CellSeq) =
dealloc(s.d)
s.d = nil
s.len = 0
@ -75,13 +76,13 @@ proc deinit(s: var TCellSeq) =
const
InitCellSetSize = 1024 # must be a power of two!
proc init(s: var TCellSet) =
proc init(s: var CellSet) =
s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
s.max = InitCellSetSize-1
s.counter = 0
s.head = nil
proc deinit(s: var TCellSet) =
proc deinit(s: var CellSet) =
var it = s.head
while it != nil:
var n = it.next
@ -98,14 +99,14 @@ proc nextTry(h, maxHash: int): int {.inline.} =
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc cellSetGet(t: TCellSet, key: ByteAddress): PPageDesc =
proc cellSetGet(t: CellSet, key: ByteAddress): PPageDesc =
var h = cast[int](key) and t.max
while t.data[h] != nil:
if t.data[h].key == key: return t.data[h]
h = nextTry(h, t.max)
return nil
proc cellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
proc cellSetRawInsert(t: CellSet, data: PPageDescArray, desc: PPageDesc) =
var h = cast[int](desc.key) and t.max
while data[h] != nil:
sysAssert(data[h] != desc, "CellSetRawInsert 1")
@ -113,7 +114,7 @@ proc cellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
sysAssert(data[h] == nil, "CellSetRawInsert 2")
data[h] = desc
proc cellSetEnlarge(t: var TCellSet) =
proc cellSetEnlarge(t: var CellSet) =
var oldMax = t.max
t.max = ((t.max+1)*2)-1
var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
@ -123,7 +124,7 @@ proc cellSetEnlarge(t: var TCellSet) =
dealloc(t.data)
t.data = n
proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
proc cellSetPut(t: var CellSet, key: ByteAddress): PPageDesc =
var h = cast[int](key) and t.max
while true:
var x = t.data[h]
@ -138,7 +139,7 @@ proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
while t.data[h] != nil: h = nextTry(h, t.max)
sysAssert(t.data[h] == nil, "CellSetPut")
# the new page descriptor goes into result
result = cast[PPageDesc](alloc0(sizeof(TPageDesc)))
result = cast[PPageDesc](alloc0(sizeof(PageDesc)))
result.next = t.head
result.key = key
t.head = result
@ -146,7 +147,7 @@ proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
# ---------- slightly higher level procs --------------------------------------
proc contains(s: TCellSet, cell: PCell): bool =
proc contains(s: CellSet, cell: PCell): bool =
var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
@ -155,13 +156,13 @@ proc contains(s: TCellSet, cell: PCell): bool =
else:
result = false
proc incl(s: var TCellSet, cell: PCell) {.noinline.} =
proc incl(s: var CellSet, cell: PCell) {.noinline.} =
var u = cast[ByteAddress](cell)
var t = cellSetPut(s, u shr PageShift)
u = (u %% PageSize) /% MemAlign
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc excl(s: var TCellSet, cell: PCell) =
proc excl(s: var CellSet, cell: PCell) =
var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
@ -169,7 +170,7 @@ proc excl(s: var TCellSet, cell: PCell) =
t.bits[u shr IntShift] = (t.bits[u shr IntShift] and
not (1 shl (u and IntMask)))
proc containsOrIncl(s: var TCellSet, cell: PCell): bool =
proc containsOrIncl(s: var CellSet, cell: PCell): bool =
var u = cast[ByteAddress](cell)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
@ -182,7 +183,7 @@ proc containsOrIncl(s: var TCellSet, cell: PCell): bool =
incl(s, cell)
result = false
iterator elements(t: TCellSet): PCell {.inline.} =
iterator elements(t: CellSet): PCell {.inline.} =
# while traversing it is forbidden to add pointers to the tree!
var r = t.head
while r != nil:
@ -200,7 +201,7 @@ iterator elements(t: TCellSet): PCell {.inline.} =
inc(i)
r = r.next
iterator elementsExcept(t, s: TCellSet): PCell {.inline.} =
iterator elementsExcept(t, s: CellSet): PCell {.inline.} =
var r = t.head
while r != nil:
let ss = cellSetGet(s, r.key)

View file

@ -12,12 +12,13 @@
proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
type
TLibHandle = pointer # private type
TProcAddr = pointer # library loading and loading of procs:
LibHandle = pointer # private type
ProcAddr = pointer # library loading and loading of procs:
{.deprecated: [TLibHandle: LibHandle, TProcAddr: ProcAddr].}
proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.}
proc nimLoadLibrary(path: string): LibHandle {.compilerproc.}
proc nimUnloadLibrary(lib: LibHandle) {.compilerproc.}
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {.compilerproc.}
proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}

View file

@ -19,18 +19,20 @@ when not declared(NimString):
type
pbytes = ptr array[0.. 0xffff, byte]
TRawChannel {.pure, final.} = object ## msg queue for a thread
RawChannel {.pure, final.} = object ## msg queue for a thread
rd, wr, count, mask: int
data: pbytes
lock: TSysLock
cond: TSysCond
lock: SysLock
cond: SysCond
elemType: PNimType
ready: bool
region: TMemRegion
PRawChannel = ptr TRawChannel
TLoadStoreMode = enum mStore, mLoad
TChannel* {.gcsafe.}[TMsg] = TRawChannel ## a channel for thread communication
region: MemRegion
PRawChannel = ptr RawChannel
LoadStoreMode = enum mStore, mLoad
Channel* {.gcsafe.}[TMsg] = RawChannel ## a channel for thread communication
{.deprecated: [TRawChannel: RawChannel, TLoadStoreMode: LoadStoreMode,
TChannel: Channel].}
const ChannelDeadMask = -2
proc initRawChannel(p: pointer) =
@ -49,9 +51,9 @@ proc deinitRawChannel(p: pointer) =
deinitSysCond(c.cond)
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode) {.benign.}
mode: LoadStoreMode) {.benign.}
proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
mode: TLoadStoreMode) {.benign.} =
mode: LoadStoreMode) {.benign.} =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
@ -68,7 +70,7 @@ proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
of nkNone: sysAssert(false, "storeAux")
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode) =
mode: LoadStoreMode) =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
@ -202,7 +204,7 @@ template sendImpl(q: expr) {.immediate.} =
releaseSys(q.lock)
signalSysCond(q.cond)
proc send*[TMsg](c: var TChannel[TMsg], msg: TMsg) =
proc send*[TMsg](c: var Channel[TMsg], msg: TMsg) =
## sends a message to a thread. `msg` is deeply copied.
var q = cast[PRawChannel](addr(c))
sendImpl(q)
@ -218,7 +220,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
sysFatal(ValueError, "cannot receive message of wrong type")
rawRecv(q, res, typ)
proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =
proc recv*[TMsg](c: var Channel[TMsg]): TMsg =
## receives a message from the channel `c`. This blocks until
## a message has arrived! You may use ``peek`` to avoid the blocking.
var q = cast[PRawChannel](addr(c))
@ -226,7 +228,7 @@ proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =
llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))
releaseSys(q.lock)
proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
proc tryRecv*[TMsg](c: var Channel[TMsg]): tuple[dataAvailable: bool,
msg: TMsg] =
## try to receives a message from the channel `c` if available. Otherwise
## it returns ``(false, default(msg))``.
@ -238,7 +240,7 @@ proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
result.dataAvailable = true
releaseSys(q.lock)
proc peek*[TMsg](c: var TChannel[TMsg]): int =
proc peek*[TMsg](c: var Channel[TMsg]): int =
## returns the current number of messages in the channel `c`. Returns -1
## if the channel has been closed. **Note**: This is dangerous to use
## as it encourages races. It's much better to use ``tryRecv`` instead.
@ -249,15 +251,15 @@ proc peek*[TMsg](c: var TChannel[TMsg]): int =
else:
result = -1
proc open*[TMsg](c: var TChannel[TMsg]) =
proc open*[TMsg](c: var Channel[TMsg]) =
## opens a channel `c` for inter thread communication.
initRawChannel(addr(c))
proc close*[TMsg](c: var TChannel[TMsg]) =
proc close*[TMsg](c: var Channel[TMsg]) =
## closes a channel `c` and frees its associated resources.
deinitRawChannel(addr(c))
proc ready*[TMsg](c: var TChannel[TMsg]): bool =
proc ready*[TMsg](c: var Channel[TMsg]): bool =
## returns true iff some thread is waiting on the channel `c` for
## new messages.
var q = cast[PRawChannel](addr(c))

View file

@ -10,22 +10,23 @@
## This file implements basic features for any debugger.
type
TVarSlot* {.compilerproc, final.} = object ## a slot in a frame
VarSlot* {.compilerproc, final.} = object ## a slot in a frame
address*: pointer ## the variable's address
typ*: PNimType ## the variable's type
name*: cstring ## the variable's name; for globals this is "module.name"
PExtendedFrame = ptr TExtendedFrame
TExtendedFrame = object # If the debugger is enabled the compiler
PExtendedFrame = ptr ExtendedFrame
ExtendedFrame = object # If the debugger is enabled the compiler
# provides an extended frame. Of course
# only slots that are
# needed are allocated and not 10_000,
# except for the global data description.
f: TFrame
slots: array[0..10_000, TVarSlot]
f: Frame
slots: array[0..10_000, VarSlot]
{.deprecated: [TVarSlot: VarSlot, TExtendedFrame: ExtendedFrame].}
var
dbgGlobalData: TExtendedFrame # this reserves much space, but
dbgGlobalData: ExtendedFrame # this reserves much space, but
# for now it is the most practical way
proc dbgRegisterGlobal(name: cstring, address: pointer,
@ -39,7 +40,7 @@ proc dbgRegisterGlobal(name: cstring, address: pointer,
dbgGlobalData.slots[i].address = address
inc(dbgGlobalData.f.len)
proc getLocal*(frame: PFrame; slot: int): TVarSlot {.inline.} =
proc getLocal*(frame: PFrame; slot: int): VarSlot {.inline.} =
## retrieves the meta data for the local variable at `slot`. CAUTION: An
## invalid `slot` value causes a corruption!
result = cast[PExtendedFrame](frame).slots[slot]
@ -48,7 +49,7 @@ proc getGlobalLen*(): int {.inline.} =
## gets the number of registered globals.
result = dbgGlobalData.f.len
proc getGlobal*(slot: int): TVarSlot {.inline.} =
proc getGlobal*(slot: int): VarSlot {.inline.} =
## retrieves the meta data for the global variable at `slot`. CAUTION: An
## invalid `slot` value causes a corruption!
result = dbgGlobalData.slots[slot]
@ -56,13 +57,13 @@ proc getGlobal*(slot: int): TVarSlot {.inline.} =
# ------------------- breakpoint support ------------------------------------
type
TBreakpoint* = object ## represents a break point
Breakpoint* = object ## represents a break point
low*, high*: int ## range from low to high; if disabled
## both low and high are set to their negative values
filename*: cstring ## the filename of the breakpoint
var
dbgBP: array[0..127, TBreakpoint] # breakpoints
dbgBP: array[0..127, Breakpoint] # breakpoints
dbgBPlen: int
dbgBPbloom: int64 # we use a bloom filter to speed up breakpoint checking
@ -131,16 +132,16 @@ proc canonFilename*(filename: cstring): cstring =
if fileMatches(result, filename): return result
result = nil
iterator listBreakpoints*(): ptr TBreakpoint =
iterator listBreakpoints*(): ptr Breakpoint =
## lists all breakpoints.
for i in 0..dbgBPlen-1: yield addr(dbgBP[i])
proc isActive*(b: ptr TBreakpoint): bool = b.low > 0
proc flip*(b: ptr TBreakpoint) =
proc isActive*(b: ptr Breakpoint): bool = b.low > 0
proc flip*(b: ptr Breakpoint) =
## enables or disables 'b' depending on its current state.
b.low = -b.low; b.high = -b.high
proc checkBreakpoints*(filename: cstring, line: int): ptr TBreakpoint =
proc checkBreakpoints*(filename: cstring, line: int): ptr Breakpoint =
## in which breakpoint (if any) we are.
if (dbgBPbloom and line) != line: return nil
for b in listBreakpoints():
@ -149,29 +150,30 @@ proc checkBreakpoints*(filename: cstring, line: int): ptr TBreakpoint =
# ------------------- watchpoint support ------------------------------------
type
THash = int
TWatchpoint {.pure, final.} = object
Hash = int
Watchpoint {.pure, final.} = object
name: cstring
address: pointer
typ: PNimType
oldValue: THash
oldValue: Hash
{.deprecated: [THash: Hash, TWatchpoint: Watchpoint].}
var
watchpoints: array [0..99, TWatchpoint]
watchpoints: array [0..99, Watchpoint]
watchpointsLen: int
proc `!&`(h: THash, val: int): THash {.inline.} =
proc `!&`(h: Hash, val: int): Hash {.inline.} =
result = h +% val
result = result +% result shl 10
result = result xor (result shr 6)
proc `!$`(h: THash): THash {.inline.} =
proc `!$`(h: Hash): Hash {.inline.} =
result = h +% h shl 3
result = result xor (result shr 11)
result = result +% result shl 15
proc hash(data: pointer, size: int): THash =
var h: THash = 0
proc hash(data: pointer, size: int): Hash =
var h: Hash = 0
var p = cast[cstring](data)
var i = 0
var s = size
@ -181,14 +183,14 @@ proc hash(data: pointer, size: int): THash =
dec(s)
result = !$h
proc hashGcHeader(data: pointer): THash =
proc hashGcHeader(data: pointer): Hash =
const headerSize = sizeof(int)*2
result = hash(cast[pointer](cast[int](data) -% headerSize), headerSize)
proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
h: THash): THash
h: Hash): Hash
proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool,
h: THash): THash =
h: Hash): Hash =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot:
@ -204,7 +206,7 @@ proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool,
of nkNone: sysAssert(false, "genericHashAux")
proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
h: THash): THash =
h: Hash): Hash =
sysAssert(mt != nil, "genericHashAux 2")
case mt.kind
of tyString:

View file

@ -15,7 +15,7 @@
{.push stack_trace: off.}
const
NilLibHandle: TLibHandle = nil
NilLibHandle: LibHandle = nil
proc rawWrite(f: File, s: string) =
# we cannot throw an exception here!
@ -55,22 +55,22 @@ when defined(posix):
var
RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".}
proc dlopen(path: cstring, mode: int): TLibHandle {.
proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".}
proc dlopen(path: cstring, mode: int): LibHandle {.
importc, header: "<dlfcn.h>".}
proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {.
proc dlsym(lib: LibHandle, name: cstring): ProcAddr {.
importc, header: "<dlfcn.h>".}
proc dlerror(): cstring {.importc, header: "<dlfcn.h>".}
proc nimUnloadLibrary(lib: TLibHandle) =
proc nimUnloadLibrary(lib: LibHandle) =
dlclose(lib)
proc nimLoadLibrary(path: string): TLibHandle =
proc nimLoadLibrary(path: string): LibHandle =
result = dlopen(path, RTLD_NOW)
#c_fprintf(c_stdout, "%s\n", dlerror())
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
result = dlsym(lib, name)
if result == nil: procAddrError(name)
@ -84,12 +84,12 @@ elif defined(windows) or defined(dos):
type
THINSTANCE {.importc: "HINSTANCE".} = object
x: pointer
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {.
importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.}
else:
type
THINSTANCE {.importc: "HINSTANCE".} = pointer
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
proc getProcAddress(lib: THINSTANCE, name: cstring): ProcAddr {.
importc: "GetProcAddress", header: "<windows.h>", stdcall.}
proc freeLibrary(lib: THINSTANCE) {.
@ -97,13 +97,13 @@ elif defined(windows) or defined(dos):
proc winLoadLibrary(path: cstring): THINSTANCE {.
importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
proc nimUnloadLibrary(lib: TLibHandle) =
proc nimUnloadLibrary(lib: LibHandle) =
freeLibrary(cast[THINSTANCE](lib))
proc nimLoadLibrary(path: string): TLibHandle =
result = cast[TLibHandle](winLoadLibrary(path))
proc nimLoadLibrary(path: string): LibHandle =
result = cast[LibHandle](winLoadLibrary(path))
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
result = getProcAddress(cast[THINSTANCE](lib), name)
if result == nil: procAddrError(name)
@ -115,13 +115,13 @@ elif defined(mac):
#
{.error: "no implementation for dyncalls yet".}
proc nimUnloadLibrary(lib: TLibHandle) =
proc nimUnloadLibrary(lib: LibHandle) =
NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES)
var
dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int
proc nimLoadLibrary(path: string): TLibHandle =
proc nimLoadLibrary(path: string): LibHandle =
var
img: NSObjectFileImage
ret: NSObjectFileImageReturnCode
@ -134,13 +134,13 @@ elif defined(mac):
modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or
NSLINKMODULE_OPTION_RETURN_ON_ERROR)
NSDestroyObjectFileImage(img)
result = TLibHandle(modul)
result = LibHandle(modul)
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
var
nss: NSSymbol
nss = NSLookupSymbolInModule(NSModule(lib), name)
result = TProcAddr(NSAddressOfSymbol(nss))
result = ProcAddr(NSAddressOfSymbol(nss))
if result == nil: ProcAddrError(name)
else:

View file

@ -20,63 +20,65 @@ const
EndbEnd = "***\n"
type
TStaticStr = object
StaticStr = object
len: int
data: array[0..100, char]
TBreakpointFilename = object
b: ptr TBreakpoint
filename: TStaticStr
BreakpointFilename = object
b: ptr Breakpoint
filename: StaticStr
TDbgState = enum
DbgState = enum
dbOff, # debugger is turned off
dbStepInto, # debugger is in tracing mode
dbStepOver,
dbSkipCurrent,
dbQuiting, # debugger wants to quit
dbBreakpoints # debugger is only interested in breakpoints
{.deprecated: [TStaticStr: StaticStr, TBreakpointFilename: BreakpointFilename,
TDbgState: DbgState].}
var
dbgUser: TStaticStr # buffer for user input; first command is ``step_into``
dbgUser: StaticStr # buffer for user input; first command is ``step_into``
# needs to be global cause we store the last command
# in it
dbgState: TDbgState # state of debugger
dbgState: DbgState # state of debugger
dbgSkipToFrame: PFrame # frame to be skipped to
maxDisplayRecDepth: int = 5 # do not display too much data!
brkPoints: array[0..127, TBreakpointFilename]
brkPoints: array[0..127, BreakpointFilename]
proc setLen(s: var TStaticStr, newLen=0) =
proc setLen(s: var StaticStr, newLen=0) =
s.len = newLen
s.data[newLen] = '\0'
proc add(s: var TStaticStr, c: char) =
proc add(s: var StaticStr, c: char) =
if s.len < high(s.data)-1:
s.data[s.len] = c
s.data[s.len+1] = '\0'
inc s.len
proc add(s: var TStaticStr, c: cstring) =
proc add(s: var StaticStr, c: cstring) =
var i = 0
while c[i] != '\0':
add s, c[i]
inc i
proc assign(s: var TStaticStr, c: cstring) =
proc assign(s: var StaticStr, c: cstring) =
setLen(s)
add s, c
proc `==`(a, b: TStaticStr): bool =
proc `==`(a, b: StaticStr): bool =
if a.len == b.len:
for i in 0 .. a.len-1:
if a.data[i] != b.data[i]: return false
return true
proc `==`(a: TStaticStr, b: cstring): bool =
proc `==`(a: StaticStr, b: cstring): bool =
result = c_strcmp(a.data, b) == 0
proc write(f: TFile, s: TStaticStr) =
proc write(f: File, s: StaticStr) =
write(f, cstring(s.data))
proc listBreakPoints() =
@ -95,14 +97,14 @@ proc listBreakPoints() =
write(stdout, "\n")
write(stdout, EndbEnd)
proc openAppend(filename: cstring): TFile =
proc openAppend(filename: cstring): File =
var p: pointer = fopen(filename, "ab")
if p != nil:
result = cast[TFile](p)
result = cast[File](p)
write(result, "----------------------------------------\n")
proc dbgRepr(p: pointer, typ: PNimType): string =
var cl: TReprClosure
var cl: ReprClosure
initReprClosure(cl)
cl.recDepth = maxDisplayRecDepth
# locks for the GC turned out to be a bad idea...
@ -112,12 +114,12 @@ proc dbgRepr(p: pointer, typ: PNimType): string =
# dec(recGcLock)
deinitReprClosure(cl)
proc writeVariable(stream: TFile, slot: TVarSlot) =
proc writeVariable(stream: File, slot: VarSlot) =
write(stream, slot.name)
write(stream, " = ")
writeln(stream, dbgRepr(slot.address, slot.typ))
proc listFrame(stream: TFile, f: PFrame) =
proc listFrame(stream: File, f: PFrame) =
write(stream, EndbBeg)
write(stream, "| Frame (")
write(stream, f.len)
@ -126,7 +128,7 @@ proc listFrame(stream: TFile, f: PFrame) =
writeln(stream, getLocal(f, i).name)
write(stream, EndbEnd)
proc listLocals(stream: TFile, f: PFrame) =
proc listLocals(stream: File, f: PFrame) =
write(stream, EndbBeg)
write(stream, "| Frame (")
write(stream, f.len)
@ -135,7 +137,7 @@ proc listLocals(stream: TFile, f: PFrame) =
writeVariable(stream, getLocal(f, i))
write(stream, EndbEnd)
proc listGlobals(stream: TFile) =
proc listGlobals(stream: File) =
write(stream, EndbBeg)
write(stream, "| Globals:\n")
for i in 0 .. getGlobalLen()-1:
@ -172,7 +174,7 @@ proc dbgShowExecutionPoint() =
write(stdout, framePtr.procname)
write(stdout, " ***\n")
proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int =
proc scanAndAppendWord(src: cstring, a: var StaticStr, start: int): int =
result = start
# skip whitespace:
while src[result] in {'\t', ' '}: inc(result)
@ -184,11 +186,11 @@ proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int =
else: break
inc(result)
proc scanWord(src: cstring, a: var TStaticStr, start: int): int =
proc scanWord(src: cstring, a: var StaticStr, start: int): int =
setlen(a)
result = scanAndAppendWord(src, a, start)
proc scanFilename(src: cstring, a: var TStaticStr, start: int): int =
proc scanFilename(src: cstring, a: var StaticStr, start: int): int =
result = start
setLen a
while src[result] in {'\t', ' '}: inc(result)
@ -250,8 +252,8 @@ proc hasExt(s: cstring): bool =
if s[i] == '.': return true
inc i
proc parseBreakpoint(s: cstring, start: int): TBreakpoint =
var dbgTemp: TStaticStr
proc parseBreakpoint(s: cstring, start: int): Breakpoint =
var dbgTemp: StaticStr
var i = scanNumber(s, result.low, start)
if result.low == 0: result.low = framePtr.line
i = scanNumber(s, result.high, i)
@ -279,11 +281,11 @@ proc breakpointToggle(s: cstring, start: int) =
if not b.isNil: b.flip
else: debugOut("[Warning] unknown breakpoint ")
proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) =
var dbgTemp: TStaticStr
proc dbgEvaluate(stream: File, s: cstring, start: int, f: PFrame) =
var dbgTemp: StaticStr
var i = scanWord(s, dbgTemp, start)
while s[i] in {' ', '\t'}: inc(i)
var v: TVarSlot
var v: VarSlot
if s[i] == '.':
inc(i)
add(dbgTemp, '.')
@ -299,7 +301,7 @@ proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) =
writeVariable(stream, v)
proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
var dbgTemp: TStaticStr
var dbgTemp: StaticStr
var i = scanFilename(s, dbgTemp, start)
if dbgTemp.len == 0:
invalidCommand()
@ -312,7 +314,7 @@ proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
close(stream)
proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
var dbgTemp: TStaticStr
var dbgTemp: StaticStr
var i = scanFilename(s, dbgTemp, start)
if dbgTemp.len == 0:
# just write it to stdout:
@ -325,7 +327,7 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
listFrame(stream, currFrame)
close(stream)
proc readLine(f: TFile, line: var TStaticStr): bool =
proc readLine(f: File, line: var StaticStr): bool =
while true:
var c = fgetc(f)
if c < 0'i32:
@ -358,7 +360,7 @@ proc commandPrompt() =
again = true
dbgFramePtr = framePtr # for going down and up the stack
dbgDown = 0 # how often we did go down
dbgTemp: TStaticStr
dbgTemp: StaticStr
while again:
write(stdout, "*** endb| >>")

View file

@ -365,5 +365,6 @@ when not defined(noSignalHandler):
proc setControlCHook(hook: proc () {.noconv.} not nil) =
# ugly cast, but should work on all architectures:
type TSignalHandler = proc (sig: cint) {.noconv, benign.}
c_signal(SIGINT, cast[TSignalHandler](hook))
type SignalHandler = proc (sig: cint) {.noconv, benign.}
{.deprecated: [TSignalHandler: SignalHandler].}
c_signal(SIGINT, cast[SignalHandler](hook))

View file

@ -45,17 +45,17 @@ const
rcShift = 3 # shift by rcShift to get the reference counter
colorMask = 0b011
type
TWalkOp = enum
WalkOp = enum
waMarkGlobal, # part of the backup/debug mark&sweep
waMarkPrecise, # part of the backup/debug mark&sweep
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
waCollectWhite #, waDebug
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
# A ref type can have a finalizer that is called before the object's
# storage is freed.
TGcStat {.final, pure.} = object
GcStat {.final, pure.} = object
stackScans: int # number of performed stack scans (for statistics)
cycleCollections: int # number of performed full collections
maxThreshold: int # max threshold that has been set
@ -64,35 +64,36 @@ type
cycleTableSize: int # max entries in cycle table
maxPause: int64 # max measured GC pause in nanoseconds
TGcHeap {.final, pure.} = object # this contains the zero count and
GcHeap {.final, pure.} = object # this contains the zero count and
# non-zero count table
stackBottom: pointer
cycleThreshold: int
when useCellIds:
idGenerator: int
zct: TCellSeq # the zero count table
decStack: TCellSeq # cells in the stack that are to decref again
cycleRoots: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination
zct: CellSeq # the zero count table
decStack: CellSeq # cells in the stack that are to decref again
cycleRoots: CellSet
tempStack: CellSeq # temporary stack for recursion elimination
recGcLock: int # prevent recursion via finalizers; no thread lock
when withRealTime:
maxPause: TNanos # max allowed pause in nanoseconds; active if > 0
region: TMemRegion # garbage collected region
stat: TGcStat
maxPause: Nanos # max allowed pause in nanoseconds; active if > 0
region: MemRegion # garbage collected region
stat: GcStat
when useMarkForDebug or useBackupGc:
marked: TCellSet
marked: CellSet
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcHeap: GcHeap,
TGcStat: GcStat].}
var
gch {.rtlThreadVar.}: TGcHeap
gch {.rtlThreadVar.}: GcHeap
when not defined(useNimRtl):
instantiateForRegion(gch.region)
template acquire(gch: TGcHeap) =
template acquire(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
acquireSys(HeapLock)
template release(gch: TGcHeap) =
template release(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
releaseSys(HeapLock)
@ -104,18 +105,18 @@ template gcAssert(cond: bool, msg: string) =
writeStackTrace()
quit 1
proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
proc addZCT(s: var CellSeq, c: PCell) {.noinline.} =
if (c.refcount and ZctFlag) == 0:
c.refcount = c.refcount or ZctFlag
add(s, c)
proc cellToUsr(cell: PCell): pointer {.inline.} =
# convert object (=pointer to refcount) to pointer to userdata
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
proc usrToCell(usr: pointer): PCell {.inline.} =
# convert pointer to userdata to object (=pointer to refcount)
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
proc canBeCycleRoot(c: PCell): bool {.inline.} =
result = ntfAcyclic notin c.typ.flags
@ -152,11 +153,11 @@ template gcTrace(cell, state: expr): stmt {.immediate.} =
when traceGC: traceCell(cell, state)
# forward declarations:
proc collectCT(gch: var TGcHeap) {.benign.}
proc collectCT(gch: var GcHeap) {.benign.}
proc isOnStack*(p: pointer): bool {.noinline, benign.}
proc forAllChildren(cell: PCell, op: TWalkOp) {.benign.}
proc doOperation(p: pointer, op: TWalkOp) {.benign.}
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) {.benign.}
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
proc doOperation(p: pointer, op: WalkOp) {.benign.}
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
# we need the prototype here for debugging purposes
when hasThreadSupport and hasSharedHeap:
@ -178,7 +179,7 @@ proc prepareDealloc(cell: PCell) =
# prevend recursive entering here by a lock.
# XXX: we should set the cell's children to nil!
inc(gch.recGcLock)
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(gch.recGcLock)
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
@ -276,7 +277,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
proc initGC() =
when not defined(useNimRtl):
when traceGC:
for i in low(TCellState)..high(TCellState): init(states[i])
for i in low(CellState)..high(CellState): init(states[i])
gch.cycleThreshold = InitialCycleThreshold
gch.stat.stackScans = 0
gch.stat.cycleCollections = 0
@ -308,12 +309,13 @@ proc setupForeignThreadGc*() =
when useMarkForDebug or useBackupGc:
type
TGlobalMarkerProc = proc () {.nimcall, benign.}
GlobalMarkerProc = proc () {.nimcall, benign.}
{.deprecated: [TGlobalMarkerProc: GlobalMarkerProc].}
var
globalMarkersLen: int
globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
globalMarkers: array[0.. 7_000, GlobalMarkerProc]
proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
if globalMarkersLen <= high(globalMarkers):
globalMarkers[globalMarkersLen] = markerProc
inc globalMarkersLen
@ -321,11 +323,11 @@ when useMarkForDebug or useBackupGc:
echo "[GC] cannot register global variable; too many global variables"
quit 1
proc cellsetReset(s: var TCellSet) =
proc cellsetReset(s: var CellSet) =
deinit(s)
init(s)
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
@ -345,7 +347,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: sysAssert(false, "forAllSlotsAux")
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
var d = cast[ByteAddress](dest)
if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags:
@ -359,7 +361,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: discard
proc forAllChildren(cell: PCell, op: TWalkOp) =
proc forAllChildren(cell: PCell, op: WalkOp) =
gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
gcAssert(cell.typ != nil, "forAllChildren: 3")
@ -380,7 +382,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
GenericSeqSize), cell.typ.base, op)
else: discard
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
# we check the last 8 entries (cache line) for a slot that could be reused.
# In 63% of all cases we succeed here! But we have to optimize the heck
# out of this small linear search so that ``newObj`` is not slowed down.
@ -431,13 +433,13 @@ proc gcInvariant*() =
markForDebug(gch)
{.pop.}
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
# generates a new object and sets its reference counter to 0
sysAssert(allocInv(gch.region), "rawNewObj begin")
acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch)
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT
res.typ = typ
@ -486,7 +488,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
collectCT(gch)
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT
@ -515,7 +517,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
cast[PGenericSeq](result).reserved = len
when defined(memProfiler): nimProfile(size)
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
acquire(gch)
collectCT(gch)
var ol = usrToCell(old)
@ -523,13 +525,13 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
sysAssert(allocInv(gch.region), "growObj begin")
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
var elemSize = 1
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
copyMem(res, ol, oldsize + sizeof(TCell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
# This can be wrong for intermediate temps that are nevertheless on the
@ -564,7 +566,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
decRef(ol)
else:
sysAssert(ol.typ != nil, "growObj: 5")
zeroMem(ol, sizeof(TCell))
zeroMem(ol, sizeof(Cell))
release(gch)
when useCellIds:
inc gch.idGenerator
@ -580,7 +582,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
# ---------------- cycle collector -------------------------------------------
proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
proc freeCyclicCell(gch: var GcHeap, c: PCell) =
prepareDealloc(c)
gcTrace(c, csCycFreed)
when logGC: writeCell("cycle collector dealloc cell", c)
@ -589,7 +591,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
rawDealloc(gch.region, c)
else:
gcAssert(c.typ != nil, "freeCyclicCell")
zeroMem(c, sizeof(TCell))
zeroMem(c, sizeof(Cell))
proc markGray(s: PCell) =
if s.color != rcGray:
@ -620,7 +622,7 @@ proc collectWhite(s: PCell) =
forAllChildren(s, waCollectWhite)
freeCyclicCell(gch, s)
proc markRoots(gch: var TGcHeap) =
proc markRoots(gch: var GcHeap) =
var tabSize = 0
for s in elements(gch.cycleRoots):
#writeCell("markRoot", s)
@ -635,7 +637,7 @@ proc markRoots(gch: var TGcHeap) =
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
when useBackupGc:
proc sweep(gch: var TGcHeap) =
proc sweep(gch: var GcHeap) =
for x in allObjects(gch.region):
if isCell(x):
# cast to PCell is correct here:
@ -643,7 +645,7 @@ when useBackupGc:
if c notin gch.marked: freeCyclicCell(gch, c)
when useMarkForDebug or useBackupGc:
proc markS(gch: var TGcHeap, c: PCell) =
proc markS(gch: var GcHeap, c: PCell) =
incl(gch.marked, c)
gcAssert gch.tempStack.len == 0, "stack not empty!"
forAllChildren(c, waMarkPrecise)
@ -653,10 +655,10 @@ when useMarkForDebug or useBackupGc:
if not containsOrIncl(gch.marked, d):
forAllChildren(d, waMarkPrecise)
proc markGlobals(gch: var TGcHeap) =
proc markGlobals(gch: var GcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
proc stackMarkS(gch: var TGcHeap, p: pointer) {.inline.} =
proc stackMarkS(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
var cell = usrToCell(p)
var c = cast[TAddress](cell)
@ -688,7 +690,7 @@ when logGC:
forAllChildren(s, waDebug)
c_fprintf(c_stdout, "}\n")
proc doOperation(p: pointer, op: TWalkOp) =
proc doOperation(p: pointer, op: WalkOp) =
if p == nil: return
var c: PCell = usrToCell(p)
gcAssert(c != nil, "doOperation: 1")
@ -733,19 +735,19 @@ proc doOperation(p: pointer, op: TWalkOp) =
#of waDebug: debugGraph(c)
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
doOperation(d, TWalkOp(op))
doOperation(d, WalkOp(op))
proc collectZCT(gch: var TGcHeap): bool {.benign.}
proc collectZCT(gch: var GcHeap): bool {.benign.}
when useMarkForDebug or useBackupGc:
proc markStackAndRegistersForSweep(gch: var TGcHeap) {.noinline, cdecl,
proc markStackAndRegistersForSweep(gch: var GcHeap) {.noinline, cdecl,
benign.}
proc collectRoots(gch: var TGcHeap) =
proc collectRoots(gch: var GcHeap) =
for s in elements(gch.cycleRoots):
collectWhite(s)
proc collectCycles(gch: var TGcHeap) =
proc collectCycles(gch: var GcHeap) =
# ensure the ZCT 'color' is not used:
while gch.zct.len > 0: discard collectZCT(gch)
when useBackupGc:
@ -778,7 +780,7 @@ proc collectCycles(gch: var TGcHeap) =
if cycleRootsLen != 0:
cfprintf(cstdout, "cycle roots: %ld\n", cycleRootsLen)
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
sysAssert(allocInv(gch.region), "gcMark begin")
var cell = usrToCell(p)
@ -798,7 +800,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
add(gch.decStack, cell)
sysAssert(allocInv(gch.region), "gcMark end")
proc markThreadStacks(gch: var TGcHeap) =
proc markThreadStacks(gch: var GcHeap) =
when hasThreadSupport and hasSharedHeap:
{.error: "not fully implemented".}
var it = threadList
@ -887,7 +889,7 @@ elif stackIncreases:
var
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
# a little hack to get the size of a TJmpBuf in the generated C code
# a little hack to get the size of a JmpBuf in the generated C code
# in a platform independent way
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
@ -947,18 +949,18 @@ else:
gcMark(gch, cast[PPointer](sp)[])
sp = sp +% sizeof(pointer)
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
forEachStackSlot(gch, gcMark)
when useMarkForDebug or useBackupGc:
proc markStackAndRegistersForSweep(gch: var TGcHeap) =
proc markStackAndRegistersForSweep(gch: var GcHeap) =
forEachStackSlot(gch, stackMarkS)
# ----------------------------------------------------------------------------
# end of non-portable code
# ----------------------------------------------------------------------------
proc collectZCT(gch: var TGcHeap): bool =
proc collectZCT(gch: var GcHeap): bool =
# Note: Freeing may add child objects to the ZCT! So essentially we do
# deep freeing, which is bad for incremental operation. In order to
# avoid a deep stack, we move objects to keep the ZCT small.
@ -968,7 +970,7 @@ proc collectZCT(gch: var TGcHeap): bool =
when withRealTime:
var steps = workPackage
var t0: TTicks
var t0: Ticks
if gch.maxPause > 0: t0 = getticks()
while L[] > 0:
var c = gch.zct.d[0]
@ -1001,7 +1003,7 @@ proc collectZCT(gch: var TGcHeap): bool =
rawDealloc(gch.region, c)
else:
sysAssert(c.typ != nil, "collectZCT 2")
zeroMem(c, sizeof(TCell))
zeroMem(c, sizeof(Cell))
when withRealTime:
if steps == 0:
steps = workPackage
@ -1014,7 +1016,7 @@ proc collectZCT(gch: var TGcHeap): bool =
return false
result = true
proc unmarkStackAndRegisters(gch: var TGcHeap) =
proc unmarkStackAndRegisters(gch: var GcHeap) =
var d = gch.decStack.d
for i in 0..gch.decStack.len-1:
sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
@ -1026,7 +1028,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
#sysAssert c.typ != nil, "unmarkStackAndRegisters 2"
gch.decStack.len = 0
proc collectCTBody(gch: var TGcHeap) =
proc collectCTBody(gch: var GcHeap) =
when withRealTime:
let t0 = getticks()
sysAssert(allocInv(gch.region), "collectCT: begin")
@ -1058,11 +1060,11 @@ proc collectCTBody(gch: var TGcHeap) =
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
when useMarkForDebug or useBackupGc:
proc markForDebug(gch: var TGcHeap) =
proc markForDebug(gch: var GcHeap) =
markStackAndRegistersForSweep(gch)
markGlobals(gch)
proc collectCT(gch: var TGcHeap) =
proc collectCT(gch: var GcHeap) =
# stackMarkCosts prevents some pathological behaviour: Stack marking
# becomes more expensive with large stacks and large stacks mean that
# cells with RC=0 are more likely to be kept alive by the stack.
@ -1077,13 +1079,13 @@ proc collectCT(gch: var TGcHeap) =
collectCTBody(gch)
when withRealTime:
proc toNano(x: int): TNanos {.inline.} =
proc toNano(x: int): Nanos {.inline.} =
result = x * 1000
proc GC_setMaxPause*(MaxPauseInUs: int) =
gch.maxPause = MaxPauseInUs.toNano
proc GC_step(gch: var TGcHeap, us: int, strongAdvice: bool) =
proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
acquire(gch)
gch.maxPause = us.toNano
if (gch.zct.len >= ZctThreshold or (cycleGC and

View file

@ -54,7 +54,7 @@ const
# was replaced by a resize operation.
# see growObj for details
rcColorMask = TRefCount(0b00111)
rcColorMask = RefCount(0b00111)
rcZct = 0b01000 # already added to ZCT
rcInCycleRoots = 0b10000 # already buffered as cycle candidate
@ -97,14 +97,14 @@ const
CollectCyclesStats = false
type
TWalkOp = enum
WalkOp = enum
waPush
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
# A ref type can have a finalizer that is called before the object's
# storage is freed.
TGcStat {.final, pure.} = object
GcStat {.final, pure.} = object
stackScans: int # number of performed stack scans (for statistics)
cycleCollections: int # number of performed full collections
maxThreshold: int # max threshold that has been set
@ -113,16 +113,16 @@ type
cycleTableSize: int # max entries in cycle table
maxPause: int64 # max measured GC pause in nanoseconds
TGcHeap {.final, pure.} = object # this contains the zero count and
GcHeap {.final, pure.} = object # this contains the zero count and
# non-zero count table
stackBottom: pointer
stackTop: pointer
cycleThreshold: int
zct: TCellSeq # the zero count table
decStack: TCellSeq # cells in the stack that are to decref again
cycleRoots: TCellSeq
tempStack: TCellSeq # temporary stack for recursion elimination
freeStack: TCellSeq # objects ready to be freed
zct: CellSeq # the zero count table
decStack: CellSeq # cells in the stack that are to decref again
cycleRoots: CellSeq
tempStack: CellSeq # temporary stack for recursion elimination
freeStack: CellSeq # objects ready to be freed
recGcLock: int # prevent recursion via finalizers; no thread lock
cycleRootsTrimIdx: int # Trimming is a light-weight collection of the
# cycle roots table that uses a cheap linear scan
@ -132,21 +132,22 @@ type
# This index indicates the start of the range of
# such new objects within the table.
when withRealTime:
maxPause: TNanos # max allowed pause in nanoseconds; active if > 0
region: TMemRegion # garbage collected region
stat: TGcStat
maxPause: Nanos # max allowed pause in nanoseconds; active if > 0
region: MemRegion # garbage collected region
stat: GcStat
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcStat: GcStat,
TGcHeap: GcHeap].}
var
gch* {.rtlThreadVar.}: TGcHeap
gch* {.rtlThreadVar.}: GcHeap
when not defined(useNimRtl):
instantiateForRegion(gch.region)
template acquire(gch: TGcHeap) =
template acquire(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
AcquireSys(HeapLock)
template release(gch: TGcHeap) =
template release(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
releaseSys(HeapLock)
@ -169,7 +170,7 @@ template isDead(c: Pcell): expr =
c.isBitUp(rcReallyDead) # also covers rcRetiredBuffer
template clearBit(c: PCell, bit): expr =
c.refcount = c.refcount and (not TRefCount(bit))
c.refcount = c.refcount and (not RefCount(bit))
when debugGC:
var gcCollectionIdx = 0
@ -206,7 +207,7 @@ when debugGC:
c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld\n",
msg, c, kind, c.refcount shr rcShift)
proc addZCT(zct: var TCellSeq, c: PCell) {.noinline.} =
proc addZCT(zct: var CellSeq, c: PCell) {.noinline.} =
if c.isBitDown(rcZct):
c.setBit rcZct
zct.add c
@ -221,7 +222,7 @@ template setStackTop(gch) =
var stackTop {.volatile.}: pointer
gch.stackTop = addr(stackTop)
template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
template addCycleRoot(cycleRoots: var CellSeq, c: PCell) =
if c.color != rcCycleCandidate:
c.setColor rcCycleCandidate
@ -233,11 +234,11 @@ template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
proc cellToUsr(cell: PCell): pointer {.inline.} =
# convert object (=pointer to refcount) to pointer to userdata
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
proc usrToCell*(usr: pointer): PCell {.inline.} =
# convert pointer to userdata to object (=pointer to refcount)
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
proc canbeCycleRoot(c: PCell): bool {.inline.} =
result = ntfAcyclic notin c.typ.flags
@ -254,11 +255,11 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
# forward declarations:
proc collectCT(gch: var TGcHeap)
proc collectCT(gch: var GcHeap)
proc isOnStack*(p: pointer): bool {.noinline.}
proc forAllChildren(cell: PCell, op: TWalkOp)
proc doOperation(p: pointer, op: TWalkOp)
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
proc forAllChildren(cell: PCell, op: WalkOp)
proc doOperation(p: pointer, op: WalkOp)
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp)
# we need the prototype here for debugging purposes
proc prepareDealloc(cell: PCell) =
@ -269,18 +270,19 @@ proc prepareDealloc(cell: PCell) =
# prevend recursive entering here by a lock.
# XXX: we should set the cell's children to nil!
inc(gch.recGcLock)
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(gch.recGcLock)
when traceGC:
# traceGC is a special switch to enable extensive debugging
type
TCellState = enum
CellState = enum
csAllocated, csFreed
{.deprecated: [TCellState: CellState].}
var
states: array[TCellState, TCellSet]
states: array[CellState, CellSet]
proc traceCell(c: PCell, state: TCellState) =
proc traceCell(c: PCell, state: CellState) =
case state
of csAllocated:
if c in states[csAllocated]:
@ -300,7 +302,7 @@ when traceGC:
incl(states[state], c)
proc computeCellWeight(c: PCell): int =
var x: TCellSet
var x: CellSet
x.init
let startLen = gch.tempStack.len
@ -363,30 +365,32 @@ proc rtlAddZCT(c: PCell) {.rtl, inl.} =
WithHeapLock: addZCT(gch.zct, c)
type
TCyclicMode = enum
CyclicMode = enum
Cyclic,
Acyclic,
MaybeCyclic
TReleaseType = enum
ReleaseType = enum
AddToZTC
FreeImmediately
THeapType = enum
HeapType = enum
LocalHeap
SharedHeap
{.deprecated: [TCyclicMode: CyclicMode, TReleaseType: ReleaseType,
THeapType: HeapType].}
template `++` (rc: TRefCount, heapType: THeapType): stmt =
template `++` (rc: RefCount, heapType: HeapType): stmt =
when heapType == SharedHeap:
discard atomicInc(rc, rcIncrement)
else:
inc rc, rcIncrement
template `--`(rc: TRefCount): expr =
template `--`(rc: RefCount): expr =
dec rc, rcIncrement
rc <% rcIncrement
template `--` (rc: TRefCount, heapType: THeapType): expr =
template `--` (rc: RefCount, heapType: HeapType): expr =
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
template doDecRef(cc: PCell,
@ -479,7 +483,7 @@ when hasThreadSupport and hasSharedHeap:
proc initGC() =
when not defined(useNimRtl):
when traceGC:
for i in low(TCellState)..high(TCellState): init(states[i])
for i in low(CellState)..high(CellState): init(states[i])
gch.cycleThreshold = InitialCycleThreshold
gch.stat.stackScans = 0
gch.stat.cycleCollections = 0
@ -494,7 +498,7 @@ proc initGC() =
init(gch.cycleRoots)
init(gch.decStack)
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
@ -514,7 +518,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: sysAssert(false, "forAllSlotsAux")
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
var d = cast[ByteAddress](dest)
if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags:
@ -528,7 +532,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: discard
proc forAllChildren(cell: PCell, op: TWalkOp) =
proc forAllChildren(cell: PCell, op: WalkOp) =
sysAssert(cell != nil, "forAllChildren: 1")
sysAssert(cell.typ != nil, "forAllChildren: 2")
sysAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
@ -549,7 +553,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
cell.typ.base, op)
else: discard
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
# we check the last 8 entries (cache line) for a slot that could be reused.
# In 63% of all cases we succeed here! But we have to optimize the heck
# out of this small linear search so that ``newObj`` is not slowed down.
@ -593,7 +597,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
return
add(gch.zct, res)
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap, rc1 = false): pointer =
# generates a new object and sets its reference counter to 0
acquire(gch)
sysAssert(allocInv(gch.region), "rawNewObj begin")
@ -602,7 +606,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer
collectCT(gch)
sysAssert(allocInv(gch.region), "rawNewObj after collect")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc")
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
@ -638,20 +642,20 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer
{.pop.}
proc freeCell(gch: var TGcHeap, c: PCell) =
proc freeCell(gch: var GcHeap, c: PCell) =
# prepareDealloc(c)
gcTrace(c, csFreed)
when reallyDealloc: rawDealloc(gch.region, c)
else:
sysAssert(c.typ != nil, "collectCycles")
zeroMem(c, sizeof(TCell))
zeroMem(c, sizeof(Cell))
template eraseAt(cells: var TCellSeq, at: int): stmt =
template eraseAt(cells: var CellSeq, at: int): stmt =
cells.d[at] = cells.d[cells.len - 1]
dec cells.len
template trimAt(roots: var TCellSeq, at: int): stmt =
template trimAt(roots: var CellSeq, at: int): stmt =
# This will remove a cycle root candidate during trimming.
# a candidate is removed either because it received a refup and
# it's no longer a candidate or because it received further refdowns
@ -696,7 +700,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
cast[PGenericSeq](result).len = len
cast[PGenericSeq](result).reserved = len
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
acquire(gch)
collectCT(gch)
var ol = usrToCell(old)
@ -704,7 +708,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
sysAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
sysAssert(allocInv(gch.region), "growObj begin")
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
var elemSize = if ol.typ.kind != tyString: ol.typ.base.size
else: 1
@ -713,8 +717,8 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
# XXX: This should happen outside
# call user-defined move code
# call user-defined default constructor
copyMem(res, ol, oldsize + sizeof(TCell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
@ -778,26 +782,27 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
# ---------------- cycle collector -------------------------------------------
proc doOperation(p: pointer, op: TWalkOp) =
proc doOperation(p: pointer, op: WalkOp) =
if p == nil: return
var c: PCell = usrToCell(p)
sysAssert(c != nil, "doOperation: 1")
gch.tempStack.add c
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
doOperation(d, TWalkOp(op))
doOperation(d, WalkOp(op))
type
TRecursionType = enum
RecursionType = enum
FromChildren,
FromRoot
{.deprecated: [TRecursionType: RecursionType].}
proc collectZCT(gch: var TGcHeap): bool
proc collectZCT(gch: var GcHeap): bool
template pseudoRecursion(typ: TRecursionType, body: stmt): stmt =
template pseudoRecursion(typ: RecursionType, body: stmt): stmt =
discard
proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
proc trimCycleRoots(gch: var GcHeap, startIdx = gch.cycleRootsTrimIdx) =
var i = startIdx
while i < gch.cycleRoots.len:
if gch.cycleRoots.d[i].color != rcCycleCandidate:
@ -808,7 +813,7 @@ proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
gch.cycleRootsTrimIdx = gch.cycleRoots.len
# we now use a much simpler and non-recursive algorithm for cycle removal
proc collectCycles(gch: var TGcHeap) =
proc collectCycles(gch: var GcHeap) =
if gch.cycleRoots.len == 0: return
gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, gch.cycleRoots.len)
@ -990,7 +995,7 @@ var gcDebugging* = false
var seqdbg* : proc (s: PGenericSeq) {.cdecl.}
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
sysAssert(allocInv(gch.region), "gcMark begin")
var cell = usrToCell(p)
@ -1025,7 +1030,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
add(gch.decStack, cell)
sysAssert(allocInv(gch.region), "gcMark end")
proc markThreadStacks(gch: var TGcHeap) =
proc markThreadStacks(gch: var GcHeap) =
when hasThreadSupport and hasSharedHeap:
{.error: "not fully implemented".}
var it = threadList
@ -1074,7 +1079,7 @@ proc stackSize(): int {.noinline.} =
var
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
# a little hack to get the size of a TJmpBuf in the generated C code
# a little hack to get the size of a JmpBuf in the generated C code
# in a platform independent way
when defined(sparc): # For SPARC architecture.
@ -1086,7 +1091,7 @@ when defined(sparc): # For SPARC architecture.
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
when defined(sparcv9):
asm """"flushw \n" """
else:
@ -1117,7 +1122,7 @@ elif stackIncreases:
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
var registers: C_JmpBuf
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
var max = cast[ByteAddress](gch.stackBottom)
@ -1140,7 +1145,7 @@ else:
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
# We use a jmp_buf buffer that is in the C stack.
# Used to traverse the stack and registers assuming
# that 'setjmp' will save registers in the C stack.
@ -1181,7 +1186,7 @@ else:
# end of non-portable code
# ----------------------------------------------------------------------------
proc releaseCell(gch: var TGcHeap, cell: PCell) =
proc releaseCell(gch: var GcHeap, cell: PCell) =
if cell.color != rcReallyDead:
prepareDealloc(cell)
cell.setColor rcReallyDead
@ -1210,13 +1215,13 @@ proc releaseCell(gch: var TGcHeap, cell: PCell) =
# recursion).
# We can ignore it now as the ZCT cleaner will reach it soon.
proc collectZCT(gch: var TGcHeap): bool =
proc collectZCT(gch: var GcHeap): bool =
const workPackage = 100
var L = addr(gch.zct.len)
when withRealtime:
var steps = workPackage
var t0: TTicks
var t0: Ticks
if gch.maxPause > 0: t0 = getticks()
while L[] > 0:
@ -1257,7 +1262,7 @@ proc collectZCT(gch: var TGcHeap): bool =
#deInit(gch.zct)
#init(gch.zct)
proc unmarkStackAndRegisters(gch: var TGcHeap) =
proc unmarkStackAndRegisters(gch: var GcHeap) =
var d = gch.decStack.d
for i in 0 .. <gch.decStack.len:
sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
@ -1283,7 +1288,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
gch.decStack.len = 0
proc collectCTBody(gch: var TGcHeap) =
proc collectCTBody(gch: var GcHeap) =
when withRealtime:
let t0 = getticks()
when debugGC: inc gcCollectionIdx
@ -1315,20 +1320,20 @@ proc collectCTBody(gch: var TGcHeap) =
if gch.maxPause > 0 and duration > gch.maxPause:
c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
proc collectCT(gch: var TGcHeap) =
proc collectCT(gch: var GcHeap) =
if (gch.zct.len >= ZctThreshold or (cycleGC and
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
gch.recGcLock == 0:
collectCTBody(gch)
when withRealtime:
proc toNano(x: int): TNanos {.inline.} =
proc toNano(x: int): Nanos {.inline.} =
result = x * 1000
proc GC_setMaxPause*(MaxPauseInUs: int) =
gch.maxPause = MaxPauseInUs.toNano
proc GC_step(gch: var TGcHeap, us: int, strongAdvice: bool) =
proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
acquire(gch)
gch.maxPause = us.toNano
if (gch.zct.len >= ZctThreshold or (cycleGC and

View file

@ -26,49 +26,50 @@ when defined(memProfiler):
proc nimProfile(requestedSize: int)
type
TWalkOp = enum
WalkOp = enum
waMarkGlobal, # we need to mark conservatively for global marker procs
# as these may refer to a global var and not to a thread
# local
waMarkPrecise # fast precise marking
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
# A ref type can have a finalizer that is called before the object's
# storage is freed.
TGlobalMarkerProc = proc () {.nimcall, benign.}
GlobalMarkerProc = proc () {.nimcall, benign.}
TGcStat = object
GcStat = object
collections: int # number of performed full collections
maxThreshold: int # max threshold that has been set
maxStackSize: int # max stack size
freedObjects: int # max entries in cycle table
TGcHeap = object # this contains the zero count and
GcHeap = object # this contains the zero count and
# non-zero count table
stackBottom: pointer
cycleThreshold: int
when useCellIds:
idGenerator: int
when withBitvectors:
allocated, marked: TCellSet
tempStack: TCellSeq # temporary stack for recursion elimination
allocated, marked: CellSet
tempStack: CellSeq # temporary stack for recursion elimination
recGcLock: int # prevent recursion via finalizers; no thread lock
region: TMemRegion # garbage collected region
stat: TGcStat
additionalRoots: TCellSeq # dummy roots for GC_ref/unref
region: MemRegion # garbage collected region
stat: GcStat
additionalRoots: CellSeq # dummy roots for GC_ref/unref
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcStat: GcStat,
TGlobalMarkerProc: GlobalMarkerProc, TGcHeap, GcHeap].}
var
gch {.rtlThreadVar.}: TGcHeap
gch {.rtlThreadVar.}: GcHeap
when not defined(useNimRtl):
instantiateForRegion(gch.region)
template acquire(gch: TGcHeap) =
template acquire(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
acquireSys(HeapLock)
template release(gch: TGcHeap) =
template release(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap:
releaseSys(HeapLock)
@ -80,11 +81,11 @@ template gcAssert(cond: bool, msg: string) =
proc cellToUsr(cell: PCell): pointer {.inline.} =
# convert object (=pointer to refcount) to pointer to userdata
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
proc usrToCell(usr: pointer): PCell {.inline.} =
# convert pointer to userdata to object (=pointer to refcount)
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
proc canbeCycleRoot(c: PCell): bool {.inline.} =
result = ntfAcyclic notin c.typ.flags
@ -101,9 +102,9 @@ proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
var
globalMarkersLen: int
globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
globalMarkers: array[0.. 7_000, GlobalMarkerProc]
proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
if globalMarkersLen <= high(globalMarkers):
globalMarkers[globalMarkersLen] = markerProc
inc globalMarkersLen
@ -116,11 +117,11 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
# forward declarations:
proc collectCT(gch: var TGcHeap) {.benign.}
proc collectCT(gch: var GcHeap) {.benign.}
proc isOnStack*(p: pointer): bool {.noinline, benign.}
proc forAllChildren(cell: PCell, op: TWalkOp) {.benign.}
proc doOperation(p: pointer, op: TWalkOp) {.benign.}
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) {.benign.}
proc forAllChildren(cell: PCell, op: WalkOp) {.benign.}
proc doOperation(p: pointer, op: WalkOp) {.benign.}
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
# we need the prototype here for debugging purposes
proc prepareDealloc(cell: PCell) =
@ -131,7 +132,7 @@ proc prepareDealloc(cell: PCell) =
# prevend recursive entering here by a lock.
# XXX: we should set the cell's children to nil!
inc(gch.recGcLock)
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(gch.recGcLock)
proc nimGCref(p: pointer) {.compilerProc.} =
@ -182,7 +183,7 @@ proc setupForeignThreadGc*() =
setStackBottom(addr(stackTop))
initGC()
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
@ -194,7 +195,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: sysAssert(false, "forAllSlotsAux")
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
var d = cast[ByteAddress](dest)
if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags:
@ -208,7 +209,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: discard
proc forAllChildren(cell: PCell, op: TWalkOp) =
proc forAllChildren(cell: PCell, op: WalkOp) =
gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(cell.typ != nil, "forAllChildren: 2")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
@ -228,12 +229,12 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
GenericSeqSize), cell.typ.base, op)
else: discard
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
# generates a new object and sets its reference counter to 0
acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch)
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT
res.typ = typ
@ -285,20 +286,20 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
cast[PGenericSeq](result).reserved = len
when defined(memProfiler): nimProfile(size)
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
acquire(gch)
collectCT(gch)
var ol = usrToCell(old)
sysAssert(ol.typ != nil, "growObj: 1")
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
var elemSize = 1
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
copyMem(res, ol, oldsize + sizeof(TCell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
newsize-oldsize)
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
when false:
@ -306,7 +307,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
when withBitvectors: excl(gch.allocated, ol)
when reallyDealloc: rawDealloc(gch.region, ol)
else:
zeroMem(ol, sizeof(TCell))
zeroMem(ol, sizeof(Cell))
when withBitvectors: incl(gch.allocated, res)
when useCellIds:
inc gch.idGenerator
@ -322,7 +323,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
# ----------------- collector -----------------------------------------------
proc mark(gch: var TGcHeap, c: PCell) =
proc mark(gch: var GcHeap, c: PCell) =
when withBitvectors:
incl(gch.marked, c)
gcAssert gch.tempStack.len == 0, "stack not empty!"
@ -344,7 +345,7 @@ proc mark(gch: var TGcHeap, c: PCell) =
d.refCount = rcBlack
forAllChildren(d, waMarkPrecise)
proc doOperation(p: pointer, op: TWalkOp) =
proc doOperation(p: pointer, op: WalkOp) =
if p == nil: return
var c: PCell = usrToCell(p)
gcAssert(c != nil, "doOperation: 1")
@ -359,17 +360,17 @@ proc doOperation(p: pointer, op: TWalkOp) =
of waMarkPrecise: add(gch.tempStack, c)
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
doOperation(d, TWalkOp(op))
doOperation(d, WalkOp(op))
proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
proc freeCyclicCell(gch: var GcHeap, c: PCell) =
inc gch.stat.freedObjects
prepareDealloc(c)
when reallyDealloc: rawDealloc(gch.region, c)
else:
gcAssert(c.typ != nil, "freeCyclicCell")
zeroMem(c, sizeof(TCell))
zeroMem(c, sizeof(Cell))
proc sweep(gch: var TGcHeap) =
proc sweep(gch: var GcHeap) =
when withBitvectors:
for c in gch.allocated.elementsExcept(gch.marked):
gch.allocated.excl(c)
@ -391,12 +392,12 @@ when false:
writeStackTrace()
quit 1
proc markGlobals(gch: var TGcHeap) =
proc markGlobals(gch: var GcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
let d = gch.additionalRoots.d
for i in 0 .. < gch.additionalRoots.len: mark(gch, d[i])
proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
var cell = usrToCell(p)
var c = cast[ByteAddress](cell)
@ -446,7 +447,7 @@ when defined(sparc): # For SPARC architecture.
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
when defined(sparcv9):
asm """"flushw \n" """
else:
@ -479,10 +480,10 @@ elif stackIncreases:
var
jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
# a little hack to get the size of a TJmpBuf in the generated C code
# a little hack to get the size of a JmpBuf in the generated C code
# in a platform independent way
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
var registers: C_JmpBuf
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
var max = cast[ByteAddress](gch.stackBottom)
@ -505,7 +506,7 @@ else:
var x = cast[ByteAddress](p)
result = a <=% x and x <=% b
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
# We use a jmp_buf buffer that is in the C stack.
# Used to traverse the stack and registers assuming
# that 'setjmp' will save registers in the C stack.
@ -543,7 +544,7 @@ else:
# end of non-portable code
# ----------------------------------------------------------------------------
proc collectCTBody(gch: var TGcHeap) =
proc collectCTBody(gch: var GcHeap) =
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
prepareForInteriorPointerChecking(gch.region)
markStackAndRegisters(gch)
@ -558,7 +559,7 @@ proc collectCTBody(gch: var TGcHeap) =
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
sysAssert(allocInv(gch.region), "collectCT: end")
proc collectCT(gch: var TGcHeap) =
proc collectCT(gch: var GcHeap) =
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
collectCTBody(gch)

View file

@ -15,13 +15,13 @@ else:
proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
type
PSafePoint = ptr TSafePoint
TSafePoint {.compilerproc, final.} = object
PSafePoint = ptr SafePoint
SafePoint {.compilerproc, final.} = object
prev: PSafePoint # points to next safe point
exc: ref Exception
PCallFrame = ptr TCallFrame
TCallFrame {.importc, nodecl, final.} = object
PCallFrame = ptr CallFrame
CallFrame {.importc, nodecl, final.} = object
prev: PCallFrame
procname: cstring
line: int # current line number
@ -33,6 +33,7 @@ type
lineNumber {.importc.}: int
message {.importc.}: cstring
stack {.importc.}: cstring
{.deprecated: [TSafePoint: SafePoint, TCallFrame: CallFrame].}
var
framePtr {.importc, nodecl, volatile.}: PCallFrame
@ -60,12 +61,13 @@ proc getCurrentExceptionMsg*(): string =
proc auxWriteStackTrace(f: PCallFrame): string =
type
TTempFrame = tuple[procname: cstring, line: int]
TempFrame = tuple[procname: cstring, line: int]
{.deprecated: [TTempFrame: TempFrame].}
var
it = f
i = 0
total = 0
tempFrames: array [0..63, TTempFrame]
tempFrames: array [0..63, TempFrame]
while it != nil and i <= high(tempFrames):
tempFrames[i].procname = it.procname
tempFrames[i].line = it.line
@ -260,17 +262,17 @@ proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
"""
type
TDocument {.importc.} = object of RootObj
Document {.importc.} = object of RootObj
write: proc (text: cstring) {.nimcall.}
writeln: proc (text: cstring) {.nimcall.}
createAttribute: proc (identifier: cstring): ref TNode {.nimcall.}
createElement: proc (identifier: cstring): ref TNode {.nimcall.}
createTextNode: proc (identifier: cstring): ref TNode {.nimcall.}
getElementById: proc (id: cstring): ref TNode {.nimcall.}
getElementsByName: proc (name: cstring): seq[ref TNode] {.nimcall.}
getElementsByTagName: proc (name: cstring): seq[ref TNode] {.nimcall.}
createAttribute: proc (identifier: cstring): ref Node {.nimcall.}
createElement: proc (identifier: cstring): ref Node {.nimcall.}
createTextNode: proc (identifier: cstring): ref Node {.nimcall.}
getElementById: proc (id: cstring): ref Node {.nimcall.}
getElementsByName: proc (name: cstring): seq[ref Node] {.nimcall.}
getElementsByTagName: proc (name: cstring): seq[ref Node] {.nimcall.}
TNodeType* = enum
NodeType* = enum
ElementNode = 1,
AttributeNode,
TextNode,
@ -283,35 +285,36 @@ type
DocumentTypeNode,
DocumentFragmentNode,
NotationNode
TNode* {.importc.} = object of RootObj
attributes*: seq[ref TNode]
childNodes*: seq[ref TNode]
Node* {.importc.} = object of RootObj
attributes*: seq[ref Node]
childNodes*: seq[ref Node]
data*: cstring
firstChild*: ref TNode
lastChild*: ref TNode
nextSibling*: ref TNode
firstChild*: ref Node
lastChild*: ref Node
nextSibling*: ref Node
nodeName*: cstring
nodeType*: TNodeType
nodeType*: NodeType
nodeValue*: cstring
parentNode*: ref TNode
previousSibling*: ref TNode
appendChild*: proc (child: ref TNode) {.nimcall.}
parentNode*: ref Node
previousSibling*: ref Node
appendChild*: proc (child: ref Node) {.nimcall.}
appendData*: proc (data: cstring) {.nimcall.}
cloneNode*: proc (copyContent: bool) {.nimcall.}
deleteData*: proc (start, len: int) {.nimcall.}
getAttribute*: proc (attr: cstring): cstring {.nimcall.}
getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
getElementsByTagName*: proc (): seq[ref TNode] {.nimcall.}
getAttributeNode*: proc (attr: cstring): ref Node {.nimcall.}
getElementsByTagName*: proc (): seq[ref Node] {.nimcall.}
hasChildNodes*: proc (): bool {.nimcall.}
insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
insertBefore*: proc (newNode, before: ref Node) {.nimcall.}
insertData*: proc (position: int, data: cstring) {.nimcall.}
removeAttribute*: proc (attr: cstring) {.nimcall.}
removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
removeChild*: proc (child: ref TNode) {.nimcall.}
replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
removeAttributeNode*: proc (attr: ref Node) {.nimcall.}
removeChild*: proc (child: ref Node) {.nimcall.}
replaceChild*: proc (newNode, oldNode: ref Node) {.nimcall.}
replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
setAttribute*: proc (name, value: cstring) {.nimcall.}
setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
setAttributeNode*: proc (attr: ref Node) {.nimcall.}
{.deprecated: [TNode: Node, TNodeType: NodeType, TDocument: Document].}
when defined(kwin):
proc rawEcho {.compilerproc, asmNoStackFrame.} =
@ -337,7 +340,7 @@ elif defined(nodejs):
else:
var
document {.importc, nodecl.}: ref TDocument
document {.importc, nodecl.}: ref Document
proc ewriteln(x: cstring) =
var node = document.getElementsByTagName("body")[0]

View file

@ -34,9 +34,10 @@ const
type
PPointer = ptr pointer
TByteArray = array[0..1000_0000, byte]
PByte = ptr TByteArray
ByteArray = array[0..1000_0000, byte]
PByte = ptr ByteArray
PString = ptr string
{.deprecated: [TByteArray: ByteArray].}
# Page size of the system; in most cases 4096 bytes. For exotic OS or
# CPU this needs to be changed:
@ -180,16 +181,17 @@ when defined(boehmgc):
dest[] = src
type
TMemRegion = object {.final, pure.}
MemRegion = object {.final, pure.}
{.deprecated: [TMemRegion: MemRegion].}
proc alloc(r: var TMemRegion, size: int): pointer =
proc alloc(r: var MemRegion, size: int): pointer =
result = boehmAlloc(size)
if result == nil: raiseOutOfMem()
proc alloc0(r: var TMemRegion, size: int): pointer =
proc alloc0(r: var MemRegion, size: int): pointer =
result = alloc(size)
zeroMem(result, size)
proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
proc dealloc(r: var MemRegion, p: pointer) = boehmDealloc(p)
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
proc deallocOsPages() {.inline.} = discard
include "system/cellsets"
@ -257,14 +259,15 @@ elif defined(nogc) and defined(useMalloc):
dest[] = src
type
TMemRegion = object {.final, pure.}
MemRegion = object {.final, pure.}
{.deprecated: [TMemRegion: MemRegion].}
proc alloc(r: var TMemRegion, size: int): pointer =
proc alloc(r: var MemRegion, size: int): pointer =
result = alloc(size)
proc alloc0(r: var TMemRegion, size: int): pointer =
proc alloc0(r: var MemRegion, size: int): pointer =
result = alloc0(size)
proc dealloc(r: var TMemRegion, p: pointer) = dealloc(p)
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
proc deallocOsPages() {.inline.} = discard
elif defined(nogc):
@ -313,7 +316,7 @@ elif defined(nogc):
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
var allocator {.rtlThreadVar.}: TMemRegion
var allocator {.rtlThreadVar.}: MemRegion
instantiateForRegion(allocator)
include "system/cellsets"
@ -323,7 +326,7 @@ else:
include "system/cellsets"
when not leakDetector:
sysAssert(sizeof(TCell) == sizeof(TFreeCell), "sizeof TFreeCell")
sysAssert(sizeof(Cell) == sizeof(FreeCell), "sizeof FreeCell")
when compileOption("gc", "v2"):
include "system/gc2"
elif defined(gcMarkAndSweep):

View file

@ -19,10 +19,11 @@ const
MaxTraceLen = 20 # tracking the last 20 calls is enough
type
TStackTrace* = array [0..MaxTraceLen-1, cstring]
TProfilerHook* = proc (st: TStackTrace) {.nimcall.}
StackTrace* = array [0..MaxTraceLen-1, cstring]
ProfilerHook* = proc (st: StackTrace) {.nimcall.}
{.deprecated: [TStackTrace: StackTrace, TProfilerHook: ProfilerHook].}
proc captureStackTrace(f: PFrame, st: var TStackTrace) =
proc captureStackTrace(f: PFrame, st: var StackTrace) =
const
firstCalls = 5
var
@ -51,14 +52,15 @@ proc captureStackTrace(f: PFrame, st: var TStackTrace) =
when defined(memProfiler):
type
TMemProfilerHook* = proc (st: TStackTrace, requestedSize: int) {.nimcall, benign.}
MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, benign.}
{.deprecated: [TMemProfilerHook: MemProfilerHook].}
var
profilerHook*: TMemProfilerHook
profilerHook*: MemProfilerHook
## set this variable to provide a procedure that implements a profiler in
## user space. See the `nimprof` module for a reference implementation.
proc callProfilerHook(hook: TMemProfilerHook, requestedSize: int) =
var st: TStackTrace
proc callProfilerHook(hook: MemProfilerHook, requestedSize: int) =
var st: StackTrace
captureStackTrace(framePtr, st)
hook(st, requestedSize)
@ -70,15 +72,15 @@ else:
SamplingInterval = 50_000
# set this to change the default sampling interval
var
profilerHook*: TProfilerHook
profilerHook*: ProfilerHook
## set this variable to provide a procedure that implements a profiler in
## user space. See the `nimprof` module for a reference implementation.
gTicker {.threadvar.}: int
proc callProfilerHook(hook: TProfilerHook) {.noinline.} =
proc callProfilerHook(hook: ProfilerHook) {.noinline.} =
# 'noinline' so that 'nimProfile' does not perform the stack allocation
# in the common case.
var st: TStackTrace
var st: StackTrace
captureStackTrace(framePtr, st)
hook(st)

View file

@ -121,38 +121,39 @@ proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
reprSetAux(result, p, typ)
type
TReprClosure {.final.} = object # we cannot use a global variable here
ReprClosure {.final.} = object # we cannot use a global variable here
# as this wouldn't be thread-safe
when declared(TCellSet):
marked: TCellSet
when declared(CellSet):
marked: CellSet
recdepth: int # do not recurse endlessly
indent: int # indentation
{.deprecated: [TReprClosure: ReprClosure].}
when not defined(useNimRtl):
proc initReprClosure(cl: var TReprClosure) =
proc initReprClosure(cl: var ReprClosure) =
# Important: cellsets does not lock the heap when doing allocations! We
# have to do it here ...
when hasThreadSupport and hasSharedHeap and declared(heapLock):
AcquireSys(HeapLock)
when declared(TCellSet):
when declared(CellSet):
init(cl.marked)
cl.recdepth = -1 # default is to display everything!
cl.indent = 0
proc deinitReprClosure(cl: var TReprClosure) =
when declared(TCellSet): deinit(cl.marked)
proc deinitReprClosure(cl: var ReprClosure) =
when declared(CellSet): deinit(cl.marked)
when hasThreadSupport and hasSharedHeap and declared(heapLock):
ReleaseSys(HeapLock)
proc reprBreak(result: var string, cl: TReprClosure) =
proc reprBreak(result: var string, cl: ReprClosure) =
add result, "\n"
for i in 0..cl.indent-1: add result, ' '
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) {.benign.}
cl: var ReprClosure) {.benign.}
proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
add result, "["
var bs = typ.base.size
for i in 0..typ.size div bs - 1:
@ -161,7 +162,7 @@ when not defined(useNimRtl):
add result, "]"
proc reprSequence(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
if p == nil:
add result, "nil"
return
@ -174,7 +175,7 @@ when not defined(useNimRtl):
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) {.benign.} =
cl: var ReprClosure) {.benign.} =
case n.kind
of nkNone: sysAssert(false, "reprRecordAux")
of nkSlot:
@ -191,7 +192,7 @@ when not defined(useNimRtl):
if m != nil: reprRecordAux(result, p, m, cl)
proc reprRecord(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
add result, "["
let oldLen = result.len
reprRecordAux(result, p, typ.node, cl)
@ -201,9 +202,9 @@ when not defined(useNimRtl):
add result, "]"
proc reprRef(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
# we know that p is not nil here:
when declared(TCellSet):
when declared(CellSet):
when defined(boehmGC) or defined(nogc):
var cell = cast[PCell](p)
else:
@ -216,7 +217,7 @@ when not defined(useNimRtl):
reprAux(result, p, typ.base, cl)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
cl: var ReprClosure) =
if cl.recdepth == 0:
add result, "..."
return
@ -261,7 +262,7 @@ when not defined(useNimRtl):
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
compilerRtl.} =
var
cl: TReprClosure
cl: ReprClosure
initReprClosure(cl)
result = "["
var bs = elemtyp.size
@ -274,7 +275,7 @@ proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
when not defined(useNimRtl):
proc reprAny(p: pointer, typ: PNimType): string =
var
cl: TReprClosure
cl: ReprClosure
initReprClosure(cl)
result = ""
if typ.kind in {tyObject, tyTuple, tyArray, tyArrayConstr, tySet}:

View file

@ -10,7 +10,8 @@
# set handling
type
TNimSet = array [0..4*2048-1, uint8]
NimSet = array [0..4*2048-1, uint8]
{.deprecated: [TNimSet: NimSet].}
proc countBits32(n: int32): int {.compilerproc.} =
var v = n
@ -22,7 +23,7 @@ proc countBits64(n: int64): int {.compilerproc.} =
result = countBits32(toU32(n and 0xffff'i64)) +
countBits32(toU32(n shr 16'i64))
proc cardSet(s: TNimSet, len: int): int {.compilerproc.} =
proc cardSet(s: NimSet, len: int): int {.compilerproc.} =
result = 0
for i in countup(0, len-1):
inc(result, countBits32(int32(s[i])))

View file

@ -11,8 +11,8 @@
when defined(Windows):
type
THandle = int
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
Handle = int
SysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
DebugInfo: pointer
LockCount: int32
RecursionCount: int32
@ -20,85 +20,87 @@ when defined(Windows):
LockSemaphore: int
Reserved: int32
TSysCond = THandle
SysCond = Handle
{.deprecated: [THandle: Handle, TSysLock: SysLock, TSysCond: SysCond].}
proc initSysLock(L: var TSysLock) {.stdcall, noSideEffect,
proc initSysLock(L: var SysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "InitializeCriticalSection".}
## Initializes the lock `L`.
proc tryAcquireSysAux(L: var TSysLock): int32 {.stdcall, noSideEffect,
proc tryAcquireSysAux(L: var SysLock): int32 {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "TryEnterCriticalSection".}
## Tries to acquire the lock `L`.
proc tryAcquireSys(L: var TSysLock): bool {.inline.} =
proc tryAcquireSys(L: var SysLock): bool {.inline.} =
result = tryAcquireSysAux(L) != 0'i32
proc acquireSys(L: var TSysLock) {.stdcall, noSideEffect,
proc acquireSys(L: var SysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "EnterCriticalSection".}
## Acquires the lock `L`.
proc releaseSys(L: var TSysLock) {.stdcall, noSideEffect,
proc releaseSys(L: var SysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "LeaveCriticalSection".}
## Releases the lock `L`.
proc deinitSys(L: var TSysLock) {.stdcall, noSideEffect,
proc deinitSys(L: var SysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "DeleteCriticalSection".}
proc createEvent(lpEventAttributes: pointer,
bManualReset, bInitialState: int32,
lpName: cstring): TSysCond {.stdcall, noSideEffect,
lpName: cstring): SysCond {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "CreateEventA".}
proc closeHandle(hObject: THandle) {.stdcall, noSideEffect,
proc closeHandle(hObject: Handle) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "CloseHandle".}
proc waitForSingleObject(hHandle: THandle, dwMilliseconds: int32): int32 {.
proc waitForSingleObject(hHandle: Handle, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject", noSideEffect.}
proc signalSysCond(hEvent: TSysCond) {.stdcall, noSideEffect,
proc signalSysCond(hEvent: SysCond) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "SetEvent".}
proc initSysCond(cond: var TSysCond) {.inline.} =
proc initSysCond(cond: var SysCond) {.inline.} =
cond = createEvent(nil, 0'i32, 0'i32, nil)
proc deinitSysCond(cond: var TSysCond) {.inline.} =
proc deinitSysCond(cond: var SysCond) {.inline.} =
closeHandle(cond)
proc waitSysCond(cond: var TSysCond, lock: var TSysLock) =
proc waitSysCond(cond: var SysCond, lock: var SysLock) =
releaseSys(lock)
discard waitForSingleObject(cond, -1'i32)
acquireSys(lock)
proc waitSysCondWindows(cond: var TSysCond) =
proc waitSysCondWindows(cond: var SysCond) =
discard waitForSingleObject(cond, -1'i32)
else:
type
TSysLock {.importc: "pthread_mutex_t", pure, final,
SysLock {.importc: "pthread_mutex_t", pure, final,
header: "<sys/types.h>".} = object
TSysCond {.importc: "pthread_cond_t", pure, final,
SysCond {.importc: "pthread_cond_t", pure, final,
header: "<sys/types.h>".} = object
proc initSysLock(L: var TSysLock, attr: pointer = nil) {.
proc initSysLock(L: var SysLock, attr: pointer = nil) {.
importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
proc acquireSys(L: var TSysLock) {.noSideEffect,
proc acquireSys(L: var SysLock) {.noSideEffect,
importc: "pthread_mutex_lock", header: "<pthread.h>".}
proc tryAcquireSysAux(L: var TSysLock): cint {.noSideEffect,
proc tryAcquireSysAux(L: var SysLock): cint {.noSideEffect,
importc: "pthread_mutex_trylock", header: "<pthread.h>".}
proc tryAcquireSys(L: var TSysLock): bool {.inline.} =
proc tryAcquireSys(L: var SysLock): bool {.inline.} =
result = tryAcquireSysAux(L) == 0'i32
proc releaseSys(L: var TSysLock) {.noSideEffect,
proc releaseSys(L: var SysLock) {.noSideEffect,
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
proc deinitSys(L: var TSysLock) {.noSideEffect,
proc deinitSys(L: var SysLock) {.noSideEffect,
importc: "pthread_mutex_destroy", header: "<pthread.h>".}
proc initSysCond(cond: var TSysCond, cond_attr: pointer = nil) {.
proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) {.
importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
proc waitSysCond(cond: var TSysCond, lock: var TSysLock) {.
proc waitSysCond(cond: var SysCond, lock: var SysLock) {.
importc: "pthread_cond_wait", header: "<pthread.h>", noSideEffect.}
proc signalSysCond(cond: var TSysCond) {.
proc signalSysCond(cond: var SysCond) {.
importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
proc deinitSysCond(cond: var TSysCond) {.noSideEffect,
proc deinitSysCond(cond: var SysCond) {.noSideEffect,
importc: "pthread_cond_destroy", header: "<pthread.h>".}

View file

@ -19,9 +19,9 @@ when not declared(NimString):
type
CondVar = object
c: TSysCond
c: SysCond
when defined(posix):
stupidLock: TSysLock
stupidLock: SysLock
counter: int
proc createCondVar(): CondVar =

View file

@ -24,8 +24,8 @@
## import locks
##
## var
## thr: array [0..4, TThread[tuple[a,b: int]]]
## L: TLock
## thr: array [0..4, Thread[tuple[a,b: int]]]
## L: Lock
##
## proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
## for i in interval.a..interval.b:
@ -51,40 +51,41 @@ const
when defined(windows):
type
TSysThread = THandle
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
SysThread = Handle
WinThreadProc = proc (x: pointer): int32 {.stdcall.}
{.deprecated: [TSysThread: SysThread, TWinThreadProc: WinThreadProc].}
proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
lpStartAddress: TWinThreadProc,
lpStartAddress: WinThreadProc,
lpParameter: pointer,
dwCreationFlags: int32,
lpThreadId: var int32): TSysThread {.
lpThreadId: var int32): SysThread {.
stdcall, dynlib: "kernel32", importc: "CreateThread".}
proc winSuspendThread(hThread: TSysThread): int32 {.
proc winSuspendThread(hThread: SysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "SuspendThread".}
proc winResumeThread(hThread: TSysThread): int32 {.
proc winResumeThread(hThread: SysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
proc waitForMultipleObjects(nCount: int32,
lpHandles: ptr TSysThread,
lpHandles: ptr SysThread,
bWaitAll: int32,
dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
proc terminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
proc terminateThread(hThread: SysThread, dwExitCode: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
type
TThreadVarSlot = distinct int32
ThreadVarSlot = distinct int32
when true:
proc threadVarAlloc(): TThreadVarSlot {.
proc threadVarAlloc(): ThreadVarSlot {.
importc: "TlsAlloc", stdcall, header: "<windows.h>".}
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, header: "<windows.h>".}
proc tlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
proc tlsGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
importc: "TlsGetValue", stdcall, header: "<windows.h>".}
proc getLastError(): uint32 {.
@ -92,16 +93,16 @@ when defined(windows):
proc setLastError(x: uint32) {.
importc: "SetLastError", stdcall, header: "<windows.h>".}
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer =
proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer =
let realLastError = getLastError()
result = tlsGetValue(dwTlsIndex)
setLastError(realLastError)
else:
proc threadVarAlloc(): TThreadVarSlot {.
proc threadVarAlloc(): ThreadVarSlot {.
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
proc threadVarSetValue(dwTlsIndex: ThreadVarSlot, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
proc threadVarGetValue(dwTlsIndex: ThreadVarSlot): pointer {.
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
else:
@ -111,55 +112,58 @@ else:
{.passC: "-pthread".}
type
TSysThread {.importc: "pthread_t", header: "<sys/types.h>",
SysThread {.importc: "pthread_t", header: "<sys/types.h>",
final, pure.} = object
Tpthread_attr {.importc: "pthread_attr_t",
Pthread_attr {.importc: "pthread_attr_t",
header: "<sys/types.h>", final, pure.} = object
Ttimespec {.importc: "struct timespec",
Timespec {.importc: "struct timespec",
header: "<time.h>", final, pure.} = object
tv_sec: int
tv_nsec: int
{.deprecated: [TSysThread: SysThread, Tpthread_attr: PThreadAttr,
Ttimespec: Timespec].}
proc pthread_attr_init(a1: var TPthread_attr) {.
proc pthread_attr_init(a1: var PthreadAttr) {.
importc, header: "<pthread.h>".}
proc pthread_attr_setstacksize(a1: var TPthread_attr, a2: int) {.
proc pthread_attr_setstacksize(a1: var PthreadAttr, a2: int) {.
importc, header: "<pthread.h>".}
proc pthread_create(a1: var TSysThread, a2: var TPthread_attr,
proc pthread_create(a1: var SysThread, a2: var PthreadAttr,
a3: proc (x: pointer): pointer {.noconv.},
a4: pointer): cint {.importc: "pthread_create",
header: "<pthread.h>".}
proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
proc pthread_join(a1: SysThread, a2: ptr pointer): cint {.
importc, header: "<pthread.h>".}
proc pthread_cancel(a1: TSysThread): cint {.
proc pthread_cancel(a1: SysThread): cint {.
importc: "pthread_cancel", header: "<pthread.h>".}
type
TThreadVarSlot {.importc: "pthread_key_t", pure, final,
ThreadVarSlot {.importc: "pthread_key_t", pure, final,
header: "<sys/types.h>".} = object
{.deprecated: [TThreadVarSlot: ThreadVarSlot].}
proc pthread_getspecific(a1: TThreadVarSlot): pointer {.
proc pthread_getspecific(a1: ThreadVarSlot): pointer {.
importc: "pthread_getspecific", header: "<pthread.h>".}
proc pthread_key_create(a1: ptr TThreadVarSlot,
proc pthread_key_create(a1: ptr ThreadVarSlot,
destruct: proc (x: pointer) {.noconv.}): int32 {.
importc: "pthread_key_create", header: "<pthread.h>".}
proc pthread_key_delete(a1: TThreadVarSlot): int32 {.
proc pthread_key_delete(a1: ThreadVarSlot): int32 {.
importc: "pthread_key_delete", header: "<pthread.h>".}
proc pthread_setspecific(a1: TThreadVarSlot, a2: pointer): int32 {.
proc pthread_setspecific(a1: ThreadVarSlot, a2: pointer): int32 {.
importc: "pthread_setspecific", header: "<pthread.h>".}
proc threadVarAlloc(): TThreadVarSlot {.inline.} =
proc threadVarAlloc(): ThreadVarSlot {.inline.} =
discard pthread_key_create(addr(result), nil)
proc threadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
proc threadVarSetValue(s: ThreadVarSlot, value: pointer) {.inline.} =
discard pthread_setspecific(s, value)
proc threadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
proc threadVarGetValue(s: ThreadVarSlot): pointer {.inline.} =
result = pthread_getspecific(s)
when useStackMaskHack:
proc pthread_attr_setstack(attr: var TPthread_attr, stackaddr: pointer,
proc pthread_attr_setstack(attr: var PthreadAttr, stackaddr: pointer,
size: int): cint {.
importc: "pthread_attr_setstack", header: "<pthread.h>".}
@ -175,13 +179,13 @@ when emulatedThreadVars:
# allocations are needed. Currently less than 7K are used on a 64bit machine.
# We use ``float`` for proper alignment:
type
TThreadLocalStorage = array [0..1_000, float]
ThreadLocalStorage = array [0..1_000, float]
PGcThread = ptr TGcThread
TGcThread {.pure, inheritable.} = object
sys: TSysThread
PGcThread = ptr GcThread
GcThread {.pure, inheritable.} = object
sys: SysThread
when emulatedThreadVars and not useStackMaskHack:
tls: TThreadLocalStorage
tls: ThreadLocalStorage
else:
nil
when hasSharedHeap:
@ -190,15 +194,16 @@ type
stackSize: int
else:
nil
{.deprecated: [TThreadLocalStorage: ThreadLocalStorage, TGcThread: GcThread].}
# XXX it'd be more efficient to not use a global variable for the
# thread storage slot, but to rely on the implementation to assign slot X
# for us... ;-)
var globalsSlot: TThreadVarSlot
var globalsSlot: ThreadVarSlot
when not defined(useNimRtl):
when not useStackMaskHack:
var mainThread: TGcThread
var mainThread: GcThread
proc initThreadVarsEmulation() {.compilerProc, inline.} =
when not defined(useNimRtl):
@ -206,7 +211,7 @@ proc initThreadVarsEmulation() {.compilerProc, inline.} =
when declared(mainThread):
threadVarSetValue(globalsSlot, addr(mainThread))
#const globalsSlot = TThreadVarSlot(0)
#const globalsSlot = ThreadVarSlot(0)
#sysAssert checkSlot.int == globalsSlot.int
when emulatedThreadVars:
@ -228,7 +233,7 @@ when not defined(useNimRtl):
initGC()
when emulatedThreadVars:
if nimThreadVarsSize() > sizeof(TThreadLocalStorage):
if nimThreadVarsSize() > sizeof(ThreadLocalStorage):
echo "too large thread local storage size requested"
quit 1
@ -269,26 +274,27 @@ when not defined(useNimRtl):
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.
type
TThread* {.pure, final.}[TArg] =
object of TGcThread ## Nim thread. A thread is a heavy object (~14K)
Thread* {.pure, final.}[TArg] =
object of GcThread ## Nim thread. A thread is a heavy object (~14K)
## that **must not** be part of a message! Use
## a ``TThreadId`` for that.
## a ``ThreadId`` for that.
when TArg is void:
dataFn: proc () {.nimcall, gcsafe.}
else:
dataFn: proc (m: TArg) {.nimcall, gcsafe.}
data: TArg
TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
ThreadId*[TArg] = ptr Thread[TArg] ## the current implementation uses
## a pointer as a thread ID.
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}
when not defined(boehmgc) and not hasSharedHeap:
proc deallocOsPages()
template threadProcWrapperBody(closure: expr) {.immediate.} =
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
var t = cast[ptr TThread[TArg]](closure)
var t = cast[ptr Thread[TArg]](closure)
when useStackMaskHack:
var tls: TThreadLocalStorage
var tls: ThreadLocalStorage
when not defined(boehmgc) and not defined(nogc) and not hasSharedHeap:
# init the GC for this thread:
setStackBottom(addr(t))
@ -319,35 +325,35 @@ else:
threadProcWrapperBody(closure)
{.pop.}
proc running*[TArg](t: TThread[TArg]): bool {.inline.} =
proc running*[TArg](t: Thread[TArg]): bool {.inline.} =
## returns true if `t` is running.
result = t.dataFn != nil
when hostOS == "windows":
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
## waits for the thread `t` to finish.
discard waitForSingleObject(t.sys, -1'i32)
proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
## waits for every thread in `t` to finish.
var a: array[0..255, TSysThread]
var a: array[0..255, SysThread]
sysAssert a.len >= t.len, "a.len >= t.len"
for i in 0..t.high: a[i] = t[i].sys
discard waitForMultipleObjects(t.len.int32,
cast[ptr TSysThread](addr(a)), 1, -1)
cast[ptr SysThread](addr(a)), 1, -1)
else:
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
## waits for the thread `t` to finish.
discard pthread_join(t.sys, nil)
proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
## waits for every thread in `t` to finish.
for i in 0..t.high: joinThread(t[i])
when false:
# XXX a thread should really release its heap here somehow:
proc destroyThread*[TArg](t: var TThread[TArg]) =
proc destroyThread*[TArg](t: var Thread[TArg]) =
## forces the thread `t` to terminate. This is potentially dangerous if
## you don't have full control over `t` and its acquired resources.
when hostOS == "windows":
@ -358,7 +364,7 @@ when false:
t.dataFn = nil
when hostOS == "windows":
proc createThread*[TArg](t: var TThread[TArg],
proc createThread*[TArg](t: var Thread[TArg],
tp: proc (arg: TArg) {.thread.},
param: TArg) =
## creates a new thread `t` and starts its execution. Entry point is the
@ -373,7 +379,7 @@ when hostOS == "windows":
if t.sys <= 0:
raise newException(ResourceExhaustedError, "cannot create thread")
else:
proc createThread*[TArg](t: var TThread[TArg],
proc createThread*[TArg](t: var Thread[TArg],
tp: proc (arg: TArg) {.thread.},
param: TArg) =
## creates a new thread `t` and starts its execution. Entry point is the
@ -382,29 +388,29 @@ else:
when TArg isnot void: t.data = param
t.dataFn = tp
when hasSharedHeap: t.stackSize = ThreadStackSize
var a {.noinit.}: Tpthread_attr
var a {.noinit.}: PthreadAttr
pthread_attr_init(a)
pthread_attr_setstacksize(a, ThreadStackSize)
if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0:
raise newException(ResourceExhaustedError, "cannot create thread")
proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} =
proc threadId*[TArg](t: var Thread[TArg]): ThreadId[TArg] {.inline.} =
## returns the thread ID of `t`.
result = addr(t)
proc myThreadId*[TArg](): TThreadId[TArg] =
proc myThreadId*[TArg](): ThreadId[TArg] =
## returns the thread ID of the thread that calls this proc. This is unsafe
## because the type ``TArg`` is not checked for consistency!
result = cast[TThreadId[TArg]](threadVarGetValue(globalsSlot))
result = cast[ThreadId[TArg]](threadVarGetValue(globalsSlot))
when false:
proc mainThreadId*[TArg](): TThreadId[TArg] =
proc mainThreadId*[TArg](): ThreadId[TArg] =
## returns the thread ID of the main thread.
result = cast[TThreadId[TArg]](addr(mainThread))
result = cast[ThreadId[TArg]](addr(mainThread))
when useStackMaskHack:
proc runMain(tp: proc () {.thread.}) {.compilerproc.} =
var mainThread: TThread[pointer]
var mainThread: Thread[pointer]
createThread(mainThread, tp)
joinThread(mainThread)

View file

@ -11,83 +11,86 @@
## `<https://github.com/jckarter/clay/blob/master/compiler/src/hirestimer.cpp>`_
type
TTicks = distinct int64
TNanos = int64
Ticks = distinct int64
Nanos = int64
{.deprecated: [TTicks: Ticks, TNanos: Nanos].}
when defined(windows):
proc QueryPerformanceCounter(res: var TTicks) {.
proc QueryPerformanceCounter(res: var Ticks) {.
importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".}
proc QueryPerformanceFrequency(res: var int64) {.
importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".}
proc getTicks(): TTicks {.inline.} =
proc getTicks(): Ticks {.inline.} =
QueryPerformanceCounter(result)
proc `-`(a, b: TTicks): TNanos =
proc `-`(a, b: Ticks): Nanos =
var frequency: int64
QueryPerformanceFrequency(frequency)
var performanceCounterRate = 1e+9'f64 / float64(frequency)
result = TNanos(float64(a.int64 - b.int64) * performanceCounterRate)
result = Nanos(float64(a.int64 - b.int64) * performanceCounterRate)
elif defined(macosx):
type
TMachTimebaseInfoData {.pure, final,
MachTimebaseInfoData {.pure, final,
importc: "mach_timebase_info_data_t",
header: "<mach/mach_time.h>".} = object
numer, denom: int32
{.deprecated: [TMachTimebaseInfoData: MachTimebaseInfoData].}
proc mach_absolute_time(): int64 {.importc, header: "<mach/mach.h>".}
proc mach_timebase_info(info: var TMachTimebaseInfoData) {.importc,
proc mach_timebase_info(info: var MachTimebaseInfoData) {.importc,
header: "<mach/mach_time.h>".}
proc getTicks(): TTicks {.inline.} =
result = TTicks(mach_absolute_time())
proc getTicks(): Ticks {.inline.} =
result = Ticks(mach_absolute_time())
var timeBaseInfo: TMachTimebaseInfoData
var timeBaseInfo: MachTimebaseInfoData
mach_timebase_info(timeBaseInfo)
proc `-`(a, b: TTicks): TNanos =
proc `-`(a, b: Ticks): Nanos =
result = (a.int64 - b.int64) * timeBaseInfo.numer div timeBaseInfo.denom
elif defined(posixRealtime):
type
TClockid {.importc: "clockid_t", header: "<time.h>", final.} = object
Clockid {.importc: "clockid_t", header: "<time.h>", final.} = object
TTimeSpec {.importc: "struct timespec", header: "<time.h>",
TimeSpec {.importc: "struct timespec", header: "<time.h>",
final, pure.} = object ## struct timespec
tv_sec: int ## Seconds.
tv_nsec: int ## Nanoseconds.
{.deprecated: [TClockid: Clickid, TTimeSpec: TimeSpec].}
var
CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: TClockid
CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: Clockid
proc clock_gettime(clkId: TClockid, tp: var TTimespec) {.
proc clock_gettime(clkId: Clockid, tp: var Timespec) {.
importc: "clock_gettime", header: "<time.h>".}
proc getTicks(): TTicks =
var t: TTimespec
proc getTicks(): Ticks =
var t: Timespec
clock_gettime(CLOCK_REALTIME, t)
result = TTicks(int64(t.tv_sec) * 1000000000'i64 + int64(t.tv_nsec))
result = Ticks(int64(t.tv_sec) * 1000000000'i64 + int64(t.tv_nsec))
proc `-`(a, b: TTicks): TNanos {.borrow.}
proc `-`(a, b: Ticks): Nanos {.borrow.}
else:
# fallback Posix implementation:
type
Ttimeval {.importc: "struct timeval", header: "<sys/select.h>",
Timeval {.importc: "struct timeval", header: "<sys/select.h>",
final, pure.} = object ## struct timeval
tv_sec: int ## Seconds.
tv_usec: int ## Microseconds.
proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {.
{.deprecated: [Ttimeval: Timeval].}
proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
importc: "gettimeofday", header: "<sys/time.h>".}
proc getTicks(): TTicks =
var t: Ttimeval
proc getTicks(): Ticks =
var t: Timeval
posix_gettimeofday(t)
result = TTicks(int64(t.tv_sec) * 1000_000_000'i64 +
result = Ticks(int64(t.tv_sec) * 1000_000_000'i64 +
int64(t.tv_usec) * 1000'i64)
proc `-`(a, b: TTicks): TNanos {.borrow.}
proc `-`(a, b: Ticks): Nanos {.borrow.}

View file

@ -14,8 +14,9 @@ when not declared(NimString):
{.error: "You must not import this module explicitly".}
type
TUtf16Char* = distinct int16
WideCString* = ref array[0.. 1_000_000, TUtf16Char]
Utf16Char* = distinct int16
WideCString* = ref array[0.. 1_000_000, Utf16Char]
{.deprecated: [TUtf16Char: Utf16Char].}
proc len*(w: WideCString): int =
## returns the length of a widestring. This traverses the whole string to
@ -23,7 +24,7 @@ proc len*(w: WideCString): int =
while int16(w[result]) != 0'i16: inc result
const
UNI_REPLACEMENT_CHAR = TUtf16Char(0xFFFD'i16)
UNI_REPLACEMENT_CHAR = Utf16Char(0xFFFD'i16)
UNI_MAX_BMP = 0x0000FFFF
UNI_MAX_UTF16 = 0x0010FFFF
UNI_MAX_UTF32 = 0x7FFFFFFF
@ -89,16 +90,16 @@ proc newWideCString*(source: cstring, L: int): WideCString =
if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_LOW_END:
result[d] = UNI_REPLACEMENT_CHAR
else:
result[d] = TUtf16Char(toU16(ch))
result[d] = Utf16Char(toU16(ch))
elif ch >% UNI_MAX_UTF16:
result[d] = UNI_REPLACEMENT_CHAR
else:
let ch = ch -% halfBase
result[d] = TUtf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
result[d] = Utf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
inc d
result[d] = TUtf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
result[d] = Utf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
inc d
result[d] = TUtf16Char(0'i16)
result[d] = Utf16Char(0'i16)
proc newWideCString*(s: cstring): WideCString =
if s.isNil: return nil

View file

@ -29,12 +29,12 @@ import
type
MMRESULT* = uint32
MMVERSION* = uint32
HWAVEOUT* = THandle
HWAVEOUT* = Handle
LPHWAVEOUT* = ptr HWAVEOUT
HWAVEIN* = THandle
HWAVEIN* = Handle
LPHWAVEIN* = ptr HWAVEOUT
HWAVE* = THandle
LPHWAVE* = ptr THandle
HWAVE* = Handle
LPHWAVE* = ptr Handle
LPUINT* = ptr uint32
const
@ -151,7 +151,7 @@ const
CALLBACK_FUNCTION* = 0x00030000
type
HDRVR* = THandle
HDRVR* = Handle
const
DRV_LOAD* = 1
@ -178,7 +178,7 @@ const
DRV_MCI_LAST* = (DRV_RESERVED + 0x00000FFF)
type
PDRVCALLBACK* = proc (hdrvr: THandle, uMsg: uint32, dwUser, dw1, dw2: DWORD){.
PDRVCALLBACK* = proc (hdrvr: Handle, uMsg: uint32, dwUser, dw1, dw2: DWORD){.
stdcall.}
proc sndPlaySoundA*(Name: LPCSTR, flags: uint32): bool{.stdcall,
@ -991,7 +991,6 @@ type
NPMMTIME* = ptr MMTIME
LPMMTIME* = ptr MMTIME
PWAVEHDR* = ptr WAVEHDR
TMMTime* = MMTIME
WAVEHDR* {.final.} = object
lpData*: cstring
dwBufferLength*: DWORD
@ -1002,7 +1001,6 @@ type
lpNext*: PWAVEHDR
reserved*: DWORD
TWAVEHDR* = WAVEHDR
NPWAVEHDR* = ptr WAVEHDR
LPWAVEHDR* = ptr WAVEHDR
WAVEOUTCAPSA* {.final.} = object
@ -1015,7 +1013,6 @@ type
wReserved1*: int16
dwSupport*: DWORD
TWAVEOUTCAPSA* = WAVEOUTCAPSA
PWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
NPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
LPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
@ -1032,7 +1029,8 @@ type
PWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
NPWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
LPWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
TWAVEOUTCAPSW* = WAVEOUTCAPSW
{.deprecated: [Twavehdr: Wavehdr, Tmmtime: Mmtime, Twaveoutcapsa: Waveoutcapsa,
Twaveoutcapsw: Waveoutcapsw].}
when defined(UNICODE):
type
@ -1127,10 +1125,10 @@ type
LPWAVEFORMATEX* = ptr WAVEFORMATEX
LPCWAVEFORMATEX* = ptr WAVEFORMATEX
TWAVEFORMATEX* = WAVEFORMATEX
HMIDI* = THandle
HMIDIIN* = THandle
HMIDIOUT* = THandle
HMIDISTRM* = THandle
HMIDI* = Handle
HMIDIIN* = Handle
HMIDIOUT* = Handle
HMIDISTRM* = Handle
LPHMIDI* = ptr HMIDI
LPHMIDIIN* = ptr HMIDIIN
LPHMIDIOUT* = ptr HMIDIOUT
@ -1299,9 +1297,9 @@ else:
LPAUXCAPS* = LPAUXCAPSA
type
TAUXCAPS* = AUXCAPS
HMIXEROBJ* = THandle
HMIXEROBJ* = Handle
LPHMIXEROBJ* = ptr HMIXEROBJ
HMIXER* = THandle
HMIXER* = Handle
LPHMIXER* = ptr HMIXER
proc mixerGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
@ -1647,7 +1645,7 @@ type
TJOYINFOEX* = JOYINFOEX
FOURCC* = DWORD
HPSTR* = cstring
HMMIO* = THandle
HMMIO* = Handle
LPMMIOPROC* = proc (x1: LPSTR, x2: uint32, x3, x4: LPARAM): LRESULT{.stdcall.}
TMMIOPROC* = LPMMIOPROC
MMIOINFO* {.final.} = object
@ -2096,14 +2094,14 @@ else:
type
MCI_ANIM_RECT_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
rc*: RECT
PMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
LPMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
TMCI_ANIM_RECT_PARMS* = MCI_ANIM_RECT_PARMS
MCI_ANIM_UPDATE_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
rc*: RECT
hDC*: HDC
PMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS
@ -2179,7 +2177,7 @@ type
TMCI_OVLY_WINDOW_PARMS* = MCI_OVLY_WINDOW_PARMSW
MCI_OVLY_RECT_PARMS* {.final.} = object
dwCallback*: DWORD
rc*: TRECT
rc*: RECT
PMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
LPMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
@ -2187,7 +2185,7 @@ type
MCI_OVLY_SAVE_PARMSA* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCSTR
rc*: TRECT
rc*: RECT
PMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
LPMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
@ -2195,7 +2193,7 @@ type
MCI_OVLY_SAVE_PARMSW* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCWSTR
rc*: TRECT
rc*: RECT
PMCI_OVLY_SAVE_PARMSW* = ptr MCI_OVLY_SAVE_PARMSW
LPMCI_OVLY_SAVE_PARMSW* = ptr MCI_OVLY_SAVE_PARMSW
@ -2216,7 +2214,7 @@ type
MCI_OVLY_LOAD_PARMSA* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCSTR
rc*: TRECT
rc*: RECT
PMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
LPMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
@ -2224,7 +2222,7 @@ type
MCI_OVLY_LOAD_PARMSW* {.final.} = object
dwCallback*: DWORD
lpfilename*: LPCWSTR
rc*: TRECT
rc*: RECT
PMCI_OVLY_LOAD_PARMSW* = ptr MCI_OVLY_LOAD_PARMSW
LPMCI_OVLY_LOAD_PARMSW* = ptr MCI_OVLY_LOAD_PARMSW

View file

@ -20,9 +20,9 @@ const
MAX_LANA* = 254 # lana's in range 0 to MAX_LANA inclusive
type # Network Control Block
PNCB* = ptr TNCB
TNCBPostProc* = proc (P: PNCB) {.stdcall.}
TNCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
PNCB* = ptr NCB
NCBPostProc* = proc (P: PNCB) {.stdcall.}
NCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
# by an array of NAME_BUFFER structures.
ncb_command*: char # command code
ncb_retcode*: char # return code
@ -34,17 +34,17 @@ type # Network Control Block
ncb_name*: array[0..NCBNAMSZ - 1, char] # our blank-padded netname
ncb_rto*: char # rcv timeout/retry count
ncb_sto*: char # send timeout/sys timeout
ncb_post*: TNCBPostProc # POST routine address
ncb_post*: NCBPostProc # POST routine address
ncb_lana_num*: char # lana (adapter) number
ncb_cmd_cplt*: char # 0xff => commmand pending
ncb_reserve*: array[0..9, char] # reserved, used by BIOS
ncb_event*: THandle # HANDLE to Win32 event which
ncb_event*: Handle # HANDLE to Win32 event which
# will be set to the signalled
# state when an ASYNCH command
# completes
PAdapterStatus* = ptr TAdapterStatus
TAdapterStatus* {.final.} = object
PAdapterStatus* = ptr AdapterStatus
AdapterStatus* {.final.} = object
adapter_address*: array[0..5, char]
rev_major*: char
reserved0*: char
@ -73,11 +73,13 @@ type # Network Control Block
max_sess_pkt_size*: int16
name_count*: int16
PNameBuffer* = ptr TNameBuffer
TNameBuffer* {.final.} = object
PNameBuffer* = ptr NameBuffer
NameBuffer* {.final.} = object
name*: array[0..NCBNAMSZ - 1, char]
name_num*: char
name_flags*: char
{.deprecated: [TNCB: NCB, TNCBPostProc: NCBPostProc,
TAdapterStatus: AdapterStatus, TNameBuffer: NameBuffer].}
const # values for name_flags bits.
@ -94,21 +96,22 @@ type # Structure returned to the NCB command NCBSSTAT is SESSION_HEADER followed
# by an array of SESSION_BUFFER structures. If the NCB_NAME starts with an
# asterisk then an array of these structures is returned containing the
# status for all names.
PSessionHeader* = ptr TSessionHeader
TSessionHeader* {.final.} = object
PSessionHeader* = ptr SessionHeader
SessionHeader* {.final.} = object
sess_name*: char
num_sess*: char
rcv_dg_outstanding*: char
rcv_any_outstanding*: char
PSessionBuffer* = ptr TSessionBuffer
TSessionBuffer* {.final.} = object
PSessionBuffer* = ptr SessionBuffer
SessionBuffer* {.final.} = object
lsn*: char
state*: char
local_name*: array[0..NCBNAMSZ - 1, char]
remote_name*: array[0..NCBNAMSZ - 1, char]
rcvs_outstanding*: char
sends_outstanding*: char
{.deprecated: [TSessionHeader: SessionHeader, TSessionBuffer: SessionBuffer].}
const # Values for state
@ -128,14 +131,14 @@ type # Structure returned to the NCB command NCBENUM.
len*: char # Number of valid entries in lana[]
lana*: array[0..MAX_LANA, char]
PFindNameHeader* = ptr TFindNameHeader
TFindNameHeader* {.final.} = object
PFindNameHeader* = ptr FindNameHeader
FindNameHeader* {.final.} = object
node_count*: int16
reserved*: char
unique_group*: char
PFindNameBuffer* = ptr TFindNameBuffer
TFindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
PFindNameBuffer* = ptr FindNameBuffer
FindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
# transport specific extensions to netbios.
len*: char
access_control*: char
@ -144,12 +147,13 @@ type # Structure returned to the NCB command NCBENUM.
source_addr*: array[0..5, char]
routing_info*: array[0..17, char]
PActionHeader* = ptr TActionHeader
TActionHeader* {.final.} = object
PActionHeader* = ptr ActionHeader
ActionHeader* {.final.} = object
transport_id*: int32
action_code*: int16
reserved*: int16
{.deprecated: [TFindNameHeader: FindNameHeader, TFindNameBuffer: FindNameBuffer,
TActionHeader: ActionHeader].}
const # Values for transport_id
ALL_TRANSPORTS* = "M\0\0\0"

View file

@ -31,7 +31,7 @@ import
windows
type
HDROP* = THandle
HDROP* = Handle
UINT_PTR* = ptr uint32
DWORD_PTR* = ptr DWORD
PHICON* = ptr HICON
@ -57,8 +57,8 @@ type
hStdError*: HANDLE
LPSTARTUPINFOW* = ptr STARTUPINFOW
TSTARTUPINFOW* = STARTUPINFOW
PSTARTUPINFOW* = ptr STARTUPINFOW #unicode
{.deprecated: [TSTARTUPINFOW: STARTUPINFOW].}
proc DragQueryFileA*(arg1: HDROP, arg2: uint32, arg3: LPSTR, arg4: uint32): uint32{.
stdcall, dynlib: "shell32.dll", importc: "DragQueryFileA".}
@ -132,7 +132,6 @@ type # init with sizeof(DRAGINFO)
lpFileList*: LPSTR
grfKeyState*: DWORD
TDRAGINFOA* = DRAGINFOA
LPDRAGINFOA* = ptr DRAGINFOA # init with sizeof(DRAGINFO)
DRAGINFOW* {.final.} = object
uSize*: uint32
@ -141,19 +140,19 @@ type # init with sizeof(DRAGINFO)
lpFileList*: LPWSTR
grfKeyState*: DWORD
TDRAGINFOW* = DRAGINFOW
LPDRAGINFOW* = ptr DRAGINFOW
{.deprecated: [TDRAGINFOA: DRAGINFOA, TDRAGINFOW: DRAGINFOW].}
when defined(UNICODE):
type
DRAGINFO* = DRAGINFOW
TDRAGINFO* = DRAGINFOW
LPDRAGINFO* = LPDRAGINFOW
{.deprecated: [TDRAGINFO: DRAGINFOW].}
else:
type
DRAGINFO* = DRAGINFOA
TDRAGINFO* = DRAGINFOW
LPDRAGINFO* = LPDRAGINFOA
{.deprecated: [TDRAGINFO: DRAGINFOW].}
const
ABM_NEW* = 0x00000000
ABM_REMOVE* = 0x00000001
@ -189,8 +188,8 @@ type
rc*: RECT
lParam*: LPARAM # message specific
TAPPBARDATA* = AppBarData
PAPPBARDATA* = ptr AppBarData
{.deprecated: [TAPPBARDATA: AppBarData].}
proc SHAppBarMessage*(dwMessage: DWORD, pData: APPBARDATA): UINT_PTR{.stdcall,
dynlib: "shell32.dll", importc: "SHAppBarMessage".}
@ -299,7 +298,6 @@ type
hNameMappings*: LPVOID
lpszProgressTitle*: LPCSTR # only used if FOF_SIMPLEPROGRESS
TSHFILEOPSTRUCTA* = SHFILEOPSTRUCTA
LPSHFILEOPSTRUCTA* = ptr SHFILEOPSTRUCTA
SHFILEOPSTRUCTW* {.final.} = object
hwnd*: HWND
@ -311,19 +309,21 @@ type
hNameMappings*: LPVOID
lpszProgressTitle*: LPCWSTR
TSHFILEOPSTRUCTW* = SHFILEOPSTRUCTW
LPSHFILEOPSTRUCTW* = ptr SHFILEOPSTRUCTW
{.deprecated: [TSHFILEOPSTRUCTA: SHFILEOPSTRUCTA,
TSHFILEOPSTRUCTW: SHFILEOPSTRUCTW].}
when defined(UNICODE):
type
SHFILEOPSTRUCT* = SHFILEOPSTRUCTW
TSHFILEOPSTRUCT* = SHFILEOPSTRUCTW
LPSHFILEOPSTRUCT* = LPSHFILEOPSTRUCTW
{.deprecated: [TSHFILEOPSTRUCT: SHFILEOPSTRUCTW].}
else:
type
SHFILEOPSTRUCT* = SHFILEOPSTRUCTA
TSHFILEOPSTRUCT* = SHFILEOPSTRUCTA
LPSHFILEOPSTRUCT* = LPSHFILEOPSTRUCTA
{.deprecated: [TSHFILEOPSTRUCT: SHFILEOPSTRUCTA].}
proc SHFileOperationA*(lpFileOp: LPSHFILEOPSTRUCTA): int32{.stdcall,
dynlib: "shell32.dll", importc: "SHFileOperationA".}
proc SHFileOperationW*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall,
@ -332,7 +332,7 @@ proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTA): int32{.stdcall,
dynlib: "shell32.dll", importc: "SHFileOperationA".}
proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall,
dynlib: "shell32.dll", importc: "SHFileOperationW".}
proc SHFreeNameMappings*(hNameMappings: THandle){.stdcall,
proc SHFreeNameMappings*(hNameMappings: Handle){.stdcall,
dynlib: "shell32.dll", importc: "SHFreeNameMappings".}
type
SHNAMEMAPPINGA* {.final.} = object
@ -341,7 +341,6 @@ type
cchOldPath*: int32
cchNewPath*: int32
TSHNAMEMAPPINGA* = SHNAMEMAPPINGA
LPSHNAMEMAPPINGA* = ptr SHNAMEMAPPINGA
SHNAMEMAPPINGW* {.final.} = object
pszOldPath*: LPWSTR
@ -349,19 +348,20 @@ type
cchOldPath*: int32
cchNewPath*: int32
TSHNAMEMAPPINGW* = SHNAMEMAPPINGW
LPSHNAMEMAPPINGW* = ptr SHNAMEMAPPINGW
{.deprecated: [TSHNAMEMAPPINGA: SHNAMEMAPPINGA,
TSHNAMEMAPPINGW: SHNAMEMAPPINGW].}
when not(defined(UNICODE)):
type
SHNAMEMAPPING* = SHNAMEMAPPINGW
TSHNAMEMAPPING* = SHNAMEMAPPINGW
LPSHNAMEMAPPING* = LPSHNAMEMAPPINGW
{.deprecated: [TSHNAMEMAPPING: SHNAMEMAPPINGW].}
else:
type
SHNAMEMAPPING* = SHNAMEMAPPINGA
TSHNAMEMAPPING* = SHNAMEMAPPINGA
LPSHNAMEMAPPING* = LPSHNAMEMAPPINGA
{.deprecated: [TSHNAMEMAPPING: SHNAMEMAPPINGA].}
#
# End Shell File Operations
#
@ -424,7 +424,6 @@ type
hMonitor*: HANDLE # also: hIcon
hProcess*: HANDLE
TSHELLEXECUTEINFOA* = SHELLEXECUTEINFOA
LPSHELLEXECUTEINFOA* = ptr SHELLEXECUTEINFOA
SHELLEXECUTEINFOW* {.final.} = object
cbSize*: DWORD
@ -443,19 +442,21 @@ type
hMonitor*: HANDLE # also: hIcon
hProcess*: HANDLE
TSHELLEXECUTEINFOW* = SHELLEXECUTEINFOW
LPSHELLEXECUTEINFOW* = ptr SHELLEXECUTEINFOW
{.deprecated: [TSHELLEXECUTEINFOA: SHELLEXECUTEINFOA,
TSHELLEXECUTEINFOW: SHELLEXECUTEINFOW].}
when defined(UNICODE):
type
SHELLEXECUTEINFO* = SHELLEXECUTEINFOW
TSHELLEXECUTEINFO* = SHELLEXECUTEINFOW
LPSHELLEXECUTEINFO* = LPSHELLEXECUTEINFOW
{.deprecated: [TSHELLEXECUTEINFO: SHELLEXECUTEINFOW].}
else:
type
SHELLEXECUTEINFO* = SHELLEXECUTEINFOA
TSHELLEXECUTEINFO* = SHELLEXECUTEINFOA
LPSHELLEXECUTEINFO* = LPSHELLEXECUTEINFOA
{.deprecated: [TSHELLEXECUTEINFO: SHELLEXECUTEINFOA].}
proc ShellExecuteExA*(lpExecInfo: LPSHELLEXECUTEINFOA): bool{.stdcall,
dynlib: "shell32.dll", importc: "ShellExecuteExA".}
proc ShellExecuteExW*(lpExecInfo: LPSHELLEXECUTEINFOW): bool{.stdcall,
@ -492,8 +493,8 @@ type
lpStartupInfo*: LPSTARTUPINFOW
lpProcessInformation*: LPPROCESS_INFORMATION
TSHCREATEPROCESSINFOW* = SHCREATEPROCESSINFOW
PSHCREATEPROCESSINFOW* = ptr SHCREATEPROCESSINFOW
{.deprecated: [TSHCREATEPROCESSINFOW: SHCREATEPROCESSINFOW].}
proc SHCreateProcessAsUserW*(pscpi: PSHCREATEPROCESSINFOW): bool{.stdcall,
dynlib: "shell32.dll", importc: "SHCreateProcessAsUserW".}
@ -510,8 +511,8 @@ type
i64Size*: int64
i64NumItems*: int64
TSHQUERYRBINFO* = SHQUERYRBINFO
LPSHQUERYRBINFO* = ptr SHQUERYRBINFO # flags for SHEmptyRecycleBin
{.deprecated: [TSHQUERYRBINFO: SHQUERYRBINFO].}
const
SHERB_NOCONFIRMATION* = 0x00000001
@ -555,9 +556,8 @@ type
uTimeout*: uint32 # also: uVersion
szInfoTitle*: array[0..63, char]
dwInfoFlags*: DWORD
guidItem*: TGUID
guidItem*: GUID
TNOTIFYICONDATAA* = NOTIFYICONDATAA
PNOTIFYICONDATAA* = ptr NOTIFYICONDATAA
NOTIFYICONDATAW* {.final.} = object
cbSize*: DWORD
@ -573,21 +573,22 @@ type
uTimeout*: uint32 # also uVersion : UINT
szInfoTitle*: array[0..63, char]
dwInfoFlags*: DWORD
guidItem*: TGUID
guidItem*: GUID
TNOTIFYICONDATAW* = NOTIFYICONDATAW
PNOTIFYICONDATAW* = ptr NOTIFYICONDATAW
{.deprecated: [TNOTIFYICONDATAA: NOTIFYICONDATAA,
TNOTIFYICONDATAW: NOTIFYICONDATAW].}
when defined(UNICODE):
type
NOTIFYICONDATA* = NOTIFYICONDATAW
TNOTIFYICONDATA* = NOTIFYICONDATAW
PNOTIFYICONDATA* = PNOTIFYICONDATAW
{.deprecated: [TNOTIFYICONDATA: NOTIFYICONDATAW].}
else:
type
NOTIFYICONDATA* = NOTIFYICONDATAA
TNOTIFYICONDATA* = NOTIFYICONDATAA
PNOTIFYICONDATA* = PNOTIFYICONDATAA
{.deprecated: [TNOTIFYICONDATA: NOTIFYICONDATAA].}
const
NIN_SELECT* = WM_USER + 0
NINF_KEY* = 0x00000001
@ -655,7 +656,6 @@ type
szDisplayName*: array[0..(MAX_PATH) - 1, char] # out: display name (or path)
szTypeName*: array[0..79, char] # out: type name
TSHFILEINFOA* = SHFILEINFOA
PSHFILEINFOA* = ptr SHFILEINFOA
SHFILEINFOW* {.final.} = object
hIcon*: HICON # out: icon
@ -664,19 +664,19 @@ type
szDisplayName*: array[0..(MAX_PATH) - 1, Wchar] # out: display name (or path)
szTypeName*: array[0..79, Wchar] # out: type name
TSHFILEINFOW* = SHFILEINFOW
PSHFILEINFOW* = ptr SHFILEINFOW
{.deprecated: [TSHFILEINFOA: SHFILEINFOA, TSHFILEINFOW: SHFILEINFOW].}
when defined(UNICODE):
type
SHFILEINFO* = SHFILEINFOW
TSHFILEINFO* = SHFILEINFOW
pFILEINFO* = SHFILEINFOW
{.deprecated: [TSHFILEINFO: SHFILEINFOW].}
else:
type
SHFILEINFO* = SHFILEINFOA
TSHFILEINFO* = SHFILEINFOA
pFILEINFO* = SHFILEINFOA
{.deprecated: [TSHFILEINFO: SHFILEINFOA].}
# NOTE: This is also in shlwapi.h. Please keep in synch.
const
@ -710,16 +710,16 @@ proc SHGetFileInfo*(pszPath: LPCSTR, dwFileAttributes: DWORD,
psfi: PSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
proc SHGetFileInfoA*(pszPath: LPCSTR, dwFileAttributes: DWORD,
psfi: var TSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
psfi: var SHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
proc SHGetFileInfoW*(pszPath: LPCWSTR, dwFileAttributes: DWORD,
psfi: var TSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
psfi: var SHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".}
proc SHGetFileInfo*(pszPath: LPCSTR, dwFileAttributes: DWORD,
psfi: var TSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
psfi: var SHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
proc SHGetFileInfo*(pszPath: LPCWSTR, dwFileAttributes: DWORD,
psfi: var TSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
psfi: var SHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".}
proc SHGetDiskFreeSpaceExA*(pszDirectoryName: LPCSTR,
pulFreeBytesAvailableToCaller: PULARGE_INTEGER,

View file

@ -72,22 +72,22 @@ const
CSIDL_FLAG_CREATE* = 0x00008000 # (force creation of requested folder if it doesn't exist yet)
# Original entry points
proc SHGetFolderPathA*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord,
proc SHGetFolderPathA*(Ahwnd: HWND, Csidl: int, Token: Handle, Flags: DWord,
Path: cstring): HRESULT{.stdcall, dynlib: LibName,
importc: "SHGetFolderPathA".}
proc SHGetFolderPathW*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord,
proc SHGetFolderPathW*(Ahwnd: HWND, Csidl: int, Token: Handle, Flags: DWord,
Path: cstring): HRESULT{.stdcall, dynlib: LibName,
importc: "SHGetFolderPathW".}
proc SHGetFolderPath*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord,
proc SHGetFolderPath*(Ahwnd: HWND, Csidl: int, Token: Handle, Flags: DWord,
Path: cstring): HRESULT{.stdcall, dynlib: LibName,
importc: "SHGetFolderPathA".}
type
PFNSHGetFolderPathA* = proc (Ahwnd: HWND, Csidl: int, Token: THandle,
PFNSHGetFolderPathA* = proc (Ahwnd: HWND, Csidl: int, Token: Handle,
Flags: DWord, Path: cstring): HRESULT{.stdcall.}
PFNSHGetFolderPathW* = proc (Ahwnd: HWND, Csidl: int, Token: THandle,
PFNSHGetFolderPathW* = proc (Ahwnd: HWND, Csidl: int, Token: Handle,
Flags: DWord, Path: cstring): HRESULT{.stdcall.}
PFNSHGetFolderPath* = PFNSHGetFolderPathA
TSHGetFolderPathA* = PFNSHGetFolderPathA
TSHGetFolderPathW* = PFNSHGetFolderPathW
TSHGetFolderPath* = TSHGetFolderPathA
{.deprecated: [TSHGetFolderPathA: PFNSHGetFolderPathA,
TSHGetFolderPathW: PFNSHGetFolderPathW,
TSHGetFolderPath: SHGetFolderPathA].}

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ const
useWinUnicode* = not defined(useWinAnsi)
type
THandle* = int
Handle* = int
LONG* = int32
ULONG* = int
PULONG* = ptr int
@ -24,15 +24,15 @@ type
DWORD* = int32
PDWORD* = ptr DWORD
LPINT* = ptr int32
HDC* = THandle
HGLRC* = THandle
HDC* = Handle
HGLRC* = Handle
TSECURITY_ATTRIBUTES* {.final, pure.} = object
SECURITY_ATTRIBUTES* {.final, pure.} = object
nLength*: int32
lpSecurityDescriptor*: pointer
bInheritHandle*: WINBOOL
TSTARTUPINFO* {.final, pure.} = object
STARTUPINFO* {.final, pure.} = object
cb*: int32
lpReserved*: cstring
lpDesktop*: cstring
@ -48,25 +48,25 @@ type
wShowWindow*: int16
cbReserved2*: int16
lpReserved2*: pointer
hStdInput*: THandle
hStdOutput*: THandle
hStdError*: THandle
hStdInput*: Handle
hStdOutput*: Handle
hStdError*: Handle
TPROCESS_INFORMATION* {.final, pure.} = object
hProcess*: THandle
hThread*: THandle
PROCESS_INFORMATION* {.final, pure.} = object
hProcess*: Handle
hThread*: Handle
dwProcessId*: int32
dwThreadId*: int32
TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
FILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
dwLowDateTime*: DWORD
dwHighDateTime*: DWORD
TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
BY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
dwFileAttributes*: DWORD
ftCreationTime*: TFILETIME
ftLastAccessTime*: TFILETIME
ftLastWriteTime*: TFILETIME
ftCreationTime*: FILETIME
ftLastAccessTime*: FILETIME
ftLastWriteTime*: FILETIME
dwVolumeSerialNumber*: DWORD
nFileSizeHigh*: DWORD
nFileSizeLow*: DWORD
@ -74,10 +74,16 @@ type
nFileIndexHigh*: DWORD
nFileIndexLow*: DWORD
{.deprecated: [THandle: Handle, TSECURITY_ATTRIBUTES: SECURITY_ATTRIBUTES,
TSTARTUPINFO: STARTUPINFO, TPROCESS_INFORMATION: PROCESS_INFORMATION,
TFILETIME: FILETIME, TBY_HANDLE_FILE_INFORMATION: BY_HANDLE_FILE_INFORMATION].}
when useWinUnicode:
type TWinChar* = TUtf16Char
type WinChar* = Utf16Char
{.deprecated: [TWinChar: WinChar].}
else:
type TWinChar* = char
type WinChar* = char
{.deprecated: [TWinChar: WinChar].}
const
STARTF_USESHOWWINDOW* = 1'i32
@ -98,67 +104,67 @@ const
DETACHED_PROCESS* = 8'i32
SW_SHOWNORMAL* = 1'i32
INVALID_HANDLE_VALUE* = THandle(-1)
INVALID_HANDLE_VALUE* = Handle(-1)
CREATE_UNICODE_ENVIRONMENT* = 1024'i32
proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "CloseHandle".}
proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
proc readFile*(hFile: Handle, Buffer: pointer, nNumberOfBytesToRead: int32,
lpNumberOfBytesRead: ptr int32, lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "ReadFile".}
proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
proc writeFile*(hFile: Handle, Buffer: pointer, nNumberOfBytesToWrite: int32,
lpNumberOfBytesWritten: ptr int32,
lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "WriteFile".}
proc createPipe*(hReadPipe, hWritePipe: var THandle,
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
proc createPipe*(hReadPipe, hWritePipe: var Handle,
lpPipeAttributes: var SECURITY_ATTRIBUTES,
nSize: int32): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
when useWinUnicode:
proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
lpThreadAttributes: ptr SECURITY_ATTRIBUTES,
bInheritHandles: WINBOOL, dwCreationFlags: int32,
lpEnvironment, lpCurrentDirectory: WideCString,
lpStartupInfo: var TSTARTUPINFO,
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
lpStartupInfo: var STARTUPINFO,
lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreateProcessW".}
else:
proc createProcessA*(lpApplicationName, lpCommandLine: cstring,
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
lpThreadAttributes: ptr SECURITY_ATTRIBUTES,
bInheritHandles: WINBOOL, dwCreationFlags: int32,
lpEnvironment: pointer, lpCurrentDirectory: cstring,
lpStartupInfo: var TSTARTUPINFO,
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
lpStartupInfo: var STARTUPINFO,
lpProcessInformation: var PROCESS_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreateProcessA".}
proc suspendThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32",
proc suspendThread*(hThread: Handle): int32 {.stdcall, dynlib: "kernel32",
importc: "SuspendThread".}
proc resumeThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32",
proc resumeThread*(hThread: Handle): int32 {.stdcall, dynlib: "kernel32",
importc: "ResumeThread".}
proc waitForSingleObject*(hHandle: THandle, dwMilliseconds: int32): int32 {.
proc waitForSingleObject*(hHandle: Handle, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
proc terminateProcess*(hProcess: THandle, uExitCode: int): WINBOOL {.stdcall,
proc terminateProcess*(hProcess: Handle, uExitCode: int): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "TerminateProcess".}
proc getExitCodeProcess*(hProcess: THandle, lpExitCode: var int32): WINBOOL {.
proc getExitCodeProcess*(hProcess: Handle, lpExitCode: var int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}
proc getStdHandle*(nStdHandle: int32): THandle {.stdcall, dynlib: "kernel32",
proc getStdHandle*(nStdHandle: int32): Handle {.stdcall, dynlib: "kernel32",
importc: "GetStdHandle".}
proc setStdHandle*(nStdHandle: int32, hHandle: THandle): WINBOOL {.stdcall,
proc setStdHandle*(nStdHandle: int32, hHandle: Handle): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "SetStdHandle".}
proc flushFileBuffers*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
proc flushFileBuffers*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "FlushFileBuffers".}
proc getLastError*(): int32 {.importc: "GetLastError",
@ -193,7 +199,7 @@ when useWinUnicode:
proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {.
stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}
proc getModuleFileNameW*(handle: THandle, buf: WideCString,
proc getModuleFileNameW*(handle: Handle, buf: WideCString,
size: int32): int32 {.importc: "GetModuleFileNameW",
dynlib: "kernel32", stdcall.}
else:
@ -208,7 +214,7 @@ else:
proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {.
stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".}
proc getModuleFileNameA*(handle: THandle, buf: cstring, size: int32): int32 {.
proc getModuleFileNameA*(handle: Handle, buf: cstring, size: int32): int32 {.
importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
when useWinUnicode:
@ -239,34 +245,35 @@ const
MAX_PATH* = 260
type
TWIN32_FIND_DATA* {.pure.} = object
WIN32_FIND_DATA* {.pure.} = object
dwFileAttributes*: int32
ftCreationTime*: TFILETIME
ftLastAccessTime*: TFILETIME
ftLastWriteTime*: TFILETIME
ftCreationTime*: FILETIME
ftLastAccessTime*: FILETIME
ftLastWriteTime*: FILETIME
nFileSizeHigh*: int32
nFileSizeLow*: int32
dwReserved0: int32
dwReserved1: int32
cFileName*: array[0..(MAX_PATH) - 1, TWinChar]
cAlternateFileName*: array[0..13, TWinChar]
cFileName*: array[0..(MAX_PATH) - 1, WinChar]
cAlternateFileName*: array[0..13, WinChar]
{.deprecated: [TWIN32_FIND_DATA: WIN32_FIND_DATA].}
when useWinUnicode:
proc findFirstFileW*(lpFileName: WideCString,
lpFindFileData: var TWIN32_FIND_DATA): THandle {.
lpFindFileData: var WIN32_FIND_DATA): Handle {.
stdcall, dynlib: "kernel32", importc: "FindFirstFileW".}
proc findNextFileW*(hFindFile: THandle,
lpFindFileData: var TWIN32_FIND_DATA): int32 {.
proc findNextFileW*(hFindFile: Handle,
lpFindFileData: var WIN32_FIND_DATA): int32 {.
stdcall, dynlib: "kernel32", importc: "FindNextFileW".}
else:
proc findFirstFileA*(lpFileName: cstring,
lpFindFileData: var TWIN32_FIND_DATA): THANDLE {.
lpFindFileData: var WIN32_FIND_DATA): THANDLE {.
stdcall, dynlib: "kernel32", importc: "FindFirstFileA".}
proc findNextFileA*(hFindFile: THANDLE,
lpFindFileData: var TWIN32_FIND_DATA): int32 {.
lpFindFileData: var WIN32_FIND_DATA): int32 {.
stdcall, dynlib: "kernel32", importc: "FindNextFileA".}
proc findClose*(hFindFile: THandle) {.stdcall, dynlib: "kernel32",
proc findClose*(hFindFile: Handle) {.stdcall, dynlib: "kernel32",
importc: "FindClose".}
when useWinUnicode:
@ -326,32 +333,32 @@ else:
proc getCommandLineA*(): cstring {.
importc: "GetCommandLineA", stdcall, dynlib: "kernel32".}
proc rdFileTime*(f: TFILETIME): int64 =
proc rdFileTime*(f: FILETIME): int64 =
result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32)
proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
proc rdFileSize*(f: WIN32_FIND_DATA): int64 =
result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32)
proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var FILETIME) {.
importc: "GetSystemTimeAsFileTime", dynlib: "kernel32", stdcall.}
proc sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32",
importc: "Sleep".}
when useWinUnicode:
proc shellExecuteW*(HWND: THandle, lpOperation, lpFile,
proc shellExecuteW*(HWND: Handle, lpOperation, lpFile,
lpParameters, lpDirectory: WideCString,
nShowCmd: int32): THandle{.
nShowCmd: int32): Handle{.
stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW".}
else:
proc shellExecuteA*(HWND: THandle, lpOperation, lpFile,
proc shellExecuteA*(HWND: Handle, lpOperation, lpFile,
lpParameters, lpDirectory: cstring,
nShowCmd: int32): THandle{.
nShowCmd: int32): Handle{.
stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
proc getFileInformationByHandle*(hFile: THandle,
lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{.
proc getFileInformationByHandle*(hFile: Handle,
lpFileInformation: ptr BY_HANDLE_FILE_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}
const
@ -374,7 +381,6 @@ proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
type
SocketHandle* = distinct int
{.deprecated: [TSocketHandle: SocketHandle].}
type
@ -451,7 +457,6 @@ type
ai_next*: ptr AddrInfo ## Pointer to next in list.
SockLen* = cuint
{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo,
TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval,
TWSADATA: WSADATA, Thostent: Hostent, TServent: Servent,
@ -571,8 +576,9 @@ const
MAXIMUM_WAIT_OBJECTS* = 0x00000040
type
TWOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, THandle]
PWOHandleArray* = ptr TWOHandleArray
WOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, Handle]
PWOHandleArray* = ptr WOHandleArray
{.deprecated: [TWOHandleArray: WOHandleArray].}
proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
@ -613,7 +619,7 @@ when useWinUnicode:
proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
lpSecurityAttributes: pointer,
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
hTemplateFile: THandle): THandle {.
hTemplateFile: Handle): Handle {.
stdcall, dynlib: "kernel32", importc: "CreateFileW".}
proc deleteFileW*(pathName: WideCString): int32 {.
importc: "DeleteFileW", dynlib: "kernel32", stdcall.}
@ -626,28 +632,28 @@ else:
proc deleteFileA*(pathName: cstring): int32 {.
importc: "DeleteFileA", dynlib: "kernel32", stdcall.}
proc setEndOfFile*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
proc setEndOfFile*(hFile: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "SetEndOfFile".}
proc setFilePointer*(hFile: THandle, lDistanceToMove: LONG,
proc setFilePointer*(hFile: Handle, lDistanceToMove: LONG,
lpDistanceToMoveHigh: ptr LONG,
dwMoveMethod: DWORD): DWORD {.
stdcall, dynlib: "kernel32", importc: "SetFilePointer".}
proc getFileSize*(hFile: THandle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
proc getFileSize*(hFile: Handle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
dynlib: "kernel32", importc: "GetFileSize".}
proc mapViewOfFileEx*(hFileMappingObject: THandle, dwDesiredAccess: DWORD,
proc mapViewOfFileEx*(hFileMappingObject: Handle, dwDesiredAccess: DWORD,
dwFileOffsetHigh, dwFileOffsetLow: DWORD,
dwNumberOfBytesToMap: DWORD,
lpBaseAddress: pointer): pointer{.
stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".}
proc createFileMappingW*(hFile: THandle,
proc createFileMappingW*(hFile: Handle,
lpFileMappingAttributes: pointer,
flProtect, dwMaximumSizeHigh: DWORD,
dwMaximumSizeLow: DWORD,
lpName: pointer): THandle {.
lpName: pointer): Handle {.
stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}
when not useWinUnicode:
@ -661,23 +667,24 @@ proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "UnmapViewOfFile".}
type
TOVERLAPPED* {.pure, inheritable.} = object
OVERLAPPED* {.pure, inheritable.} = object
internal*: PULONG
internalHigh*: PULONG
offset*: DWORD
offsetHigh*: DWORD
hEvent*: THandle
hEvent*: Handle
POVERLAPPED* = ptr TOVERLAPPED
POVERLAPPED* = ptr OVERLAPPED
POVERLAPPED_COMPLETION_ROUTINE* = proc (para1: DWORD, para2: DWORD,
para3: POVERLAPPED){.stdcall.}
TGUID* {.final, pure.} = object
GUID* {.final, pure.} = object
D1*: int32
D2*: int16
D3*: int16
D4*: array [0..7, int8]
{.deprecated: [TOVERLAPPED: OVERLAPPED, TGUID: GUID].}
const
ERROR_IO_PENDING* = 997 # a.k.a WSA_IO_PENDING
@ -689,18 +696,18 @@ const
WSAETIMEDOUT* = 10060
ERROR_NETNAME_DELETED* = 64
proc createIoCompletionPort*(FileHandle: THandle, ExistingCompletionPort: THandle,
proc createIoCompletionPort*(FileHandle: Handle, ExistingCompletionPort: Handle,
CompletionKey: DWORD,
NumberOfConcurrentThreads: DWORD): THandle{.stdcall,
NumberOfConcurrentThreads: DWORD): Handle{.stdcall,
dynlib: "kernel32", importc: "CreateIoCompletionPort".}
proc getQueuedCompletionStatus*(CompletionPort: THandle,
proc getQueuedCompletionStatus*(CompletionPort: Handle,
lpNumberOfBytesTransferred: PDWORD, lpCompletionKey: PULONG,
lpOverlapped: ptr POVERLAPPED,
dwMilliseconds: DWORD): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "GetQueuedCompletionStatus".}
proc getOverlappedResult*(hFile: THandle, lpOverlapped: TOVERLAPPED,
proc getOverlappedResult*(hFile: Handle, lpOverlapped: OVERLAPPED,
lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
@ -717,11 +724,11 @@ const
SO_UPDATE_ACCEPT_CONTEXT* = 0x700B
var
WSAID_CONNECTEX*: TGUID = TGUID(D1: 0x25a207b9, D2: 0xddf3'i16, D3: 0x4660, D4: [
WSAID_CONNECTEX*: GUID = GUID(D1: 0x25a207b9, D2: 0xddf3'i16, D3: 0x4660, D4: [
0x8e'i8, 0xe9'i8, 0x76'i8, 0xe5'i8, 0x8c'i8, 0x74'i8, 0x06'i8, 0x3e'i8])
WSAID_ACCEPTEX*: TGUID = TGUID(D1: 0xb5367df1'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
WSAID_ACCEPTEX*: GUID = GUID(D1: 0xb5367df1'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8])
WSAID_GETACCEPTEXSOCKADDRS*: TGUID = TGUID(D1: 0xb5367df2'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
WSAID_GETACCEPTEXSOCKADDRS*: GUID = GUID(D1: 0xb5367df2'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8])
proc WSAIoctl*(s: SocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer,
@ -745,13 +752,13 @@ proc WSASend*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
stdcall, importc: "WSASend", dynlib: "Ws2_32.dll".}
proc get_osfhandle*(fd:FileHandle): THandle {.
proc get_osfhandle*(fd:FileHandle): Handle {.
importc: "_get_osfhandle", header:"<io.h>".}
proc getSystemTimes*(lpIdleTime, lpKernelTime,
lpUserTime: var TFILETIME): WINBOOL {.stdcall,
lpUserTime: var FILETIME): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "GetSystemTimes".}
proc getProcessTimes*(hProcess: THandle; lpCreationTime, lpExitTime,
lpKernelTime, lpUserTime: var TFILETIME): WINBOOL {.stdcall,
proc getProcessTimes*(hProcess: Handle; lpCreationTime, lpExitTime,
lpKernelTime, lpUserTime: var FILETIME): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "GetProcessTimes".}

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more