Merge branch 'master' of https://github.com/Araq/Nimrod
This commit is contained in:
commit
4855055bca
52 changed files with 3526 additions and 2362 deletions
|
|
@ -712,7 +712,6 @@ type
|
||||||
# -1 means that the size is unkwown
|
# -1 means that the size is unkwown
|
||||||
align*: int # the type's alignment requirements
|
align*: int # the type's alignment requirements
|
||||||
loc*: TLoc
|
loc*: TLoc
|
||||||
testeeName*: PIdent # the test variable in user-defined type classes
|
|
||||||
|
|
||||||
TPair*{.final.} = object
|
TPair*{.final.} = object
|
||||||
key*, val*: PObject
|
key*, val*: PObject
|
||||||
|
|
@ -1088,7 +1087,6 @@ proc assignType(dest, src: PType) =
|
||||||
dest.size = src.size
|
dest.size = src.size
|
||||||
dest.align = src.align
|
dest.align = src.align
|
||||||
dest.destructor = src.destructor
|
dest.destructor = src.destructor
|
||||||
dest.testeeName = src.testeeName
|
|
||||||
# this fixes 'type TLock = TSysLock':
|
# this fixes 'type TLock = TSysLock':
|
||||||
if src.sym != nil:
|
if src.sym != nil:
|
||||||
if dest.sym != nil:
|
if dest.sym != nil:
|
||||||
|
|
|
||||||
|
|
@ -583,7 +583,7 @@ proc CallCCompiler*(projectfile: string) =
|
||||||
else:
|
else:
|
||||||
rawMessage(errGenerated, " execution of an external program failed; " &
|
rawMessage(errGenerated, " execution of an external program failed; " &
|
||||||
"rerun with --parallelBuild:1 to see the error message")
|
"rerun with --parallelBuild:1 to see the error message")
|
||||||
if optNoLinking notin gGlobalOptions and cmds.len > 0:
|
if optNoLinking notin gGlobalOptions:
|
||||||
# call the linker:
|
# call the linker:
|
||||||
var it = PStrEntry(toLink.head)
|
var it = PStrEntry(toLink.head)
|
||||||
var objfiles = ""
|
var objfiles = ""
|
||||||
|
|
|
||||||
|
|
@ -437,6 +437,13 @@ type
|
||||||
line*, col*: int16
|
line*, col*: int16
|
||||||
fileIndex*: int32
|
fileIndex*: int32
|
||||||
|
|
||||||
|
TErrorOutput* = enum
|
||||||
|
eStdOut
|
||||||
|
eStdErr
|
||||||
|
eInMemory
|
||||||
|
|
||||||
|
TErrorOutputs* = set[TErrorOutput]
|
||||||
|
|
||||||
ERecoverableError* = object of EInvalidValue
|
ERecoverableError* = object of EInvalidValue
|
||||||
ESuggestDone* = object of EBase
|
ESuggestDone* = object of EBase
|
||||||
|
|
||||||
|
|
@ -534,13 +541,27 @@ var
|
||||||
gHintCounter*: int = 0
|
gHintCounter*: int = 0
|
||||||
gWarnCounter*: int = 0
|
gWarnCounter*: int = 0
|
||||||
gErrorMax*: int = 1 # stop after gErrorMax errors
|
gErrorMax*: int = 1 # stop after gErrorMax errors
|
||||||
gSilence*: int # == 0 if we produce any output at all
|
|
||||||
|
|
||||||
when useCaas:
|
when useCaas:
|
||||||
var stdoutSocket*: TSocket
|
var stdoutSocket*: TSocket
|
||||||
|
|
||||||
|
proc UnknownLineInfo*(): TLineInfo =
|
||||||
|
result.line = int16(-1)
|
||||||
|
result.col = int16(-1)
|
||||||
|
result.fileIndex = -1
|
||||||
|
|
||||||
|
var
|
||||||
|
msgContext: seq[TLineInfo] = @[]
|
||||||
|
lastError = UnknownLineInfo()
|
||||||
|
bufferedMsgs*: seq[string]
|
||||||
|
|
||||||
|
errorOutputs* = {eStdOut, eStdErr}
|
||||||
|
|
||||||
|
proc clearBufferedMsgs* =
|
||||||
|
bufferedMsgs = nil
|
||||||
|
|
||||||
proc SuggestWriteln*(s: string) =
|
proc SuggestWriteln*(s: string) =
|
||||||
if gSilence == 0:
|
if eStdOut in errorOutputs:
|
||||||
when useCaas:
|
when useCaas:
|
||||||
if isNil(stdoutSocket): Writeln(stdout, s)
|
if isNil(stdoutSocket): Writeln(stdout, s)
|
||||||
else:
|
else:
|
||||||
|
|
@ -549,6 +570,9 @@ proc SuggestWriteln*(s: string) =
|
||||||
else:
|
else:
|
||||||
Writeln(stdout, s)
|
Writeln(stdout, s)
|
||||||
|
|
||||||
|
if eInMemory in errorOutputs:
|
||||||
|
bufferedMsgs.safeAdd(s)
|
||||||
|
|
||||||
proc SuggestQuit*() =
|
proc SuggestQuit*() =
|
||||||
if not isServing:
|
if not isServing:
|
||||||
quit(0)
|
quit(0)
|
||||||
|
|
@ -570,14 +594,6 @@ const
|
||||||
RawWarningFormat* = "Warning: $1"
|
RawWarningFormat* = "Warning: $1"
|
||||||
RawHintFormat* = "Hint: $1"
|
RawHintFormat* = "Hint: $1"
|
||||||
|
|
||||||
proc UnknownLineInfo*(): TLineInfo =
|
|
||||||
result.line = int16(-1)
|
|
||||||
result.col = int16(-1)
|
|
||||||
result.fileIndex = -1
|
|
||||||
|
|
||||||
var
|
|
||||||
msgContext: seq[TLineInfo] = @[]
|
|
||||||
|
|
||||||
proc getInfoContextLen*(): int = return msgContext.len
|
proc getInfoContextLen*(): int = return msgContext.len
|
||||||
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
|
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
|
||||||
|
|
||||||
|
|
@ -642,14 +658,18 @@ proc addCheckpoint*(filename: string, line: int) =
|
||||||
|
|
||||||
proc OutWriteln*(s: string) =
|
proc OutWriteln*(s: string) =
|
||||||
## Writes to stdout. Always.
|
## Writes to stdout. Always.
|
||||||
if gSilence == 0: Writeln(stdout, s)
|
if eStdOut in errorOutputs: Writeln(stdout, s)
|
||||||
|
|
||||||
proc MsgWriteln*(s: string) =
|
proc MsgWriteln*(s: string) =
|
||||||
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
## Writes to stdout. If --stdout option is given, writes to stderr instead.
|
||||||
if gSilence == 0:
|
|
||||||
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||||
if optStdout in gGlobalOptions: Writeln(stderr, s)
|
|
||||||
else: Writeln(stdout, s)
|
if optStdout in gGlobalOptions:
|
||||||
|
if eStdErr in errorOutputs: Writeln(stderr, s)
|
||||||
|
else:
|
||||||
|
if eStdOut in errorOutputs: Writeln(stdout, s)
|
||||||
|
|
||||||
|
if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
|
||||||
|
|
||||||
proc coordToStr(coord: int): string =
|
proc coordToStr(coord: int): string =
|
||||||
if coord == -1: result = "???"
|
if coord == -1: result = "???"
|
||||||
|
|
@ -736,9 +756,6 @@ proc rawMessage*(msg: TMsgKind, args: openarray[string]) =
|
||||||
proc rawMessage*(msg: TMsgKind, arg: string) =
|
proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||||
rawMessage(msg, [arg])
|
rawMessage(msg, [arg])
|
||||||
|
|
||||||
var
|
|
||||||
lastError = UnknownLineInfo()
|
|
||||||
|
|
||||||
proc writeSurroundingSrc(info: TLineInfo) =
|
proc writeSurroundingSrc(info: TLineInfo) =
|
||||||
const indent = " "
|
const indent = " "
|
||||||
MsgWriteln(indent & info.sourceLine.ropeToStr)
|
MsgWriteln(indent & info.sourceLine.ropeToStr)
|
||||||
|
|
|
||||||
|
|
@ -1624,10 +1624,23 @@ proc parseObject(p: var TParser): PNode =
|
||||||
return
|
return
|
||||||
addSon(result, parseObjectPart(p))
|
addSon(result, parseObjectPart(p))
|
||||||
|
|
||||||
|
proc parseTypeClassParam(p: var TParser): PNode =
|
||||||
|
if p.tok.tokType == tkVar:
|
||||||
|
getTok(p)
|
||||||
|
result = newNode(nkVarTy)
|
||||||
|
result.addSon(p.parseSymbol)
|
||||||
|
else:
|
||||||
|
result = p.parseSymbol
|
||||||
|
|
||||||
proc parseTypeClass(p: var TParser): PNode =
|
proc parseTypeClass(p: var TParser): PNode =
|
||||||
result = newNodeP(nkTypeClassTy, p)
|
result = newNodeP(nkTypeClassTy, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
addSon(result, p.parseSymbol)
|
var args = newNode(nkArgList)
|
||||||
|
addSon(result, args)
|
||||||
|
addSon(args, p.parseTypeClassParam)
|
||||||
|
while p.tok.TokType == tkComma:
|
||||||
|
getTok(p)
|
||||||
|
addSon(args, p.parseTypeClassParam)
|
||||||
if p.tok.tokType == tkCurlyDotLe and p.validInd:
|
if p.tok.tokType == tkCurlyDotLe and p.validInd:
|
||||||
addSon(result, parsePragma(p))
|
addSon(result, parsePragma(p))
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
||||||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
proc tryExpr(c: PContext, n: PNode,
|
||||||
|
flags: TExprFlags = {}, bufferErrors = false): PNode
|
||||||
proc fixImmediateParams(n: PNode): PNode
|
proc fixImmediateParams(n: PNode): PNode
|
||||||
proc activate(c: PContext, n: PNode)
|
proc activate(c: PContext, n: PNode)
|
||||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ type
|
||||||
threadEntries*: TSymSeq # list of thread entries to check
|
threadEntries*: TSymSeq # list of thread entries to check
|
||||||
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
|
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
|
||||||
# store this info in the syms themselves!)
|
# store this info in the syms themselves!)
|
||||||
|
InTypeClass*: int # > 0 if we are in a user-defined type class
|
||||||
InGenericContext*: int # > 0 if we are in a generic type
|
InGenericContext*: int # > 0 if we are in a generic type
|
||||||
InUnrolledContext*: int # > 0 if we are unrolling a loop
|
InUnrolledContext*: int # > 0 if we are unrolling a loop
|
||||||
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
|
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
|
||||||
|
|
@ -72,7 +73,8 @@ type
|
||||||
libs*: TLinkedList # all libs used by this module
|
libs*: TLinkedList # all libs used by this module
|
||||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
|
||||||
|
bufferErrors = false): PNode {.nimcall.}
|
||||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||||
n.typ = getSysType(tyBool)
|
n.typ = getSysType(tyBool)
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc IsOpImpl(c: PContext, n: PNode): PNode =
|
proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||||
InternalAssert n.sonsLen == 3 and
|
InternalAssert n.sonsLen == 3 and
|
||||||
n[1].kind == nkSym and n[1].sym.kind == skType and
|
n[1].kind == nkSym and n[1].sym.kind == skType and
|
||||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||||
|
|
@ -321,10 +321,19 @@ proc IsOpImpl(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
var match: bool
|
var match: bool
|
||||||
let t2 = n[2].typ
|
let t2 = n[2].typ
|
||||||
if t2.kind == tyTypeClass:
|
case t2.kind
|
||||||
|
of tyTypeClass:
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
InitCandidate(m, t2)
|
InitCandidate(m, t2)
|
||||||
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
|
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
|
||||||
|
of tyOrdinal:
|
||||||
|
var m: TCandidate
|
||||||
|
InitCandidate(m, t2)
|
||||||
|
match = isOrdinalType(t1)
|
||||||
|
of tySequence, tyArray, tySet:
|
||||||
|
var m: TCandidate
|
||||||
|
InitCandidate(m, t2)
|
||||||
|
match = typeRel(m, t2, t1) != isNone
|
||||||
else:
|
else:
|
||||||
match = sameType(t1, t2)
|
match = sameType(t1, t2)
|
||||||
|
|
||||||
|
|
@ -353,7 +362,7 @@ proc semIs(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
let t1 = n[1].typ.sons[0]
|
let t1 = n[1].typ.sons[0]
|
||||||
# BUGFIX: don't evaluate this too early: ``T is void``
|
# BUGFIX: don't evaluate this too early: ``T is void``
|
||||||
if not containsGenericType(t1): result = IsOpImpl(c, n)
|
if not containsGenericType(t1): result = isOpImpl(c, n)
|
||||||
|
|
||||||
proc semOpAux(c: PContext, n: PNode) =
|
proc semOpAux(c: PContext, n: PNode) =
|
||||||
const flags = {efDetermineType}
|
const flags = {efDetermineType}
|
||||||
|
|
@ -763,6 +772,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||||
analyseIfAddressTakenInCall(c, result)
|
analyseIfAddressTakenInCall(c, result)
|
||||||
if callee.magic != mNone:
|
if callee.magic != mNone:
|
||||||
result = magicsAfterOverloadResolution(c, result, flags)
|
result = magicsAfterOverloadResolution(c, result, flags)
|
||||||
|
if c.InTypeClass == 0:
|
||||||
result = evalAtCompileTime(c, result)
|
result = evalAtCompileTime(c, result)
|
||||||
|
|
||||||
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
@ -814,7 +824,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
proc semExprNoType(c: PContext, n: PNode): PNode =
|
proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||||
result = semExpr(c, n, {efWantStmt})
|
result = semExpr(c, n, {efWantStmt})
|
||||||
discardCheck(result)
|
discardCheck(c, result)
|
||||||
|
|
||||||
proc isTypeExpr(n: PNode): bool =
|
proc isTypeExpr(n: PNode): bool =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -1208,7 +1218,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||||
a.sons[1] = result
|
a.sons[1] = result
|
||||||
result = semAsgn(c, a)
|
result = semAsgn(c, a)
|
||||||
else:
|
else:
|
||||||
discardCheck(result)
|
discardCheck(c, result)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
||||||
|
|
@ -1429,12 +1439,12 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||||
newNode(nkCall, n.info, quotes)])
|
newNode(nkCall, n.info, quotes)])
|
||||||
result = semExpandToAst(c, result)
|
result = semExpandToAst(c, result)
|
||||||
|
|
||||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc tryExpr(c: PContext, n: PNode,
|
||||||
|
flags: TExprFlags = {}, bufferErrors = false): PNode =
|
||||||
# watch out, hacks ahead:
|
# watch out, hacks ahead:
|
||||||
let oldErrorCount = msgs.gErrorCounter
|
let oldErrorCount = msgs.gErrorCounter
|
||||||
let oldErrorMax = msgs.gErrorMax
|
let oldErrorMax = msgs.gErrorMax
|
||||||
inc c.InCompilesContext
|
inc c.InCompilesContext
|
||||||
inc msgs.gSilence
|
|
||||||
# do not halt after first error:
|
# do not halt after first error:
|
||||||
msgs.gErrorMax = high(int)
|
msgs.gErrorMax = high(int)
|
||||||
|
|
||||||
|
|
@ -1443,6 +1453,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
openScope(c)
|
openScope(c)
|
||||||
let oldOwnerLen = len(gOwners)
|
let oldOwnerLen = len(gOwners)
|
||||||
let oldGenerics = c.generics
|
let oldGenerics = c.generics
|
||||||
|
let oldErrorOutputs = errorOutputs
|
||||||
|
errorOutputs = if bufferErrors: {eInMemory} else: {}
|
||||||
let oldContextLen = msgs.getInfoContextLen()
|
let oldContextLen = msgs.getInfoContextLen()
|
||||||
|
|
||||||
let oldInGenericContext = c.InGenericContext
|
let oldInGenericContext = c.InGenericContext
|
||||||
|
|
@ -1465,7 +1477,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
setlen(gOwners, oldOwnerLen)
|
setlen(gOwners, oldOwnerLen)
|
||||||
c.currentScope = oldScope
|
c.currentScope = oldScope
|
||||||
dec c.InCompilesContext
|
dec c.InCompilesContext
|
||||||
dec msgs.gSilence
|
errorOutputs = oldErrorOutputs
|
||||||
msgs.gErrorCounter = oldErrorCount
|
msgs.gErrorCounter = oldErrorCount
|
||||||
msgs.gErrorMax = oldErrorMax
|
msgs.gErrorMax = oldErrorMax
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ proc fixNilType(n: PNode) =
|
||||||
for it in n: fixNilType(it)
|
for it in n: fixNilType(it)
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
|
|
||||||
proc discardCheck(result: PNode) =
|
proc discardCheck(c: PContext, result: PNode) =
|
||||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
|
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
|
||||||
if result.kind == nkNilLit:
|
if result.kind == nkNilLit:
|
||||||
result.typ = nil
|
result.typ = nil
|
||||||
|
|
@ -142,6 +142,10 @@ proc discardCheck(result: PNode) =
|
||||||
while n.kind in skipForDiscardable:
|
while n.kind in skipForDiscardable:
|
||||||
n = n.lastSon
|
n = n.lastSon
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
|
elif c.InTypeClass > 0 and result.typ.kind == tyBool:
|
||||||
|
let verdict = semConstExpr(c, result)
|
||||||
|
if verdict.intVal == 0:
|
||||||
|
localError(result.info, "type class predicate failed.")
|
||||||
elif result.typ.kind != tyError and gCmd != cmdInteractive:
|
elif result.typ.kind != tyError and gCmd != cmdInteractive:
|
||||||
if result.typ.kind == tyNil:
|
if result.typ.kind == tyNil:
|
||||||
fixNilType(result)
|
fixNilType(result)
|
||||||
|
|
@ -169,7 +173,7 @@ proc semIf(c: PContext, n: PNode): PNode =
|
||||||
typ = commonType(typ, it.sons[0].typ)
|
typ = commonType(typ, it.sons[0].typ)
|
||||||
else: illFormedAst(it)
|
else: illFormedAst(it)
|
||||||
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
|
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
|
||||||
for it in n: discardCheck(it.lastSon)
|
for it in n: discardCheck(c, it.lastSon)
|
||||||
result.kind = nkIfStmt
|
result.kind = nkIfStmt
|
||||||
# propagate any enforced VoidContext:
|
# propagate any enforced VoidContext:
|
||||||
if typ == EnforceVoidContext: result.typ = EnforceVoidContext
|
if typ == EnforceVoidContext: result.typ = EnforceVoidContext
|
||||||
|
|
@ -230,7 +234,7 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
localError(n.info, errNotAllCasesCovered)
|
localError(n.info, errNotAllCasesCovered)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
|
if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
|
||||||
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
|
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
||||||
# propagate any enforced VoidContext:
|
# propagate any enforced VoidContext:
|
||||||
if typ == EnforceVoidContext:
|
if typ == EnforceVoidContext:
|
||||||
result.typ = EnforceVoidContext
|
result.typ = EnforceVoidContext
|
||||||
|
|
@ -275,8 +279,8 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
typ = commonType(typ, a.sons[length-1].typ)
|
typ = commonType(typ, a.sons[length-1].typ)
|
||||||
dec c.p.inTryStmt
|
dec c.p.inTryStmt
|
||||||
if isEmptyType(typ) or typ.kind == tyNil:
|
if isEmptyType(typ) or typ.kind == tyNil:
|
||||||
discardCheck(n.sons[0])
|
discardCheck(c, n.sons[0])
|
||||||
for i in 1..n.len-1: discardCheck(n.sons[i].lastSon)
|
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
||||||
if typ == EnforceVoidContext:
|
if typ == EnforceVoidContext:
|
||||||
result.typ = EnforceVoidContext
|
result.typ = EnforceVoidContext
|
||||||
else:
|
else:
|
||||||
|
|
@ -880,7 +884,8 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||||
illFormedAst(n) # process parameters:
|
illFormedAst(n) # process parameters:
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
if n.sons[paramsPos].kind != nkEmpty:
|
||||||
semParamList(c, n.sons[ParamsPos], nil, s)
|
var gp = newNodeI(nkGenericParams, n.info)
|
||||||
|
semParamList(c, n.sons[ParamsPos], gp, s)
|
||||||
ParamsTypeCheck(c, s.typ)
|
ParamsTypeCheck(c, s.typ)
|
||||||
else:
|
else:
|
||||||
s.typ = newTypeS(tyProc, c)
|
s.typ = newTypeS(tyProc, c)
|
||||||
|
|
@ -1104,24 +1109,24 @@ proc finishMethod(c: PContext, s: PSym) =
|
||||||
methodDef(s, false)
|
methodDef(s, false)
|
||||||
|
|
||||||
proc semMethod(c: PContext, n: PNode): PNode =
|
proc semMethod(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "method")
|
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
|
||||||
result = semProcAux(c, n, skMethod, methodPragmas)
|
result = semProcAux(c, n, skMethod, methodPragmas)
|
||||||
|
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
if not isGenericRoutine(s):
|
if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
|
||||||
if hasObjParam(s):
|
if hasObjParam(s):
|
||||||
methodDef(s, false)
|
methodDef(s, fromCache=false)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errXNeedsParamObjectType, "method")
|
localError(n.info, errXNeedsParamObjectType, "method")
|
||||||
|
|
||||||
proc semConverterDef(c: PContext, n: PNode): PNode =
|
proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
|
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
result = semProcAux(c, n, skConverter, converterPragmas)
|
result = semProcAux(c, n, skConverter, converterPragmas)
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "converter")
|
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter")
|
||||||
if sonsLen(t) != 2: LocalError(n.info, errXRequiresOneArgument, "converter")
|
if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
|
||||||
addConverter(c, s)
|
addConverter(c, s)
|
||||||
|
|
||||||
proc semMacroDef(c: PContext, n: PNode): PNode =
|
proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -1129,9 +1134,9 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
result = semProcAux(c, n, skMacro, macroPragmas)
|
result = semProcAux(c, n, skMacro, macroPragmas)
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "macro")
|
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
|
||||||
if n.sons[bodyPos].kind == nkEmpty:
|
if n.sons[bodyPos].kind == nkEmpty:
|
||||||
LocalError(n.info, errImplOfXexpected, s.name.s)
|
localError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
||||||
proc evalInclude(c: PContext, n: PNode): PNode =
|
proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkStmtList, n.info)
|
result = newNodeI(nkStmtList, n.info)
|
||||||
|
|
@ -1221,7 +1226,7 @@ proc semStmtList(c: PContext, n: PNode): PNode =
|
||||||
voidContext = true
|
voidContext = true
|
||||||
n.typ = EnforceVoidContext
|
n.typ = EnforceVoidContext
|
||||||
if i != last or voidContext:
|
if i != last or voidContext:
|
||||||
discardCheck(n.sons[i])
|
discardCheck(c, n.sons[i])
|
||||||
else:
|
else:
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
if not isEmptyType(n.typ):
|
if not isEmptyType(n.typ):
|
||||||
|
|
|
||||||
|
|
@ -876,8 +876,7 @@ proc freshType(res, prev: PType): PType {.inline.} =
|
||||||
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||||
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
# if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
|
||||||
result = newOrPrevType(tyTypeClass, prev, c)
|
result = newOrPrevType(tyTypeClass, prev, c)
|
||||||
result.testeeName = considerAcc(n[0])
|
result.n = n
|
||||||
result.n = n[3]
|
|
||||||
|
|
||||||
let
|
let
|
||||||
pragmas = n[1]
|
pragmas = n[1]
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
|
||||||
c.calleeSym = callee
|
c.calleeSym = callee
|
||||||
c.calleeScope = calleeScope
|
c.calleeScope = calleeScope
|
||||||
initIdTable(c.bindings)
|
initIdTable(c.bindings)
|
||||||
|
c.errors = nil
|
||||||
if binding != nil and callee.kind in RoutineKinds:
|
if binding != nil and callee.kind in RoutineKinds:
|
||||||
var typeParams = callee.ast[genericParamsPos]
|
var typeParams = callee.ast[genericParamsPos]
|
||||||
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
|
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
|
||||||
|
|
@ -202,7 +203,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||||
add(result, argTypeToString(arg))
|
add(result, argTypeToString(arg))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation
|
proc typeRel*(c: var TCandidate, f, a: PType): TTypeRelation
|
||||||
proc concreteType(c: TCandidate, t: PType): PType =
|
proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyArrayConstr:
|
of tyArrayConstr:
|
||||||
|
|
@ -750,40 +751,55 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
|
|
||||||
# pushInfoContext(arg.info)
|
# pushInfoContext(arg.info)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
inc c.InTypeClass
|
||||||
|
|
||||||
var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info)
|
finally:
|
||||||
testee.typ = a
|
dec c.InTypeClass
|
||||||
addDecl(c, testee)
|
closeScope(c)
|
||||||
|
|
||||||
|
for param in f.n[0]:
|
||||||
|
var
|
||||||
|
dummyName: PNode
|
||||||
|
dummyType: PType
|
||||||
|
|
||||||
|
if param.kind == nkVarTy:
|
||||||
|
dummyName = param[0]
|
||||||
|
dummyType = makeVarType(c, a)
|
||||||
|
else:
|
||||||
|
dummyName = param
|
||||||
|
dummyType = a
|
||||||
|
|
||||||
|
InternalAssert dummyName.kind == nkIdent
|
||||||
|
var dummyParam = newSym(skType, dummyName.ident, f.sym, f.sym.info)
|
||||||
|
dummyParam.typ = dummyType
|
||||||
|
addDecl(c, dummyParam)
|
||||||
|
|
||||||
|
for stmt in f.n[3]:
|
||||||
|
var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false)
|
||||||
|
m.errors = bufferedMsgs
|
||||||
|
clearBufferedMsgs()
|
||||||
|
if e == nil: return nil
|
||||||
|
|
||||||
for stmt in f.n:
|
|
||||||
var e = c.semTryExpr(c, copyTree(stmt))
|
|
||||||
if e == nil:
|
|
||||||
let expStr = renderTree(stmt, {renderNoComments})
|
|
||||||
m.errors.safeAdd("can't compile " & expStr & " for " & a.typeToString)
|
|
||||||
return nil
|
|
||||||
case e.kind
|
case e.kind
|
||||||
of nkReturnStmt:
|
of nkReturnStmt: nil
|
||||||
nil
|
|
||||||
of nkTypeSection: nil
|
of nkTypeSection: nil
|
||||||
of nkConstDef: nil
|
of nkConstDef: nil
|
||||||
else:
|
else: nil
|
||||||
if e.typ.kind == tyBool:
|
|
||||||
let verdict = c.semConstExpr(c, e)
|
|
||||||
if verdict.intVal == 0:
|
|
||||||
let expStr = renderTree(stmt, {renderNoComments})
|
|
||||||
m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString)
|
|
||||||
return nil
|
|
||||||
|
|
||||||
closeScope(c)
|
|
||||||
|
|
||||||
result = arg
|
result = arg
|
||||||
put(m.bindings, f, a)
|
put(m.bindings, f, a)
|
||||||
|
|
||||||
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
|
||||||
argSemantized, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
var arg = argSemantized
|
var
|
||||||
var r: TTypeRelation
|
r: TTypeRelation
|
||||||
let fMaybeExpr = f.skipTypes({tyDistinct})
|
arg = argSemantized
|
||||||
|
|
||||||
|
let
|
||||||
|
a = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc})
|
||||||
|
else: argType
|
||||||
|
fMaybeExpr = f.skipTypes({tyDistinct})
|
||||||
|
|
||||||
case fMaybeExpr.kind
|
case fMaybeExpr.kind
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
if fMaybeExpr.sonsLen == 0:
|
if fMaybeExpr.sonsLen == 0:
|
||||||
|
|
|
||||||
|
|
@ -837,8 +837,12 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
result = sameObjectStructures(a, b, c) and sameFlags(a, b)
|
result = sameObjectStructures(a, b, c) and sameFlags(a, b)
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
CycleCheck()
|
CycleCheck()
|
||||||
if c.cmp == dcEq: result = sameDistinctTypes(a, b) and sameFlags(a, b)
|
if c.cmp == dcEq:
|
||||||
else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
|
if sameFlags(a, b):
|
||||||
|
IfFastObjectTypeCheckFailed(a, b):
|
||||||
|
result = sameTypeAux(a.sons[0], b.sons[0], c)
|
||||||
|
else:
|
||||||
|
result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
|
||||||
of tyEnum, tyForward, tyProxy:
|
of tyEnum, tyForward, tyProxy:
|
||||||
# XXX generic enums do not make much sense, but require structural checking
|
# XXX generic enums do not make much sense, but require structural checking
|
||||||
result = a.id == b.id and sameFlags(a, b)
|
result = a.id == b.id and sameFlags(a, b)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ Introduction
|
||||||
This document describes how the GC works and how to tune it for
|
This document describes how the GC works and how to tune it for
|
||||||
(soft) `realtime systems`:idx:.
|
(soft) `realtime systems`:idx:.
|
||||||
|
|
||||||
The basic algorithm is *Deferrent Reference Counting* with cycle detection.
|
The basic algorithm is *Deferred Reference Counting* with cycle detection.
|
||||||
References on the stack are not counted for better performance (and easier C
|
References on the stack are not counted for better performance (and easier C
|
||||||
code generation). The GC **never** scans the whole heap but it may scan the
|
code generation). The GC **never** scans the whole heap but it may scan the
|
||||||
delta-subgraph of the heap that changed since its last run.
|
delta-subgraph of the heap that changed since its last run.
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,11 @@ For a release version use::
|
||||||
nimrod c koch.nim
|
nimrod c koch.nim
|
||||||
./koch boot -d:release
|
./koch boot -d:release
|
||||||
|
|
||||||
|
And for a debug version compatible with GDB::
|
||||||
|
|
||||||
|
nimrod c koch.nim
|
||||||
|
./koch boot --debuginfo --linedir:on
|
||||||
|
|
||||||
The ``koch`` program is Nimrod's maintenance script. It is a replacement for
|
The ``koch`` program is Nimrod's maintenance script. It is a replacement for
|
||||||
make and shell scripting with the advantage that it is much more portable.
|
make and shell scripting with the advantage that it is much more portable.
|
||||||
|
|
||||||
|
|
@ -64,7 +69,7 @@ Coding Guidelines
|
||||||
* Max line length is 80 characters.
|
* Max line length is 80 characters.
|
||||||
* Provide spaces around binary operators if that enhances readability.
|
* Provide spaces around binary operators if that enhances readability.
|
||||||
* Use a space after a colon, but not before it.
|
* Use a space after a colon, but not before it.
|
||||||
* Start types with a capital ``T``, unless they are pointers which start
|
* Start types with a capital ``T``, unless they are pointers/references which start
|
||||||
with ``P``.
|
with ``P``.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,8 @@ Core
|
||||||
Collections and algorithms
|
Collections and algorithms
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
* `algorithm <algorithm.html>`_
|
||||||
|
Implements some common generic algorithms like sort or binary search.
|
||||||
* `tables <tables.html>`_
|
* `tables <tables.html>`_
|
||||||
Nimrod hash table support. Contains tables, ordered tables and count tables.
|
Nimrod hash table support. Contains tables, ordered tables and count tables.
|
||||||
* `sets <sets.html>`_
|
* `sets <sets.html>`_
|
||||||
|
|
|
||||||
|
|
@ -893,11 +893,12 @@ integers from 0 to ``len(A)-1``. An array expression may be constructed by the
|
||||||
array constructor ``[]``.
|
array constructor ``[]``.
|
||||||
|
|
||||||
`Sequences`:idx: are similar to arrays but of dynamic length which may change
|
`Sequences`:idx: are similar to arrays but of dynamic length which may change
|
||||||
during runtime (like strings). A sequence ``S`` is always indexed by integers
|
during runtime (like strings). Sequences are implemented as growable arrays,
|
||||||
from 0 to ``len(S)-1`` and its bounds are checked. Sequences can be
|
allocating pieces of memory as items are added. A sequence ``S`` is always
|
||||||
constructed by the array constructor ``[]`` in conjunction with the array to
|
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
|
||||||
sequence operator ``@``. Another way to allocate space for a sequence is to
|
Sequences can be constructed by the array constructor ``[]`` in conjunction
|
||||||
call the built-in ``newSeq`` procedure.
|
with the array to sequence operator ``@``. Another way to allocate space for a
|
||||||
|
sequence is to call the built-in ``newSeq`` procedure.
|
||||||
|
|
||||||
A sequence may be passed to a parameter that is of type *open array*.
|
A sequence may be passed to a parameter that is of type *open array*.
|
||||||
|
|
||||||
|
|
@ -3288,27 +3289,36 @@ Declarative type classes are written in the following form:
|
||||||
for value in c:
|
for value in c:
|
||||||
type(value) is T
|
type(value) is T
|
||||||
|
|
||||||
|
The type class will be matched if:
|
||||||
The identifiers following the `generic` keyword are treated as variables of
|
|
||||||
the matched type and the body of the type class consists of arbitrary code that
|
|
||||||
must be valid under these circumstances.
|
|
||||||
|
|
||||||
Specifically, the type class will be matched if:
|
|
||||||
|
|
||||||
a) all of the expressions within the body can be compiled for the tested type
|
a) all of the expressions within the body can be compiled for the tested type
|
||||||
b) all statically evaluatable boolean expressions in the body must be true
|
b) all statically evaluatable boolean expressions in the body must be true
|
||||||
|
|
||||||
Please note that the ``is`` operator allows you to easily verify the precise type
|
The identifiers following the `generic` keyword represent instances of the
|
||||||
signatures of the required operations, but since type inference and default
|
currently matched type. These instances can act both as variables of the type,
|
||||||
parameters are still applied in the provided block, it's also possible to encode
|
when used in contexts, where a value is expected, and as the type itself, when
|
||||||
usage protocols that doesn't reveal implementation details.
|
used in a contexts, where a type is expected.
|
||||||
|
|
||||||
|
Please note that the ``is`` operator allows you to easily verify the precise
|
||||||
|
type signatures of the required operations, but since type inference and
|
||||||
|
default parameters are still applied in the provided block, it's also possible
|
||||||
|
to encode usage protocols that doesn't reveal implementation details.
|
||||||
|
|
||||||
|
As a special rule providing further convenience when writing type classes, any
|
||||||
|
type value appearing in a callable expression will be treated as a variable of
|
||||||
|
the designated type for overload resolution purposes, unless the type value was
|
||||||
|
passed in its explicit ``typedesc[T]`` form:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
type
|
||||||
|
OutputStream = generic S
|
||||||
|
write(var S, string)
|
||||||
|
|
||||||
Much like generics, the user defined type classes will be instantiated exactly
|
Much like generics, the user defined type classes will be instantiated exactly
|
||||||
once for each tested type and any static code included within them will also be
|
once for each tested type and any static code included within them will also be
|
||||||
executed once.
|
executed once.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Return Type Inference
|
Return Type Inference
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
@ -4673,9 +4683,10 @@ A proc can be marked with the `noStackFrame`:idx: pragma to tell the compiler
|
||||||
it should not generate a stack frame for the proc. There are also no exit
|
it should not generate a stack frame for the proc. There are also no exit
|
||||||
statements like ``return result;`` generated and the generated C function is
|
statements like ``return result;`` generated and the generated C function is
|
||||||
declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on
|
declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on
|
||||||
the used C compiler). This is useful for procs that only consist of an
|
the used C compiler).
|
||||||
assembler statement.
|
|
||||||
|
|
||||||
|
**Note**: This pragma should only be used by procs which consist solely of assembler
|
||||||
|
statements.
|
||||||
|
|
||||||
error pragma
|
error pragma
|
||||||
------------
|
------------
|
||||||
|
|
|
||||||
|
|
@ -610,7 +610,7 @@ allow to silently throw away a return value:
|
||||||
discard yes("May I ask a pointless question?")
|
discard yes("May I ask a pointless question?")
|
||||||
|
|
||||||
|
|
||||||
The return value can be ignored implicitely if the called proc/iterator has
|
The return value can be ignored implicitly if the called proc/iterator has
|
||||||
been declared with the ``discardable`` pragma:
|
been declared with the ``discardable`` pragma:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -1077,7 +1077,7 @@ can also be used to include elements (and ranges of elements):
|
||||||
TCharSet = set[char]
|
TCharSet = set[char]
|
||||||
var
|
var
|
||||||
x: TCharSet
|
x: TCharSet
|
||||||
x = {'a'..'z', '0'..'9'} # This constructs a set that conains the
|
x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
|
||||||
# letters from 'a' to 'z' and the digits
|
# letters from 'a' to 'z' and the digits
|
||||||
# from '0' to '9'
|
# from '0' to '9'
|
||||||
|
|
||||||
|
|
@ -1201,7 +1201,7 @@ to specify a range from zero to the specified index minus one:
|
||||||
Sequences
|
Sequences
|
||||||
---------
|
---------
|
||||||
`Sequences`:idx: are similar to arrays but of dynamic length which may change
|
`Sequences`:idx: are similar to arrays but of dynamic length which may change
|
||||||
during runtime (like strings). Since sequences are resizeable they are always
|
during runtime (like strings). Since sequences are resizable they are always
|
||||||
allocated on the heap and garbage collected.
|
allocated on the heap and garbage collected.
|
||||||
|
|
||||||
Sequences are always indexed with an ``int`` starting at position 0.
|
Sequences are always indexed with an ``int`` starting at position 0.
|
||||||
|
|
@ -1547,7 +1547,7 @@ exported symbols. An alternative that only imports listed symbols is the
|
||||||
|
|
||||||
Include statement
|
Include statement
|
||||||
-----------------
|
-----------------
|
||||||
The `include`:idx: statement does something fundametally different than
|
The `include`:idx: statement does something fundamentally different than
|
||||||
importing a module: it merely includes the contents of a file. The ``include``
|
importing a module: it merely includes the contents of a file. The ``include``
|
||||||
statement is useful to split up a large module into several files:
|
statement is useful to split up a large module into several files:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -869,6 +869,12 @@ proc parseLine(p: var TRstParser, father: PRstNode) =
|
||||||
of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
|
of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
|
||||||
else: break
|
else: break
|
||||||
|
|
||||||
|
proc parseUntilNewline(p: var TRstParser, 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)
|
proc parseSection(p: var TRstParser, result: PRstNode)
|
||||||
proc parseField(p: var TRstParser): PRstNode =
|
proc parseField(p: var TRstParser): PRstNode =
|
||||||
result = newRstNode(rnField)
|
result = newRstNode(rnField)
|
||||||
|
|
@ -1078,7 +1084,7 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
|
||||||
|
|
||||||
proc parseHeadline(p: var TRstParser): PRstNode =
|
proc parseHeadline(p: var TRstParser): PRstNode =
|
||||||
result = newRstNode(rnHeadline)
|
result = newRstNode(rnHeadline)
|
||||||
parseLine(p, result)
|
parseUntilNewLine(p, result)
|
||||||
assert(p.tok[p.idx].kind == tkIndent)
|
assert(p.tok[p.idx].kind == tkIndent)
|
||||||
assert(p.tok[p.idx + 1].kind == tkAdornment)
|
assert(p.tok[p.idx + 1].kind == tkAdornment)
|
||||||
var c = p.tok[p.idx + 1].symbol[0]
|
var c = p.tok[p.idx + 1].symbol[0]
|
||||||
|
|
@ -1172,7 +1178,7 @@ proc parseOverline(p: var TRstParser): PRstNode =
|
||||||
inc(p.idx, 2)
|
inc(p.idx, 2)
|
||||||
result = newRstNode(rnOverline)
|
result = newRstNode(rnOverline)
|
||||||
while true:
|
while true:
|
||||||
parseLine(p, result)
|
parseUntilNewline(p, result)
|
||||||
if p.tok[p.idx].kind == tkIndent:
|
if p.tok[p.idx].kind == tkIndent:
|
||||||
inc(p.idx)
|
inc(p.idx)
|
||||||
if p.tok[p.idx - 1].ival > currInd(p):
|
if p.tok[p.idx - 1].ival > currInd(p):
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@ else:
|
||||||
## A type representing a directory stream.
|
## A type representing a directory stream.
|
||||||
|
|
||||||
type
|
type
|
||||||
|
TSocketHandle* = distinct cint # The type used to represent socket descriptors
|
||||||
|
|
||||||
Tdirent* {.importc: "struct dirent",
|
Tdirent* {.importc: "struct dirent",
|
||||||
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
|
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
|
||||||
d_ino*: TIno ## File serial number.
|
d_ino*: TIno ## File serial number.
|
||||||
|
|
@ -1791,7 +1793,7 @@ proc dlopen*(a1: cstring, a2: cint): pointer {.importc, header: "<dlfcn.h>".}
|
||||||
proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "<dlfcn.h>".}
|
proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "<dlfcn.h>".}
|
||||||
|
|
||||||
proc creat*(a1: cstring, a2: Tmode): cint {.importc, header: "<fcntl.h>".}
|
proc creat*(a1: cstring, a2: Tmode): cint {.importc, header: "<fcntl.h>".}
|
||||||
proc fcntl*(a1: cint, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
|
proc fcntl*(a1: cint | TSocketHandle, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
|
||||||
proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
|
proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
|
||||||
proc posix_fadvise*(a1: cint, a2, a3: Toff, a4: cint): cint {.
|
proc posix_fadvise*(a1: cint, a2, a3: Toff, a4: cint): cint {.
|
||||||
importc, header: "<fcntl.h>".}
|
importc, header: "<fcntl.h>".}
|
||||||
|
|
@ -2068,7 +2070,7 @@ proc access*(a1: cstring, a2: cint): cint {.importc, header: "<unistd.h>".}
|
||||||
proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
|
proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
|
||||||
proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
|
proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
|
||||||
proc chown*(a1: cstring, a2: Tuid, a3: Tgid): cint {.importc, header: "<unistd.h>".}
|
proc chown*(a1: cstring, a2: Tuid, a3: Tgid): cint {.importc, header: "<unistd.h>".}
|
||||||
proc close*(a1: cint): cint {.importc, header: "<unistd.h>".}
|
proc close*(a1: cint | TSocketHandle): cint {.importc, header: "<unistd.h>".}
|
||||||
proc confstr*(a1: cint, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
|
proc confstr*(a1: cint, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
|
||||||
proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".}
|
proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".}
|
||||||
proc ctermid*(a1: cstring): cstring {.importc, header: "<unistd.h>".}
|
proc ctermid*(a1: cstring): cstring {.importc, header: "<unistd.h>".}
|
||||||
|
|
@ -2346,9 +2348,9 @@ proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".}
|
||||||
proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
|
proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
|
||||||
|
|
||||||
proc FD_CLR*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
|
proc FD_CLR*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
|
||||||
proc FD_ISSET*(a1: cint, a2: var Tfd_set): cint {.
|
proc FD_ISSET*(a1: cint | TSocketHandle, a2: var Tfd_set): cint {.
|
||||||
importc, header: "<sys/select.h>".}
|
importc, header: "<sys/select.h>".}
|
||||||
proc FD_SET*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
|
proc FD_SET*(a1: cint | TSocketHandle, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
|
||||||
proc FD_ZERO*(a1: var Tfd_set) {.importc, header: "<sys/select.h>".}
|
proc FD_ZERO*(a1: var Tfd_set) {.importc, header: "<sys/select.h>".}
|
||||||
|
|
||||||
proc pselect*(a1: cint, a2, a3, a4: ptr Tfd_set, a5: ptr ttimespec,
|
proc pselect*(a1: cint, a2, a3, a4: ptr Tfd_set, a5: ptr ttimespec,
|
||||||
|
|
@ -2428,44 +2430,49 @@ proc CMSG_NXTHDR*(mhdr: ptr TMsgHdr, cmsg: ptr TCMsgHdr): ptr TCmsgHdr {.
|
||||||
proc CMSG_FIRSTHDR*(mhdr: ptr TMsgHdr): ptr TCMsgHdr {.
|
proc CMSG_FIRSTHDR*(mhdr: ptr TMsgHdr): ptr TCMsgHdr {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
|
|
||||||
proc accept*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
|
const
|
||||||
|
INVALID_SOCKET* = TSocketHandle(-1)
|
||||||
|
|
||||||
|
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
|
||||||
|
|
||||||
|
proc accept*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): TSocketHandle {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
|
|
||||||
proc bindSocket*(a1: cint, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
|
proc bindSocket*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
|
||||||
importc: "bind", header: "<sys/socket.h>".}
|
importc: "bind", header: "<sys/socket.h>".}
|
||||||
## is Posix's ``bind``, because ``bind`` is a reserved word
|
## is Posix's ``bind``, because ``bind`` is a reserved word
|
||||||
|
|
||||||
proc connect*(a1: cint, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
|
proc connect*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc getpeername*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
|
proc getpeername*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc getsockname*(a1: cint, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
|
proc getsockname*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
|
|
||||||
proc getsockopt*(a1, a2, a3: cint, a4: pointer, a5: ptr Tsocklen): cint {.
|
proc getsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: ptr Tsocklen): cint {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
|
|
||||||
proc listen*(a1, a2: cint): cint {.
|
proc listen*(a1: TSocketHandle, a2: cint): cint {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc recv*(a1: cint, a2: pointer, a3: int, a4: cint): int {.
|
proc recv*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc recvfrom*(a1: cint, a2: pointer, a3: int, a4: cint,
|
proc recvfrom*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint,
|
||||||
a5: ptr Tsockaddr, a6: ptr Tsocklen): int {.
|
a5: ptr Tsockaddr, a6: ptr Tsocklen): int {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc recvmsg*(a1: cint, a2: ptr Tmsghdr, a3: cint): int {.
|
proc recvmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc send*(a1: cint, a2: pointer, a3: int, a4: cint): int {.
|
proc send*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc sendmsg*(a1: cint, a2: ptr Tmsghdr, a3: cint): int {.
|
proc sendmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc sendto*(a1: cint, a2: pointer, a3: int, a4: cint, a5: ptr Tsockaddr,
|
proc sendto*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint, a5: ptr Tsockaddr,
|
||||||
a6: Tsocklen): int {.
|
a6: Tsocklen): int {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc setsockopt*(a1, a2, a3: cint, a4: pointer, a5: Tsocklen): cint {.
|
proc setsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: Tsocklen): cint {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc shutdown*(a1, a2: cint): cint {.
|
proc shutdown*(a1: TSocketHandle, a2: cint): cint {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc socket*(a1, a2, a3: cint): cint {.
|
proc socket*(a1, a2, a3: cint): TSocketHandle {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
proc sockatmark*(a1: cint): cint {.
|
proc sockatmark*(a1: cint): cint {.
|
||||||
importc, header: "<sys/socket.h>".}
|
importc, header: "<sys/socket.h>".}
|
||||||
|
|
|
||||||
|
|
@ -89,13 +89,13 @@ import sockets, os
|
||||||
## getSocket(s).accept(client)
|
## getSocket(s).accept(client)
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
from winlean import TTimeVal, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
|
from winlean import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
|
||||||
else:
|
else:
|
||||||
from posix import TTimeVal, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
|
from posix import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select
|
||||||
|
|
||||||
type
|
type
|
||||||
TDelegate* = object
|
TDelegate* = object
|
||||||
fd*: cint
|
fd*: TSocketHandle
|
||||||
deleVal*: PObject
|
deleVal*: PObject
|
||||||
|
|
||||||
handleRead*: proc (h: PObject) {.nimcall.}
|
handleRead*: proc (h: PObject) {.nimcall.}
|
||||||
|
|
@ -213,6 +213,7 @@ proc asyncSockHandleRead(h: PObject) =
|
||||||
else:
|
else:
|
||||||
PAsyncSocket(h).handleAccept(PAsyncSocket(h))
|
PAsyncSocket(h).handleAccept(PAsyncSocket(h))
|
||||||
|
|
||||||
|
proc close*(sock: PAsyncSocket)
|
||||||
proc asyncSockHandleWrite(h: PObject) =
|
proc asyncSockHandleWrite(h: PObject) =
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if PAsyncSocket(h).socket.isSSL and not
|
if PAsyncSocket(h).socket.isSSL and not
|
||||||
|
|
@ -230,6 +231,7 @@ proc asyncSockHandleWrite(h: PObject) =
|
||||||
else:
|
else:
|
||||||
if PAsyncSocket(h).sendBuffer != "":
|
if PAsyncSocket(h).sendBuffer != "":
|
||||||
let sock = PAsyncSocket(h)
|
let sock = PAsyncSocket(h)
|
||||||
|
try:
|
||||||
let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
|
let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
|
||||||
assert bytesSent > 0
|
assert bytesSent > 0
|
||||||
if bytesSent != sock.sendBuffer.len:
|
if bytesSent != sock.sendBuffer.len:
|
||||||
|
|
@ -239,6 +241,9 @@ proc asyncSockHandleWrite(h: PObject) =
|
||||||
|
|
||||||
if PAsyncSocket(h).handleWrite != nil:
|
if PAsyncSocket(h).handleWrite != nil:
|
||||||
PAsyncSocket(h).handleWrite(PAsyncSocket(h))
|
PAsyncSocket(h).handleWrite(PAsyncSocket(h))
|
||||||
|
except EOS:
|
||||||
|
# Most likely the socket closed before the full buffer could be sent to it.
|
||||||
|
sock.close() # TODO: Provide a handleError for users?
|
||||||
else:
|
else:
|
||||||
if PAsyncSocket(h).handleWrite != nil:
|
if PAsyncSocket(h).handleWrite != nil:
|
||||||
PAsyncSocket(h).handleWrite(PAsyncSocket(h))
|
PAsyncSocket(h).handleWrite(PAsyncSocket(h))
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
const
|
const
|
||||||
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
|
||||||
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
|
template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} =
|
||||||
## encodes `s` into base64 representation. After `lineLen` characters, a
|
## encodes `s` into base64 representation. After `lineLen` characters, a
|
||||||
## `newline` is added.
|
## `newline` is added.
|
||||||
var total = ((len(s) + 2) div 3) * 4
|
var total = ((len(s) + 2) div 3) * 4
|
||||||
|
|
@ -60,6 +60,16 @@ proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
|
||||||
else:
|
else:
|
||||||
assert(r == result.len)
|
assert(r == result.len)
|
||||||
|
|
||||||
|
proc encode*[T:TInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string =
|
||||||
|
## encodes `s` into base64 representation. After `lineLen` characters, a
|
||||||
|
## `newline` is added.
|
||||||
|
encodeInternal(s, lineLen, newLine)
|
||||||
|
|
||||||
|
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
|
||||||
|
## encodes `s` into base64 representation. After `lineLen` characters, a
|
||||||
|
## `newline` is added.
|
||||||
|
encodeInternal(s, lineLen, newLine)
|
||||||
|
|
||||||
proc decodeByte(b: char): int {.inline.} =
|
proc decodeByte(b: char): int {.inline.} =
|
||||||
case b
|
case b
|
||||||
of '+': result = ord('>')
|
of '+': result = ord('>')
|
||||||
|
|
|
||||||
581
lib/pure/collections/LockFreeHash.nim
Normal file
581
lib/pure/collections/LockFreeHash.nim
Normal file
|
|
@ -0,0 +1,581 @@
|
||||||
|
#nimrod c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim
|
||||||
|
|
||||||
|
import baseutils, unsigned, math, hashes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
minTableSize = 8
|
||||||
|
reProbeLimit = 12
|
||||||
|
minCopyWork = 4096
|
||||||
|
intSize = sizeof(int)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
when sizeof(int) == 4: # 32bit
|
||||||
|
type
|
||||||
|
TRaw = range[0..1073741823]
|
||||||
|
## The range of uint values that can be stored directly in a value slot
|
||||||
|
## when on a 32 bit platform
|
||||||
|
|
||||||
|
elif sizeof(int) == 8: # 64bit
|
||||||
|
type
|
||||||
|
TRaw = range[0..4611686018427387903]
|
||||||
|
## The range of uint values that can be stored directly in a value slot
|
||||||
|
## when on a 64 bit platform
|
||||||
|
else: echo("unsupported platform")
|
||||||
|
|
||||||
|
type
|
||||||
|
TEntry = tuple
|
||||||
|
key: int
|
||||||
|
value: int
|
||||||
|
|
||||||
|
TEntryArr = ptr array[0..10_000_000, TEntry]
|
||||||
|
|
||||||
|
PConcTable[K,V] = ptr object {.pure.}
|
||||||
|
len: int
|
||||||
|
used: int
|
||||||
|
active: int
|
||||||
|
copyIdx: int
|
||||||
|
copyDone: int
|
||||||
|
next: PConcTable[K,V]
|
||||||
|
data: TEntryArr
|
||||||
|
|
||||||
|
|
||||||
|
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
|
||||||
|
expVal: int, match: bool): int
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Create a new table
|
||||||
|
proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
|
||||||
|
let
|
||||||
|
dataLen = max(nextPowerOfTwo(size), minTableSize)
|
||||||
|
dataSize = dataLen*sizeof(TEntry)
|
||||||
|
dataMem = allocShared0(dataSize)
|
||||||
|
tableSize = 7 * intSize
|
||||||
|
tableMem = allocShared0(tableSize)
|
||||||
|
table = cast[PConcTable[K,V]](tableMem)
|
||||||
|
table.len = dataLen
|
||||||
|
table.used = 0
|
||||||
|
table.active = 0
|
||||||
|
table.copyIdx = 0
|
||||||
|
table.copyDone = 0
|
||||||
|
table.next = nil
|
||||||
|
table.data = cast[TEntryArr](dataMem)
|
||||||
|
result = table
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Delete a table
|
||||||
|
proc deleteConcTable[K,V](tbl: PConcTable[K,V]) =
|
||||||
|
deallocShared(tbl.data)
|
||||||
|
deallocShared(tbl)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var TEntry {.inline.} =
|
||||||
|
table.data[i]
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# State flags stored in ptr
|
||||||
|
|
||||||
|
|
||||||
|
proc pack[T](x: T): int {.inline.} =
|
||||||
|
result = (cast[int](x) shl 2)
|
||||||
|
#echo("packKey ",cast[int](x) , " -> ", result)
|
||||||
|
|
||||||
|
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
|
||||||
|
proc pop(x: int): int {.inline.} =
|
||||||
|
result = x and 0xFFFFFFFC'i32
|
||||||
|
|
||||||
|
# Pop the raw value off of our Key or Val
|
||||||
|
proc popRaw(x: int): int {.inline.} =
|
||||||
|
result = x shr 2
|
||||||
|
|
||||||
|
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
|
||||||
|
proc popPtr[V](x: int): ptr V {.inline.} =
|
||||||
|
result = cast[ptr V](pop(x))
|
||||||
|
#echo("popPtr " & $x & " -> " & $cast[int](result))
|
||||||
|
|
||||||
|
# Ghost (sentinel)
|
||||||
|
# K or V is no longer valid use new table
|
||||||
|
const Ghost = 0xFFFFFFFC
|
||||||
|
proc isGhost(x: int): bool {.inline.} =
|
||||||
|
result = x == 0xFFFFFFFC
|
||||||
|
|
||||||
|
# Tombstone
|
||||||
|
# applied to V = K is dead
|
||||||
|
proc isTomb(x: int): bool {.inline.} =
|
||||||
|
result = (x and 0x00000002) != 0
|
||||||
|
|
||||||
|
proc setTomb(x: int): int {.inline.} =
|
||||||
|
result = x or 0x00000002
|
||||||
|
|
||||||
|
# Prime
|
||||||
|
# K or V is in new table copied from old
|
||||||
|
proc isPrime(x: int): bool {.inline.} =
|
||||||
|
result = (x and 0x00000001) != 0
|
||||||
|
|
||||||
|
proc setPrime(x: int): int {.inline.} =
|
||||||
|
result = x or 0x00000001
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
##This is for i32 only need to override for i64
|
||||||
|
proc hashInt(x: int):int {.inline.} =
|
||||||
|
var h = uint32(x) #shr 2'u32
|
||||||
|
h = h xor (h shr 16'u32)
|
||||||
|
h *= 0x85ebca6b'u32
|
||||||
|
h = h xor (h shr 13'u32)
|
||||||
|
h *= 0xc2b2ae35'u32
|
||||||
|
h = h xor (h shr 16'u32)
|
||||||
|
result = int(h)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc resize[K,V](self: PConcTable[K,V]): PConcTable[K,V] =
|
||||||
|
var next = atomic_load_n(self.next.addr, ATOMIC_RELAXED)
|
||||||
|
#echo("next = " & $cast[int](next))
|
||||||
|
if next != nil:
|
||||||
|
#echo("A new table already exists, copy in progress")
|
||||||
|
return next
|
||||||
|
var
|
||||||
|
oldLen = atomic_load_n(self.len.addr, ATOMIC_RELAXED)
|
||||||
|
newTable = newLFTable[K,V](oldLen*2)
|
||||||
|
success = atomic_compare_exchange_n(self.next.addr, next.addr, newTable,
|
||||||
|
false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||||
|
if not success:
|
||||||
|
echo("someone beat us to it! delete table we just created and return his " & $cast[int](next))
|
||||||
|
deleteConcTable(newTable)
|
||||||
|
return next
|
||||||
|
else:
|
||||||
|
echo("Created New Table! " & $cast[int](newTable) & " Size = " & $newTable.len)
|
||||||
|
return newTable
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
#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:
|
||||||
|
if key1 == key2:
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
var
|
||||||
|
p1 = popPtr[K](key1)
|
||||||
|
p2 = popPtr[K](key2)
|
||||||
|
if p1 != nil and p2 != nil:
|
||||||
|
if cast[int](p1) == cast[int](p2):
|
||||||
|
return true
|
||||||
|
if p1[] == p2[]:
|
||||||
|
return true
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#proc tableFull(self: var PConcTable[K,V]) : bool {.inline.} =
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable[K,V]): bool =
|
||||||
|
#echo("Copy idx " & $idx)
|
||||||
|
var
|
||||||
|
oldVal = 0
|
||||||
|
oldkey = 0
|
||||||
|
ok = false
|
||||||
|
result = false
|
||||||
|
#Block the key so no other threads waste time here
|
||||||
|
while not ok:
|
||||||
|
ok = atomic_compare_exchange_n(oldTbl[idx].key.addr, oldKey.addr,
|
||||||
|
setTomb(oldKey), false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||||
|
#echo("oldKey was = " & $oldKey & " set it to tomb " & $setTomb(oldKey))
|
||||||
|
#Prevent new values from appearing in the old table by priming
|
||||||
|
oldVal = atomic_load_n(oldTbl[idx].value.addr, ATOMIC_RELAXED)
|
||||||
|
while not isPrime(oldVal):
|
||||||
|
var box = if oldVal == NULL or isTomb(oldVal) : oldVal.setTomb.setPrime
|
||||||
|
else: oldVal.setPrime
|
||||||
|
if atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
|
||||||
|
box, false, ATOMIC_RELAXED, ATOMIC_RELAXED):
|
||||||
|
if isPrime(box) and isTomb(box):
|
||||||
|
return true
|
||||||
|
oldVal = box
|
||||||
|
break
|
||||||
|
#echo("oldVal was = ", oldVal, " set it to prime ", box)
|
||||||
|
if isPrime(oldVal) and isTomb(oldVal):
|
||||||
|
#when not (K is TRaw):
|
||||||
|
# deallocShared(popPtr[K](oldKey))
|
||||||
|
return false
|
||||||
|
if isTomb(oldVal):
|
||||||
|
echo("oldVal is Tomb!!!, should not happen")
|
||||||
|
if pop(oldVal) != NULL:
|
||||||
|
result = setVal(newTbl, pop(oldKey), pop(oldVal), NULL, true) == NULL
|
||||||
|
if result:
|
||||||
|
#echo("Copied a Slot! idx= " & $idx & " key= " & $oldKey & " val= " & $oldVal)
|
||||||
|
else:
|
||||||
|
#echo("copy slot failed")
|
||||||
|
# Our copy is done so we disable the old slot
|
||||||
|
while not ok:
|
||||||
|
ok = atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
|
||||||
|
oldVal.setTomb.setPrime , false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||||
|
#echo("disabled old slot")
|
||||||
|
#echo"---------------------"
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc promote[K,V](table: var PConcTable[K,V]) =
|
||||||
|
var
|
||||||
|
newData = atomic_load_n(table.next.data.addr, ATOMIC_RELAXED)
|
||||||
|
newLen = atomic_load_n(table.next.len.addr, ATOMIC_RELAXED)
|
||||||
|
newUsed = atomic_load_n(table.next.used.addr, ATOMIC_RELAXED)
|
||||||
|
|
||||||
|
deallocShared(table.data)
|
||||||
|
atomic_store_n(table.data.addr, newData, ATOMIC_RELAXED)
|
||||||
|
atomic_store_n(table.len.addr, newLen, ATOMIC_RELAXED)
|
||||||
|
atomic_store_n(table.used.addr, newUsed, ATOMIC_RELAXED)
|
||||||
|
atomic_store_n(table.copyIdx.addr, 0, ATOMIC_RELAXED)
|
||||||
|
atomic_store_n(table.copyDone.addr, 0, ATOMIC_RELAXED)
|
||||||
|
deallocShared(table.next)
|
||||||
|
atomic_store_n(table.next.addr, nil, ATOMIC_RELAXED)
|
||||||
|
echo("new table swapped!")
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc checkAndPromote[K,V](table: var PConcTable[K,V], workDone: int): bool =
|
||||||
|
var
|
||||||
|
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
|
||||||
|
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
|
||||||
|
ok: bool
|
||||||
|
result = false
|
||||||
|
if workDone > 0:
|
||||||
|
#echo("len to copy =" & $oldLen)
|
||||||
|
#echo("copyDone + workDone = " & $copyDone & " + " & $workDone)
|
||||||
|
while not ok:
|
||||||
|
ok = atomic_compare_exchange_n(table.copyDone.addr, copyDone.addr,
|
||||||
|
copyDone + workDone, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||||
|
#if ok: echo("set copyDone")
|
||||||
|
# If the copy is done we can promote this table
|
||||||
|
if copyDone + workDone >= oldLen:
|
||||||
|
# Swap new data
|
||||||
|
#echo("work is done!")
|
||||||
|
table.promote
|
||||||
|
result = true
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc copySlotAndCheck[K,V](table: var PConcTable[K,V], idx: int):
|
||||||
|
PConcTable[K,V] =
|
||||||
|
var
|
||||||
|
newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
|
||||||
|
result = newTable
|
||||||
|
if newTable != nil and copySlot(idx, table, newTable):
|
||||||
|
#echo("copied a single slot, idx = " & $idx)
|
||||||
|
if checkAndPromote(table, 1): return table
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc helpCopy[K,V](table: var PConcTable[K,V]): PConcTable[K,V] =
|
||||||
|
var
|
||||||
|
newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
|
||||||
|
result = newTable
|
||||||
|
if newTable != nil:
|
||||||
|
var
|
||||||
|
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
|
||||||
|
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
|
||||||
|
copyIdx = 0
|
||||||
|
work = min(oldLen, minCopyWork)
|
||||||
|
#panicStart = -1
|
||||||
|
workDone = 0
|
||||||
|
if copyDone < oldLen:
|
||||||
|
var ok: bool
|
||||||
|
while not ok:
|
||||||
|
ok = atomic_compare_exchange_n(table.copyIdx.addr, copyIdx.addr,
|
||||||
|
copyIdx + work, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||||
|
#echo("copy idx = ", copyIdx)
|
||||||
|
for i in 0..work-1:
|
||||||
|
var idx = (copyIdx + i) and (oldLen - 1)
|
||||||
|
if copySlot(idx, table, newTable):
|
||||||
|
workDone += 1
|
||||||
|
if workDone > 0:
|
||||||
|
#echo("did work ", workDone, " on thread ", cast[int](myThreadID[pointer]()))
|
||||||
|
if checkAndPromote(table, workDone): return table
|
||||||
|
# In case a thread finished all the work then got stalled before promotion
|
||||||
|
if checkAndPromote(table, 0): return table
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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:
|
||||||
|
var idx = hashInt(key)
|
||||||
|
else:
|
||||||
|
var idx = popPtr[K](key)[].hash
|
||||||
|
var
|
||||||
|
nextTable: PConcTable[K,V]
|
||||||
|
probes = 1
|
||||||
|
# spin until we find a key slot or build and jump to next table
|
||||||
|
while true:
|
||||||
|
idx = idx and (table.len - 1)
|
||||||
|
#echo("try set idx = " & $idx & "for" & $key)
|
||||||
|
var
|
||||||
|
probedKey = NULL
|
||||||
|
openKey = atomic_compare_exchange_n(table[idx].key.addr, probedKey.addr,
|
||||||
|
key, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
|
||||||
|
if openKey:
|
||||||
|
if val.isTomb:
|
||||||
|
#echo("val was tomb, bail, no reason to set an open slot to tomb")
|
||||||
|
return val
|
||||||
|
#increment used slots
|
||||||
|
#echo("found an open slot, total used = " &
|
||||||
|
#$atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED))
|
||||||
|
discard atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED)
|
||||||
|
break # We found an open slot
|
||||||
|
#echo("set idx ", idx, " key = ", key, " probed = ", probedKey)
|
||||||
|
if keyEQ[K](probedKey, key):
|
||||||
|
#echo("we found the matching slot")
|
||||||
|
break # We found a matching slot
|
||||||
|
if (not(expVal != NULL and match)) and (probes >= reProbeLimit or key.isTomb):
|
||||||
|
if key.isTomb: echo("Key is Tombstone")
|
||||||
|
#if probes >= reProbeLimit: echo("Too much probing " & $probes)
|
||||||
|
#echo("try to resize")
|
||||||
|
#create next bigger table
|
||||||
|
nextTable = resize(table)
|
||||||
|
#help do some copying
|
||||||
|
#echo("help copy old table to new")
|
||||||
|
nextTable = helpCopy(table)
|
||||||
|
#now setVal in the new table instead
|
||||||
|
#echo("jumping to next table to set val")
|
||||||
|
return setVal(nextTable, key, val, expVal, match)
|
||||||
|
else:
|
||||||
|
idx += 1
|
||||||
|
probes += 1
|
||||||
|
# Done spinning for a new slot
|
||||||
|
var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)
|
||||||
|
if val == oldVal:
|
||||||
|
#echo("this val is alredy in the slot")
|
||||||
|
return oldVal
|
||||||
|
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
|
||||||
|
if nextTable == nil and
|
||||||
|
((oldVal == NULL and
|
||||||
|
(probes >= reProbeLimit or table.used / table.len > 0.8)) or
|
||||||
|
(isPrime(oldVal))):
|
||||||
|
if table.used / table.len > 0.8: echo("resize because usage ratio = " &
|
||||||
|
$(table.used / table.len))
|
||||||
|
if isPrime(oldVal): echo("old val isPrime, should be a rare mem ordering event")
|
||||||
|
nextTable = resize(table)
|
||||||
|
if nextTable != nil:
|
||||||
|
#echo("tomb old slot then set in new table")
|
||||||
|
nextTable = copySlotAndCheck(table,idx)
|
||||||
|
return setVal(nextTable, key, val, expVal, match)
|
||||||
|
# Finaly ready to add new val to table
|
||||||
|
while true:
|
||||||
|
if match and oldVal != expVal:
|
||||||
|
#echo("set failed, no match oldVal= " & $oldVal & " expVal= " & $expVal)
|
||||||
|
return oldVal
|
||||||
|
if atomic_compare_exchange_n(table[idx].value.addr, oldVal.addr,
|
||||||
|
val, false, ATOMIC_RELEASE, ATOMIC_RELAXED):
|
||||||
|
#echo("val set at table " & $cast[int](table))
|
||||||
|
if expVal != NULL:
|
||||||
|
if (oldVal == NULL or isTomb(oldVal)) and not isTomb(val):
|
||||||
|
discard atomic_add_fetch(table.active.addr, 1, ATOMIC_RELAXED)
|
||||||
|
elif not (oldVal == NULL or isTomb(oldVal)) and isTomb(val):
|
||||||
|
discard atomic_add_fetch(table.active.addr, -1, ATOMIC_RELAXED)
|
||||||
|
if oldVal == NULL and expVal != NULL:
|
||||||
|
return setTomb(oldVal)
|
||||||
|
else: return oldVal
|
||||||
|
if isPrime(oldVal):
|
||||||
|
nextTable = copySlotAndCheck(table, idx)
|
||||||
|
return setVal(nextTable, key, val, expVal, match)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
|
||||||
|
#echo("-try get- key = " & $key)
|
||||||
|
when K is TRaw:
|
||||||
|
var idx = hashInt(key)
|
||||||
|
else:
|
||||||
|
var idx = popPtr[K](key)[].hash
|
||||||
|
#echo("get idx ", idx)
|
||||||
|
var
|
||||||
|
probes = 0
|
||||||
|
val: int
|
||||||
|
while true:
|
||||||
|
idx = idx and (table.len - 1)
|
||||||
|
var
|
||||||
|
newTable: PConcTable[K,V] # = atomic_load_n(table.next.addr, ATOMIC_ACQUIRE)
|
||||||
|
probedKey = atomic_load_n(table[idx].key.addr, ATOMIC_SEQ_CST)
|
||||||
|
if keyEQ[K](probedKey, key):
|
||||||
|
#echo("found key after ", probes+1)
|
||||||
|
val = atomic_load_n(table[idx].value.addr, ATOMIC_ACQUIRE)
|
||||||
|
if not isPrime(val):
|
||||||
|
if isTomb(val):
|
||||||
|
#echo("val was tomb but not prime")
|
||||||
|
return NULL
|
||||||
|
else:
|
||||||
|
#echo("-GotIt- idx = ", idx, " key = ", key, " val ", val )
|
||||||
|
return val
|
||||||
|
else:
|
||||||
|
newTable = copySlotAndCheck(table, idx)
|
||||||
|
return getVal(newTable, key)
|
||||||
|
else:
|
||||||
|
#echo("probe ", probes, " idx = ", idx, " key = ", key, " found ", probedKey )
|
||||||
|
if probes >= reProbeLimit*4 or key.isTomb:
|
||||||
|
if newTable == nil:
|
||||||
|
#echo("too many probes and no new table ", key, " ", idx )
|
||||||
|
return NULL
|
||||||
|
else:
|
||||||
|
newTable = helpCopy(table)
|
||||||
|
return getVal(newTable, key)
|
||||||
|
idx += 1
|
||||||
|
probes += 1
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) =
|
||||||
|
# discard setVal(table, pack(key), pack(key), NULL, false)
|
||||||
|
|
||||||
|
#proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) =
|
||||||
|
# discard setVal(table, pack(key), cast[int](val), NULL, false)
|
||||||
|
|
||||||
|
proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
|
||||||
|
when not (K is TRaw):
|
||||||
|
var newKey = cast[int](copyShared(key))
|
||||||
|
else:
|
||||||
|
var newKey = pack(key)
|
||||||
|
when not (V is TRaw):
|
||||||
|
var newVal = cast[int](copyShared(val))
|
||||||
|
else:
|
||||||
|
var newVal = pack(val)
|
||||||
|
var oldPtr = pop(setVal(table, newKey, newVal, NULL, false))
|
||||||
|
#echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
|
||||||
|
when not (V is TRaw):
|
||||||
|
if newVal != oldPtr and oldPtr != NULL:
|
||||||
|
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):
|
||||||
|
return popPtr[V](getVal(table, cast[int](key.addr)))[]
|
||||||
|
else:
|
||||||
|
return popPtr[V](getVal(table, pack(key)))[]
|
||||||
|
else:
|
||||||
|
when not (K is TRaw):
|
||||||
|
return popRaw(getVal(table, cast[int](key.addr)))
|
||||||
|
else:
|
||||||
|
return popRaw(getVal(table, pack(key)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#proc `[]`[K,V](table: var PConcTable[K,V], key: K): PEntry[K,V] {.inline.} =
|
||||||
|
# getVal(table, key)
|
||||||
|
|
||||||
|
#proc `[]=`[K,V](table: var PConcTable[K,V], key: K, val: V): PEntry[K,V] {.inline.} =
|
||||||
|
# setVal(table, key, val)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#Tests ----------------------------
|
||||||
|
when isMainModule:
|
||||||
|
import locks, times, mersenne
|
||||||
|
|
||||||
|
const
|
||||||
|
numTests = 100000
|
||||||
|
numThreads = 10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
TTestObj = tuple
|
||||||
|
thr: int
|
||||||
|
f0: int
|
||||||
|
f1: int
|
||||||
|
|
||||||
|
TData = tuple[k: string,v: TTestObj]
|
||||||
|
PDataArr = array[0..numTests-1, TData]
|
||||||
|
Dict = PConcTable[string,TTestObj]
|
||||||
|
|
||||||
|
var
|
||||||
|
thr: array[0..numThreads-1, TThread[Dict]]
|
||||||
|
|
||||||
|
table = newLFTable[string,TTestObj](8)
|
||||||
|
rand = newMersenneTwister(2525)
|
||||||
|
|
||||||
|
proc createSampleData(len: int): PDataArr =
|
||||||
|
#result = cast[PDataArr](allocShared0(sizeof(TData)*numTests))
|
||||||
|
for i in 0..len-1:
|
||||||
|
result[i].k = "mark" & $(i+1)
|
||||||
|
#echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))
|
||||||
|
result[i].v.thr = 0
|
||||||
|
result[i].v.f0 = i+1
|
||||||
|
result[i].v.f1 = 0
|
||||||
|
#echo("key = " & $(i+1) & " Val ptr = " & $cast[int](result[i].v.addr))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proc threadProc(tp: Dict) {.thread.} =
|
||||||
|
var t = cpuTime();
|
||||||
|
for i in 1..numTests:
|
||||||
|
var key = "mark" & $(i)
|
||||||
|
var got = table.get(key)
|
||||||
|
got.thr = cast[int](myThreadID[pointer]())
|
||||||
|
got.f1 = got.f1 + 1
|
||||||
|
table.set(key, got)
|
||||||
|
t = cpuTime() - t
|
||||||
|
echo t
|
||||||
|
|
||||||
|
|
||||||
|
var testData = createSampleData(numTests)
|
||||||
|
|
||||||
|
for i in 0..numTests-1:
|
||||||
|
table.set(testData[i].k, testData[i].v)
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
while i < numThreads:
|
||||||
|
createThread(thr[i], threadProc, table)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
joinThreads(thr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var fails = 0
|
||||||
|
|
||||||
|
for i in 0..numTests-1:
|
||||||
|
var got = table.get(testData[i].k)
|
||||||
|
if got.f0 != i+1 or got.f1 != numThreads:
|
||||||
|
fails += 1
|
||||||
|
echo(got)
|
||||||
|
|
||||||
|
echo("Failed read or write = ", fails)
|
||||||
|
|
||||||
|
|
||||||
|
#for i in 1..numTests:
|
||||||
|
# echo(i, " = ", hashInt(i) and 8191)
|
||||||
|
|
||||||
|
deleteConcTable(table)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
41
lib/pure/collections/baseutils.nim
Normal file
41
lib/pure/collections/baseutils.nim
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
## Useful Constants
|
||||||
|
const NULL* = 0
|
||||||
|
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
## Memory Utility Functions
|
||||||
|
|
||||||
|
proc newHeap*[T](): ptr T =
|
||||||
|
result = cast[ptr T](alloc0(sizeof(T)))
|
||||||
|
|
||||||
|
proc copyNew*[T](x: var T): ptr T =
|
||||||
|
var
|
||||||
|
size = sizeof(T)
|
||||||
|
mem = alloc(size)
|
||||||
|
copyMem(mem, x.addr, size)
|
||||||
|
return cast[ptr T](mem)
|
||||||
|
|
||||||
|
proc copyTo*[T](val: var T, dest: int) =
|
||||||
|
copyMem(pointer(dest), val.addr, sizeof(T))
|
||||||
|
|
||||||
|
proc allocType*[T](): pointer = alloc(sizeof(T))
|
||||||
|
|
||||||
|
proc newShared*[T](): ptr T =
|
||||||
|
result = cast[ptr T](allocShared0(sizeof(T)))
|
||||||
|
|
||||||
|
proc copyShared*[T](x: var T): ptr T =
|
||||||
|
var
|
||||||
|
size = sizeof(T)
|
||||||
|
mem = allocShared(size)
|
||||||
|
copyMem(mem, x.addr, size)
|
||||||
|
return cast[ptr T](mem)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
## Pointer arithmetic
|
||||||
|
|
||||||
|
proc `+`*(p: pointer, i: int): pointer {.inline.} =
|
||||||
|
cast[pointer](cast[int](p) + i)
|
||||||
|
|
@ -117,6 +117,57 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
|
||||||
## assert f2 == @["yellow"]
|
## assert f2 == @["yellow"]
|
||||||
accumulateResult(filter(seq1, pred))
|
accumulateResult(filter(seq1, pred))
|
||||||
|
|
||||||
|
proc delete*[T](s: var seq[T], first=0, last=0) =
|
||||||
|
## Deletes in `s` the items at position `first` .. `last`. This modifies
|
||||||
|
## `s` itself, it does not return a copy.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
##.. code-block:: nimrod
|
||||||
|
## let outcome = @[1,1,1,1,1,1,1,1]
|
||||||
|
## var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||||
|
## dest.delete(3, 8)
|
||||||
|
## assert outcome == dest
|
||||||
|
|
||||||
|
var i = first
|
||||||
|
var j = last+1
|
||||||
|
var newLen = len(s)-j+i
|
||||||
|
while i < newLen:
|
||||||
|
s[i].shallowCopy(s[j])
|
||||||
|
inc(i)
|
||||||
|
inc(j)
|
||||||
|
setlen(s, newLen)
|
||||||
|
|
||||||
|
proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
|
||||||
|
## Inserts items from `src` into `dest` at position `pos`. This modifies
|
||||||
|
## `dest` itself, it does not return a copy.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
##.. code-block:: nimrod
|
||||||
|
## var dest = @[1,1,1,1,1,1,1,1]
|
||||||
|
## let
|
||||||
|
## src = @[2,2,2,2,2,2]
|
||||||
|
## outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||||
|
## dest.insert(src, 3)
|
||||||
|
## assert dest == outcome
|
||||||
|
|
||||||
|
var j = len(dest) - 1
|
||||||
|
var i = len(dest) + len(src) - 1
|
||||||
|
dest.setLen(i + 1)
|
||||||
|
|
||||||
|
# Move items after `pos` to the end of the sequence.
|
||||||
|
while j >= pos:
|
||||||
|
dest[i].shallowCopy(dest[j])
|
||||||
|
dec(i)
|
||||||
|
dec(j)
|
||||||
|
# Insert items from `dest` into `dest` at `pos`
|
||||||
|
inc(j)
|
||||||
|
for item in src:
|
||||||
|
dest[j] = item
|
||||||
|
inc(j)
|
||||||
|
|
||||||
|
|
||||||
template filterIt*(seq1, pred: expr): expr {.immediate.} =
|
template filterIt*(seq1, pred: expr): expr {.immediate.} =
|
||||||
## Returns a new sequence with all the items that fulfilled the predicate.
|
## Returns a new sequence with all the items that fulfilled the predicate.
|
||||||
##
|
##
|
||||||
|
|
@ -312,4 +363,22 @@ when isMainModule:
|
||||||
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
||||||
assert concatenation == "nimrodiscool"
|
assert concatenation == "nimrodiscool"
|
||||||
|
|
||||||
|
block: # delete tests
|
||||||
|
let outcome = @[1,1,1,1,1,1,1,1]
|
||||||
|
var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||||
|
dest.delete(3, 8)
|
||||||
|
assert outcome == dest, """\
|
||||||
|
Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||||
|
is [1,1,1,1,1,1,1,1]"""
|
||||||
|
|
||||||
|
block: # insert tests
|
||||||
|
var dest = @[1,1,1,1,1,1,1,1]
|
||||||
|
let
|
||||||
|
src = @[2,2,2,2,2,2]
|
||||||
|
outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
|
||||||
|
dest.insert(src, 3)
|
||||||
|
assert dest == outcome, """\
|
||||||
|
Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
|
||||||
|
at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
|
||||||
|
|
||||||
echo "Finished doc tests"
|
echo "Finished doc tests"
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ proc expectReply(ftp: PFTPClient): TaintedString =
|
||||||
proc send*(ftp: PFTPClient, m: string): TaintedString =
|
proc send*(ftp: PFTPClient, m: string): TaintedString =
|
||||||
## Send a message to the server, and wait for a primary reply.
|
## Send a message to the server, and wait for a primary reply.
|
||||||
## ``\c\L`` is added for you.
|
## ``\c\L`` is added for you.
|
||||||
|
blockingOperation(ftp.getCSock()):
|
||||||
ftp.getCSock().send(m & "\c\L")
|
ftp.getCSock().send(m & "\c\L")
|
||||||
return ftp.expectReply()
|
return ftp.expectReply()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -224,11 +224,13 @@ type
|
||||||
TAsyncHTTPServer = object of TServer
|
TAsyncHTTPServer = object of TServer
|
||||||
asyncSocket: PAsyncSocket
|
asyncSocket: PAsyncSocket
|
||||||
|
|
||||||
proc open*(s: var TServer, port = TPort(80)) =
|
proc open*(s: var TServer, port = TPort(80), reuseAddr = false) =
|
||||||
## creates a new server at port `port`. If ``port == 0`` a free port is
|
## creates a new server at port `port`. If ``port == 0`` a free port is
|
||||||
## acquired that can be accessed later by the ``port`` proc.
|
## acquired that can be accessed later by the ``port`` proc.
|
||||||
s.socket = socket(AF_INET)
|
s.socket = socket(AF_INET)
|
||||||
if s.socket == InvalidSocket: OSError(OSLastError())
|
if s.socket == InvalidSocket: OSError(OSLastError())
|
||||||
|
if reuseAddr:
|
||||||
|
s.socket.setSockOpt(OptReuseAddr, True)
|
||||||
bindAddr(s.socket, port)
|
bindAddr(s.socket, port)
|
||||||
listen(s.socket)
|
listen(s.socket)
|
||||||
|
|
||||||
|
|
@ -399,6 +401,7 @@ proc nextAsync(s: PAsyncHTTPServer) =
|
||||||
var value = ""
|
var value = ""
|
||||||
i = header.parseUntil(key, ':')
|
i = header.parseUntil(key, ':')
|
||||||
inc(i) # skip :
|
inc(i) # skip :
|
||||||
|
if i < header.len:
|
||||||
i += header.skipWhiteSpace(i)
|
i += header.skipWhiteSpace(i)
|
||||||
i += header.parseUntil(value, {'\c', '\L'}, i)
|
i += header.parseUntil(value, {'\c', '\L'}, i)
|
||||||
s.headers[key] = value
|
s.headers[key] = value
|
||||||
|
|
@ -475,7 +478,8 @@ proc nextAsync(s: PAsyncHTTPServer) =
|
||||||
|
|
||||||
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
|
proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket,
|
||||||
path, query: string): bool {.closure.},
|
path, query: string): bool {.closure.},
|
||||||
port = TPort(80), address = ""): PAsyncHTTPServer =
|
port = TPort(80), address = "",
|
||||||
|
reuseAddr = false): PAsyncHTTPServer =
|
||||||
## Creates an Asynchronous HTTP server at ``port``.
|
## Creates an Asynchronous HTTP server at ``port``.
|
||||||
var capturedRet: PAsyncHTTPServer
|
var capturedRet: PAsyncHTTPServer
|
||||||
new(capturedRet)
|
new(capturedRet)
|
||||||
|
|
@ -486,6 +490,8 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo
|
||||||
let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
|
let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
|
||||||
capturedRet.query)
|
capturedRet.query)
|
||||||
if quit: capturedRet.asyncSocket.close()
|
if quit: capturedRet.asyncSocket.close()
|
||||||
|
if reuseAddr:
|
||||||
|
capturedRet.asyncSocket.setSockOpt(OptReuseAddr, True)
|
||||||
|
|
||||||
capturedRet.asyncSocket.bindAddr(port, address)
|
capturedRet.asyncSocket.bindAddr(port, address)
|
||||||
capturedRet.asyncSocket.listen()
|
capturedRet.asyncSocket.listen()
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ type
|
||||||
params*: seq[string] ## Parameters of the IRC message
|
params*: seq[string] ## Parameters of the IRC message
|
||||||
origin*: string ## The channel/user that this msg originated from
|
origin*: string ## The channel/user that this msg originated from
|
||||||
raw*: string ## Raw IRC message
|
raw*: string ## Raw IRC message
|
||||||
|
timestamp*: TTime ## UNIX epoch time the message was received
|
||||||
|
|
||||||
proc send*(irc: PIRC, message: string, sendImmediately = false) =
|
proc send*(irc: PIRC, message: string, sendImmediately = false) =
|
||||||
## Sends ``message`` as a raw command. It adds ``\c\L`` for you.
|
## Sends ``message`` as a raw command. It adds ``\c\L`` for you.
|
||||||
|
|
@ -163,6 +164,7 @@ proc parseMessage(msg: string): TIRCEvent =
|
||||||
result.typ = EvMsg
|
result.typ = EvMsg
|
||||||
result.cmd = MUnknown
|
result.cmd = MUnknown
|
||||||
result.raw = msg
|
result.raw = msg
|
||||||
|
result.timestamp = times.getTime()
|
||||||
var i = 0
|
var i = 0
|
||||||
# Process the prefix
|
# Process the prefix
|
||||||
if msg[i] == ':':
|
if msg[i] == ':':
|
||||||
|
|
|
||||||
39
lib/pure/mersenne.nim
Normal file
39
lib/pure/mersenne.nim
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import unsigned
|
||||||
|
|
||||||
|
type
|
||||||
|
TMersenneTwister* = object
|
||||||
|
mt: array[0..623, uint32]
|
||||||
|
index: int
|
||||||
|
|
||||||
|
proc newMersenneTwister*(seed: int): TMersenneTwister =
|
||||||
|
result.index = 0
|
||||||
|
result.mt[0]= uint32(seed)
|
||||||
|
for i in 1..623'u32:
|
||||||
|
result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i)
|
||||||
|
|
||||||
|
proc generateNumbers(m: var TMersenneTwister) =
|
||||||
|
for i in 0..623:
|
||||||
|
var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32)
|
||||||
|
m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32)
|
||||||
|
if (y mod 2'u32) != 0:
|
||||||
|
m.mt[i] = m.mt[i] xor 0x9908b0df'u32
|
||||||
|
|
||||||
|
proc getNum*(m: var TMersenneTwister): int =
|
||||||
|
if m.index == 0:
|
||||||
|
generateNumbers(m)
|
||||||
|
var y = m.mt[m.index]
|
||||||
|
y = y xor (y shr 11'u32)
|
||||||
|
y = y xor ((7'u32 shl y) and 0x9d2c5680'u32)
|
||||||
|
y = y xor ((15'u32 shl y) and 0xefc60000'u32)
|
||||||
|
y = y xor (y shr 18'u32)
|
||||||
|
m.index = (m.index+1) mod 624
|
||||||
|
return int(y)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Test
|
||||||
|
when isMainModule:
|
||||||
|
var mt = newMersenneTwister(2525)
|
||||||
|
|
||||||
|
for i in 0..99:
|
||||||
|
echo mt.getNum
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod's Runtime Library
|
# Nimrod's Runtime Library
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -52,6 +52,10 @@ proc oidToString*(oid: TOid, str: cstring) =
|
||||||
inc(i)
|
inc(i)
|
||||||
str[24] = '\0'
|
str[24] = '\0'
|
||||||
|
|
||||||
|
proc `$`*(oid: TOid): string =
|
||||||
|
result = newString(25)
|
||||||
|
oidToString(oid, result)
|
||||||
|
|
||||||
var
|
var
|
||||||
incr: int
|
incr: int
|
||||||
fuzz: int32
|
fuzz: int32
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ type
|
||||||
TProcess = object of TObject
|
TProcess = object of TObject
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
FProcessHandle: Thandle
|
FProcessHandle: Thandle
|
||||||
inputHandle, outputHandle, errorHandle: TFileHandle
|
inHandle, outHandle, errHandle: TFileHandle
|
||||||
id: THandle
|
id: THandle
|
||||||
else:
|
else:
|
||||||
inputHandle, outputHandle, errorHandle: TFileHandle
|
inHandle, outHandle, errHandle: TFileHandle
|
||||||
inStream, outStream, errStream: PStream
|
inStream, outStream, errStream: PStream
|
||||||
id: TPid
|
id: TPid
|
||||||
exitCode: cint
|
exitCode: cint
|
||||||
|
|
@ -113,23 +113,47 @@ proc peekExitCode*(p: PProcess): int {.tags: [].}
|
||||||
## return -1 if the process is still running. Otherwise the process' exit code
|
## return -1 if the process is still running. Otherwise the process' exit code
|
||||||
|
|
||||||
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## returns ``p``'s input stream for writing to
|
## returns ``p``'s input stream for writing to.
|
||||||
##
|
##
|
||||||
## **Warning**: The returned `PStream` should not be closed manually as it
|
## **Warning**: The returned `PStream` should not be closed manually as it
|
||||||
## is closed when closing the PProcess ``p``.
|
## is closed when closing the PProcess ``p``.
|
||||||
|
|
||||||
proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## returns ``p``'s output stream for reading from
|
## returns ``p``'s output stream for reading from.
|
||||||
##
|
##
|
||||||
## **Warning**: The returned `PStream` should not be closed manually as it
|
## **Warning**: The returned `PStream` should not be closed manually as it
|
||||||
## is closed when closing the PProcess ``p``.
|
## is closed when closing the PProcess ``p``.
|
||||||
|
|
||||||
proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
|
||||||
## returns ``p``'s output stream for reading from
|
## returns ``p``'s error stream for reading from.
|
||||||
##
|
##
|
||||||
## **Warning**: The returned `PStream` should not be closed manually as it
|
## **Warning**: The returned `PStream` should not be closed manually as it
|
||||||
## is closed when closing the PProcess ``p``.
|
## is closed when closing the PProcess ``p``.
|
||||||
|
|
||||||
|
proc inputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
|
||||||
|
tags: [].} =
|
||||||
|
## returns ``p``'s input file handle for writing to.
|
||||||
|
##
|
||||||
|
## **Warning**: The returned `TFileHandle` should not be closed manually as
|
||||||
|
## it is closed when closing the PProcess ``p``.
|
||||||
|
result = p.inHandle
|
||||||
|
|
||||||
|
proc outputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
|
||||||
|
tags: [].} =
|
||||||
|
## returns ``p``'s output file handle for reading from.
|
||||||
|
##
|
||||||
|
## **Warning**: The returned `TFileHandle` should not be closed manually as
|
||||||
|
## it is closed when closing the PProcess ``p``.
|
||||||
|
result = p.outHandle
|
||||||
|
|
||||||
|
proc errorHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
|
||||||
|
tags: [].} =
|
||||||
|
## returns ``p``'s error file handle for reading from.
|
||||||
|
##
|
||||||
|
## **Warning**: The returned `TFileHandle` should not be closed manually as
|
||||||
|
## it is closed when closing the PProcess ``p``.
|
||||||
|
result = p.errHandle
|
||||||
|
|
||||||
when defined(macosx) or defined(bsd):
|
when defined(macosx) or defined(bsd):
|
||||||
const
|
const
|
||||||
CTL_HW = 6
|
CTL_HW = 6
|
||||||
|
|
@ -212,8 +236,8 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
inc(i)
|
inc(i)
|
||||||
if i > high(cmds): break
|
if i > high(cmds): break
|
||||||
for j in 0..m-1:
|
for j in 0..m-1:
|
||||||
if q[j] != nil: close(q[j])
|
|
||||||
result = max(waitForExit(q[j]), result)
|
result = max(waitForExit(q[j]), result)
|
||||||
|
if q[j] != nil: close(q[j])
|
||||||
else:
|
else:
|
||||||
for i in 0..high(cmds):
|
for i in 0..high(cmds):
|
||||||
var p = startCmd(cmds[i], options=options)
|
var p = startCmd(cmds[i], options=options)
|
||||||
|
|
@ -339,16 +363,16 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
HE = HO
|
HE = HO
|
||||||
else:
|
else:
|
||||||
CreatePipeHandles(HE, Si.hStdError)
|
CreatePipeHandles(HE, Si.hStdError)
|
||||||
result.inputHandle = TFileHandle(hi)
|
result.inHandle = TFileHandle(hi)
|
||||||
result.outputHandle = TFileHandle(ho)
|
result.outHandle = TFileHandle(ho)
|
||||||
result.errorHandle = TFileHandle(he)
|
result.errHandle = TFileHandle(he)
|
||||||
else:
|
else:
|
||||||
SI.hStdError = GetStdHandle(STD_ERROR_HANDLE)
|
SI.hStdError = GetStdHandle(STD_ERROR_HANDLE)
|
||||||
SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE)
|
SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE)
|
||||||
SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
|
SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||||
result.inputHandle = TFileHandle(si.hStdInput)
|
result.inHandle = TFileHandle(si.hStdInput)
|
||||||
result.outputHandle = TFileHandle(si.hStdOutput)
|
result.outHandle = TFileHandle(si.hStdOutput)
|
||||||
result.errorHandle = TFileHandle(si.hStdError)
|
result.errHandle = TFileHandle(si.hStdError)
|
||||||
|
|
||||||
var cmdl: cstring
|
var cmdl: cstring
|
||||||
when false: # poUseShell in options:
|
when false: # poUseShell in options:
|
||||||
|
|
@ -389,9 +413,9 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
proc close(p: PProcess) =
|
proc close(p: PProcess) =
|
||||||
when false:
|
when false:
|
||||||
# somehow this does not work on Windows:
|
# somehow this does not work on Windows:
|
||||||
discard CloseHandle(p.inputHandle)
|
discard CloseHandle(p.inHandle)
|
||||||
discard CloseHandle(p.outputHandle)
|
discard CloseHandle(p.outHandle)
|
||||||
discard CloseHandle(p.errorHandle)
|
discard CloseHandle(p.errHandle)
|
||||||
discard CloseHandle(p.FProcessHandle)
|
discard CloseHandle(p.FProcessHandle)
|
||||||
|
|
||||||
proc suspend(p: PProcess) =
|
proc suspend(p: PProcess) =
|
||||||
|
|
@ -425,13 +449,13 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
proc inputStream(p: PProcess): PStream =
|
proc inputStream(p: PProcess): PStream =
|
||||||
result = newFileHandleStream(p.inputHandle)
|
result = newFileHandleStream(p.inHandle)
|
||||||
|
|
||||||
proc outputStream(p: PProcess): PStream =
|
proc outputStream(p: PProcess): PStream =
|
||||||
result = newFileHandleStream(p.outputHandle)
|
result = newFileHandleStream(p.outHandle)
|
||||||
|
|
||||||
proc errorStream(p: PProcess): PStream =
|
proc errorStream(p: PProcess): PStream =
|
||||||
result = newFileHandleStream(p.errorHandle)
|
result = newFileHandleStream(p.errHandle)
|
||||||
|
|
||||||
proc execCmd(command: string): int =
|
proc execCmd(command: string): int =
|
||||||
var
|
var
|
||||||
|
|
@ -626,20 +650,20 @@ elif not defined(useNimRtl):
|
||||||
|
|
||||||
if poParentStreams in options:
|
if poParentStreams in options:
|
||||||
# does not make much sense, but better than nothing:
|
# does not make much sense, but better than nothing:
|
||||||
result.inputHandle = 0
|
result.inHandle = 0
|
||||||
result.outputHandle = 1
|
result.outHandle = 1
|
||||||
if poStdErrToStdOut in options:
|
if poStdErrToStdOut in options:
|
||||||
result.errorHandle = result.outputHandle
|
result.errHandle = result.outHandle
|
||||||
else:
|
else:
|
||||||
result.errorHandle = 2
|
result.errHandle = 2
|
||||||
else:
|
else:
|
||||||
result.inputHandle = p_stdin[writeIdx]
|
result.inHandle = p_stdin[writeIdx]
|
||||||
result.outputHandle = p_stdout[readIdx]
|
result.outHandle = p_stdout[readIdx]
|
||||||
if poStdErrToStdOut in options:
|
if poStdErrToStdOut in options:
|
||||||
result.errorHandle = result.outputHandle
|
result.errHandle = result.outHandle
|
||||||
discard close(p_stderr[readIdx])
|
discard close(p_stderr[readIdx])
|
||||||
else:
|
else:
|
||||||
result.errorHandle = p_stderr[readIdx]
|
result.errHandle = p_stderr[readIdx]
|
||||||
discard close(p_stderr[writeIdx])
|
discard close(p_stderr[writeIdx])
|
||||||
discard close(p_stdin[readIdx])
|
discard close(p_stdin[readIdx])
|
||||||
discard close(p_stdout[writeIdx])
|
discard close(p_stdout[writeIdx])
|
||||||
|
|
@ -648,9 +672,9 @@ elif not defined(useNimRtl):
|
||||||
if p.inStream != nil: close(p.inStream)
|
if p.inStream != nil: close(p.inStream)
|
||||||
if p.outStream != nil: close(p.outStream)
|
if p.outStream != nil: close(p.outStream)
|
||||||
if p.errStream != nil: close(p.errStream)
|
if p.errStream != nil: close(p.errStream)
|
||||||
discard close(p.inputHandle)
|
discard close(p.inHandle)
|
||||||
discard close(p.outputHandle)
|
discard close(p.outHandle)
|
||||||
discard close(p.errorHandle)
|
discard close(p.errHandle)
|
||||||
|
|
||||||
proc suspend(p: PProcess) =
|
proc suspend(p: PProcess) =
|
||||||
if kill(-p.id, SIGSTOP) != 0'i32: OSError(OSLastError())
|
if kill(-p.id, SIGSTOP) != 0'i32: OSError(OSLastError())
|
||||||
|
|
@ -696,17 +720,17 @@ elif not defined(useNimRtl):
|
||||||
|
|
||||||
proc inputStream(p: PProcess): PStream =
|
proc inputStream(p: PProcess): PStream =
|
||||||
if p.inStream == nil:
|
if p.inStream == nil:
|
||||||
createStream(p.inStream, p.inputHandle, fmWrite)
|
createStream(p.inStream, p.inHandle, fmWrite)
|
||||||
return p.inStream
|
return p.inStream
|
||||||
|
|
||||||
proc outputStream(p: PProcess): PStream =
|
proc outputStream(p: PProcess): PStream =
|
||||||
if p.outStream == nil:
|
if p.outStream == nil:
|
||||||
createStream(p.outStream, p.outputHandle, fmRead)
|
createStream(p.outStream, p.outHandle, fmRead)
|
||||||
return p.outStream
|
return p.outStream
|
||||||
|
|
||||||
proc errorStream(p: PProcess): PStream =
|
proc errorStream(p: PProcess): PStream =
|
||||||
if p.errStream == nil:
|
if p.errStream == nil:
|
||||||
createStream(p.errStream, p.errorHandle, fmRead)
|
createStream(p.errStream, p.errHandle, fmRead)
|
||||||
return p.errStream
|
return p.errStream
|
||||||
|
|
||||||
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
|
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
|
||||||
|
|
@ -717,14 +741,14 @@ elif not defined(useNimRtl):
|
||||||
proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
|
proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
|
||||||
FD_ZERO(fd)
|
FD_ZERO(fd)
|
||||||
for i in items(s):
|
for i in items(s):
|
||||||
m = max(m, int(i.outputHandle))
|
m = max(m, int(i.outHandle))
|
||||||
FD_SET(cint(i.outputHandle), fd)
|
FD_SET(cint(i.outHandle), fd)
|
||||||
|
|
||||||
proc pruneProcessSet(s: var seq[PProcess], fd: var TFdSet) =
|
proc pruneProcessSet(s: var seq[PProcess], fd: var TFdSet) =
|
||||||
var i = 0
|
var i = 0
|
||||||
var L = s.len
|
var L = s.len
|
||||||
while i < L:
|
while i < L:
|
||||||
if FD_ISSET(cint(s[i].outputHandle), fd) != 0'i32:
|
if FD_ISSET(cint(s[i].outHandle), fd) != 0'i32:
|
||||||
s[i] = s[L-1]
|
s[i] = s[L-1]
|
||||||
dec(L)
|
dec(L)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,8 @@ proc recvBuffer(s: var TScgiState, L: int) =
|
||||||
scgiError("could not read all data")
|
scgiError("could not read all data")
|
||||||
setLen(s.input, L)
|
setLen(s.input, L)
|
||||||
|
|
||||||
proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1") =
|
proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1",
|
||||||
|
reuseAddr = False) =
|
||||||
## opens a connection.
|
## opens a connection.
|
||||||
s.bufLen = 4000
|
s.bufLen = 4000
|
||||||
s.input = newString(s.buflen) # will be reused
|
s.input = newString(s.buflen) # will be reused
|
||||||
|
|
@ -104,6 +105,8 @@ proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1") =
|
||||||
new(s.client) # Initialise s.client for `next`
|
new(s.client) # Initialise s.client for `next`
|
||||||
if s.server == InvalidSocket: scgiError("could not open socket")
|
if s.server == InvalidSocket: scgiError("could not open socket")
|
||||||
#s.server.connect(connectionName, port)
|
#s.server.connect(connectionName, port)
|
||||||
|
if reuseAddr:
|
||||||
|
s.server.setSockOpt(OptReuseAddr, True)
|
||||||
bindAddr(s.server, port, address)
|
bindAddr(s.server, port, address)
|
||||||
listen(s.server)
|
listen(s.server)
|
||||||
|
|
||||||
|
|
@ -243,7 +246,8 @@ proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
|
||||||
|
|
||||||
proc open*(handleRequest: proc (client: PAsyncSocket,
|
proc open*(handleRequest: proc (client: PAsyncSocket,
|
||||||
input: string, headers: PStringTable) {.closure.},
|
input: string, headers: PStringTable) {.closure.},
|
||||||
port = TPort(4000), address = "127.0.0.1"): PAsyncScgiState =
|
port = TPort(4000), address = "127.0.0.1",
|
||||||
|
reuseAddr = false): PAsyncScgiState =
|
||||||
## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.
|
## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.
|
||||||
##
|
##
|
||||||
## After the execution of ``handleRequest`` the client socket will be closed
|
## After the execution of ``handleRequest`` the client socket will be closed
|
||||||
|
|
@ -252,6 +256,8 @@ proc open*(handleRequest: proc (client: PAsyncSocket,
|
||||||
new(cres)
|
new(cres)
|
||||||
cres.asyncServer = AsyncSocket()
|
cres.asyncServer = AsyncSocket()
|
||||||
cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres)
|
cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres)
|
||||||
|
if reuseAddr:
|
||||||
|
cres.asyncServer.setSockOpt(OptReuseAddr, True)
|
||||||
bindAddr(cres.asyncServer, port, address)
|
bindAddr(cres.asyncServer, port, address)
|
||||||
listen(cres.asyncServer)
|
listen(cres.asyncServer)
|
||||||
cres.handleRequest = handleRequest
|
cres.handleRequest = handleRequest
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ when hostos == "solaris":
|
||||||
|
|
||||||
import os, parseutils
|
import os, parseutils
|
||||||
from times import epochTime
|
from times import epochTime
|
||||||
|
import unsigned
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
import openssl
|
import openssl
|
||||||
|
|
@ -62,7 +63,7 @@ const
|
||||||
|
|
||||||
type
|
type
|
||||||
TSocketImpl = object ## socket type
|
TSocketImpl = object ## socket type
|
||||||
fd: cint
|
fd: TSocketHandle
|
||||||
case isBuffered: bool # determines whether this socket is buffered.
|
case isBuffered: bool # determines whether this socket is buffered.
|
||||||
of true:
|
of true:
|
||||||
buffer: array[0..BufferSize, char]
|
buffer: array[0..BufferSize, char]
|
||||||
|
|
@ -82,7 +83,7 @@ type
|
||||||
|
|
||||||
TSocket* = ref TSocketImpl
|
TSocket* = ref TSocketImpl
|
||||||
|
|
||||||
TPort* = distinct int16 ## port type
|
TPort* = distinct uint16 ## port type
|
||||||
|
|
||||||
TDomain* = enum ## domain, which specifies the protocol family of the
|
TDomain* = enum ## domain, which specifies the protocol family of the
|
||||||
## created socket. Other domains than those that are listed
|
## created socket. Other domains than those that are listed
|
||||||
|
|
@ -118,6 +119,10 @@ type
|
||||||
length*: int
|
length*: int
|
||||||
addrList*: seq[string]
|
addrList*: seq[string]
|
||||||
|
|
||||||
|
TSOBool* = enum ## Boolean socket options.
|
||||||
|
OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
|
||||||
|
OptOOBInline, OptReuseAddr
|
||||||
|
|
||||||
TRecvLineResult* = enum ## result for recvLineAsync
|
TRecvLineResult* = enum ## result for recvLineAsync
|
||||||
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
|
||||||
|
|
||||||
|
|
@ -126,7 +131,19 @@ type
|
||||||
|
|
||||||
ETimeout* = object of ESynch
|
ETimeout* = object of ESynch
|
||||||
|
|
||||||
proc newTSocket(fd: int32, isBuff: bool): TSocket =
|
let
|
||||||
|
InvalidSocket*: TSocket = nil ## invalid socket
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
let
|
||||||
|
OSInvalidSocket = winlean.INVALID_SOCKET
|
||||||
|
else:
|
||||||
|
let
|
||||||
|
OSInvalidSocket = posix.INVALID_SOCKET
|
||||||
|
|
||||||
|
proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket =
|
||||||
|
if fd == OSInvalidSocket:
|
||||||
|
return nil
|
||||||
new(result)
|
new(result)
|
||||||
result.fd = fd
|
result.fd = fd
|
||||||
result.isBuffered = isBuff
|
result.isBuffered = isBuff
|
||||||
|
|
@ -134,15 +151,11 @@ proc newTSocket(fd: int32, isBuff: bool): TSocket =
|
||||||
result.currPos = 0
|
result.currPos = 0
|
||||||
result.nonblocking = false
|
result.nonblocking = false
|
||||||
|
|
||||||
let
|
|
||||||
InvalidSocket*: TSocket = nil ## invalid socket
|
|
||||||
|
|
||||||
proc `==`*(a, b: TPort): bool {.borrow.}
|
proc `==`*(a, b: TPort): bool {.borrow.}
|
||||||
## ``==`` for ports.
|
## ``==`` for ports.
|
||||||
|
|
||||||
proc `$`*(p: TPort): string =
|
proc `$`*(p: TPort): string {.borrow.}
|
||||||
## returns the port number as a string
|
## returns the port number as a string
|
||||||
result = $ze(int16(p))
|
|
||||||
|
|
||||||
proc ntohl*(x: int32): int32 =
|
proc ntohl*(x: int32): int32 =
|
||||||
## Converts 32-bit integers from network to host byte order.
|
## Converts 32-bit integers from network to host byte order.
|
||||||
|
|
@ -212,6 +225,8 @@ else:
|
||||||
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
||||||
protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket =
|
protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket =
|
||||||
## Creates a new socket; returns `InvalidSocket` if an error occurs.
|
## Creates a new socket; returns `InvalidSocket` if an error occurs.
|
||||||
|
|
||||||
|
# TODO: Perhaps this should just raise EOS when an error occurs.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
|
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
|
||||||
else:
|
else:
|
||||||
|
|
@ -456,7 +471,7 @@ template acceptAddrPlain(noClientRet, successRet: expr,
|
||||||
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
|
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
|
||||||
addr(addrLen))
|
addr(addrLen))
|
||||||
|
|
||||||
if sock < 0:
|
if sock == OSInvalidSocket:
|
||||||
let err = OSLastError()
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
if err.int32 == WSAEINPROGRESS:
|
if err.int32 == WSAEINPROGRESS:
|
||||||
|
|
@ -529,7 +544,7 @@ proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {.
|
||||||
SSLError("Unknown error")
|
SSLError("Unknown error")
|
||||||
|
|
||||||
proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].}
|
proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].}
|
||||||
## sets blocking mode on socket
|
## Sets blocking mode on socket
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
proc acceptAddrSSL*(server: TSocket, client: var TSocket,
|
proc acceptAddrSSL*(server: TSocket, client: var TSocket,
|
||||||
|
|
@ -623,24 +638,32 @@ proc close*(socket: TSocket) =
|
||||||
discard SSLShutdown(socket.sslHandle)
|
discard SSLShutdown(socket.sslHandle)
|
||||||
|
|
||||||
proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
|
proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
|
||||||
## well-known getservbyname proc.
|
## Searches the database from the beginning and finds the first entry for
|
||||||
|
## which the service name specified by ``name`` matches the s_name member
|
||||||
|
## and the protocol name specified by ``proto`` matches the s_proto member.
|
||||||
|
##
|
||||||
|
## On posix this will search through the ``/etc/services`` file.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var s = winlean.getservbyname(name, proto)
|
var s = winlean.getservbyname(name, proto)
|
||||||
else:
|
else:
|
||||||
var s = posix.getservbyname(name, proto)
|
var s = posix.getservbyname(name, proto)
|
||||||
if s == nil: OSError(OSLastError())
|
if s == nil: raise newException(EOS, "Service not found.")
|
||||||
result.name = $s.s_name
|
result.name = $s.s_name
|
||||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||||
result.port = TPort(s.s_port)
|
result.port = TPort(s.s_port)
|
||||||
result.proto = $s.s_proto
|
result.proto = $s.s_proto
|
||||||
|
|
||||||
proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
|
proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
|
||||||
## well-known getservbyport proc.
|
## Searches the database from the beginning and finds the first entry for
|
||||||
|
## which the port specified by ``port`` matches the s_port member and the
|
||||||
|
## protocol name specified by ``proto`` matches the s_proto member.
|
||||||
|
##
|
||||||
|
## On posix this will search through the ``/etc/services`` file.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
||||||
else:
|
else:
|
||||||
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
||||||
if s == nil: OSError(OSLastError())
|
if s == nil: raise newException(EOS, "Service not found.")
|
||||||
result.name = $s.s_name
|
result.name = $s.s_name
|
||||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||||
result.port = TPort(s.s_port)
|
result.port = TPort(s.s_port)
|
||||||
|
|
@ -676,7 +699,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
|
||||||
result.length = int(s.h_length)
|
result.length = int(s.h_length)
|
||||||
|
|
||||||
proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
||||||
## well-known gethostbyname proc.
|
## This function will lookup the IP address of a hostname.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var s = winlean.gethostbyname(name)
|
var s = winlean.gethostbyname(name)
|
||||||
else:
|
else:
|
||||||
|
|
@ -714,6 +737,34 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||||
sizeof(value).TSockLen) < 0'i32:
|
sizeof(value).TSockLen) < 0'i32:
|
||||||
OSError(OSLastError())
|
OSError(OSLastError())
|
||||||
|
|
||||||
|
proc toCInt(opt: TSOBool): cint =
|
||||||
|
case opt
|
||||||
|
of OptAcceptConn: SO_ACCEPTCONN
|
||||||
|
of OptBroadcast: SO_BROADCAST
|
||||||
|
of OptDebug: SO_DEBUG
|
||||||
|
of OptDontRoute: SO_DONTROUTE
|
||||||
|
of OptKeepAlive: SO_KEEPALIVE
|
||||||
|
of OptOOBInline: SO_OOBINLINE
|
||||||
|
of OptReuseAddr: SO_REUSEADDR
|
||||||
|
|
||||||
|
proc getSockOpt*(socket: TSocket, opt: TSOBool, level = SOL_SOCKET): bool {.
|
||||||
|
tags: [FReadIO].} =
|
||||||
|
## Retrieves option ``opt`` as a boolean value.
|
||||||
|
var res: cint
|
||||||
|
var size = sizeof(res).TSockLen
|
||||||
|
if getsockopt(socket.fd, cint(level), toCInt(opt),
|
||||||
|
addr(res), addr(size)) < 0'i32:
|
||||||
|
OSError(OSLastError())
|
||||||
|
result = res != 0
|
||||||
|
|
||||||
|
proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {.
|
||||||
|
tags: [FWriteIO].} =
|
||||||
|
## Sets option ``opt`` to a boolean value specified by ``value``.
|
||||||
|
var valuei = cint(if value: 1 else: 0)
|
||||||
|
if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),
|
||||||
|
sizeof(valuei).TSockLen) < 0'i32:
|
||||||
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc connect*(socket: TSocket, address: string, port = TPort(0),
|
proc connect*(socket: TSocket, address: string, port = TPort(0),
|
||||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
||||||
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
|
## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
|
||||||
|
|
@ -866,11 +917,6 @@ proc timeValFromMilliseconds(timeout = 500): TTimeVal =
|
||||||
var seconds = timeout div 1000
|
var seconds = timeout div 1000
|
||||||
result.tv_sec = seconds.int32
|
result.tv_sec = seconds.int32
|
||||||
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
||||||
#proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint,
|
|
||||||
# fromm: ptr TSockAddr, fromlen: ptr cint): cint
|
|
||||||
|
|
||||||
#proc sendto*(s: TWinSocket, buf: cstring, len, flags: cint,
|
|
||||||
# to: ptr TSockAddr, tolen: cint): cint
|
|
||||||
|
|
||||||
proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) =
|
proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) =
|
||||||
FD_ZERO(fd)
|
FD_ZERO(fd)
|
||||||
|
|
@ -1608,14 +1654,14 @@ when defined(Windows):
|
||||||
FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
|
FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
|
||||||
(102 shl 8) or 126
|
(102 shl 8) or 126
|
||||||
|
|
||||||
proc ioctlsocket(s: TWinSocket, cmd: clong,
|
proc ioctlsocket(s: TSocketHandle, cmd: clong,
|
||||||
argptr: ptr clong): cint {.
|
argptr: ptr clong): cint {.
|
||||||
stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".}
|
stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".}
|
||||||
|
|
||||||
proc setBlocking(s: TSocket, blocking: bool) =
|
proc setBlocking(s: TSocket, blocking: bool) =
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
|
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
|
||||||
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
|
if ioctlsocket(TSocketHandle(s.fd), FIONBIO, addr(mode)) == -1:
|
||||||
OSError(OSLastError())
|
OSError(OSLastError())
|
||||||
else: # BSD sockets
|
else: # BSD sockets
|
||||||
var x: int = fcntl(s.fd, F_GETFL, 0)
|
var x: int = fcntl(s.fd, F_GETFL, 0)
|
||||||
|
|
@ -1656,9 +1702,12 @@ proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
|
||||||
proc isSSL*(socket: TSocket): bool = return socket.isSSL
|
proc isSSL*(socket: TSocket): bool = return socket.isSSL
|
||||||
## Determines whether ``socket`` is a SSL socket.
|
## Determines whether ``socket`` is a SSL socket.
|
||||||
|
|
||||||
proc getFD*(socket: TSocket): cint = return socket.fd
|
proc getFD*(socket: TSocket): TSocketHandle = return socket.fd
|
||||||
## Returns the socket's file descriptor
|
## Returns the socket's file descriptor
|
||||||
|
|
||||||
|
proc isBlocking*(socket: TSocket): bool = not socket.nonblocking
|
||||||
|
## Determines whether ``socket`` is blocking.
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var wsa: TWSADATA
|
var wsa: TWSADATA
|
||||||
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
|
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,8 @@ proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float =
|
||||||
else:
|
else:
|
||||||
curMonth.inc()
|
curMonth.inc()
|
||||||
result += float(newinterv.days * 24 * 60 * 60)
|
result += float(newinterv.days * 24 * 60 * 60)
|
||||||
result += float(newinterv.minutes * 60 * 60)
|
result += float(newinterv.hours * 60 * 60)
|
||||||
|
result += float(newinterv.minutes * 60)
|
||||||
result += float(newinterv.seconds)
|
result += float(newinterv.seconds)
|
||||||
result += newinterv.miliseconds / 1000
|
result += newinterv.miliseconds / 1000
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,31 +55,31 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
|
||||||
result = TRune(ord(s[i]))
|
result = TRune(ord(s[i]))
|
||||||
when doInc: inc(i)
|
when doInc: inc(i)
|
||||||
elif ord(s[i]) shr 5 == 0b110:
|
elif ord(s[i]) shr 5 == 0b110:
|
||||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
# assert(ord(s[i+1]) shr 6 == 0b10)
|
||||||
result = TRune((ord(s[i]) and (ones(5))) shl 6 or
|
result = TRune((ord(s[i]) and (ones(5))) shl 6 or
|
||||||
(ord(s[i+1]) and ones(6)))
|
(ord(s[i+1]) and ones(6)))
|
||||||
when doInc: inc(i, 2)
|
when doInc: inc(i, 2)
|
||||||
elif ord(s[i]) shr 4 == 0b1110:
|
elif ord(s[i]) shr 4 == 0b1110:
|
||||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
# assert(ord(s[i+1]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
# assert(ord(s[i+2]) shr 6 == 0b10)
|
||||||
result = TRune((ord(s[i]) and ones(4)) shl 12 or
|
result = TRune((ord(s[i]) and ones(4)) shl 12 or
|
||||||
(ord(s[i+1]) and ones(6)) shl 6 or
|
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||||
(ord(s[i+2]) and ones(6)))
|
(ord(s[i+2]) and ones(6)))
|
||||||
when doInc: inc(i, 3)
|
when doInc: inc(i, 3)
|
||||||
elif ord(s[i]) shr 3 == 0b11110:
|
elif ord(s[i]) shr 3 == 0b11110:
|
||||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
# assert(ord(s[i+1]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
# assert(ord(s[i+2]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
# assert(ord(s[i+3]) shr 6 == 0b10)
|
||||||
result = TRune((ord(s[i]) and ones(3)) shl 18 or
|
result = TRune((ord(s[i]) and ones(3)) shl 18 or
|
||||||
(ord(s[i+1]) and ones(6)) shl 12 or
|
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||||
(ord(s[i+2]) and ones(6)) shl 6 or
|
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||||
(ord(s[i+3]) and ones(6)))
|
(ord(s[i+3]) and ones(6)))
|
||||||
when doInc: inc(i, 4)
|
when doInc: inc(i, 4)
|
||||||
elif ord(s[i]) shr 2 == 0b111110:
|
elif ord(s[i]) shr 2 == 0b111110:
|
||||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
# assert(ord(s[i+1]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
# assert(ord(s[i+2]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
# assert(ord(s[i+3]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+4]) shr 6 == 0b10)
|
# assert(ord(s[i+4]) shr 6 == 0b10)
|
||||||
result = TRune((ord(s[i]) and ones(2)) shl 24 or
|
result = TRune((ord(s[i]) and ones(2)) shl 24 or
|
||||||
(ord(s[i+1]) and ones(6)) shl 18 or
|
(ord(s[i+1]) and ones(6)) shl 18 or
|
||||||
(ord(s[i+2]) and ones(6)) shl 12 or
|
(ord(s[i+2]) and ones(6)) shl 12 or
|
||||||
|
|
@ -87,11 +87,11 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
|
||||||
(ord(s[i+4]) and ones(6)))
|
(ord(s[i+4]) and ones(6)))
|
||||||
when doInc: inc(i, 5)
|
when doInc: inc(i, 5)
|
||||||
elif ord(s[i]) shr 1 == 0b1111110:
|
elif ord(s[i]) shr 1 == 0b1111110:
|
||||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
# assert(ord(s[i+1]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
# assert(ord(s[i+2]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
# assert(ord(s[i+3]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+4]) shr 6 == 0b10)
|
# assert(ord(s[i+4]) shr 6 == 0b10)
|
||||||
assert(ord(s[i+5]) shr 6 == 0b10)
|
# assert(ord(s[i+5]) shr 6 == 0b10)
|
||||||
result = TRune((ord(s[i]) and ones(1)) shl 30 or
|
result = TRune((ord(s[i]) and ones(1)) shl 30 or
|
||||||
(ord(s[i+1]) and ones(6)) shl 24 or
|
(ord(s[i+1]) and ones(6)) shl 24 or
|
||||||
(ord(s[i+2]) and ones(6)) shl 18 or
|
(ord(s[i+2]) and ones(6)) shl 18 or
|
||||||
|
|
|
||||||
|
|
@ -849,7 +849,7 @@ const
|
||||||
## a string that describes the application type. Possible values:
|
## a string that describes the application type. Possible values:
|
||||||
## "console", "gui", "lib".
|
## "console", "gui", "lib".
|
||||||
|
|
||||||
seqShallowFlag = 1 shl (sizeof(int)*8-1)
|
seqShallowFlag = low(int)
|
||||||
|
|
||||||
proc compileOption*(option: string): bool {.
|
proc compileOption*(option: string): bool {.
|
||||||
magic: "CompileOption", noSideEffect.}
|
magic: "CompileOption", noSideEffect.}
|
||||||
|
|
@ -1795,7 +1795,7 @@ when defined(JS):
|
||||||
|
|
||||||
elif hostOS != "standalone":
|
elif hostOS != "standalone":
|
||||||
{.push stack_trace:off, profiler:off.}
|
{.push stack_trace:off, profiler:off.}
|
||||||
proc add*(x: var string, y: cstring) {.noStackFrame.} =
|
proc add*(x: var string, y: cstring) =
|
||||||
var i = 0
|
var i = 0
|
||||||
while y[i] != '\0':
|
while y[i] != '\0':
|
||||||
add(x, y[i])
|
add(x, y[i])
|
||||||
|
|
|
||||||
|
|
@ -520,11 +520,18 @@ proc allocInv(a: TMemRegion): bool =
|
||||||
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
|
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
|
||||||
var c = a.freeSmallChunks[s]
|
var c = a.freeSmallChunks[s]
|
||||||
while c != nil:
|
while c != nil:
|
||||||
if c.next == c: return false
|
if c.next == c:
|
||||||
if c.size != s * MemAlign: return false
|
echo "[SYSASSERT] c.next == c"
|
||||||
|
return false
|
||||||
|
if c.size != s * MemAlign:
|
||||||
|
echo "[SYSASSERT] c.size != s * MemAlign"
|
||||||
|
return false
|
||||||
var it = c.freeList
|
var it = c.freeList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
if it.zeroField != 0: return false
|
if it.zeroField != 0:
|
||||||
|
echo "[SYSASSERT] it.zeroField != 0"
|
||||||
|
cprintf("%ld %p\n", it.zeroField, it)
|
||||||
|
return false
|
||||||
it = it.next
|
it = it.next
|
||||||
c = c.next
|
c = c.next
|
||||||
result = true
|
result = true
|
||||||
|
|
@ -591,6 +598,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
|
||||||
add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size)
|
add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size)
|
||||||
sysAssert(isAccessible(a, result), "rawAlloc 14")
|
sysAssert(isAccessible(a, result), "rawAlloc 14")
|
||||||
sysAssert(allocInv(a), "rawAlloc: end")
|
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 TMemRegion, requestedSize: int): pointer =
|
||||||
result = rawAlloc(a, requestedSize)
|
result = rawAlloc(a, requestedSize)
|
||||||
|
|
@ -638,6 +646,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
|
||||||
del(a, a.root, cast[int](addr(c.data)))
|
del(a, a.root, cast[int](addr(c.data)))
|
||||||
freeBigChunk(a, c)
|
freeBigChunk(a, c)
|
||||||
sysAssert(allocInv(a), "rawDealloc: end")
|
sysAssert(allocInv(a), "rawDealloc: end")
|
||||||
|
when logAlloc: cprintf("rawDealloc: %p\n", p)
|
||||||
|
|
||||||
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
|
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
|
||||||
if isAccessible(a, p):
|
if isAccessible(a, p):
|
||||||
|
|
|
||||||
|
|
@ -9,68 +9,207 @@
|
||||||
|
|
||||||
# Atomic operations for Nimrod.
|
# Atomic operations for Nimrod.
|
||||||
|
|
||||||
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport and
|
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
|
||||||
not defined(windows):
|
|
||||||
proc sync_add_and_fetch(p: var int, val: int): int {.
|
type
|
||||||
importc: "__sync_add_and_fetch", nodecl.}
|
AtomMemModel* = enum
|
||||||
proc sync_sub_and_fetch(p: var int, val: int): int {.
|
ATOMIC_RELAXED,
|
||||||
importc: "__sync_sub_and_fetch", nodecl.}
|
## No barriers or synchronization.
|
||||||
|
ATOMIC_CONSUME,
|
||||||
|
## Data dependency only for both barrier and synchronization with another thread.
|
||||||
|
ATOMIC_ACQUIRE,
|
||||||
|
## Barrier to hoisting of code and synchronizes with release (or stronger)
|
||||||
|
## semantic stores from another thread.
|
||||||
|
ATOMIC_RELEASE,
|
||||||
|
## Barrier to sinking of code and synchronizes with acquire (or stronger)
|
||||||
|
## semantic loads from another thread.
|
||||||
|
ATOMIC_ACQ_REL,
|
||||||
|
## Full barrier in both directions and synchronizes with acquire loads
|
||||||
|
## and release stores in another thread.
|
||||||
|
ATOMIC_SEQ_CST
|
||||||
|
## Full barrier in both directions and synchronizes with acquire loads
|
||||||
|
## and release stores in all threads.
|
||||||
|
|
||||||
|
TAtomType* = TNumber|pointer|ptr|char
|
||||||
|
## Type Class representing valid types for use with atomic procs
|
||||||
|
|
||||||
|
proc atomic_load_n*[T: TAtomType](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 atomic_load*[T: TAtomType](p: ptr T, 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 atomic_store_n*[T: TAtomType](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 atomic_store*[T: TAtomType](p: ptr T, 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 atomic_exchange_n*[T: TAtomType](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 atomic_exchange*[T: TAtomType](p: ptr T, val: ptr T, 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 atomic_compare_exchange_n*[T: TAtomType](p: ptr T, 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
|
||||||
|
## contents at p with the contents at expected and if equal, writes desired at p.
|
||||||
|
## If they are not equal, the current contents at p is written into expected.
|
||||||
|
## Weak is true for weak compare_exchange, and false for the strong variation.
|
||||||
|
## Many targets only offer the strong variation and ignore the parameter.
|
||||||
|
## When in doubt, use the strong variation.
|
||||||
|
## True is returned if desired is written at p and the execution is considered
|
||||||
|
## to conform to the memory model specified by success_memmodel. There are no
|
||||||
|
## restrictions on what memory model can be used here. False is returned otherwise,
|
||||||
|
## and the execution is considered to conform to failure_memmodel. This memory model
|
||||||
|
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
|
||||||
|
## than that specified by success_memmodel.
|
||||||
|
|
||||||
|
proc atomic_compare_exchange*[T: TAtomType](p: ptr T, expected: ptr T, desired: ptr T,
|
||||||
|
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
|
||||||
|
importc: "__atomic_compare_exchange_n ", nodecl.}
|
||||||
|
## This proc implements the generic version of atomic_compare_exchange.
|
||||||
|
## The proc is virtually identical to atomic_compare_exchange_n, except the desired
|
||||||
|
## value is also a pointer.
|
||||||
|
|
||||||
|
## Perform the operation return the new value, all memory models are valid
|
||||||
|
proc atomic_add_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_add_fetch", nodecl.}
|
||||||
|
proc atomic_sub_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_sub_fetch", nodecl.}
|
||||||
|
proc atomic_or_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_or_fetch ", nodecl.}
|
||||||
|
proc atomic_and_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_and_fetch", nodecl.}
|
||||||
|
proc atomic_xor_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_xor_fetch", nodecl.}
|
||||||
|
proc atomic_nand_fetch*[T: TAtomType](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 atomic_fetch_add*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_fetch_add ", nodecl.}
|
||||||
|
proc atomic_fetch_sub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_fetch_sub ", nodecl.}
|
||||||
|
proc atomic_fetch_or*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_fetch_or ", nodecl.}
|
||||||
|
proc atomic_fetch_and*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_fetch_and ", nodecl.}
|
||||||
|
proc atomic_fetch_xor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_fetch_xor ", nodecl.}
|
||||||
|
proc atomic_fetch_nand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
|
||||||
|
importc: "__atomic_fetch_nand", nodecl.}
|
||||||
|
|
||||||
|
proc atomic_test_and_set*(p: pointer, mem: AtomMemModel): bool {.
|
||||||
|
importc: "__atomic_test_and_set ", nodecl.}
|
||||||
|
## This built-in function performs an atomic test-and-set operation on the byte at p.
|
||||||
|
## The byte is set to some implementation defined nonzero “set” value and the return
|
||||||
|
## value is true if and only if the previous contents were “set”.
|
||||||
|
## All memory models are valid.
|
||||||
|
|
||||||
|
proc atomic_clear*(p: pointer, mem: AtomMemModel) {.
|
||||||
|
importc: "__atomic_clear", nodecl.}
|
||||||
|
## This built-in function performs an atomic clear operation at p.
|
||||||
|
## After the operation, at p contains 0.
|
||||||
|
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_RELEASE
|
||||||
|
|
||||||
|
proc atomic_thread_fence*(mem: AtomMemModel) {.
|
||||||
|
importc: "__atomic_thread_fence ", nodecl.}
|
||||||
|
## This built-in function acts as a synchronization fence between threads based
|
||||||
|
## on the specified memory model. All memory orders are valid.
|
||||||
|
|
||||||
|
proc atomic_signal_fence*(mem: AtomMemModel) {.
|
||||||
|
importc: "__atomic_signal_fence ", nodecl.}
|
||||||
|
## This built-in function acts as a synchronization fence between a thread and
|
||||||
|
## signal handlers based in the same thread. All memory orders are valid.
|
||||||
|
|
||||||
|
proc atomic_always_lock_free*(size: int, p: pointer): bool {.
|
||||||
|
importc: "__atomic_always_lock_free ", nodecl.}
|
||||||
|
## This built-in function returns true if objects of size bytes always generate
|
||||||
|
## lock free atomic instructions for the target architecture. size must resolve
|
||||||
|
## to a compile-time constant and the result also resolves to a compile-time constant.
|
||||||
|
## ptr is an optional pointer to the object that may be used to determine alignment.
|
||||||
|
## A value of 0 indicates typical alignment should be used. The compiler may also
|
||||||
|
## ignore this parameter.
|
||||||
|
|
||||||
|
proc atomic_is_lock_free*(size: int, p: pointer): bool {.
|
||||||
|
importc: "__atomic_is_lock_free ", nodecl.}
|
||||||
|
## This built-in function returns true if objects of size bytes always generate
|
||||||
|
## lock free atomic instructions for the target architecture. If it is not known
|
||||||
|
## to be lock free a call is made to a runtime routine named __atomic_is_lock_free.
|
||||||
|
## ptr is an optional pointer to the object that may be used to determine alignment.
|
||||||
|
## A value of 0 indicates typical alignment should be used. The compiler may also
|
||||||
|
## ignore this parameter.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
elif defined(vcc) and hasThreadSupport:
|
elif defined(vcc) and hasThreadSupport:
|
||||||
proc sync_add_and_fetch(p: var int, val: int): int {.
|
proc add_and_fetch*(p: ptr int, val: int): int {.
|
||||||
importc: "NimXadd", nodecl.}
|
importc: "NimXadd", nodecl.}
|
||||||
else:
|
else:
|
||||||
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} =
|
proc add_and_fetch*(p: ptr int, val: int): int {.inline.} =
|
||||||
inc(p, val)
|
inc(p[], val)
|
||||||
result = p
|
result = p[]
|
||||||
|
|
||||||
proc atomicInc(memLoc: var int, x: int = 1): int =
|
|
||||||
when hasThreadSupport:
|
|
||||||
result = sync_add_and_fetch(memLoc, x)
|
|
||||||
|
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
|
||||||
|
|
||||||
|
#if defined(windows) and not defined(gcc) and hasThreadSupport:
|
||||||
|
# proc InterlockedCompareExchangePointer(mem: ptr pointer,
|
||||||
|
# newValue: pointer, comparand: pointer) : pointer {.nodecl,
|
||||||
|
# importc: "InterlockedCompareExchangePointer", header:"windows.h".}
|
||||||
|
|
||||||
|
# proc compareAndSwap*[T](mem: ptr T,
|
||||||
|
# expected: T, newValue: T): bool {.inline.}=
|
||||||
|
# ## Returns true if successfully set value at mem to newValue when value
|
||||||
|
# ## at mem == expected
|
||||||
|
# return InterlockedCompareExchangePointer(addr(mem),
|
||||||
|
# addr(newValue), addr(expected))[] == expected
|
||||||
|
|
||||||
|
#elif not hasThreadSupport:
|
||||||
|
# proc compareAndSwap*[T](mem: ptr T,
|
||||||
|
# expected: T, newValue: T): bool {.inline.} =
|
||||||
|
# ## Returns true if successfully set value at mem to newValue when value
|
||||||
|
# ## at mem == expected
|
||||||
|
# var oldval = mem[]
|
||||||
|
# if oldval == expected:
|
||||||
|
# mem[] = newValue
|
||||||
|
# return true
|
||||||
|
# return false
|
||||||
|
|
||||||
|
|
||||||
|
# Some convenient functions
|
||||||
|
proc atomicInc*(memLoc: var int, x: int = 1): int =
|
||||||
|
when defined(gcc) and hasThreadSupport:
|
||||||
|
result = atomic_add_fetch(memLoc.addr, x, ATOMIC_RELAXED)
|
||||||
else:
|
else:
|
||||||
inc(memLoc, x)
|
inc(memLoc, x)
|
||||||
result = memLoc
|
result = memLoc
|
||||||
|
|
||||||
proc atomicDec(memLoc: var int, x: int = 1): int =
|
proc atomicDec*(memLoc: var int, x: int = 1): int =
|
||||||
when hasThreadSupport:
|
when defined(gcc) and hasThreadSupport:
|
||||||
when defined(sync_sub_and_fetch):
|
when defined(atomic_sub_fetch):
|
||||||
result = sync_sub_and_fetch(memLoc, x)
|
result = atomic_sub_fetch(memLoc.addr, x, ATOMIC_RELAXED)
|
||||||
else:
|
else:
|
||||||
result = sync_add_and_fetch(memLoc, -x)
|
result = atomic_add_fetch(memLoc.addr, -x, ATOMIC_RELAXED)
|
||||||
else:
|
else:
|
||||||
dec(memLoc, x)
|
dec(memLoc, x)
|
||||||
result = memLoc
|
result = memLoc
|
||||||
|
|
||||||
|
|
||||||
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
|
|
||||||
|
|
||||||
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
|
|
||||||
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T, expected: T, newValue: T): bool {.nodecl,
|
|
||||||
importc: " __sync_bool_compare_and_swap".}
|
|
||||||
## Returns true if successfully set value at mem to newValue when value
|
|
||||||
## at mem == expected
|
|
||||||
|
|
||||||
elif defined(windows) and hasThreadSupport:
|
|
||||||
proc InterlockedCompareExchangePointer(mem: ptr pointer,
|
|
||||||
newValue: pointer, comparand: pointer) : pointer {.nodecl,
|
|
||||||
importc: "InterlockedCompareExchangePointer", header:"windows.h".}
|
|
||||||
|
|
||||||
|
|
||||||
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T,
|
|
||||||
expected: T, newValue: T): bool {.inline.}=
|
|
||||||
## Returns true if successfully set value at mem to newValue when value
|
|
||||||
## at mem == expected
|
|
||||||
return InterlockedCompareExchangePointer(addr(mem),
|
|
||||||
newValue, expected) == expected
|
|
||||||
|
|
||||||
elif not hasThreadSupport:
|
|
||||||
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T,
|
|
||||||
expected: T, newValue: T): bool {.inline.} =
|
|
||||||
## Returns true if successfully set value at mem to newValue when value
|
|
||||||
## at mem == expected
|
|
||||||
var oldval = mem
|
|
||||||
if oldval == expected:
|
|
||||||
mem = newValue
|
|
||||||
return true
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
# Garbage Collector
|
# Garbage Collector
|
||||||
#
|
#
|
||||||
# The basic algorithm is *Deferrent Reference Counting* with cycle detection.
|
# The basic algorithm is *Deferred Reference Counting* with cycle detection.
|
||||||
# This is achieved by combining a Deutsch-Bobrow garbage collector
|
# This is achieved by combining a Deutsch-Bobrow garbage collector
|
||||||
# together with Christoper's partial mark-sweep garbage collector.
|
# together with Christoper's partial mark-sweep garbage collector.
|
||||||
#
|
#
|
||||||
|
|
@ -407,12 +407,17 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||||
return
|
return
|
||||||
add(gch.zct, res)
|
add(gch.zct, res)
|
||||||
|
|
||||||
|
{.push stackTrace: off, profiler:off.}
|
||||||
|
proc gcInvariant*(msg: string) =
|
||||||
|
sysAssert(allocInv(gch.region), msg)
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
||||||
# generates a new object and sets its reference counter to 0
|
# generates a new object and sets its reference counter to 0
|
||||||
|
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
||||||
gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
# now it is buffered in the ZCT
|
# now it is buffered in the ZCT
|
||||||
|
|
@ -517,7 +522,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
writeCell("growObj new cell", res)
|
writeCell("growObj new cell", res)
|
||||||
gcTrace(ol, csZctFreed)
|
gcTrace(ol, csZctFreed)
|
||||||
gcTrace(res, csAllocated)
|
gcTrace(res, csAllocated)
|
||||||
when reallyDealloc: rawDealloc(gch.region, ol)
|
when reallyDealloc:
|
||||||
|
sysAssert(allocInv(gch.region), "growObj before dealloc")
|
||||||
|
rawDealloc(gch.region, ol)
|
||||||
else:
|
else:
|
||||||
sysAssert(ol.typ != nil, "growObj: 5")
|
sysAssert(ol.typ != nil, "growObj: 5")
|
||||||
zeroMem(ol, sizeof(TCell))
|
zeroMem(ol, sizeof(TCell))
|
||||||
|
|
@ -537,7 +544,9 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
|
||||||
prepareDealloc(c)
|
prepareDealloc(c)
|
||||||
gcTrace(c, csCycFreed)
|
gcTrace(c, csCycFreed)
|
||||||
when logGC: writeCell("cycle collector dealloc cell", c)
|
when logGC: writeCell("cycle collector dealloc cell", c)
|
||||||
when reallyDealloc: rawDealloc(gch.region, c)
|
when reallyDealloc:
|
||||||
|
sysAssert(allocInv(gch.region), "free cyclic cell")
|
||||||
|
rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
gcAssert(c.typ != nil, "freeCyclicCell")
|
gcAssert(c.typ != nil, "freeCyclicCell")
|
||||||
zeroMem(c, sizeof(TCell))
|
zeroMem(c, sizeof(TCell))
|
||||||
|
|
@ -910,7 +919,9 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
# access invalid memory. This is done by prepareDealloc():
|
# access invalid memory. This is done by prepareDealloc():
|
||||||
prepareDealloc(c)
|
prepareDealloc(c)
|
||||||
forAllChildren(c, waZctDecRef)
|
forAllChildren(c, waZctDecRef)
|
||||||
when reallyDealloc: rawDealloc(gch.region, c)
|
when reallyDealloc:
|
||||||
|
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
|
||||||
|
rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
sysAssert(c.typ != nil, "collectZCT 2")
|
sysAssert(c.typ != nil, "collectZCT 2")
|
||||||
zeroMem(c, sizeof(TCell))
|
zeroMem(c, sizeof(TCell))
|
||||||
|
|
|
||||||
|
|
@ -387,8 +387,7 @@ template `--`(rc: TRefCount): expr =
|
||||||
rc <% rcIncrement
|
rc <% rcIncrement
|
||||||
|
|
||||||
template `--` (rc: TRefCount, heapType: THeapType): expr =
|
template `--` (rc: TRefCount, heapType: THeapType): expr =
|
||||||
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement
|
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
|
||||||
else: --rc)
|
|
||||||
|
|
||||||
template doDecRef(cc: PCell,
|
template doDecRef(cc: PCell,
|
||||||
heapType = LocalHeap,
|
heapType = LocalHeap,
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ const
|
||||||
reallyOsDealloc = true
|
reallyOsDealloc = true
|
||||||
coalescRight = true
|
coalescRight = true
|
||||||
coalescLeft = true
|
coalescLeft = true
|
||||||
|
logAlloc = false
|
||||||
|
|
||||||
type
|
type
|
||||||
PPointer = ptr pointer
|
PPointer = ptr pointer
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,9 @@ const
|
||||||
|
|
||||||
proc WSAGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
|
proc WSAGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
|
||||||
|
|
||||||
|
type
|
||||||
|
TSocketHandle* = distinct int
|
||||||
|
|
||||||
type
|
type
|
||||||
TWSAData* {.pure, final, importc: "WSADATA", header: "Winsock2.h".} = object
|
TWSAData* {.pure, final, importc: "WSADATA", header: "Winsock2.h".} = object
|
||||||
wVersion, wHighVersion: int16
|
wVersion, wHighVersion: int16
|
||||||
|
|
@ -390,11 +393,9 @@ type
|
||||||
h_length*: int16
|
h_length*: int16
|
||||||
h_addr_list*: cstringArray
|
h_addr_list*: cstringArray
|
||||||
|
|
||||||
TWinSocket* = cint
|
|
||||||
|
|
||||||
TFdSet* {.pure, final.} = object
|
TFdSet* {.pure, final.} = object
|
||||||
fd_count*: cint # unsigned
|
fd_count*: cint # unsigned
|
||||||
fd_array*: array[0..FD_SETSIZE-1, TWinSocket]
|
fd_array*: array[0..FD_SETSIZE-1, TSocketHandle]
|
||||||
|
|
||||||
TTimeval* {.pure, final.} = object
|
TTimeval* {.pure, final.} = object
|
||||||
tv_sec*, tv_usec*: int32
|
tv_sec*, tv_usec*: int32
|
||||||
|
|
@ -413,6 +414,22 @@ type
|
||||||
|
|
||||||
var
|
var
|
||||||
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
|
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
|
||||||
|
INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
|
||||||
|
SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
|
||||||
|
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
|
||||||
|
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
|
||||||
|
SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse
|
||||||
|
SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive
|
||||||
|
SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses
|
||||||
|
SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs
|
||||||
|
SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible
|
||||||
|
SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present
|
||||||
|
SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line
|
||||||
|
|
||||||
|
SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
|
||||||
|
SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
|
||||||
|
|
||||||
|
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
|
||||||
|
|
||||||
proc getservbyname*(name, proto: cstring): ptr TServent {.
|
proc getservbyname*(name, proto: cstring): ptr TServent {.
|
||||||
stdcall, importc: "getservbyname", dynlib: ws2dll.}
|
stdcall, importc: "getservbyname", dynlib: ws2dll.}
|
||||||
|
|
@ -426,45 +443,45 @@ proc gethostbyaddr*(ip: ptr TInAddr, len: cuint, theType: cint): ptr THostEnt {.
|
||||||
proc gethostbyname*(name: cstring): ptr THostEnt {.
|
proc gethostbyname*(name: cstring): ptr THostEnt {.
|
||||||
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
|
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc socket*(af, typ, protocol: cint): TWinSocket {.
|
proc socket*(af, typ, protocol: cint): TSocketHandle {.
|
||||||
stdcall, importc: "socket", dynlib: ws2dll.}
|
stdcall, importc: "socket", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc closesocket*(s: TWinSocket): cint {.
|
proc closesocket*(s: TSocketHandle): cint {.
|
||||||
stdcall, importc: "closesocket", dynlib: ws2dll.}
|
stdcall, importc: "closesocket", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc accept*(s: TWinSocket, a: ptr TSockAddr, addrlen: ptr TSockLen): TWinSocket {.
|
proc accept*(s: TSocketHandle, a: ptr TSockAddr, addrlen: ptr TSockLen): TSocketHandle {.
|
||||||
stdcall, importc: "accept", dynlib: ws2dll.}
|
stdcall, importc: "accept", dynlib: ws2dll.}
|
||||||
proc bindSocket*(s: TWinSocket, name: ptr TSockAddr, namelen: TSockLen): cint {.
|
proc bindSocket*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
|
||||||
stdcall, importc: "bind", dynlib: ws2dll.}
|
stdcall, importc: "bind", dynlib: ws2dll.}
|
||||||
proc connect*(s: TWinSocket, name: ptr TSockAddr, namelen: TSockLen): cint {.
|
proc connect*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {.
|
||||||
stdcall, importc: "connect", dynlib: ws2dll.}
|
stdcall, importc: "connect", dynlib: ws2dll.}
|
||||||
proc getsockname*(s: TWinSocket, name: ptr TSockAddr,
|
proc getsockname*(s: TSocketHandle, name: ptr TSockAddr,
|
||||||
namelen: ptr TSockLen): cint {.
|
namelen: ptr TSockLen): cint {.
|
||||||
stdcall, importc: "getsockname", dynlib: ws2dll.}
|
stdcall, importc: "getsockname", dynlib: ws2dll.}
|
||||||
proc getsockopt*(s: TWinSocket, level, optname: cint, optval: pointer,
|
proc getsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer,
|
||||||
optlen: ptr TSockLen): cint {.
|
optlen: ptr TSockLen): cint {.
|
||||||
stdcall, importc: "getsockopt", dynlib: ws2dll.}
|
stdcall, importc: "getsockopt", dynlib: ws2dll.}
|
||||||
proc setsockopt*(s: TWinSocket, level, optname: cint, optval: pointer,
|
proc setsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer,
|
||||||
optlen: TSockLen): cint {.
|
optlen: TSockLen): cint {.
|
||||||
stdcall, importc: "setsockopt", dynlib: ws2dll.}
|
stdcall, importc: "setsockopt", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc listen*(s: TWinSocket, backlog: cint): cint {.
|
proc listen*(s: TSocketHandle, backlog: cint): cint {.
|
||||||
stdcall, importc: "listen", dynlib: ws2dll.}
|
stdcall, importc: "listen", dynlib: ws2dll.}
|
||||||
proc recv*(s: TWinSocket, buf: pointer, len, flags: cint): cint {.
|
proc recv*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
|
||||||
stdcall, importc: "recv", dynlib: ws2dll.}
|
stdcall, importc: "recv", dynlib: ws2dll.}
|
||||||
proc recvfrom*(s: TWinSocket, buf: cstring, len, flags: cint,
|
proc recvfrom*(s: TSocketHandle, buf: cstring, len, flags: cint,
|
||||||
fromm: ptr TSockAddr, fromlen: ptr Tsocklen): cint {.
|
fromm: ptr TSockAddr, fromlen: ptr Tsocklen): cint {.
|
||||||
stdcall, importc: "recvfrom", dynlib: ws2dll.}
|
stdcall, importc: "recvfrom", dynlib: ws2dll.}
|
||||||
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
|
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
|
||||||
timeout: ptr TTimeval): cint {.
|
timeout: ptr TTimeval): cint {.
|
||||||
stdcall, importc: "select", dynlib: ws2dll.}
|
stdcall, importc: "select", dynlib: ws2dll.}
|
||||||
proc send*(s: TWinSocket, buf: pointer, len, flags: cint): cint {.
|
proc send*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
|
||||||
stdcall, importc: "send", dynlib: ws2dll.}
|
stdcall, importc: "send", dynlib: ws2dll.}
|
||||||
proc sendto*(s: TWinSocket, buf: pointer, len, flags: cint,
|
proc sendto*(s: TSocketHandle, buf: pointer, len, flags: cint,
|
||||||
to: ptr TSockAddr, tolen: Tsocklen): cint {.
|
to: ptr TSockAddr, tolen: Tsocklen): cint {.
|
||||||
stdcall, importc: "sendto", dynlib: ws2dll.}
|
stdcall, importc: "sendto", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc shutdown*(s: TWinSocket, how: cint): cint {.
|
proc shutdown*(s: TSocketHandle, how: cint): cint {.
|
||||||
stdcall, importc: "shutdown", dynlib: ws2dll.}
|
stdcall, importc: "shutdown", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
|
proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
|
||||||
|
|
@ -475,13 +492,13 @@ proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
|
||||||
proc inet_addr*(cp: cstring): int32 {.
|
proc inet_addr*(cp: cstring): int32 {.
|
||||||
stdcall, importc: "inet_addr", dynlib: ws2dll.}
|
stdcall, importc: "inet_addr", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc WSAFDIsSet(s: TWinSocket, FDSet: var TFDSet): bool {.
|
proc WSAFDIsSet(s: TSocketHandle, FDSet: var TFDSet): bool {.
|
||||||
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll.}
|
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc FD_ISSET*(Socket: TWinSocket, FDSet: var TFDSet): cint =
|
proc FD_ISSET*(Socket: TSocketHandle, FDSet: var TFDSet): cint =
|
||||||
result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32
|
result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32
|
||||||
|
|
||||||
proc FD_SET*(Socket: TWinSocket, FDSet: var TFDSet) =
|
proc FD_SET*(Socket: TSocketHandle, FDSet: var TFDSet) =
|
||||||
if FDSet.fd_count < FD_SETSIZE:
|
if FDSet.fd_count < FD_SETSIZE:
|
||||||
FDSet.fd_array[int(FDSet.fd_count)] = Socket
|
FDSet.fd_array[int(FDSet.fd_count)] = Socket
|
||||||
inc(FDSet.fd_count)
|
inc(FDSet.fd_count)
|
||||||
|
|
|
||||||
|
|
@ -36,23 +36,23 @@ else:
|
||||||
const
|
const
|
||||||
dllname = "libGL.so"
|
dllname = "libGL.so"
|
||||||
const
|
const
|
||||||
GLX_USE_GL* = 1
|
GLX_USE_GL* = 1'i32
|
||||||
GLX_BUFFER_SIZE* = 2
|
GLX_BUFFER_SIZE* = 2'i32
|
||||||
GLX_LEVEL* = 3
|
GLX_LEVEL* = 3'i32
|
||||||
GLX_RGBA* = 4
|
GLX_RGBA* = 4'i32
|
||||||
GLX_DOUBLEBUFFER* = 5
|
GLX_DOUBLEBUFFER* = 5'i32
|
||||||
GLX_STEREO* = 6
|
GLX_STEREO* = 6'i32
|
||||||
GLX_AUX_BUFFERS* = 7
|
GLX_AUX_BUFFERS* = 7'i32
|
||||||
GLX_RED_SIZE* = 8
|
GLX_RED_SIZE* = 8'i32
|
||||||
GLX_GREEN_SIZE* = 9
|
GLX_GREEN_SIZE* = 9'i32
|
||||||
GLX_BLUE_SIZE* = 10
|
GLX_BLUE_SIZE* = 10'i32
|
||||||
GLX_ALPHA_SIZE* = 11
|
GLX_ALPHA_SIZE* = 11'i32
|
||||||
GLX_DEPTH_SIZE* = 12
|
GLX_DEPTH_SIZE* = 12'i32
|
||||||
GLX_STENCIL_SIZE* = 13
|
GLX_STENCIL_SIZE* = 13'i32
|
||||||
GLX_ACCUM_RED_SIZE* = 14
|
GLX_ACCUM_RED_SIZE* = 14'i32
|
||||||
GLX_ACCUM_GREEN_SIZE* = 15
|
GLX_ACCUM_GREEN_SIZE* = 15'i32
|
||||||
GLX_ACCUM_BLUE_SIZE* = 16
|
GLX_ACCUM_BLUE_SIZE* = 16'i32
|
||||||
GLX_ACCUM_ALPHA_SIZE* = 17 # GLX_EXT_visual_info extension
|
GLX_ACCUM_ALPHA_SIZE* = 17'i32 # GLX_EXT_visual_info extension
|
||||||
GLX_X_VISUAL_TYPE_EXT* = 0x00000022
|
GLX_X_VISUAL_TYPE_EXT* = 0x00000022
|
||||||
GLX_TRANSPARENT_TYPE_EXT* = 0x00000023
|
GLX_TRANSPARENT_TYPE_EXT* = 0x00000023
|
||||||
GLX_TRANSPARENT_INDEX_VALUE_EXT* = 0x00000024
|
GLX_TRANSPARENT_INDEX_VALUE_EXT* = 0x00000024
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ when defined(WINDOWS):
|
||||||
const
|
const
|
||||||
DLLSSLName = "(ssleay32|libssl32).dll"
|
DLLSSLName = "(ssleay32|libssl32).dll"
|
||||||
DLLUtilName = "libeay32.dll"
|
DLLUtilName = "libeay32.dll"
|
||||||
|
from winlean import TSocketHandle
|
||||||
else:
|
else:
|
||||||
const
|
const
|
||||||
versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
|
versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
|
||||||
|
|
@ -56,6 +57,7 @@ else:
|
||||||
const
|
const
|
||||||
DLLSSLName = "libssl.so" & versions
|
DLLSSLName = "libssl.so" & versions
|
||||||
DLLUtilName = "libcrypto.so" & versions
|
DLLUtilName = "libcrypto.so" & versions
|
||||||
|
from posix import TSocketHandle
|
||||||
|
|
||||||
type
|
type
|
||||||
SslStruct {.final, pure.} = object
|
SslStruct {.final, pure.} = object
|
||||||
|
|
@ -225,7 +227,7 @@ proc SSL_CTX_use_PrivateKey_file*(ctx: PSSL_CTX,
|
||||||
proc SSL_CTX_check_private_key*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName,
|
proc SSL_CTX_check_private_key*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName,
|
||||||
importc.}
|
importc.}
|
||||||
|
|
||||||
proc SSL_set_fd*(ssl: PSSL, fd: cint): cint{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SSL_set_fd*(ssl: PSSL, fd: TSocketHandle): cint{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
proc SSL_shutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SSL_shutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
proc SSL_connect*(ssl: PSSL): cint{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SSL_connect*(ssl: PSSL): cint{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1811,210 +1811,217 @@ proc XSetAuthorization*(para1: cstring, para2: cint, para3: cstring, para4: cint
|
||||||
# _Xmbtowc?
|
# _Xmbtowc?
|
||||||
# _Xwctomb?
|
# _Xwctomb?
|
||||||
#
|
#
|
||||||
when defined(MACROS):
|
#when defined(MACROS):
|
||||||
proc ConnectionNumber*(dpy: PDisplay): cint
|
proc ConnectionNumber*(dpy: PDisplay): cint
|
||||||
proc RootWindow*(dpy: PDisplay, scr: cint): TWindow
|
proc RootWindow*(dpy: PDisplay, scr: cint): TWindow
|
||||||
proc DefaultScreen*(dpy: PDisplay): cint
|
proc DefaultScreen*(dpy: PDisplay): cint
|
||||||
proc DefaultRootWindow*(dpy: PDisplay): TWindow
|
proc DefaultRootWindow*(dpy: PDisplay): TWindow
|
||||||
proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual
|
proc DefaultVisual*(dpy: PDisplay, scr: cint): PVisual
|
||||||
proc DefaultGC*(dpy: PDisplay, scr: cint): TGC
|
proc DefaultGC*(dpy: PDisplay, scr: cint): TGC
|
||||||
proc BlackPixel*(dpy: PDisplay, scr: cint): culong
|
proc BlackPixel*(dpy: PDisplay, scr: cint): culong
|
||||||
proc WhitePixel*(dpy: PDisplay, scr: cint): culong
|
proc WhitePixel*(dpy: PDisplay, scr: cint): culong
|
||||||
proc QLength*(dpy: PDisplay): cint
|
proc QLength*(dpy: PDisplay): cint
|
||||||
proc DisplayWidth*(dpy: PDisplay, scr: cint): cint
|
proc DisplayWidth*(dpy: PDisplay, scr: cint): cint
|
||||||
proc DisplayHeight*(dpy: PDisplay, scr: cint): cint
|
proc DisplayHeight*(dpy: PDisplay, scr: cint): cint
|
||||||
proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint
|
proc DisplayWidthMM*(dpy: PDisplay, scr: cint): cint
|
||||||
proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint
|
proc DisplayHeightMM*(dpy: PDisplay, scr: cint): cint
|
||||||
proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint
|
proc DisplayPlanes*(dpy: PDisplay, scr: cint): cint
|
||||||
proc DisplayCells*(dpy: PDisplay, scr: cint): cint
|
proc DisplayCells*(dpy: PDisplay, scr: cint): cint
|
||||||
proc ScreenCount*(dpy: PDisplay): cint
|
proc ScreenCount*(dpy: PDisplay): cint
|
||||||
proc ServerVendor*(dpy: PDisplay): cstring
|
proc ServerVendor*(dpy: PDisplay): cstring
|
||||||
proc ProtocolVersion*(dpy: PDisplay): cint
|
proc ProtocolVersion*(dpy: PDisplay): cint
|
||||||
proc ProtocolRevision*(dpy: PDisplay): cint
|
proc ProtocolRevision*(dpy: PDisplay): cint
|
||||||
proc VendorRelease*(dpy: PDisplay): cint
|
proc VendorRelease*(dpy: PDisplay): cint
|
||||||
proc DisplayString*(dpy: PDisplay): cstring
|
proc DisplayString*(dpy: PDisplay): cstring
|
||||||
proc DefaultDepth*(dpy: PDisplay, scr: cint): cint
|
proc DefaultDepth*(dpy: PDisplay, scr: cint): cint
|
||||||
proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap
|
proc DefaultColormap*(dpy: PDisplay, scr: cint): TColormap
|
||||||
proc BitmapUnit*(dpy: PDisplay): cint
|
proc BitmapUnit*(dpy: PDisplay): cint
|
||||||
proc BitmapBitOrder*(dpy: PDisplay): cint
|
proc BitmapBitOrder*(dpy: PDisplay): cint
|
||||||
proc BitmapPad*(dpy: PDisplay): cint
|
proc BitmapPad*(dpy: PDisplay): cint
|
||||||
proc ImageByteOrder*(dpy: PDisplay): cint
|
proc ImageByteOrder*(dpy: PDisplay): cint
|
||||||
proc NextRequest*(dpy: PDisplay): culong
|
proc NextRequest*(dpy: PDisplay): culong
|
||||||
proc LastKnownRequestProcessed*(dpy: PDisplay): culong
|
proc LastKnownRequestProcessed*(dpy: PDisplay): culong
|
||||||
proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen
|
proc ScreenOfDisplay*(dpy: PDisplay, scr: cint): PScreen
|
||||||
proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen
|
proc DefaultScreenOfDisplay*(dpy: PDisplay): PScreen
|
||||||
proc DisplayOfScreen*(s: PScreen): PDisplay
|
proc DisplayOfScreen*(s: PScreen): PDisplay
|
||||||
proc RootWindowOfScreen*(s: PScreen): TWindow
|
proc RootWindowOfScreen*(s: PScreen): TWindow
|
||||||
proc BlackPixelOfScreen*(s: PScreen): culong
|
proc BlackPixelOfScreen*(s: PScreen): culong
|
||||||
proc WhitePixelOfScreen*(s: PScreen): culong
|
proc WhitePixelOfScreen*(s: PScreen): culong
|
||||||
proc DefaultColormapOfScreen*(s: PScreen): TColormap
|
proc DefaultColormapOfScreen*(s: PScreen): TColormap
|
||||||
proc DefaultDepthOfScreen*(s: PScreen): cint
|
proc DefaultDepthOfScreen*(s: PScreen): cint
|
||||||
proc DefaultGCOfScreen*(s: PScreen): TGC
|
proc DefaultGCOfScreen*(s: PScreen): TGC
|
||||||
proc DefaultVisualOfScreen*(s: PScreen): PVisual
|
proc DefaultVisualOfScreen*(s: PScreen): PVisual
|
||||||
proc WidthOfScreen*(s: PScreen): cint
|
proc WidthOfScreen*(s: PScreen): cint
|
||||||
proc HeightOfScreen*(s: PScreen): cint
|
proc HeightOfScreen*(s: PScreen): cint
|
||||||
proc WidthMMOfScreen*(s: PScreen): cint
|
proc WidthMMOfScreen*(s: PScreen): cint
|
||||||
proc HeightMMOfScreen*(s: PScreen): cint
|
proc HeightMMOfScreen*(s: PScreen): cint
|
||||||
proc PlanesOfScreen*(s: PScreen): cint
|
proc PlanesOfScreen*(s: PScreen): cint
|
||||||
proc CellsOfScreen*(s: PScreen): cint
|
proc CellsOfScreen*(s: PScreen): cint
|
||||||
proc MinCmapsOfScreen*(s: PScreen): cint
|
proc MinCmapsOfScreen*(s: PScreen): cint
|
||||||
proc MaxCmapsOfScreen*(s: PScreen): cint
|
proc MaxCmapsOfScreen*(s: PScreen): cint
|
||||||
proc DoesSaveUnders*(s: PScreen): TBool
|
proc DoesSaveUnders*(s: PScreen): TBool
|
||||||
proc DoesBackingStore*(s: PScreen): cint
|
proc DoesBackingStore*(s: PScreen): cint
|
||||||
proc EventMaskOfScreen*(s: PScreen): clong
|
proc EventMaskOfScreen*(s: PScreen): clong
|
||||||
proc XAllocID*(dpy: PDisplay): TXID
|
proc XAllocID*(dpy: PDisplay): TXID
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
when defined(MACROS):
|
#when defined(MACROS):
|
||||||
proc ConnectionNumber(dpy: PDisplay): cint =
|
template privDisp : expr = cast[PXPrivDisplay](dpy)
|
||||||
ConnectionNumber = (PXPrivDisplay(dpy))[] .fd
|
|
||||||
|
|
||||||
proc RootWindow(dpy: PDisplay, scr: cint): TWindow =
|
proc ConnectionNumber(dpy: PDisplay): cint =
|
||||||
RootWindow = (ScreenOfDisplay(dpy, scr))[] .root
|
privDisp.fd
|
||||||
|
|
||||||
proc DefaultScreen(dpy: PDisplay): cint =
|
proc RootWindow(dpy: PDisplay, scr: cint): TWindow =
|
||||||
DefaultScreen = (PXPrivDisplay(dpy))[] .default_screen
|
ScreenOfDisplay(dpy, scr).root
|
||||||
|
|
||||||
proc DefaultRootWindow(dpy: PDisplay): TWindow =
|
proc DefaultScreen(dpy: PDisplay): cint =
|
||||||
DefaultRootWindow = (ScreenOfDisplay(dpy, DefaultScreen(dpy)))[] .root
|
privDisp.default_screen
|
||||||
|
|
||||||
proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual =
|
proc DefaultRootWindow(dpy: PDisplay): TWindow =
|
||||||
DefaultVisual = (ScreenOfDisplay(dpy, scr))[] .root_visual
|
ScreenOfDisplay(dpy, DefaultScreen(dpy)).root
|
||||||
|
|
||||||
proc DefaultGC(dpy: PDisplay, scr: cint): TGC =
|
proc DefaultVisual(dpy: PDisplay, scr: cint): PVisual =
|
||||||
DefaultGC = (ScreenOfDisplay(dpy, scr))[] .default_gc
|
ScreenOfDisplay(dpy, scr).root_visual
|
||||||
|
|
||||||
proc BlackPixel(dpy: PDisplay, scr: cint): culong =
|
proc DefaultGC(dpy: PDisplay, scr: cint): TGC =
|
||||||
BlackPixel = (ScreenOfDisplay(dpy, scr))[] .black_pixel
|
ScreenOfDisplay(dpy, scr).default_gc
|
||||||
|
|
||||||
proc WhitePixel(dpy: PDisplay, scr: cint): culong =
|
proc BlackPixel(dpy: PDisplay, scr: cint): culong =
|
||||||
WhitePixel = (ScreenOfDisplay(dpy, scr))[] .white_pixel
|
ScreenOfDisplay(dpy, scr).black_pixel
|
||||||
|
|
||||||
proc QLength(dpy: PDisplay): cint =
|
proc WhitePixel(dpy: PDisplay, scr: cint): culong =
|
||||||
QLength = (PXPrivDisplay(dpy))[] .qlen
|
ScreenOfDisplay(dpy, scr).white_pixel
|
||||||
|
|
||||||
proc DisplayWidth(dpy: PDisplay, scr: cint): cint =
|
proc QLength(dpy: PDisplay): cint =
|
||||||
DisplayWidth = (ScreenOfDisplay(dpy, scr))[] .width
|
privDisp.qlen
|
||||||
|
|
||||||
proc DisplayHeight(dpy: PDisplay, scr: cint): cint =
|
proc DisplayWidth(dpy: PDisplay, scr: cint): cint =
|
||||||
DisplayHeight = (ScreenOfDisplay(dpy, scr))[] .height
|
ScreenOfDisplay(dpy, scr).width
|
||||||
|
|
||||||
proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint =
|
proc DisplayHeight(dpy: PDisplay, scr: cint): cint =
|
||||||
DisplayWidthMM = (ScreenOfDisplay(dpy, scr))[] .mwidth
|
ScreenOfDisplay(dpy, scr).height
|
||||||
|
|
||||||
proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint =
|
proc DisplayWidthMM(dpy: PDisplay, scr: cint): cint =
|
||||||
DisplayHeightMM = (ScreenOfDisplay(dpy, scr))[] .mheight
|
ScreenOfDisplay(dpy, scr).mwidth
|
||||||
|
|
||||||
proc DisplayPlanes(dpy: PDisplay, scr: cint): cint =
|
proc DisplayHeightMM(dpy: PDisplay, scr: cint): cint =
|
||||||
DisplayPlanes = (ScreenOfDisplay(dpy, scr))[] .root_depth
|
ScreenOfDisplay(dpy, scr).mheight
|
||||||
|
|
||||||
proc DisplayCells(dpy: PDisplay, scr: cint): cint =
|
proc DisplayPlanes(dpy: PDisplay, scr: cint): cint =
|
||||||
DisplayCells = (DefaultVisual(dpy, scr))[] .map_entries
|
ScreenOfDisplay(dpy, scr).root_depth
|
||||||
|
|
||||||
proc ScreenCount(dpy: PDisplay): cint =
|
proc DisplayCells(dpy: PDisplay, scr: cint): cint =
|
||||||
ScreenCount = (PXPrivDisplay(dpy))[] .nscreens
|
DefaultVisual(dpy, scr).map_entries
|
||||||
|
|
||||||
proc ServerVendor(dpy: PDisplay): cstring =
|
proc ScreenCount(dpy: PDisplay): cint =
|
||||||
ServerVendor = (PXPrivDisplay(dpy))[] .vendor
|
privDisp.nscreens
|
||||||
|
|
||||||
proc ProtocolVersion(dpy: PDisplay): cint =
|
proc ServerVendor(dpy: PDisplay): cstring =
|
||||||
ProtocolVersion = (PXPrivDisplay(dpy))[] .proto_major_version
|
privDisp.vendor
|
||||||
|
|
||||||
proc ProtocolRevision(dpy: PDisplay): cint =
|
proc ProtocolVersion(dpy: PDisplay): cint =
|
||||||
ProtocolRevision = (PXPrivDisplay(dpy))[] .proto_minor_version
|
privDisp.proto_major_version
|
||||||
|
|
||||||
proc VendorRelease(dpy: PDisplay): cint =
|
proc ProtocolRevision(dpy: PDisplay): cint =
|
||||||
VendorRelease = (PXPrivDisplay(dpy))[] .release
|
privDisp.proto_minor_version
|
||||||
|
|
||||||
proc DisplayString(dpy: PDisplay): cstring =
|
proc VendorRelease(dpy: PDisplay): cint =
|
||||||
DisplayString = (PXPrivDisplay(dpy))[] .display_name
|
privDisp.release
|
||||||
|
|
||||||
proc DefaultDepth(dpy: PDisplay, scr: cint): cint =
|
proc DisplayString(dpy: PDisplay): cstring =
|
||||||
DefaultDepth = (ScreenOfDisplay(dpy, scr))[] .root_depth
|
privDisp.display_name
|
||||||
|
|
||||||
proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap =
|
proc DefaultDepth(dpy: PDisplay, scr: cint): cint =
|
||||||
DefaultColormap = (ScreenOfDisplay(dpy, scr))[] .cmap
|
ScreenOfDisplay(dpy, scr).root_depth
|
||||||
|
|
||||||
proc BitmapUnit(dpy: PDisplay): cint =
|
proc DefaultColormap(dpy: PDisplay, scr: cint): TColormap =
|
||||||
BitmapUnit = (PXPrivDisplay(dpy))[] .bitmap_unit
|
ScreenOfDisplay(dpy, scr).cmap
|
||||||
|
|
||||||
proc BitmapBitOrder(dpy: PDisplay): cint =
|
proc BitmapUnit(dpy: PDisplay): cint =
|
||||||
BitmapBitOrder = (PXPrivDisplay(dpy))[] .bitmap_bit_order
|
privDisp.bitmap_unit
|
||||||
|
|
||||||
proc BitmapPad(dpy: PDisplay): cint =
|
proc BitmapBitOrder(dpy: PDisplay): cint =
|
||||||
BitmapPad = (PXPrivDisplay(dpy))[] .bitmap_pad
|
privDisp.bitmap_bit_order
|
||||||
|
|
||||||
proc ImageByteOrder(dpy: PDisplay): cint =
|
proc BitmapPad(dpy: PDisplay): cint =
|
||||||
ImageByteOrder = (PXPrivDisplay(dpy))[] .byte_order
|
privDisp.bitmap_pad
|
||||||
|
|
||||||
proc NextRequest(dpy: PDisplay): culong =
|
proc ImageByteOrder(dpy: PDisplay): cint =
|
||||||
NextRequest = ((PXPrivDisplay(dpy))[] .request) + 1
|
privDisp.byte_order
|
||||||
|
|
||||||
proc LastKnownRequestProcessed(dpy: PDisplay): culong =
|
import unsigned
|
||||||
LastKnownRequestProcessed = (PXPrivDisplay(dpy))[] .last_request_read
|
proc NextRequest(dpy: PDisplay): culong =
|
||||||
|
privDisp.request + 1.culong
|
||||||
|
|
||||||
proc ScreenOfDisplay(dpy: PDisplay, scr: cint): PScreen =
|
proc LastKnownRequestProcessed(dpy: PDisplay): culong =
|
||||||
ScreenOfDisplay = addr((((PXPrivDisplay(dpy))[] .screens)[scr]))
|
privDisp.last_request_read
|
||||||
|
|
||||||
proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen =
|
# from fowltek/pointer_arithm, required for ScreenOfDisplay()
|
||||||
DefaultScreenOfDisplay = ScreenOfDisplay(dpy, DefaultScreen(dpy))
|
proc offset[A] (some: ptr A; b: int): ptr A =
|
||||||
|
cast[ptr A](cast[int](some) + (b * sizeof(A)))
|
||||||
|
proc ScreenOfDisplay(dpy: PDisplay, scr: cint): PScreen =
|
||||||
|
#addr(((privDisp.screens)[scr]))
|
||||||
|
privDisp.screens.offset(scr.int)
|
||||||
|
|
||||||
proc DisplayOfScreen(s: PScreen): PDisplay =
|
proc DefaultScreenOfDisplay(dpy: PDisplay): PScreen =
|
||||||
DisplayOfScreen = s[] .display
|
ScreenOfDisplay(dpy, DefaultScreen(dpy))
|
||||||
|
|
||||||
proc RootWindowOfScreen(s: PScreen): TWindow =
|
proc DisplayOfScreen(s: PScreen): PDisplay =
|
||||||
RootWindowOfScreen = s[] .root
|
s.display
|
||||||
|
|
||||||
proc BlackPixelOfScreen(s: PScreen): culong =
|
proc RootWindowOfScreen(s: PScreen): TWindow =
|
||||||
BlackPixelOfScreen = s[] .black_pixel
|
s.root
|
||||||
|
|
||||||
proc WhitePixelOfScreen(s: PScreen): culong =
|
proc BlackPixelOfScreen(s: PScreen): culong =
|
||||||
WhitePixelOfScreen = s[] .white_pixel
|
s.black_pixel
|
||||||
|
|
||||||
proc DefaultColormapOfScreen(s: PScreen): TColormap =
|
proc WhitePixelOfScreen(s: PScreen): culong =
|
||||||
DefaultColormapOfScreen = s[] .cmap
|
s.white_pixel
|
||||||
|
|
||||||
proc DefaultDepthOfScreen(s: PScreen): cint =
|
proc DefaultColormapOfScreen(s: PScreen): TColormap =
|
||||||
DefaultDepthOfScreen = s[] .root_depth
|
s.cmap
|
||||||
|
|
||||||
proc DefaultGCOfScreen(s: PScreen): TGC =
|
proc DefaultDepthOfScreen(s: PScreen): cint =
|
||||||
DefaultGCOfScreen = s[] .default_gc
|
s.root_depth
|
||||||
|
|
||||||
proc DefaultVisualOfScreen(s: PScreen): PVisual =
|
proc DefaultGCOfScreen(s: PScreen): TGC =
|
||||||
DefaultVisualOfScreen = s[] .root_visual
|
s.default_gc
|
||||||
|
|
||||||
proc WidthOfScreen(s: PScreen): cint =
|
proc DefaultVisualOfScreen(s: PScreen): PVisual =
|
||||||
WidthOfScreen = s[] .width
|
s.root_visual
|
||||||
|
|
||||||
proc HeightOfScreen(s: PScreen): cint =
|
proc WidthOfScreen(s: PScreen): cint =
|
||||||
HeightOfScreen = s[] .height
|
s.width
|
||||||
|
|
||||||
proc WidthMMOfScreen(s: PScreen): cint =
|
proc HeightOfScreen(s: PScreen): cint =
|
||||||
WidthMMOfScreen = s[] .mwidth
|
s.height
|
||||||
|
|
||||||
proc HeightMMOfScreen(s: PScreen): cint =
|
proc WidthMMOfScreen(s: PScreen): cint =
|
||||||
HeightMMOfScreen = s[] .mheight
|
s.mwidth
|
||||||
|
|
||||||
proc PlanesOfScreen(s: PScreen): cint =
|
proc HeightMMOfScreen(s: PScreen): cint =
|
||||||
PlanesOfScreen = s[] .root_depth
|
s.mheight
|
||||||
|
|
||||||
proc CellsOfScreen(s: PScreen): cint =
|
proc PlanesOfScreen(s: PScreen): cint =
|
||||||
CellsOfScreen = (DefaultVisualOfScreen(s))[] .map_entries
|
s.root_depth
|
||||||
|
|
||||||
proc MinCmapsOfScreen(s: PScreen): cint =
|
proc CellsOfScreen(s: PScreen): cint =
|
||||||
MinCmapsOfScreen = s[] .min_maps
|
DefaultVisualOfScreen(s).map_entries
|
||||||
|
|
||||||
proc MaxCmapsOfScreen(s: PScreen): cint =
|
proc MinCmapsOfScreen(s: PScreen): cint =
|
||||||
MaxCmapsOfScreen = s[] .max_maps
|
s.min_maps
|
||||||
|
|
||||||
proc DoesSaveUnders(s: PScreen): TBool =
|
proc MaxCmapsOfScreen(s: PScreen): cint =
|
||||||
DoesSaveUnders = s[] .save_unders
|
s.max_maps
|
||||||
|
|
||||||
proc DoesBackingStore(s: PScreen): cint =
|
proc DoesSaveUnders(s: PScreen): TBool =
|
||||||
DoesBackingStore = s[] .backing_store
|
s.save_unders
|
||||||
|
|
||||||
proc EventMaskOfScreen(s: PScreen): clong =
|
proc DoesBackingStore(s: PScreen): cint =
|
||||||
EventMaskOfScreen = s[] .root_input_mask
|
s.backing_store
|
||||||
|
|
||||||
proc XAllocID(dpy: PDisplay): TXID =
|
proc EventMaskOfScreen(s: PScreen): clong =
|
||||||
XAllocID = (PXPrivDisplay(dpy))[] .resource_alloc(dpy)
|
s.root_input_mask
|
||||||
|
|
||||||
|
proc XAllocID(dpy: PDisplay): TXID =
|
||||||
|
privDisp.resource_alloc(dpy)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
x, xlib, keysym
|
x, xlib, keysym, unsigned
|
||||||
|
|
||||||
#const
|
#const
|
||||||
# libX11* = "libX11.so"
|
# libX11* = "libX11.so"
|
||||||
|
|
@ -356,57 +356,57 @@ proc XWMGeometry*(para1: PDisplay, para2: cint, para3: cstring, para4: cstring,
|
||||||
dynlib: libX11, importc.}
|
dynlib: libX11, importc.}
|
||||||
proc XXorRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{.cdecl,
|
proc XXorRegion*(para1: TRegion, para2: TRegion, para3: TRegion): cint{.cdecl,
|
||||||
dynlib: libX11, importc.}
|
dynlib: libX11, importc.}
|
||||||
when defined(MACROS):
|
#when defined(MACROS):
|
||||||
proc XDestroyImage*(ximage: PXImage): cint
|
proc XDestroyImage*(ximage: PXImage): cint
|
||||||
proc XGetPixel*(ximage: PXImage, x, y: cint): culong
|
proc XGetPixel*(ximage: PXImage, x, y: cint): culong
|
||||||
proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint
|
proc XPutPixel*(ximage: PXImage, x, y: cint, pixel: culong): cint
|
||||||
proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage
|
proc XSubImage*(ximage: PXImage, x, y: cint, width, height: cuint): PXImage
|
||||||
proc XAddPixel*(ximage: PXImage, value: clong): cint
|
proc XAddPixel*(ximage: PXImage, value: clong): cint
|
||||||
proc IsKeypadKey*(keysym: TKeySym): bool
|
proc IsKeypadKey*(keysym: TKeySym): bool
|
||||||
proc IsPrivateKeypadKey*(keysym: TKeySym): bool
|
proc IsPrivateKeypadKey*(keysym: TKeySym): bool
|
||||||
proc IsCursorKey*(keysym: TKeySym): bool
|
proc IsCursorKey*(keysym: TKeySym): bool
|
||||||
proc IsPFKey*(keysym: TKeySym): bool
|
proc IsPFKey*(keysym: TKeySym): bool
|
||||||
proc IsFunctionKey*(keysym: TKeySym): bool
|
proc IsFunctionKey*(keysym: TKeySym): bool
|
||||||
proc IsMiscFunctionKey*(keysym: TKeySym): bool
|
proc IsMiscFunctionKey*(keysym: TKeySym): bool
|
||||||
proc IsModifierKey*(keysym: TKeySym): bool
|
proc IsModifierKey*(keysym: TKeySym): bool
|
||||||
#function XUniqueContext : TXContext;
|
#function XUniqueContext : TXContext;
|
||||||
#function XStringToContext(_string : Pchar) : TXContext;
|
#function XStringToContext(_string : Pchar) : TXContext;
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
when defined(MACROS):
|
#when defined(MACROS):
|
||||||
proc XDestroyImage(ximage: PXImage): cint =
|
proc XDestroyImage(ximage: PXImage): cint =
|
||||||
XDestroyImage = ximage[] .f.destroy_image(ximage)
|
ximage.f.destroy_image(ximage)
|
||||||
|
|
||||||
proc XGetPixel(ximage: PXImage, x, y: cint): culong =
|
proc XGetPixel(ximage: PXImage, x, y: cint): culong =
|
||||||
XGetPixel = ximage[] .f.get_pixel(ximage, x, y)
|
ximage.f.get_pixel(ximage, x, y)
|
||||||
|
|
||||||
proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint =
|
proc XPutPixel(ximage: PXImage, x, y: cint, pixel: culong): cint =
|
||||||
XPutPixel = ximage[] .f.put_pixel(ximage, x, y, pixel)
|
ximage.f.put_pixel(ximage, x, y, pixel)
|
||||||
|
|
||||||
proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage =
|
proc XSubImage(ximage: PXImage, x, y: cint, width, height: cuint): PXImage =
|
||||||
XSubImage = ximage[] .f.sub_image(ximage, x, y, width, height)
|
ximage.f.sub_image(ximage, x, y, width, height)
|
||||||
|
|
||||||
proc XAddPixel(ximage: PXImage, value: clong): cint =
|
proc XAddPixel(ximage: PXImage, value: clong): cint =
|
||||||
XAddPixel = ximage[] .f.add_pixel(ximage, value)
|
ximage.f.add_pixel(ximage, value)
|
||||||
|
|
||||||
proc IsKeypadKey(keysym: TKeySym): bool =
|
proc IsKeypadKey(keysym: TKeySym): bool =
|
||||||
IsKeypadKey = (keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal)
|
(keysym >= XK_KP_Space) and (keysym <= XK_KP_Equal)
|
||||||
|
|
||||||
proc IsPrivateKeypadKey(keysym: TKeySym): bool =
|
proc IsPrivateKeypadKey(keysym: TKeySym): bool =
|
||||||
IsPrivateKeypadKey = (keysym >= 0x11000000) and (keysym <= 0x1100FFFF)
|
(keysym >= 0x11000000.TKeySym) and (keysym <= 0x1100FFFF.TKeySym)
|
||||||
|
|
||||||
proc IsCursorKey(keysym: TKeySym): bool =
|
proc IsCursorKey(keysym: TKeySym): bool =
|
||||||
IsCursorKey = (keysym >= XK_Home) and (keysym < XK_Select)
|
(keysym >= XK_Home) and (keysym < XK_Select)
|
||||||
|
|
||||||
proc IsPFKey(keysym: TKeySym): bool =
|
proc IsPFKey(keysym: TKeySym): bool =
|
||||||
IsPFKey = (keysym >= XK_KP_F1) and (keysym <= XK_KP_F4)
|
(keysym >= XK_KP_F1) and (keysym <= XK_KP_F4)
|
||||||
|
|
||||||
proc IsFunctionKey(keysym: TKeySym): bool =
|
proc IsFunctionKey(keysym: TKeySym): bool =
|
||||||
IsFunctionKey = (keysym >= XK_F1) and (keysym <= XK_F35)
|
(keysym >= XK_F1) and (keysym <= XK_F35)
|
||||||
|
|
||||||
proc IsMiscFunctionKey(keysym: TKeySym): bool =
|
proc IsMiscFunctionKey(keysym: TKeySym): bool =
|
||||||
IsMiscFunctionKey = (keysym >= XK_Select) and (keysym <= XK_Break)
|
(keysym >= XK_Select) and (keysym <= XK_Break)
|
||||||
|
|
||||||
proc IsModifierKey(keysym: TKeySym): bool =
|
proc IsModifierKey(keysym: TKeySym): bool =
|
||||||
IsModifierKey = ((keysym >= XK_Shift_L) And (keysym <= XK_Hyper_R)) Or
|
((keysym >= XK_Shift_L) And (keysym <= XK_Hyper_R)) Or
|
||||||
(keysym == XK_Mode_switch) Or (keysym == XK_Num_Lock)
|
(keysym == XK_Mode_switch) Or (keysym == XK_Num_Lock)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ proc compress2*(dest: pbytef, destLen: puLongf, source: pbytef,
|
||||||
proc uncompress*(dest: pbytef, destLen: puLongf, source: pbytef,
|
proc uncompress*(dest: pbytef, destLen: puLongf, source: pbytef,
|
||||||
sourceLen: uLong): cint{.cdecl, dynlib: libz,
|
sourceLen: uLong): cint{.cdecl, dynlib: libz,
|
||||||
importc: "uncompress".}
|
importc: "uncompress".}
|
||||||
|
proc compressBound*(sourceLen: uLong): uLong {.cdecl, dynlib: libz, importc.}
|
||||||
proc gzopen*(path: cstring, mode: cstring): gzFile{.cdecl, dynlib: libz,
|
proc gzopen*(path: cstring, mode: cstring): gzFile{.cdecl, dynlib: libz,
|
||||||
importc: "gzopen".}
|
importc: "gzopen".}
|
||||||
proc gzdopen*(fd: int32, mode: cstring): gzFile{.cdecl, dynlib: libz,
|
proc gzdopen*(fd: int32, mode: cstring): gzFile{.cdecl, dynlib: libz,
|
||||||
|
|
|
||||||
10
readme.md
10
readme.md
|
|
@ -9,7 +9,7 @@ the C source of an older version of the compiler are needed to bootstrap the
|
||||||
latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
|
latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
|
||||||
|
|
||||||
Pre-compiled snapshots of the compiler are also available on
|
Pre-compiled snapshots of the compiler are also available on
|
||||||
[Nimbuild](http://build.nimrod-code.org/). Your platform however may not
|
[Nimbuild](http://build.nimrod-lang.org/). Your platform however may not
|
||||||
currently be built for.
|
currently be built for.
|
||||||
|
|
||||||
The compiler currently supports the following platform and architecture
|
The compiler currently supports the following platform and architecture
|
||||||
|
|
@ -47,9 +47,11 @@ The above steps can be performed on Windows in a similar fashion, the
|
||||||
instead of ``build.sh``.
|
instead of ``build.sh``.
|
||||||
|
|
||||||
## Getting help
|
## Getting help
|
||||||
A [forum](http://forum.nimrod-code.org/) is available if you have any questions,
|
A [forum](http://forum.nimrod-lang.org/) is available if you have any
|
||||||
and you can also get help in the IRC channel
|
questions, and you can also get help in the IRC channel on
|
||||||
on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
|
[Freenode](irc://irc.freenode.net/nimrod) in #nimrod. If you ask questions on
|
||||||
|
[StackOverflow use the nimrod
|
||||||
|
tag](http://stackoverflow.com/questions/tagged/nimrod).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
The compiler and the standard library are licensed under the MIT license,
|
The compiler and the standard library are licensed under the MIT license,
|
||||||
|
|
|
||||||
10
readme.txt
10
readme.txt
|
|
@ -9,7 +9,7 @@ the C source of an older version of the compiler are needed to bootstrap the
|
||||||
latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
|
latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
|
||||||
|
|
||||||
Pre-compiled snapshots of the compiler are also available on
|
Pre-compiled snapshots of the compiler are also available on
|
||||||
[Nimbuild](http://build.nimrod-code.org/). Your platform however may not
|
[Nimbuild](http://build.nimrod-lang.org/). Your platform however may not
|
||||||
currently be built for.
|
currently be built for.
|
||||||
|
|
||||||
The compiler currently supports the following platform and architecture
|
The compiler currently supports the following platform and architecture
|
||||||
|
|
@ -47,9 +47,11 @@ The above steps can be performed on Windows in a similar fashion, the
|
||||||
instead of ``build.sh``.
|
instead of ``build.sh``.
|
||||||
|
|
||||||
## Getting help
|
## Getting help
|
||||||
A [forum](http://forum.nimrod-code.org/) is available if you have any questions,
|
A [forum](http://forum.nimrod-lang.org/) is available if you have any
|
||||||
and you can also get help in the IRC channel
|
questions, and you can also get help in the IRC channel on
|
||||||
on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
|
[Freenode](irc://irc.freenode.net/nimrod) in #nimrod. If you ask questions on
|
||||||
|
[StackOverflow use the nimrod
|
||||||
|
tag](http://stackoverflow.com/questions/tagged/nimrod).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
The compiler and the standard library are licensed under the MIT license,
|
The compiler and the standard library are licensed under the MIT license,
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ static int cvariable = 420;
|
||||||
|
|
||||||
""".}
|
""".}
|
||||||
|
|
||||||
proc embedsC() {.noStackFrame.} =
|
proc embedsC() =
|
||||||
var nimrodVar = 89
|
var nimrodVar = 89
|
||||||
{.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimrodVar`);""".}
|
{.emit: """printf("%d\n", cvariable + (int)`nimrodVar`);""".}
|
||||||
|
|
||||||
embedsC()
|
embedsC()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@ type
|
||||||
TBar[T; I: expr[int]] = object
|
TBar[T; I: expr[int]] = object
|
||||||
data: array[I, T]
|
data: array[I, T]
|
||||||
|
|
||||||
|
TA1[T; I: expr[int]] = array[I, T]
|
||||||
|
TA2[T; I: expr[int]] = array[0..I, T]
|
||||||
|
TA3[T; I: expr[int]] = array[I-1, T]
|
||||||
|
|
||||||
proc takeFoo(x: TFoo) =
|
proc takeFoo(x: TFoo) =
|
||||||
echo "abracadabra"
|
echo "abracadabra"
|
||||||
echo TFoo.Val
|
echo TFoo.Val
|
||||||
|
|
@ -20,3 +24,8 @@ takeFoo(x)
|
||||||
var y: TBar[float, 4]
|
var y: TBar[float, 4]
|
||||||
echo high(y.data)
|
echo high(y.data)
|
||||||
|
|
||||||
|
var
|
||||||
|
t1: TA1
|
||||||
|
t2: TA2
|
||||||
|
t3: TA3
|
||||||
|
|
||||||
|
|
|
||||||
28
tests/run/tusertypeclasses.nim
Normal file
28
tests/run/tusertypeclasses.nim
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
discard """
|
||||||
|
output: "Sortable\nSortable\nContainer"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
type
|
||||||
|
TObj = object
|
||||||
|
x: int
|
||||||
|
|
||||||
|
Sortable = generic x, y
|
||||||
|
(x < y) is bool
|
||||||
|
|
||||||
|
ObjectContainer = generic C
|
||||||
|
C.len is ordinal
|
||||||
|
for v in items(C):
|
||||||
|
v.type is tuple|object
|
||||||
|
|
||||||
|
proc foo(c: ObjectContainer) =
|
||||||
|
echo "Container"
|
||||||
|
|
||||||
|
proc foo(x: Sortable) =
|
||||||
|
echo "Sortable"
|
||||||
|
|
||||||
|
foo 10
|
||||||
|
foo "test"
|
||||||
|
foo(@[TObj(x: 10), TObj(x: 20)])
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ case $uos in
|
||||||
myos="linux"
|
myos="linux"
|
||||||
LINK_FLAGS="$LINK_FLAGS -ldl -lm"
|
LINK_FLAGS="$LINK_FLAGS -ldl -lm"
|
||||||
;;
|
;;
|
||||||
*freebsd* )
|
*freebsd* | *dragonfly* )
|
||||||
myos="freebsd"
|
myos="freebsd"
|
||||||
LINK_FLAGS="$LINK_FLAGS -lm"
|
LINK_FLAGS="$LINK_FLAGS -lm"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue