Merge remote-tracking branch 'origin/devel' into appveyor
This commit is contained in:
commit
e2dbf222e6
59 changed files with 1127 additions and 324 deletions
|
|
@ -75,7 +75,7 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||||
ga('send', 'pageview');
|
ga('send', 'pageview');
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
""" % [config["doc.googleAnalytics"]]
|
""" % [config.getOrDefault"doc.googleAnalytics"]
|
||||||
else:
|
else:
|
||||||
result.analytics = ""
|
result.analytics = ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||||
if s.kind != skEnumField:
|
if s.kind != skEnumField:
|
||||||
if s.kind notin ExportableSymKinds:
|
if s.kind notin ExportableSymKinds:
|
||||||
internalError(s.info, "importAllSymbols: " & $s.kind)
|
internalError(s.info, "importAllSymbols: " & $s.kind)
|
||||||
if exceptSet.empty or s.name.id notin exceptSet:
|
if exceptSet.isNil or s.name.id notin exceptSet:
|
||||||
rawImportSymbol(c, s)
|
rawImportSymbol(c, s)
|
||||||
s = nextIter(i, fromMod.tab)
|
s = nextIter(i, fromMod.tab)
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
||||||
let s = a.sym
|
let s = a.sym
|
||||||
if s.kind == skModule:
|
if s.kind == skModule:
|
||||||
importAllSymbolsExcept(c, s, exceptSet)
|
importAllSymbolsExcept(c, s, exceptSet)
|
||||||
elif exceptSet.empty or s.name.id notin exceptSet:
|
elif exceptSet.isNil or s.name.id notin exceptSet:
|
||||||
rawImportSymbol(c, s)
|
rawImportSymbol(c, s)
|
||||||
of nkExportExceptStmt:
|
of nkExportExceptStmt:
|
||||||
localError(n.info, errGenerated, "'export except' not implemented")
|
localError(n.info, errGenerated, "'export except' not implemented")
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import
|
||||||
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
||||||
cgen, jsgen, json, nversion,
|
cgen, jsgen, json, nversion,
|
||||||
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||||
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
|
docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
|
||||||
|
|
||||||
from magicsys import systemModule, resetSysTypes
|
from magicsys import systemModule, resetSysTypes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ proc addPackage(packages: StringTableRef, p: string) =
|
||||||
let name = p.substr(0, x-1)
|
let name = p.substr(0, x-1)
|
||||||
if x < p.len:
|
if x < p.len:
|
||||||
let version = p.substr(x+1)
|
let version = p.substr(x+1)
|
||||||
if packages[name] <. version:
|
if packages.getOrDefault(name) <. version:
|
||||||
packages[name] = version
|
packages[name] = version
|
||||||
else:
|
else:
|
||||||
packages[name] = latest
|
packages[name] = latest
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ type # please make sure we have under 32 options
|
||||||
gcNone, gcBoehm, gcGo, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
|
gcNone, gcBoehm, gcGo, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
|
||||||
|
|
||||||
IdeCmd* = enum
|
IdeCmd* = enum
|
||||||
ideNone, ideSug, ideCon, ideDef, ideUse
|
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus
|
||||||
|
|
||||||
var
|
var
|
||||||
gIdeCmd*: IdeCmd
|
gIdeCmd*: IdeCmd
|
||||||
|
|
@ -173,7 +173,7 @@ proc existsConfigVar*(key: string): bool =
|
||||||
result = hasKey(gConfigVars, key)
|
result = hasKey(gConfigVars, key)
|
||||||
|
|
||||||
proc getConfigVar*(key: string): string =
|
proc getConfigVar*(key: string): string =
|
||||||
result = gConfigVars[key]
|
result = gConfigVars.getOrDefault key
|
||||||
|
|
||||||
proc setConfigVar*(key, val: string) =
|
proc setConfigVar*(key, val: string) =
|
||||||
gConfigVars[key] = val
|
gConfigVars[key] = val
|
||||||
|
|
@ -421,6 +421,7 @@ proc parseIdeCmd*(s: string): IdeCmd =
|
||||||
of "con": ideCon
|
of "con": ideCon
|
||||||
of "def": ideDef
|
of "def": ideDef
|
||||||
of "use": ideUse
|
of "use": ideUse
|
||||||
|
of "dus": ideDus
|
||||||
else: ideNone
|
else: ideNone
|
||||||
|
|
||||||
proc `$`*(c: IdeCmd): string =
|
proc `$`*(c: IdeCmd): string =
|
||||||
|
|
@ -429,4 +430,5 @@ proc `$`*(c: IdeCmd): string =
|
||||||
of ideCon: "con"
|
of ideCon: "con"
|
||||||
of ideDef: "def"
|
of ideDef: "def"
|
||||||
of ideUse: "use"
|
of ideUse: "use"
|
||||||
|
of ideDus: "dus"
|
||||||
of ideNone: "none"
|
of ideNone: "none"
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
||||||
else:
|
else:
|
||||||
internalError(info, "decodeSym: no ident")
|
internalError(info, "decodeSym: no ident")
|
||||||
#echo "decoding: {", ident.s
|
#echo "decoding: {", ident.s
|
||||||
result = r.syms[id]
|
result = r.syms.getOrDefault(id)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
new(result)
|
new(result)
|
||||||
result.id = id
|
result.id = id
|
||||||
|
|
@ -491,7 +491,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
var key = decodeVInt(r.s, r.pos)
|
var key = decodeVInt(r.s, r.pos)
|
||||||
inc(r.pos) # #10
|
inc(r.pos) # #10
|
||||||
var s = r.syms[key]
|
var s = r.syms.getOrDefault(key)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
s = newStub(r, w, key)
|
s = newStub(r, w, key)
|
||||||
s.owner = module
|
s.owner = module
|
||||||
|
|
@ -737,7 +737,7 @@ proc getReader(moduleId: int): PRodReader =
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
||||||
result = r.syms[id]
|
result = r.syms.getOrDefault(id)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
# load the symbol:
|
# load the symbol:
|
||||||
var d = iiTableGet(r.index.tab, id)
|
var d = iiTableGet(r.index.tab, id)
|
||||||
|
|
|
||||||
|
|
@ -309,6 +309,10 @@ proc suggestSym*(info: TLineInfo; s: PSym) {.inline.} =
|
||||||
findUsages(info, s)
|
findUsages(info, s)
|
||||||
elif gIdeCmd == ideDef:
|
elif gIdeCmd == ideDef:
|
||||||
findDefinition(info, s)
|
findDefinition(info, s)
|
||||||
|
elif gIdeCmd == ideDus and s != nil:
|
||||||
|
if isTracked(info, s.name.s.len):
|
||||||
|
suggestResult(symToSuggest(s, isLocal=false, $ideDef))
|
||||||
|
findUsages(info, s)
|
||||||
|
|
||||||
proc markUsed(info: TLineInfo; s: PSym) =
|
proc markUsed(info: TLineInfo; s: PSym) =
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
|
@ -366,7 +370,7 @@ proc suggestExpr*(c: PContext, node: PNode) =
|
||||||
suggestCall(c, a, n, outputs)
|
suggestCall(c, a, n, outputs)
|
||||||
|
|
||||||
dec(c.compilesContextId)
|
dec(c.compilesContextId)
|
||||||
if outputs > 0 and gIdeCmd != ideUse: suggestQuit()
|
if outputs > 0 and gIdeCmd notin {ideUse, ideDus}: suggestQuit()
|
||||||
|
|
||||||
proc suggestStmt*(c: PContext, n: PNode) =
|
proc suggestStmt*(c: PContext, n: PNode) =
|
||||||
suggestExpr(c, n)
|
suggestExpr(c, n)
|
||||||
|
|
|
||||||
|
|
@ -825,11 +825,13 @@ proc flattenStmts(n: PNode) =
|
||||||
var goOn = true
|
var goOn = true
|
||||||
while goOn:
|
while goOn:
|
||||||
goOn = false
|
goOn = false
|
||||||
for i in 0..<n.len:
|
var i = 0
|
||||||
|
while i < n.len:
|
||||||
let it = n[i]
|
let it = n[i]
|
||||||
if it.kind in {nkStmtList, nkStmtListExpr}:
|
if it.kind in {nkStmtList, nkStmtListExpr}:
|
||||||
n.sons[i..i] = it.sons[0..<it.len]
|
n.sons[i..i] = it.sons[0..<it.len]
|
||||||
goOn = true
|
goOn = true
|
||||||
|
inc i
|
||||||
|
|
||||||
proc liftDeferAux(n: PNode) =
|
proc liftDeferAux(n: PNode) =
|
||||||
if n.kind in {nkStmtList, nkStmtListExpr}:
|
if n.kind in {nkStmtList, nkStmtListExpr}:
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,14 @@ proc setResult*(a: VmArgs; v: string) =
|
||||||
s[a.ra].node = newNode(nkStrLit)
|
s[a.ra].node = newNode(nkStrLit)
|
||||||
s[a.ra].node.strVal = v
|
s[a.ra].node.strVal = v
|
||||||
|
|
||||||
|
proc setResult*(a: VmArgs; n: PNode) =
|
||||||
|
var s: seq[TFullReg]
|
||||||
|
move(s, cast[seq[TFullReg]](a.slots))
|
||||||
|
if s[a.ra].kind != rkNode:
|
||||||
|
myreset(s[a.ra])
|
||||||
|
s[a.ra].kind = rkNode
|
||||||
|
s[a.ra].node = n
|
||||||
|
|
||||||
proc setResult*(a: VmArgs; v: seq[string]) =
|
proc setResult*(a: VmArgs; v: seq[string]) =
|
||||||
var s: seq[TFullReg]
|
var s: seq[TFullReg]
|
||||||
move(s, cast[seq[TFullReg]](a.slots))
|
move(s, cast[seq[TFullReg]](a.slots))
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ proc loadAny(p: var JsonParser, t: PType,
|
||||||
result = newNode(nkNilLit)
|
result = newNode(nkNilLit)
|
||||||
next(p)
|
next(p)
|
||||||
of jsonInt:
|
of jsonInt:
|
||||||
result = tab[p.getInt]
|
result = tab.getOrDefault(p.getInt)
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
raiseParseErr(p, "cannot load object with address " & $p.getInt)
|
raiseParseErr(p, "cannot load object with address " & $p.getInt)
|
||||||
next(p)
|
next(p)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Test high level features
|
# Test high level features
|
||||||
|
|
||||||
import strutils
|
import strutils, sequtils
|
||||||
|
|
||||||
echo "Give a list of numbers (separated by spaces): "
|
echo "Give a list of numbers (separated by spaces): "
|
||||||
stdin.readLine.split.map(parseInt).max.`$`.echo(" is the maximum!")
|
stdin.readLine.split.map(parseInt).max.`$`.echo(" is the maximum!")
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
import
|
import
|
||||||
pcre, strutils, rtarrays
|
pcre, strutils, rtarrays
|
||||||
|
|
||||||
|
{.deprecated.}
|
||||||
|
|
||||||
const
|
const
|
||||||
MaxSubpatterns* = 20
|
MaxSubpatterns* = 20
|
||||||
## defines the maximum number of subpatterns that can be captured.
|
## defines the maximum number of subpatterns that can be captured.
|
||||||
|
|
@ -46,7 +48,7 @@ type
|
||||||
h: ptr Pcre
|
h: ptr Pcre
|
||||||
e: ptr ExtraData
|
e: ptr ExtraData
|
||||||
|
|
||||||
Regex* {.deprecated.} = ref RegexDesc ## a compiled regular expression
|
Regex* = ref RegexDesc ## a compiled regular expression
|
||||||
|
|
||||||
RegexError* = object of ValueError
|
RegexError* = object of ValueError
|
||||||
## is raised if the pattern is no valid regular expression.
|
## is raised if the pattern is no valid regular expression.
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget,
|
||||||
g.seenIndexTerms = initTable[string, int]()
|
g.seenIndexTerms = initTable[string, int]()
|
||||||
g.msgHandler = msgHandler
|
g.msgHandler = msgHandler
|
||||||
|
|
||||||
let s = config["split.item.toc"]
|
let s = config.getOrDefault"split.item.toc"
|
||||||
if s != "": g.splitAfter = parseInt(s)
|
if s != "": g.splitAfter = parseInt(s)
|
||||||
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
|
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
|
||||||
|
|
||||||
|
|
@ -341,10 +341,10 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
||||||
## previously appeared to give a different identifier value for each.
|
## previously appeared to give a different identifier value for each.
|
||||||
let refname = n.rstnodeToRefname
|
let refname = n.rstnodeToRefname
|
||||||
if d.seenIndexTerms.hasKey(refname):
|
if d.seenIndexTerms.hasKey(refname):
|
||||||
d.seenIndexTerms[refname] = d.seenIndexTerms[refname] + 1
|
d.seenIndexTerms[refname] = d.seenIndexTerms.getOrDefault(refname) + 1
|
||||||
else:
|
else:
|
||||||
d.seenIndexTerms[refname] = 1
|
d.seenIndexTerms[refname] = 1
|
||||||
let id = refname & '_' & $d.seenIndexTerms[refname]
|
let id = refname & '_' & $d.seenIndexTerms.getOrDefault(refname)
|
||||||
|
|
||||||
var term = ""
|
var term = ""
|
||||||
renderAux(d, n, term)
|
renderAux(d, n, term)
|
||||||
|
|
@ -518,7 +518,7 @@ proc generateDocumentationIndex(docs: IndexedDocs): string =
|
||||||
sort(titles, cmp)
|
sort(titles, cmp)
|
||||||
|
|
||||||
for title in titles:
|
for title in titles:
|
||||||
let tocList = generateDocumentationTOC(docs[title])
|
let tocList = generateDocumentationTOC(docs.getOrDefault(title))
|
||||||
result.add("<ul><li><a href=\"" &
|
result.add("<ul><li><a href=\"" &
|
||||||
title.link & "\">" & title.keyword & "</a>\n" & tocList & "</ul>\n")
|
title.link & "\">" & title.keyword & "</a>\n" & tocList & "</ul>\n")
|
||||||
|
|
||||||
|
|
@ -786,7 +786,8 @@ proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
|
||||||
dispA(d.target, result,
|
dispA(d.target, result,
|
||||||
"""<img src="$1" width="15"
|
"""<img src="$1" width="15"
|
||||||
height="17" hspace="2" vspace="2" class="smiley" />""",
|
height="17" hspace="2" vspace="2" class="smiley" />""",
|
||||||
"\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text])
|
"\\includegraphics{$1}",
|
||||||
|
[d.config.getOrDefault"doc.smiley_format" % n.text])
|
||||||
|
|
||||||
proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
|
proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
|
||||||
## Parses useful fields which can appear before a code block.
|
## Parses useful fields which can appear before a code block.
|
||||||
|
|
@ -844,8 +845,8 @@ proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string):
|
||||||
inc d.listingCounter
|
inc d.listingCounter
|
||||||
let id = $d.listingCounter
|
let id = $d.listingCounter
|
||||||
if not params.numberLines:
|
if not params.numberLines:
|
||||||
result = (d.config["doc.listing_start"] % id,
|
result = (d.config.getOrDefault"doc.listing_start" % id,
|
||||||
d.config["doc.listing_end"] % id)
|
d.config.getOrDefault"doc.listing_end" % id)
|
||||||
return
|
return
|
||||||
|
|
||||||
var codeLines = 1 + code.strip.countLines
|
var codeLines = 1 + code.strip.countLines
|
||||||
|
|
@ -856,9 +857,11 @@ proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string):
|
||||||
result.beginTable.add($line & "\n")
|
result.beginTable.add($line & "\n")
|
||||||
line.inc
|
line.inc
|
||||||
codeLines.dec
|
codeLines.dec
|
||||||
result.beginTable.add("</pre></td><td>" & (d.config["doc.listing_start"] % id))
|
result.beginTable.add("</pre></td><td>" & (
|
||||||
result.endTable = (d.config["doc.listing_end"] % id) &
|
d.config.getOrDefault"doc.listing_start" % id))
|
||||||
"</td></tr></tbody></table>" & (d.config["doc.listing_button"] % id)
|
result.endTable = (d.config.getOrDefault"doc.listing_end" % id) &
|
||||||
|
"</td></tr></tbody></table>" & (
|
||||||
|
d.config.getOrDefault"doc.listing_button" % id)
|
||||||
|
|
||||||
proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
||||||
## Renders a code block, appending it to `result`.
|
## Renders a code block, appending it to `result`.
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ proc processClient(client: AsyncSocket, address: string,
|
||||||
if request.reqMethod == "post":
|
if request.reqMethod == "post":
|
||||||
# Check for Expect header
|
# Check for Expect header
|
||||||
if request.headers.hasKey("Expect"):
|
if request.headers.hasKey("Expect"):
|
||||||
if request.headers["Expect"].toLower == "100-continue":
|
if request.headers.getOrDefault("Expect").toLower == "100-continue":
|
||||||
await client.sendStatus("100 Continue")
|
await client.sendStatus("100 Continue")
|
||||||
else:
|
else:
|
||||||
await client.sendStatus("417 Expectation Failed")
|
await client.sendStatus("417 Expectation Failed")
|
||||||
|
|
@ -221,7 +221,8 @@ proc processClient(client: AsyncSocket, address: string,
|
||||||
# - Check for Content-length header
|
# - Check for Content-length header
|
||||||
if request.headers.hasKey("Content-Length"):
|
if request.headers.hasKey("Content-Length"):
|
||||||
var contentLength = 0
|
var contentLength = 0
|
||||||
if parseInt(request.headers["Content-Length"], contentLength) == 0:
|
if parseInt(request.headers.getOrDefault("Content-Length"),
|
||||||
|
contentLength) == 0:
|
||||||
await request.respond(Http400, "Bad Request. Invalid Content-Length.")
|
await request.respond(Http400, "Bad Request. Invalid Content-Length.")
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
|
@ -232,16 +233,18 @@ proc processClient(client: AsyncSocket, address: string,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
case request.reqMethod
|
case request.reqMethod
|
||||||
of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
|
of "get", "post", "head", "put", "delete", "trace", "options",
|
||||||
|
"connect", "patch":
|
||||||
await callback(request)
|
await callback(request)
|
||||||
else:
|
else:
|
||||||
await request.respond(Http400, "Invalid request method. Got: " & request.reqMethod)
|
await request.respond(Http400, "Invalid request method. Got: " &
|
||||||
|
request.reqMethod)
|
||||||
|
|
||||||
# Persistent connections
|
# Persistent connections
|
||||||
if (request.protocol == HttpVer11 and
|
if (request.protocol == HttpVer11 and
|
||||||
request.headers["connection"].normalize != "close") or
|
request.headers.getOrDefault("connection").normalize != "close") or
|
||||||
(request.protocol == HttpVer10 and
|
(request.protocol == HttpVer10 and
|
||||||
request.headers["connection"].normalize == "keep-alive"):
|
request.headers.getOrDefault("connection").normalize == "keep-alive"):
|
||||||
# In HTTP 1.1 we assume that connection is persistent. Unless connection
|
# In HTTP 1.1 we assume that connection is persistent. Unless connection
|
||||||
# header states otherwise.
|
# header states otherwise.
|
||||||
# In HTTP 1.0 we assume that the connection should not be persistent.
|
# In HTTP 1.0 we assume that the connection should not be persistent.
|
||||||
|
|
|
||||||
|
|
@ -387,7 +387,7 @@ var
|
||||||
proc getCookie*(name: string): TaintedString =
|
proc getCookie*(name: string): TaintedString =
|
||||||
## Gets a cookie. If no cookie of `name` exists, "" is returned.
|
## Gets a cookie. If no cookie of `name` exists, "" is returned.
|
||||||
if gcookies == nil: gcookies = parseCookies(getHttpCookie())
|
if gcookies == nil: gcookies = parseCookies(getHttpCookie())
|
||||||
result = TaintedString(gcookies[name])
|
result = TaintedString(gcookies.getOrDefault(name))
|
||||||
|
|
||||||
proc existsCookie*(name: string): bool =
|
proc existsCookie*(name: string): bool =
|
||||||
## Checks if a cookie of `name` exists.
|
## Checks if a cookie of `name` exists.
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
## container for a set or a mapping of strings. Based on the excellent paper
|
## container for a set or a mapping of strings. Based on the excellent paper
|
||||||
## by Adam Langley.
|
## by Adam Langley.
|
||||||
|
|
||||||
|
include "system/inclrtl"
|
||||||
|
|
||||||
type
|
type
|
||||||
NodeObj[T] = object {.acyclic.}
|
NodeObj[T] = object {.acyclic.}
|
||||||
byte: int ## byte index of the difference
|
byte: int ## byte index of the difference
|
||||||
|
|
@ -140,20 +142,32 @@ proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) =
|
||||||
var n = rawInsert(c, key)
|
var n = rawInsert(c, key)
|
||||||
n.val = val
|
n.val = val
|
||||||
|
|
||||||
proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} =
|
template get[T](c: CritBitTree[T], key: string): T {.immediate.} =
|
||||||
## retrieves the value at ``c[key]``. If `key` is not in `t`,
|
|
||||||
## default empty value for the type `B` is returned
|
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
|
||||||
## exists.
|
|
||||||
let n = rawGet(c, key)
|
let n = rawGet(c, key)
|
||||||
if n != nil: result = n.val
|
if n != nil: result = n.val
|
||||||
|
else:
|
||||||
|
when compiles($key):
|
||||||
|
raise newException(KeyError, "key not found: " & $key)
|
||||||
|
else:
|
||||||
|
raise newException(KeyError, "key not found")
|
||||||
|
|
||||||
proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline.} =
|
proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline, deprecatedGet.} =
|
||||||
|
## retrieves the value at ``c[key]``. If `key` is not in `t`, the
|
||||||
|
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||||
|
## the key exists.
|
||||||
|
get(c, key)
|
||||||
|
|
||||||
|
proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline,
|
||||||
|
deprecatedGet.} =
|
||||||
## retrieves the value at ``c[key]``. The value can be modified.
|
## retrieves the value at ``c[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
let n = rawGet(c, key)
|
get(c, key)
|
||||||
if n != nil: result = n.val
|
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline, deprecated.} =
|
||||||
|
## retrieves the value at ``c[key]``. The value can be modified.
|
||||||
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
|
## Use ```[]``` instead.
|
||||||
|
get(c, key)
|
||||||
|
|
||||||
proc excl*[T](c: var CritBitTree[T], key: string) =
|
proc excl*[T](c: var CritBitTree[T], key: string) =
|
||||||
## removes `key` (and its associated value) from the set `c`.
|
## removes `key` (and its associated value) from the set `c`.
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,8 @@ proc initIntSet*: IntSet =
|
||||||
result.counter = 0
|
result.counter = 0
|
||||||
result.head = nil
|
result.head = nil
|
||||||
|
|
||||||
|
proc isNil*(x: IntSet): bool {.inline.} = x.head.isNil
|
||||||
|
|
||||||
proc assign*(dest: var IntSet, src: IntSet) =
|
proc assign*(dest: var IntSet, src: IntSet) =
|
||||||
## copies `src` to `dest`. `dest` does not need to be initialized by
|
## copies `src` to `dest`. `dest` does not need to be initialized by
|
||||||
## `initIntSet`.
|
## `initIntSet`.
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
||||||
result[i] = itm
|
result[i] = itm
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
proc repeat*[T](s: seq[T], n: Natural): seq[T] =
|
proc cycle*[T](s: seq[T], n: Natural): seq[T] =
|
||||||
## Returns a new sequence with the items of `s` repeated `n` times.
|
## Returns a new sequence with the items of `s` repeated `n` times.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -56,15 +56,29 @@ proc repeat*[T](s: seq[T], n: Natural): seq[T] =
|
||||||
##
|
##
|
||||||
## let
|
## let
|
||||||
## s = @[1, 2, 3]
|
## s = @[1, 2, 3]
|
||||||
## total = s.repeat(3)
|
## total = s.cycle(3)
|
||||||
## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||||
result = newSeq[T](n * s.len)
|
result = newSeq[T](n * s.len)
|
||||||
var o = 0
|
var o = 0
|
||||||
for x in 1..n:
|
for x in 0..<n:
|
||||||
for e in s:
|
for e in s:
|
||||||
result[o] = e
|
result[o] = e
|
||||||
inc o
|
inc o
|
||||||
|
|
||||||
|
proc repeat*[T](x: T, n: Natural): seq[T] =
|
||||||
|
## Returns a new sequence with the item `x` repeated `n` times.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block:
|
||||||
|
##
|
||||||
|
## let
|
||||||
|
## total = repeat(5, 3)
|
||||||
|
## assert total == @[5, 5, 5]
|
||||||
|
result = newSeq[T](n)
|
||||||
|
for i in 0..<n:
|
||||||
|
result[i] = x
|
||||||
|
|
||||||
proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
||||||
## Returns a new sequence without duplicates.
|
## Returns a new sequence without duplicates.
|
||||||
##
|
##
|
||||||
|
|
@ -169,6 +183,77 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
|
||||||
first = last
|
first = last
|
||||||
|
|
||||||
|
|
||||||
|
proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}):
|
||||||
|
seq[S]{.inline.} =
|
||||||
|
## Returns a new sequence with the results of `op` applied to every item in
|
||||||
|
## `data`.
|
||||||
|
##
|
||||||
|
## Since the input is not modified you can use this version of ``map`` to
|
||||||
|
## transform the type of the elements in the input sequence. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## let
|
||||||
|
## a = @[1, 2, 3, 4]
|
||||||
|
## b = map(a, proc(x: int): string = $x)
|
||||||
|
## assert b == @["1", "2", "3", "4"]
|
||||||
|
newSeq(result, data.len)
|
||||||
|
for i in 0..data.len-1: result[i] = op(data[i])
|
||||||
|
|
||||||
|
proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.})
|
||||||
|
{.deprecated.} =
|
||||||
|
## Applies `op` to every item in `data` modifying it directly.
|
||||||
|
##
|
||||||
|
## Note that this version of ``map`` requires your input and output types to
|
||||||
|
## be the same, since they are modified in-place. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## var a = @["1", "2", "3", "4"]
|
||||||
|
## echo repr(a)
|
||||||
|
## # --> ["1", "2", "3", "4"]
|
||||||
|
## map(a, proc(x: var string) = x &= "42")
|
||||||
|
## echo repr(a)
|
||||||
|
## # --> ["142", "242", "342", "442"]
|
||||||
|
## **Deprecated since version 0.12.0:** Use the ``apply`` proc instead.
|
||||||
|
for i in 0..data.len-1: op(data[i])
|
||||||
|
|
||||||
|
proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.})
|
||||||
|
{.inline.} =
|
||||||
|
## Applies `op` to every item in `data` modifying it directly.
|
||||||
|
##
|
||||||
|
## Note that this requires your input and output types to
|
||||||
|
## be the same, since they are modified in-place.
|
||||||
|
## The parameter function takes a ``var T`` type parameter.
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## var a = @["1", "2", "3", "4"]
|
||||||
|
## echo repr(a)
|
||||||
|
## # --> ["1", "2", "3", "4"]
|
||||||
|
## map(a, proc(x: var string) = x &= "42")
|
||||||
|
## echo repr(a)
|
||||||
|
## # --> ["142", "242", "342", "442"]
|
||||||
|
##
|
||||||
|
for i in 0..data.len-1: op(data[i])
|
||||||
|
|
||||||
|
proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.})
|
||||||
|
{.inline.} =
|
||||||
|
## Applies `op` to every item in `data` modifying it directly.
|
||||||
|
##
|
||||||
|
## Note that this requires your input and output types to
|
||||||
|
## be the same, since they are modified in-place.
|
||||||
|
## The parameter function takes and returns a ``T`` type variable.
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## var a = @["1", "2", "3", "4"]
|
||||||
|
## echo repr(a)
|
||||||
|
## # --> ["1", "2", "3", "4"]
|
||||||
|
## map(a, proc(x: string): string = x & "42")
|
||||||
|
## echo repr(a)
|
||||||
|
## # --> ["142", "242", "342", "442"]
|
||||||
|
##
|
||||||
|
for i in 0..data.len-1: data[i] = op(data[i])
|
||||||
|
|
||||||
|
|
||||||
iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
|
iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
|
||||||
## Iterates through a sequence and yields every item that fulfills the
|
## Iterates through a sequence and yields every item that fulfills the
|
||||||
|
|
@ -181,11 +266,12 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
|
||||||
## for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
|
## for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
|
||||||
## echo($n)
|
## echo($n)
|
||||||
## # echoes 4, 8, 4 in separate lines
|
## # echoes 4, 8, 4 in separate lines
|
||||||
for i in countup(0, len(seq1)-1):
|
for i in 0..<seq1.len:
|
||||||
var item = seq1[i]
|
if pred(seq1[i]):
|
||||||
if pred(item): yield seq1[i]
|
yield seq1[i]
|
||||||
|
|
||||||
proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
|
proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T]
|
||||||
|
{.inline.} =
|
||||||
## Returns a new sequence with all the items that fulfilled the predicate.
|
## Returns a new sequence with all the items that fulfilled the predicate.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -197,9 +283,13 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
|
||||||
## f2 = filter(colors) do (x: string) -> bool : x.len > 5
|
## f2 = filter(colors) do (x: string) -> bool : x.len > 5
|
||||||
## assert f1 == @["red", "black"]
|
## assert f1 == @["red", "black"]
|
||||||
## assert f2 == @["yellow"]
|
## assert f2 == @["yellow"]
|
||||||
accumulateResult(filter(seq1, pred))
|
result = newSeq[T]()
|
||||||
|
for i in 0..<seq1.len:
|
||||||
|
if pred(seq1[i]):
|
||||||
|
result.add(seq1[i])
|
||||||
|
|
||||||
proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
|
proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.})
|
||||||
|
{.inline.} =
|
||||||
## Keeps the items in the passed sequence if they fulfilled the predicate.
|
## Keeps the items in the passed sequence if they fulfilled the predicate.
|
||||||
## Same as the ``filter`` proc, but modifies the sequence directly.
|
## Same as the ``filter`` proc, but modifies the sequence directly.
|
||||||
##
|
##
|
||||||
|
|
@ -213,7 +303,7 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
|
||||||
for i in 0 .. <len(seq1):
|
for i in 0 .. <len(seq1):
|
||||||
if pred(seq1[i]):
|
if pred(seq1[i]):
|
||||||
if pos != i:
|
if pos != i:
|
||||||
seq1[pos] = seq1[i]
|
shallowCopy(seq1[pos], seq1[i])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
setLen(seq1, pos)
|
setLen(seq1, pos)
|
||||||
|
|
||||||
|
|
@ -268,7 +358,7 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
|
||||||
inc(j)
|
inc(j)
|
||||||
|
|
||||||
|
|
||||||
template filterIt*(seq1, pred: expr): expr {.immediate.} =
|
template filterIt*(seq1, pred: expr): expr =
|
||||||
## Returns a new sequence with all the items that fulfilled the predicate.
|
## Returns a new sequence with all the items that fulfilled the predicate.
|
||||||
##
|
##
|
||||||
## Unlike the `proc` version, the predicate needs to be an expression using
|
## Unlike the `proc` version, the predicate needs to be an expression using
|
||||||
|
|
@ -282,12 +372,12 @@ template filterIt*(seq1, pred: expr): expr {.immediate.} =
|
||||||
## notAcceptable = filterIt(temperatures, it > 50 or it < -10)
|
## notAcceptable = filterIt(temperatures, it > 50 or it < -10)
|
||||||
## assert acceptable == @[-2.0, 24.5, 44.31]
|
## assert acceptable == @[-2.0, 24.5, 44.31]
|
||||||
## assert notAcceptable == @[-272.15, 99.9, -113.44]
|
## assert notAcceptable == @[-272.15, 99.9, -113.44]
|
||||||
var result {.gensym.}: type(seq1) = @[]
|
var result {.gensym.} = newSeq[type(seq1[0])]()
|
||||||
for it {.inject.} in items(seq1):
|
for it {.inject.} in items(seq1):
|
||||||
if pred: result.add(it)
|
if pred: result.add(it)
|
||||||
result
|
result
|
||||||
|
|
||||||
template keepItIf*(varSeq, pred: expr) =
|
template keepItIf*(varSeq: seq, pred: expr) =
|
||||||
## Convenience template around the ``keepIf`` proc to reduce typing.
|
## Convenience template around the ``keepIf`` proc to reduce typing.
|
||||||
##
|
##
|
||||||
## Unlike the `proc` version, the predicate needs to be an expression using
|
## Unlike the `proc` version, the predicate needs to be an expression using
|
||||||
|
|
@ -303,10 +393,71 @@ template keepItIf*(varSeq, pred: expr) =
|
||||||
let it {.inject.} = varSeq[i]
|
let it {.inject.} = varSeq[i]
|
||||||
if pred:
|
if pred:
|
||||||
if pos != i:
|
if pos != i:
|
||||||
varSeq[pos] = varSeq[i]
|
shallowCopy(varSeq[pos], varSeq[i])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
setLen(varSeq, pos)
|
setLen(varSeq, pos)
|
||||||
|
|
||||||
|
proc all*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
|
||||||
|
## Iterates through a sequence and checks if every item fulfills the
|
||||||
|
## predicate.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
|
## assert all(numbers, proc (x: int): bool = return x < 10) == true
|
||||||
|
## assert all(numbers, proc (x: int): bool = return x < 9) == false
|
||||||
|
for i in seq1:
|
||||||
|
if not pred(i):
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
template allIt*(seq1, pred: expr): bool {.immediate.} =
|
||||||
|
## Checks if every item fulfills the predicate.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
|
## assert allIt(numbers, it < 10) == true
|
||||||
|
## assert allIt(numbers, it < 9) == false
|
||||||
|
var result {.gensym.} = true
|
||||||
|
for it {.inject.} in items(seq1):
|
||||||
|
if not pred:
|
||||||
|
result = false
|
||||||
|
break
|
||||||
|
result
|
||||||
|
|
||||||
|
proc any*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
|
||||||
|
## Iterates through a sequence and checks if some item fulfills the
|
||||||
|
## predicate.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
|
## assert any(numbers, proc (x: int): bool = return x > 8) == true
|
||||||
|
## assert any(numbers, proc (x: int): bool = return x > 9) == false
|
||||||
|
for i in seq1:
|
||||||
|
if pred(i):
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
template anyIt*(seq1, pred: expr): bool {.immediate.} =
|
||||||
|
## Checks if some item fulfills the predicate.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
|
## assert anyIt(numbers, it > 8) == true
|
||||||
|
## assert anyIt(numbers, it > 9) == false
|
||||||
|
var result {.gensym.} = false
|
||||||
|
for it {.inject.} in items(seq1):
|
||||||
|
if pred:
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
result
|
||||||
|
|
||||||
template toSeq*(iter: expr): expr {.immediate.} =
|
template toSeq*(iter: expr): expr {.immediate.} =
|
||||||
## Transforms any iterator into a sequence.
|
## Transforms any iterator into a sequence.
|
||||||
|
|
@ -320,13 +471,18 @@ template toSeq*(iter: expr): expr {.immediate.} =
|
||||||
## if x mod 2 == 1:
|
## if x mod 2 == 1:
|
||||||
## result = true)
|
## result = true)
|
||||||
## assert odd_numbers == @[1, 3, 5, 7, 9]
|
## assert odd_numbers == @[1, 3, 5, 7, 9]
|
||||||
##
|
|
||||||
## **Note**: Since this is an immediate macro, you cannot always invoke this
|
when compiles(iter.len):
|
||||||
## as ``x.toSeq``, depending on the ``x``.
|
var i = 0
|
||||||
## See `this <manual.html#limitations-of-the-method-call-syntax>`_
|
var result = newSeq[type(iter)](iter.len)
|
||||||
## for an explanation.
|
for x in iter:
|
||||||
var result {.gensym.}: seq[type(iter)] = @[]
|
result[i] = x
|
||||||
for x in iter: add(result, x)
|
inc i
|
||||||
|
result
|
||||||
|
else:
|
||||||
|
var result: seq[type(iter)] = @[]
|
||||||
|
for x in iter:
|
||||||
|
result.add(x)
|
||||||
result
|
result
|
||||||
|
|
||||||
template foldl*(sequence, operation: expr): expr =
|
template foldl*(sequence, operation: expr): expr =
|
||||||
|
|
@ -358,7 +514,7 @@ template foldl*(sequence, operation: expr): expr =
|
||||||
assert sequence.len > 0, "Can't fold empty sequences"
|
assert sequence.len > 0, "Can't fold empty sequences"
|
||||||
var result {.gensym.}: type(sequence[0])
|
var result {.gensym.}: type(sequence[0])
|
||||||
result = sequence[0]
|
result = sequence[0]
|
||||||
for i in countup(1, sequence.len - 1):
|
for i in 1..<sequence.len:
|
||||||
let
|
let
|
||||||
a {.inject.} = result
|
a {.inject.} = result
|
||||||
b {.inject.} = sequence[i]
|
b {.inject.} = sequence[i]
|
||||||
|
|
@ -401,7 +557,7 @@ template foldr*(sequence, operation: expr): expr =
|
||||||
result = operation
|
result = operation
|
||||||
result
|
result
|
||||||
|
|
||||||
template mapIt*(seq1, typ, op: expr): expr =
|
template mapIt*(seq1, typ, op: expr): expr {.deprecated.}=
|
||||||
## Convenience template around the ``map`` proc to reduce typing.
|
## Convenience template around the ``map`` proc to reduce typing.
|
||||||
##
|
##
|
||||||
## The template injects the ``it`` variable which you can use directly in an
|
## The template injects the ``it`` variable which you can use directly in an
|
||||||
|
|
@ -414,13 +570,45 @@ template mapIt*(seq1, typ, op: expr): expr =
|
||||||
## nums = @[1, 2, 3, 4]
|
## nums = @[1, 2, 3, 4]
|
||||||
## strings = nums.mapIt(string, $(4 * it))
|
## strings = nums.mapIt(string, $(4 * it))
|
||||||
## assert strings == @["4", "8", "12", "16"]
|
## assert strings == @["4", "8", "12", "16"]
|
||||||
|
## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
|
||||||
|
## template instead.
|
||||||
var result {.gensym.}: seq[typ] = @[]
|
var result {.gensym.}: seq[typ] = @[]
|
||||||
for it {.inject.} in items(seq1):
|
for it {.inject.} in items(seq1):
|
||||||
result.add(op)
|
result.add(op)
|
||||||
result
|
result
|
||||||
|
|
||||||
template mapIt*(varSeq, op: expr) =
|
|
||||||
## Convenience template around the mutable ``map`` proc to reduce typing.
|
template mapIt*(seq1, op: expr): expr =
|
||||||
|
## Convenience template around the ``map`` proc to reduce typing.
|
||||||
|
##
|
||||||
|
## The template injects the ``it`` variable which you can use directly in an
|
||||||
|
## expression. Example:
|
||||||
|
##
|
||||||
|
## .. code-block::
|
||||||
|
## let
|
||||||
|
## nums = @[1, 2, 3, 4]
|
||||||
|
## strings = nums.mapIt($(4 * it))
|
||||||
|
## assert strings == @["4", "8", "12", "16"]
|
||||||
|
type outType = type((
|
||||||
|
block:
|
||||||
|
var it{.inject.}: type(items(seq1));
|
||||||
|
op))
|
||||||
|
var result: seq[outType]
|
||||||
|
when compiles(seq1.len):
|
||||||
|
let s = seq1
|
||||||
|
var i = 0
|
||||||
|
result = newSeq[outType](s.len)
|
||||||
|
for it {.inject.} in s:
|
||||||
|
result[i] = op
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
result = @[]
|
||||||
|
for it {.inject.} in seq1:
|
||||||
|
result.add(op)
|
||||||
|
result
|
||||||
|
|
||||||
|
template applyIt*(varSeq, op: expr) =
|
||||||
|
## Convenience template around the mutable ``apply`` proc to reduce typing.
|
||||||
##
|
##
|
||||||
## The template injects the ``it`` variable which you can use directly in an
|
## The template injects the ``it`` variable which you can use directly in an
|
||||||
## expression. The expression has to return the same type as the sequence you
|
## expression. The expression has to return the same type as the sequence you
|
||||||
|
|
@ -428,12 +616,14 @@ template mapIt*(varSeq, op: expr) =
|
||||||
##
|
##
|
||||||
## .. code-block::
|
## .. code-block::
|
||||||
## var nums = @[1, 2, 3, 4]
|
## var nums = @[1, 2, 3, 4]
|
||||||
## nums.mapIt(it * 3)
|
## nums.applyIt(it * 3)
|
||||||
## assert nums[0] + nums[3] == 15
|
## assert nums[0] + nums[3] == 15
|
||||||
for i in 0 .. <len(varSeq):
|
for i in 0 .. <varSeq.len:
|
||||||
let it {.inject.} = varSeq[i]
|
let it {.inject.} = varSeq[i]
|
||||||
varSeq[i] = op
|
varSeq[i] = op
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template newSeqWith*(len: int, init: expr): expr =
|
template newSeqWith*(len: int, init: expr): expr =
|
||||||
## creates a new sequence, calling `init` to initialize each value. Example:
|
## creates a new sequence, calling `init` to initialize each value. Example:
|
||||||
##
|
##
|
||||||
|
|
@ -513,6 +703,38 @@ when isMainModule:
|
||||||
keepItIf(candidates, it.len == 3 and it[0] == 'b')
|
keepItIf(candidates, it.len == 3 and it[0] == 'b')
|
||||||
assert candidates == @["bar", "baz"]
|
assert candidates == @["bar", "baz"]
|
||||||
|
|
||||||
|
block: # any
|
||||||
|
let
|
||||||
|
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
|
len0seq : seq[int] = @[]
|
||||||
|
assert any(numbers, proc (x: int): bool = return x > 8) == true
|
||||||
|
assert any(numbers, proc (x: int): bool = return x > 9) == false
|
||||||
|
assert any(len0seq, proc (x: int): bool = return true) == false
|
||||||
|
|
||||||
|
block: # anyIt
|
||||||
|
let
|
||||||
|
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
|
len0seq : seq[int] = @[]
|
||||||
|
assert anyIt(numbers, it > 8) == true
|
||||||
|
assert anyIt(numbers, it > 9) == false
|
||||||
|
assert anyIt(len0seq, true) == false
|
||||||
|
|
||||||
|
block: # all
|
||||||
|
let
|
||||||
|
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
|
len0seq : seq[int] = @[]
|
||||||
|
assert all(numbers, proc (x: int): bool = return x < 10) == true
|
||||||
|
assert all(numbers, proc (x: int): bool = return x < 9) == false
|
||||||
|
assert all(len0seq, proc (x: int): bool = return false) == true
|
||||||
|
|
||||||
|
block: # allIt
|
||||||
|
let
|
||||||
|
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
|
len0seq : seq[int] = @[]
|
||||||
|
assert allIt(numbers, it < 10) == true
|
||||||
|
assert allIt(numbers, it < 9) == false
|
||||||
|
assert allIt(len0seq, false) == true
|
||||||
|
|
||||||
block: # toSeq test
|
block: # toSeq test
|
||||||
let
|
let
|
||||||
numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
|
@ -568,8 +790,8 @@ when isMainModule:
|
||||||
block: # mapIt tests
|
block: # mapIt tests
|
||||||
var
|
var
|
||||||
nums = @[1, 2, 3, 4]
|
nums = @[1, 2, 3, 4]
|
||||||
strings = nums.mapIt(string, $(4 * it))
|
strings = nums.mapIt($(4 * it))
|
||||||
nums.mapIt(it * 3)
|
nums.applyIt(it * 3)
|
||||||
assert nums[0] + nums[3] == 15
|
assert nums[0] + nums[3] == 15
|
||||||
|
|
||||||
block: # distribute tests
|
block: # distribute tests
|
||||||
|
|
@ -605,15 +827,19 @@ when isMainModule:
|
||||||
seq2D[0][1] = true
|
seq2D[0][1] = true
|
||||||
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
|
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
|
||||||
|
|
||||||
block: # repeat tests
|
block: # cycle tests
|
||||||
let
|
let
|
||||||
a = @[1, 2, 3]
|
a = @[1, 2, 3]
|
||||||
b: seq[int] = @[]
|
b: seq[int] = @[]
|
||||||
|
|
||||||
doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||||
doAssert a.repeat(0) == @[]
|
doAssert a.cycle(0) == @[]
|
||||||
#doAssert a.repeat(-1) == @[] # will not compile!
|
#doAssert a.cycle(-1) == @[] # will not compile!
|
||||||
doAssert b.repeat(3) == @[]
|
doAssert b.cycle(3) == @[]
|
||||||
|
|
||||||
|
block: # repeat tests
|
||||||
|
assert repeat(10, 5) == @[10, 10, 10, 10, 10]
|
||||||
|
assert repeat(@[1,2,3], 2) == @[@[1,2,3], @[1,2,3]]
|
||||||
|
|
||||||
when not defined(testing):
|
when not defined(testing):
|
||||||
echo "Finished doc tests"
|
echo "Finished doc tests"
|
||||||
|
|
|
||||||
|
|
@ -154,9 +154,9 @@ proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: Hash): int {.inline.} =
|
||||||
proc rawGet[A](s: HashSet[A], key: A, hc: var Hash): int {.inline.} =
|
proc rawGet[A](s: HashSet[A], key: A, hc: var Hash): int {.inline.} =
|
||||||
rawGetImpl()
|
rawGetImpl()
|
||||||
|
|
||||||
proc mget*[A](s: var HashSet[A], key: A): var A =
|
proc `[]`*[A](s: var HashSet[A], key: A): var A =
|
||||||
## returns the element that is actually stored in 's' which has the same
|
## returns the element that is actually stored in 's' which has the same
|
||||||
## value as 'key' or raises the ``EInvalidKey`` exception. This is useful
|
## value as 'key' or raises the ``KeyError`` exception. This is useful
|
||||||
## when one overloaded 'hash' and '==' but still needs reference semantics
|
## when one overloaded 'hash' and '==' but still needs reference semantics
|
||||||
## for sharing.
|
## for sharing.
|
||||||
assert s.isValid, "The set needs to be initialized."
|
assert s.isValid, "The set needs to be initialized."
|
||||||
|
|
@ -165,6 +165,13 @@ proc mget*[A](s: var HashSet[A], key: A): var A =
|
||||||
if index >= 0: result = s.data[index].key
|
if index >= 0: result = s.data[index].key
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
else: raise newException(KeyError, "key not found: " & $key)
|
||||||
|
|
||||||
|
proc mget*[A](s: var HashSet[A], key: A): var A {.deprecated.} =
|
||||||
|
## returns the element that is actually stored in 's' which has the same
|
||||||
|
## value as 'key' or raises the ``KeyError`` exception. This is useful
|
||||||
|
## when one overloaded 'hash' and '==' but still needs reference semantics
|
||||||
|
## for sharing. Use ```[]``` instead.
|
||||||
|
s[key]
|
||||||
|
|
||||||
proc contains*[A](s: HashSet[A], key: A): bool =
|
proc contains*[A](s: HashSet[A], key: A): bool =
|
||||||
## Returns true iff `key` is in `s`.
|
## Returns true iff `key` is in `s`.
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@
|
||||||
import
|
import
|
||||||
hashes, math
|
hashes, math
|
||||||
|
|
||||||
|
include "system/inclrtl"
|
||||||
|
|
||||||
type
|
type
|
||||||
KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B]
|
KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B]
|
||||||
KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
|
KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
|
||||||
|
|
@ -96,18 +98,10 @@ proc len*[A, B](t: Table[A, B]): int =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
proc `[]`*[A, B](t: Table[A, B], key: A): B =
|
template get(t, key): untyped {.immediate.} =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
|
||||||
## default empty value for the type `B` is returned
|
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
|
||||||
## exists.
|
|
||||||
var hc: Hash
|
|
||||||
var index = rawGet(t, key, hc)
|
|
||||||
if index >= 0: result = t.data[index].val
|
|
||||||
|
|
||||||
proc mget*[A, B](t: var Table[A, B], key: A): var B =
|
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
|
mixin rawGet
|
||||||
var hc: Hash
|
var hc: Hash
|
||||||
var index = rawGet(t, key, hc)
|
var index = rawGet(t, key, hc)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
|
|
@ -117,6 +111,31 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
|
||||||
else:
|
else:
|
||||||
raise newException(KeyError, "key not found")
|
raise newException(KeyError, "key not found")
|
||||||
|
|
||||||
|
template getOrDefaultImpl(t, key): untyped {.immediate.} =
|
||||||
|
mixin rawGet
|
||||||
|
var hc: Hash
|
||||||
|
var index = rawGet(t, key, hc)
|
||||||
|
if index >= 0: result = t.data[index].val
|
||||||
|
|
||||||
|
proc `[]`*[A, B](t: Table[A, B], key: A): B {.deprecatedGet.} =
|
||||||
|
## retrieves the value at ``t[key]``. If `key` is not in `t`, the
|
||||||
|
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||||
|
## the key exists.
|
||||||
|
get(t, key)
|
||||||
|
|
||||||
|
proc `[]`*[A, B](t: var Table[A, B], key: A): var B {.deprecatedGet.} =
|
||||||
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
|
get(t, key)
|
||||||
|
|
||||||
|
proc mget*[A, B](t: var Table[A, B], key: A): var B {.deprecated.} =
|
||||||
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
|
## If `key` is not in `t`, the ``KeyError`` exception is raised. Use ```[]```
|
||||||
|
## instead.
|
||||||
|
get(t, key)
|
||||||
|
|
||||||
|
proc getOrDefault*[A, B](t: Table[A, B], key: A): B = getOrDefaultImpl(t, key)
|
||||||
|
|
||||||
iterator allValues*[A, B](t: Table[A, B]; key: A): B =
|
iterator allValues*[A, B](t: Table[A, B]; key: A): B =
|
||||||
## iterates over any value in the table `t` that belongs to the given `key`.
|
## iterates over any value in the table `t` that belongs to the given `key`.
|
||||||
var h: Hash = hash(key) and high(t.data)
|
var h: Hash = hash(key) and high(t.data)
|
||||||
|
|
@ -276,17 +295,19 @@ iterator mvalues*[A, B](t: TableRef[A, B]): var B =
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if isFilled(t.data[h].hcode): yield t.data[h].val
|
if isFilled(t.data[h].hcode): yield t.data[h].val
|
||||||
|
|
||||||
proc `[]`*[A, B](t: TableRef[A, B], key: A): B =
|
proc `[]`*[A, B](t: TableRef[A, B], key: A): var B {.deprecatedGet.} =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`, the
|
||||||
## default empty value for the type `B` is returned
|
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
## the key exists.
|
||||||
## exists.
|
|
||||||
result = t[][key]
|
result = t[][key]
|
||||||
|
|
||||||
proc mget*[A, B](t: TableRef[A, B], key: A): var B =
|
proc mget*[A, B](t: TableRef[A, B], key: A): var B {.deprecated.} =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
t[].mget(key)
|
## Use ```[]``` instead.
|
||||||
|
t[][key]
|
||||||
|
|
||||||
|
proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B = getOrDefault(t[], key)
|
||||||
|
|
||||||
proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
|
proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
|
||||||
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
||||||
|
|
@ -399,22 +420,26 @@ proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int {.inline
|
||||||
proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
|
proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
|
||||||
rawGetImpl()
|
rawGetImpl()
|
||||||
|
|
||||||
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
|
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B {.deprecatedGet.} =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`, the
|
||||||
## default empty value for the type `B` is returned
|
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
## the key exists.
|
||||||
## exists.
|
get(t, key)
|
||||||
var hc: Hash
|
|
||||||
var index = rawGet(t, key, hc)
|
|
||||||
if index >= 0: result = t.data[index].val
|
|
||||||
|
|
||||||
proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
|
proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B{.deprecatedGet.} =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
var hc: Hash
|
get(t, key)
|
||||||
var index = rawGet(t, key, hc)
|
|
||||||
if index >= 0: result = t.data[index].val
|
proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B {.deprecated.} =
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
|
## Use ```[]``` instead.
|
||||||
|
get(t, key)
|
||||||
|
|
||||||
|
proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B =
|
||||||
|
getOrDefaultImpl(t, key)
|
||||||
|
|
||||||
|
|
||||||
proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
|
proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
|
|
@ -572,17 +597,20 @@ iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B =
|
||||||
forAllOrderedPairs:
|
forAllOrderedPairs:
|
||||||
yield t.data[h].val
|
yield t.data[h].val
|
||||||
|
|
||||||
proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): B =
|
proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. If `key` is not in `t`, the
|
||||||
## default empty value for the type `B` is returned
|
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
## the key exists.
|
||||||
## exists.
|
|
||||||
result = t[][key]
|
result = t[][key]
|
||||||
|
|
||||||
proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B =
|
proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B {.deprecated.} =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
result = t[].mget(key)
|
## Use ```[]``` instead.
|
||||||
|
result = t[][key]
|
||||||
|
|
||||||
|
proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B =
|
||||||
|
getOrDefault(t[], key)
|
||||||
|
|
||||||
proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
|
proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
|
||||||
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
||||||
|
|
@ -683,19 +711,35 @@ proc rawGet[A](t: CountTable[A], key: A): int =
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
result = -1 - h # < 0 => MISSING; insert idx = -1 - result
|
result = -1 - h # < 0 => MISSING; insert idx = -1 - result
|
||||||
|
|
||||||
proc `[]`*[A](t: CountTable[A], key: A): int =
|
template ctget(t, key: untyped): untyped {.immediate.} =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
|
||||||
## 0 is returned. One can check with ``hasKey`` whether the key
|
|
||||||
## exists.
|
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
|
else:
|
||||||
|
when compiles($key):
|
||||||
|
raise newException(KeyError, "key not found: " & $key)
|
||||||
|
else:
|
||||||
|
raise newException(KeyError, "key not found")
|
||||||
|
|
||||||
proc mget*[A](t: var CountTable[A], key: A): var int =
|
proc `[]`*[A](t: CountTable[A], key: A): int {.deprecatedGet.} =
|
||||||
|
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||||
|
## the ``KeyError`` exception is raised. One can check with ``hasKey``
|
||||||
|
## whether the key exists.
|
||||||
|
ctget(t, key)
|
||||||
|
|
||||||
|
proc `[]`*[A](t: var CountTable[A], key: A): var int {.deprecatedGet.} =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
|
ctget(t, key)
|
||||||
|
|
||||||
|
proc mget*[A](t: var CountTable[A], key: A): var int {.deprecated.} =
|
||||||
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
|
## Use ```[]``` instead.
|
||||||
|
ctget(t, key)
|
||||||
|
|
||||||
|
proc getOrDefault*[A](t: CountTable[A], key: A): int =
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
|
||||||
|
|
||||||
proc hasKey*[A](t: CountTable[A], key: A): bool =
|
proc hasKey*[A](t: CountTable[A], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
|
|
@ -831,16 +875,19 @@ iterator mvalues*[A](t: CountTableRef[A]): var int =
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
if t.data[h].val != 0: yield t.data[h].val
|
if t.data[h].val != 0: yield t.data[h].val
|
||||||
|
|
||||||
proc `[]`*[A](t: CountTableRef[A], key: A): int =
|
proc `[]`*[A](t: CountTableRef[A], key: A): var int {.deprecatedGet.} =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## 0 is returned. One can check with ``hasKey`` whether the key
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
## exists.
|
|
||||||
result = t[][key]
|
result = t[][key]
|
||||||
|
|
||||||
proc mget*[A](t: CountTableRef[A], key: A): var int =
|
proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} =
|
||||||
## retrieves the value at ``t[key]``. The value can be modified.
|
## retrieves the value at ``t[key]``. The value can be modified.
|
||||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||||
result = t[].mget(key)
|
## Use ```[]``` instead.
|
||||||
|
result = t[][key]
|
||||||
|
|
||||||
|
proc getOrDefault*[A](t: CountTableRef[A], key: A): int =
|
||||||
|
getOrDefaultImpl(t, key)
|
||||||
|
|
||||||
proc hasKey*[A](t: CountTableRef[A], key: A): bool =
|
proc hasKey*[A](t: CountTableRef[A], key: A): bool =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements efficient computations of hash values for diverse
|
## This module implements efficient computations of hash values for diverse
|
||||||
## Nim types. All the procs are based on these two building blocks: the `!&
|
## Nim types. All the procs are based on these two building blocks:
|
||||||
## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_
|
## - `!& proc <#!&>`_ used to start or mix a hash value, and
|
||||||
## used to *finish* the hash value. If you want to implement hash procs for
|
## - `!$ proc <#!$>`_ used to *finish* the hash value.
|
||||||
|
## If you want to implement hash procs for
|
||||||
## your custom types you will end up writing the following kind of skeleton of
|
## your custom types you will end up writing the following kind of skeleton of
|
||||||
## code:
|
## code:
|
||||||
##
|
##
|
||||||
|
|
@ -108,7 +109,7 @@ proc hash*(x: int): Hash {.inline.} =
|
||||||
result = x
|
result = x
|
||||||
|
|
||||||
proc hash*(x: int64): Hash {.inline.} =
|
proc hash*(x: int64): Hash {.inline.} =
|
||||||
## efficient hashing of integers
|
## efficient hashing of int64 integers
|
||||||
result = toU32(x)
|
result = toU32(x)
|
||||||
|
|
||||||
proc hash*(x: char): Hash {.inline.} =
|
proc hash*(x: char): Hash {.inline.} =
|
||||||
|
|
@ -126,6 +127,16 @@ proc hash*(x: string): Hash =
|
||||||
h = h !& ord(x[i])
|
h = h !& ord(x[i])
|
||||||
result = !$h
|
result = !$h
|
||||||
|
|
||||||
|
proc hash*(sBuf: string, sPos, ePos: int): Hash =
|
||||||
|
## efficient hashing of a string buffer, from starting
|
||||||
|
## position `sPos` to ending position `ePos`
|
||||||
|
##
|
||||||
|
## ``hash(myStr, 0, myStr.high)`` is equivalent to ``hash(myStr)``
|
||||||
|
var h: Hash = 0
|
||||||
|
for i in sPos..ePos:
|
||||||
|
h = h !& ord(sBuf[i])
|
||||||
|
result = !$h
|
||||||
|
|
||||||
proc hashIgnoreStyle*(x: string): Hash =
|
proc hashIgnoreStyle*(x: string): Hash =
|
||||||
## efficient hashing of strings; style is ignored
|
## efficient hashing of strings; style is ignored
|
||||||
var h: Hash = 0
|
var h: Hash = 0
|
||||||
|
|
@ -145,6 +156,27 @@ proc hashIgnoreStyle*(x: string): Hash =
|
||||||
|
|
||||||
result = !$h
|
result = !$h
|
||||||
|
|
||||||
|
proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash =
|
||||||
|
## efficient hashing of a string buffer, from starting
|
||||||
|
## position `sPos` to ending position `ePos`; style is ignored
|
||||||
|
##
|
||||||
|
## ``hashIgnoreStyle(myBuf, 0, myBuf.high)`` is equivalent
|
||||||
|
## to ``hashIgnoreStyle(myBuf)``
|
||||||
|
var h: Hash = 0
|
||||||
|
var i = sPos
|
||||||
|
while i <= ePos:
|
||||||
|
var c = sBuf[i]
|
||||||
|
if c == '_':
|
||||||
|
inc(i)
|
||||||
|
elif isMagicIdentSeparatorRune(cstring(sBuf), i):
|
||||||
|
inc(i, magicIdentSeparatorRuneByteWidth)
|
||||||
|
else:
|
||||||
|
if c in {'A'..'Z'}:
|
||||||
|
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||||
|
h = h !& ord(c)
|
||||||
|
inc(i)
|
||||||
|
result = !$h
|
||||||
|
|
||||||
proc hashIgnoreCase*(x: string): Hash =
|
proc hashIgnoreCase*(x: string): Hash =
|
||||||
## efficient hashing of strings; case is ignored
|
## efficient hashing of strings; case is ignored
|
||||||
var h: Hash = 0
|
var h: Hash = 0
|
||||||
|
|
@ -155,7 +187,22 @@ proc hashIgnoreCase*(x: string): Hash =
|
||||||
h = h !& ord(c)
|
h = h !& ord(c)
|
||||||
result = !$h
|
result = !$h
|
||||||
|
|
||||||
|
proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
|
||||||
|
## efficient hashing of a string buffer, from starting
|
||||||
|
## position `sPos` to ending position `ePos`; case is ignored
|
||||||
|
##
|
||||||
|
## ``hashIgnoreCase(myBuf, 0, myBuf.high)`` is equivalent
|
||||||
|
## to ``hashIgnoreCase(myBuf)``
|
||||||
|
var h: Hash = 0
|
||||||
|
for i in sPos..ePos:
|
||||||
|
var c = sBuf[i]
|
||||||
|
if c in {'A'..'Z'}:
|
||||||
|
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||||
|
h = h !& ord(c)
|
||||||
|
result = !$h
|
||||||
|
|
||||||
proc hash*(x: float): Hash {.inline.} =
|
proc hash*(x: float): Hash {.inline.} =
|
||||||
|
## efficient hashing of floats.
|
||||||
var y = x + 1.0
|
var y = x + 1.0
|
||||||
result = cast[ptr Hash](addr(y))[]
|
result = cast[ptr Hash](addr(y))[]
|
||||||
|
|
||||||
|
|
@ -173,10 +220,29 @@ proc hash*[T: tuple](x: T): Hash =
|
||||||
result = !$result
|
result = !$result
|
||||||
|
|
||||||
proc hash*[A](x: openArray[A]): Hash =
|
proc hash*[A](x: openArray[A]): Hash =
|
||||||
|
## efficient hashing of arrays and sequences.
|
||||||
for it in items(x): result = result !& hash(it)
|
for it in items(x): result = result !& hash(it)
|
||||||
result = !$result
|
result = !$result
|
||||||
|
|
||||||
|
proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash =
|
||||||
|
## efficient hashing of portions of arrays and sequences.
|
||||||
|
##
|
||||||
|
## ``hash(myBuf, 0, myBuf.high)`` is equivalent to ``hash(myBuf)``
|
||||||
|
for i in sPos..ePos:
|
||||||
|
result = result !& hash(aBuf[i])
|
||||||
|
result = !$result
|
||||||
|
|
||||||
proc hash*[A](x: set[A]): Hash =
|
proc hash*[A](x: set[A]): Hash =
|
||||||
|
## efficient hashing of sets.
|
||||||
for it in items(x): result = result !& hash(it)
|
for it in items(x): result = result !& hash(it)
|
||||||
result = !$result
|
result = !$result
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) )
|
||||||
|
doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") )
|
||||||
|
doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") )
|
||||||
|
let xx = @['H','e','l','l','o']
|
||||||
|
let ss = "Hello"
|
||||||
|
doAssert( hash(xx) == hash(ss) )
|
||||||
|
doAssert( hash(xx) == hash(xx, 0, xx.high) )
|
||||||
|
doAssert( hash(ss) == hash(ss, 0, ss.high) )
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ type
|
||||||
## console
|
## console
|
||||||
|
|
||||||
FileLogger* = ref object of Logger ## logger that writes the messages to a file
|
FileLogger* = ref object of Logger ## logger that writes the messages to a file
|
||||||
f: File
|
file*: File ## the wrapped file.
|
||||||
|
|
||||||
RollingFileLogger* = ref object of FileLogger ## logger that writes the
|
RollingFileLogger* = ref object of FileLogger ## logger that writes the
|
||||||
## messages to a file and
|
## messages to a file and
|
||||||
|
|
@ -92,7 +92,9 @@ type
|
||||||
{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
|
{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
|
||||||
PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
|
PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
|
||||||
|
|
||||||
proc substituteLog(frmt: string, level: Level, args: varargs[string, `$`]): string =
|
proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string =
|
||||||
|
## Format a log message using the ``frmt`` format string, ``level`` and varargs.
|
||||||
|
## See the module documentation for the format string syntax.
|
||||||
var msgLen = 0
|
var msgLen = 0
|
||||||
for arg in args:
|
for arg in args:
|
||||||
msgLen += arg.len
|
msgLen += arg.len
|
||||||
|
|
@ -124,7 +126,7 @@ proc substituteLog(frmt: string, level: Level, args: varargs[string, `$`]): stri
|
||||||
|
|
||||||
method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
|
method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
|
||||||
raises: [Exception],
|
raises: [Exception],
|
||||||
tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} =
|
tags: [TimeEffect, WriteIOEffect, ReadIOEffect], base.} =
|
||||||
## Override this method in custom loggers. Default implementation does
|
## Override this method in custom loggers. Default implementation does
|
||||||
## nothing.
|
## nothing.
|
||||||
discard
|
discard
|
||||||
|
|
@ -133,15 +135,17 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
|
||||||
## Logs to the console using ``logger`` only.
|
## Logs to the console using ``logger`` only.
|
||||||
if level >= logger.levelThreshold:
|
if level >= logger.levelThreshold:
|
||||||
writeLine(stdout, substituteLog(logger.fmtStr, level, args))
|
writeLine(stdout, substituteLog(logger.fmtStr, level, args))
|
||||||
|
if level in {lvlError, lvlFatal}: flushFile(stdout)
|
||||||
|
|
||||||
method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
|
method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
|
||||||
## Logs to a file using ``logger`` only.
|
## Logs to a file using ``logger`` only.
|
||||||
if level >= logger.levelThreshold:
|
if level >= logger.levelThreshold:
|
||||||
writeLine(logger.f, substituteLog(logger.fmtStr, level, args))
|
writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
|
||||||
|
if level in {lvlError, lvlFatal}: flushFile(logger.file)
|
||||||
|
|
||||||
proc defaultFilename*(): string =
|
proc defaultFilename*(): string =
|
||||||
## Returns the default filename for a logger.
|
## Returns the default filename for a logger.
|
||||||
var (path, name, ext) = splitFile(getAppFilename())
|
var (path, name, _) = splitFile(getAppFilename())
|
||||||
result = changeFileExt(path / name, "log")
|
result = changeFileExt(path / name, "log")
|
||||||
|
|
||||||
proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
|
proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
|
||||||
|
|
@ -160,14 +164,14 @@ proc newFileLogger*(filename = defaultFilename(),
|
||||||
## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
|
## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
|
||||||
new(result)
|
new(result)
|
||||||
result.levelThreshold = levelThreshold
|
result.levelThreshold = levelThreshold
|
||||||
result.f = open(filename, mode, bufSize = bufSize)
|
result.file = open(filename, mode, bufSize = bufSize)
|
||||||
result.fmtStr = fmtStr
|
result.fmtStr = fmtStr
|
||||||
|
|
||||||
# ------
|
# ------
|
||||||
|
|
||||||
proc countLogLines(logger: RollingFileLogger): int =
|
proc countLogLines(logger: RollingFileLogger): int =
|
||||||
result = 0
|
result = 0
|
||||||
for line in logger.f.lines():
|
for line in logger.file.lines():
|
||||||
result.inc()
|
result.inc()
|
||||||
|
|
||||||
proc countFiles(filename: string): int =
|
proc countFiles(filename: string): int =
|
||||||
|
|
@ -200,7 +204,7 @@ proc newRollingFileLogger*(filename = defaultFilename(),
|
||||||
result.fmtStr = fmtStr
|
result.fmtStr = fmtStr
|
||||||
result.maxLines = maxLines
|
result.maxLines = maxLines
|
||||||
result.bufSize = bufSize
|
result.bufSize = bufSize
|
||||||
result.f = open(filename, mode, bufSize=result.bufSize)
|
result.file = open(filename, mode, bufSize=result.bufSize)
|
||||||
result.curLine = 0
|
result.curLine = 0
|
||||||
result.baseName = filename
|
result.baseName = filename
|
||||||
result.baseMode = mode
|
result.baseMode = mode
|
||||||
|
|
@ -222,13 +226,14 @@ method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`])
|
||||||
## Logs to a file using rolling ``logger`` only.
|
## Logs to a file using rolling ``logger`` only.
|
||||||
if level >= logger.levelThreshold:
|
if level >= logger.levelThreshold:
|
||||||
if logger.curLine >= logger.maxLines:
|
if logger.curLine >= logger.maxLines:
|
||||||
logger.f.close()
|
logger.file.close()
|
||||||
rotate(logger)
|
rotate(logger)
|
||||||
logger.logFiles.inc
|
logger.logFiles.inc
|
||||||
logger.curLine = 0
|
logger.curLine = 0
|
||||||
logger.f = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
|
logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
|
||||||
|
|
||||||
writeLine(logger.f, substituteLog(logger.fmtStr, level, args))
|
writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
|
||||||
|
if level in {lvlError, lvlFatal}: flushFile(logger.file)
|
||||||
logger.curLine.inc
|
logger.curLine.inc
|
||||||
|
|
||||||
# --------
|
# --------
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) =
|
||||||
setPointer(a, nil)
|
setPointer(a, nil)
|
||||||
next(p)
|
next(p)
|
||||||
of jsonInt:
|
of jsonInt:
|
||||||
setPointer(a, t[p.getInt])
|
setPointer(a, t.getOrDefault(p.getInt))
|
||||||
next(p)
|
next(p)
|
||||||
of jsonArrayStart:
|
of jsonArrayStart:
|
||||||
next(p)
|
next(p)
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,6 @@
|
||||||
|
|
||||||
## Module for computing MD5 checksums.
|
## Module for computing MD5 checksums.
|
||||||
|
|
||||||
import unsigned
|
|
||||||
|
|
||||||
type
|
type
|
||||||
MD5State = array[0..3, uint32]
|
MD5State = array[0..3, uint32]
|
||||||
MD5Block = array[0..15, uint32]
|
MD5Block = array[0..15, uint32]
|
||||||
|
|
|
||||||
|
|
@ -499,7 +499,7 @@ proc newMimetypes*(): MimeDB =
|
||||||
proc getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string =
|
proc getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string =
|
||||||
## Gets mimetype which corresponds to ``ext``. Returns ``default`` if ``ext``
|
## Gets mimetype which corresponds to ``ext``. Returns ``default`` if ``ext``
|
||||||
## could not be found.
|
## could not be found.
|
||||||
result = mimedb.mimes[ext]
|
result = mimedb.mimes.getOrDefault(ext)
|
||||||
if result == "":
|
if result == "":
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,10 @@ when not declared(getEnv) or defined(nimscript):
|
||||||
## to an environment variable
|
## to an environment variable
|
||||||
|
|
||||||
ReadDirEffect* = object of ReadIOEffect ## effect that denotes a write
|
ReadDirEffect* = object of ReadIOEffect ## effect that denotes a write
|
||||||
## operation to the directory structure
|
## operation to the directory
|
||||||
WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write operation to
|
## structure
|
||||||
|
WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write
|
||||||
|
## operation to
|
||||||
## the directory structure
|
## the directory structure
|
||||||
|
|
||||||
OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
|
OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
|
||||||
|
|
@ -63,13 +65,13 @@ when not declared(getEnv) or defined(nimscript):
|
||||||
AltSep* = '/'
|
AltSep* = '/'
|
||||||
## An alternative character used by the operating system to separate
|
## An alternative character used by the operating system to separate
|
||||||
## pathname components, or the same as `DirSep` if only one separator
|
## pathname components, or the same as `DirSep` if only one separator
|
||||||
## character exists. This is set to '/' on Windows systems where `DirSep`
|
## character exists. This is set to '/' on Windows systems
|
||||||
## is a backslash.
|
## where `DirSep` is a backslash.
|
||||||
|
|
||||||
PathSep* = ':'
|
PathSep* = ':'
|
||||||
## The character conventionally used by the operating system to separate
|
## The character conventionally used by the operating system to separate
|
||||||
## search patch components (as in PATH), such as ':' for POSIX or ';' for
|
## search patch components (as in PATH), such as ':' for POSIX
|
||||||
## Windows.
|
## or ';' for Windows.
|
||||||
|
|
||||||
FileSystemCaseSensitive* = true
|
FileSystemCaseSensitive* = true
|
||||||
## true if the file system is case sensitive, false otherwise. Used by
|
## true if the file system is case sensitive, false otherwise. Used by
|
||||||
|
|
@ -104,7 +106,8 @@ when not declared(getEnv) or defined(nimscript):
|
||||||
# MacOS directory separator is a colon ":" which is the only character not
|
# MacOS directory separator is a colon ":" which is the only character not
|
||||||
# allowed in filenames.
|
# allowed in filenames.
|
||||||
#
|
#
|
||||||
# A path containing no colon or which begins with a colon is a partial path.
|
# A path containing no colon or which begins with a colon is a partial
|
||||||
|
# path.
|
||||||
# E.g. ":kalle:petter" ":kalle" "kalle"
|
# E.g. ":kalle:petter" ":kalle" "kalle"
|
||||||
#
|
#
|
||||||
# All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:"
|
# All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:"
|
||||||
|
|
@ -206,9 +209,9 @@ when not declared(getEnv) or defined(nimscript):
|
||||||
|
|
||||||
proc joinPath*(parts: varargs[string]): string {.noSideEffect,
|
proc joinPath*(parts: varargs[string]): string {.noSideEffect,
|
||||||
rtl, extern: "nos$1OpenArray".} =
|
rtl, extern: "nos$1OpenArray".} =
|
||||||
## The same as `joinPath(head, tail)`, but works with any number of directory
|
## The same as `joinPath(head, tail)`, but works with any number of
|
||||||
## parts. You need to pass at least one element or the proc will assert in
|
## directory parts. You need to pass at least one element or the proc
|
||||||
## debug builds and crash on release builds.
|
## will assert in debug builds and crash on release builds.
|
||||||
result = parts[0]
|
result = parts[0]
|
||||||
for i in 1..high(parts):
|
for i in 1..high(parts):
|
||||||
result = joinPath(result, parts[i])
|
result = joinPath(result, parts[i])
|
||||||
|
|
@ -316,8 +319,8 @@ when not declared(getEnv) or defined(nimscript):
|
||||||
if inclusive: yield path
|
if inclusive: yield path
|
||||||
|
|
||||||
proc `/../` * (head, tail: string): string {.noSideEffect.} =
|
proc `/../` * (head, tail: string): string {.noSideEffect.} =
|
||||||
## The same as ``parentDir(head) / tail`` unless there is no parent directory.
|
## The same as ``parentDir(head) / tail`` unless there is no parent
|
||||||
## Then ``head / tail`` is performed instead.
|
## directory. Then ``head / tail`` is performed instead.
|
||||||
let sepPos = parentDirPos(head)
|
let sepPos = parentDirPos(head)
|
||||||
if sepPos >= 0:
|
if sepPos >= 0:
|
||||||
result = substr(head, 0, sepPos-1) / tail
|
result = substr(head, 0, sepPos-1) / tail
|
||||||
|
|
@ -500,7 +503,8 @@ when defined(nimdoc) and not declared(os):
|
||||||
proc existsFile(x: string): bool = discard
|
proc existsFile(x: string): bool = discard
|
||||||
|
|
||||||
when declared(getEnv) or defined(nimscript):
|
when declared(getEnv) or defined(nimscript):
|
||||||
proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} =
|
proc getHomeDir*(): string {.rtl, extern: "nos$1",
|
||||||
|
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||||
## Returns the home directory of the current user.
|
## Returns the home directory of the current user.
|
||||||
##
|
##
|
||||||
## This proc is wrapped by the expandTilde proc for the convenience of
|
## This proc is wrapped by the expandTilde proc for the convenience of
|
||||||
|
|
@ -508,18 +512,21 @@ when declared(getEnv) or defined(nimscript):
|
||||||
when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
|
when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
|
||||||
else: return string(getEnv("HOME")) & "/"
|
else: return string(getEnv("HOME")) & "/"
|
||||||
|
|
||||||
proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} =
|
proc getConfigDir*(): string {.rtl, extern: "nos$1",
|
||||||
|
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||||
## Returns the config directory of the current user for applications.
|
## Returns the config directory of the current user for applications.
|
||||||
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
||||||
else: return string(getEnv("HOME")) & "/.config/"
|
else: return string(getEnv("HOME")) & "/.config/"
|
||||||
|
|
||||||
proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
|
proc getTempDir*(): string {.rtl, extern: "nos$1",
|
||||||
|
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||||
## Returns the temporary directory of the current user for applications to
|
## Returns the temporary directory of the current user for applications to
|
||||||
## save temporary files in.
|
## save temporary files in.
|
||||||
when defined(windows): return string(getEnv("TEMP")) & "\\"
|
when defined(windows): return string(getEnv("TEMP")) & "\\"
|
||||||
else: return "/tmp/"
|
else: return "/tmp/"
|
||||||
|
|
||||||
proc expandTilde*(path: string): string {.tags: [ReadEnvEffect, ReadIOEffect].} =
|
proc expandTilde*(path: string): string {.
|
||||||
|
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||||
## Expands a path starting with ``~/`` to a full path.
|
## Expands a path starting with ``~/`` to a full path.
|
||||||
##
|
##
|
||||||
## If `path` starts with the tilde character and is followed by `/` or `\\`
|
## If `path` starts with the tilde character and is followed by `/` or `\\`
|
||||||
|
|
@ -527,8 +534,8 @@ when declared(getEnv) or defined(nimscript):
|
||||||
## the getHomeDir() proc, otherwise the input path will be returned without
|
## the getHomeDir() proc, otherwise the input path will be returned without
|
||||||
## modification.
|
## modification.
|
||||||
##
|
##
|
||||||
## The behaviour of this proc is the same on the Windows platform despite not
|
## The behaviour of this proc is the same on the Windows platform despite
|
||||||
## having this convention. Example:
|
## not having this convention. Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## let configFile = expandTilde("~" / "appname.cfg")
|
## let configFile = expandTilde("~" / "appname.cfg")
|
||||||
|
|
@ -549,7 +556,8 @@ when declared(getEnv) or defined(nimscript):
|
||||||
yield substr(s, first, last-1)
|
yield substr(s, first, last-1)
|
||||||
inc(last)
|
inc(last)
|
||||||
|
|
||||||
proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} =
|
proc findExe*(exe: string): string {.
|
||||||
|
tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} =
|
||||||
## Searches for `exe` in the current working directory and then
|
## Searches for `exe` in the current working directory and then
|
||||||
## in directories listed in the ``PATH`` environment variable.
|
## in directories listed in the ``PATH`` environment variable.
|
||||||
## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
|
## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@ proc next*(s: var ScgiState, timeout: int = -1): bool =
|
||||||
L = L * 10 + ord(d) - ord('0')
|
L = L * 10 + ord(d) - ord('0')
|
||||||
recvBuffer(s, L+1)
|
recvBuffer(s, L+1)
|
||||||
s.headers = parseHeaders(s.input, L)
|
s.headers = parseHeaders(s.input, L)
|
||||||
if s.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected")
|
if s.headers.getOrDefault("SCGI") != "1": raiseScgiError("SCGI Version 1 expected")
|
||||||
L = parseInt(s.headers["CONTENT_LENGTH"])
|
L = parseInt(s.headers.getOrDefault("CONTENT_LENGTH"))
|
||||||
recvBuffer(s, L)
|
recvBuffer(s, L)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
@ -221,10 +221,10 @@ proc handleClientRead(client: AsyncClient, s: AsyncScgiState) =
|
||||||
case ret
|
case ret
|
||||||
of ReadFullLine:
|
of ReadFullLine:
|
||||||
client.headers = parseHeaders(client.input, client.input.len-1)
|
client.headers = parseHeaders(client.input, client.input.len-1)
|
||||||
if client.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected")
|
if client.headers.getOrDefault("SCGI") != "1": raiseScgiError("SCGI Version 1 expected")
|
||||||
client.input = "" # For next part
|
client.input = "" # For next part
|
||||||
|
|
||||||
let contentLen = parseInt(client.headers["CONTENT_LENGTH"])
|
let contentLen = parseInt(client.headers.getOrDefault("CONTENT_LENGTH"))
|
||||||
if contentLen > 0:
|
if contentLen > 0:
|
||||||
client.mode = ClientReadContent
|
client.mode = ClientReadContent
|
||||||
else:
|
else:
|
||||||
|
|
@ -232,7 +232,8 @@ proc handleClientRead(client: AsyncClient, s: AsyncScgiState) =
|
||||||
checkCloseSocket(client)
|
checkCloseSocket(client)
|
||||||
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
||||||
of ClientReadContent:
|
of ClientReadContent:
|
||||||
let L = parseInt(client.headers["CONTENT_LENGTH"])-client.input.len
|
let L = parseInt(client.headers.getOrDefault("CONTENT_LENGTH")) -
|
||||||
|
client.input.len
|
||||||
if L > 0:
|
if L > 0:
|
||||||
let ret = recvBufferAsync(client, L)
|
let ret = recvBufferAsync(client, L)
|
||||||
case ret
|
case ret
|
||||||
|
|
|
||||||
|
|
@ -101,22 +101,32 @@ proc rawGet(t: StringTableRef, key: string): int =
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
result = - 1
|
result = - 1
|
||||||
|
|
||||||
proc `[]`*(t: StringTableRef, key: string): string {.rtl, extern: "nstGet".} =
|
template get(t: StringTableRef, key: string): stmt {.immediate.} =
|
||||||
## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned
|
var index = rawGet(t, key)
|
||||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
if index >= 0: result = t.data[index].val
|
||||||
## exists.
|
else:
|
||||||
|
when compiles($key):
|
||||||
|
raise newException(KeyError, "key not found: " & $key)
|
||||||
|
else:
|
||||||
|
raise newException(KeyError, "key not found")
|
||||||
|
|
||||||
|
proc `[]`*(t: StringTableRef, key: string): var string {.
|
||||||
|
rtl, extern: "nstTake", deprecatedGet.} =
|
||||||
|
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
|
||||||
|
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||||
|
## the key exists.
|
||||||
|
get(t, key)
|
||||||
|
|
||||||
|
proc mget*(t: StringTableRef, key: string): var string {.deprecated.} =
|
||||||
|
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
|
||||||
|
## ``KeyError`` exception is raised. Use ```[]``` instead.
|
||||||
|
get(t, key)
|
||||||
|
|
||||||
|
proc getOrDefault*(t: StringTableRef; key: string): string =
|
||||||
var index = rawGet(t, key)
|
var index = rawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: result = ""
|
else: result = ""
|
||||||
|
|
||||||
proc mget*(t: StringTableRef, key: string): var string {.
|
|
||||||
rtl, extern: "nstTake".} =
|
|
||||||
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
|
|
||||||
## ``KeyError`` exception is raised.
|
|
||||||
var index = rawGet(t, key)
|
|
||||||
if index >= 0: result = t.data[index].val
|
|
||||||
else: raise newException(KeyError, "key does not exist: " & key)
|
|
||||||
|
|
||||||
proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} =
|
proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} =
|
||||||
## returns true iff `key` is in the table `t`.
|
## returns true iff `key` is in the table `t`.
|
||||||
result = rawGet(t, key) >= 0
|
result = rawGet(t, key) >= 0
|
||||||
|
|
@ -152,7 +162,7 @@ proc raiseFormatException(s: string) =
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
||||||
if hasKey(t, key): return t[key]
|
if hasKey(t, key): return t.getOrDefault(key)
|
||||||
# hm difficult: assume safety in taint mode here. XXX This is dangerous!
|
# hm difficult: assume safety in taint mode here. XXX This is dangerous!
|
||||||
if useEnvironment in flags: result = os.getEnv(key).string
|
if useEnvironment in flags: result = os.getEnv(key).string
|
||||||
else: result = ""
|
else: result = ""
|
||||||
|
|
@ -248,7 +258,7 @@ when isMainModule:
|
||||||
assert x["k"] == "v"
|
assert x["k"] == "v"
|
||||||
assert x["11"] == "22"
|
assert x["11"] == "22"
|
||||||
assert x["565"] == "67"
|
assert x["565"] == "67"
|
||||||
x.mget("11") = "23"
|
x["11"] = "23"
|
||||||
assert x["11"] == "23"
|
assert x["11"] == "23"
|
||||||
|
|
||||||
x.clear(modeCaseInsensitive)
|
x.clear(modeCaseInsensitive)
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,132 @@ const
|
||||||
## doAssert "01234".find(invalid) == -1
|
## doAssert "01234".find(invalid) == -1
|
||||||
## doAssert "01A34".find(invalid) == 2
|
## doAssert "01A34".find(invalid) == 2
|
||||||
|
|
||||||
|
proc isAlpha*(c: char): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsAlphaChar".}=
|
||||||
|
## Checks whether or not `c` is alphabetical.
|
||||||
|
##
|
||||||
|
## This checks a-z, A-Z ASCII characters only.
|
||||||
|
return c in Letters
|
||||||
|
|
||||||
|
proc isAlphaNumeric*(c: char): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsAlphaNumericChar".}=
|
||||||
|
## Checks whether or not `c` is alphanumeric.
|
||||||
|
##
|
||||||
|
## This checks a-z, A-Z, 0-9 ASCII characters only.
|
||||||
|
return c in Letters or c in Digits
|
||||||
|
|
||||||
|
proc isDigit*(c: char): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsDigitChar".}=
|
||||||
|
## Checks whether or not `c` is a number.
|
||||||
|
##
|
||||||
|
## This checks 0-9 ASCII characters only.
|
||||||
|
return c in Digits
|
||||||
|
|
||||||
|
proc isSpace*(c: char): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsSpaceChar".}=
|
||||||
|
## Checks whether or not `c` is a whitespace character.
|
||||||
|
return c in Whitespace
|
||||||
|
|
||||||
|
proc isLower*(c: char): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsLowerChar".}=
|
||||||
|
## Checks whether or not `c` is a lower case character.
|
||||||
|
##
|
||||||
|
## This checks ASCII characters only.
|
||||||
|
return c in {'a'..'z'}
|
||||||
|
|
||||||
|
proc isUpper*(c: char): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsUpperChar".}=
|
||||||
|
## Checks whether or not `c` is an upper case character.
|
||||||
|
##
|
||||||
|
## This checks ASCII characters only.
|
||||||
|
return c in {'A'..'Z'}
|
||||||
|
|
||||||
|
proc isAlpha*(s: string): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsAlphaStr".}=
|
||||||
|
## Checks whether or not `s` is alphabetical.
|
||||||
|
##
|
||||||
|
## This checks a-z, A-Z ASCII characters only.
|
||||||
|
## Returns true if all characters in `s` are
|
||||||
|
## alphabetic and there is at least one character
|
||||||
|
## in `s`.
|
||||||
|
if s.len() == 0:
|
||||||
|
return false
|
||||||
|
|
||||||
|
result = true
|
||||||
|
for c in s:
|
||||||
|
result = c.isAlpha() and result
|
||||||
|
|
||||||
|
proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsAlphaNumericStr".}=
|
||||||
|
## Checks whether or not `s` is alphanumeric.
|
||||||
|
##
|
||||||
|
## This checks a-z, A-Z, 0-9 ASCII characters only.
|
||||||
|
## Returns true if all characters in `s` are
|
||||||
|
## alpanumeric and there is at least one character
|
||||||
|
## in `s`.
|
||||||
|
if s.len() == 0:
|
||||||
|
return false
|
||||||
|
|
||||||
|
result = true
|
||||||
|
for c in s:
|
||||||
|
result = c.isAlphaNumeric() and result
|
||||||
|
|
||||||
|
proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsDigitStr".}=
|
||||||
|
## Checks whether or not `s` is a numeric value.
|
||||||
|
##
|
||||||
|
## This checks 0-9 ASCII characters only.
|
||||||
|
## Returns true if all characters in `s` are
|
||||||
|
## numeric and there is at least one character
|
||||||
|
## in `s`.
|
||||||
|
if s.len() == 0:
|
||||||
|
return false
|
||||||
|
|
||||||
|
result = true
|
||||||
|
for c in s:
|
||||||
|
result = c.isDigit() and result
|
||||||
|
|
||||||
|
proc isSpace*(s: string): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsSpaceStr".}=
|
||||||
|
## Checks whether or not `s` is completely whitespace.
|
||||||
|
##
|
||||||
|
## Returns true if all characters in `s` are whitespace
|
||||||
|
## characters and there is at least one character in `s`.
|
||||||
|
if s.len() == 0:
|
||||||
|
return false
|
||||||
|
|
||||||
|
result = true
|
||||||
|
for c in s:
|
||||||
|
result = c.isSpace() and result
|
||||||
|
|
||||||
|
proc isLower*(s: string): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsLowerStr".}=
|
||||||
|
## Checks whether or not `s` contains all lower case characters.
|
||||||
|
##
|
||||||
|
## This checks ASCII characters only.
|
||||||
|
## Returns true if all characters in `s` are lower case
|
||||||
|
## and there is at least one character in `s`.
|
||||||
|
if s.len() == 0:
|
||||||
|
return false
|
||||||
|
|
||||||
|
result = true
|
||||||
|
for c in s:
|
||||||
|
result = c.isLower() and result
|
||||||
|
|
||||||
|
proc isUpper*(s: string): bool {.noSideEffect, procvar,
|
||||||
|
rtl, extern: "nsuIsUpperStr".}=
|
||||||
|
## Checks whether or not `s` contains all upper case characters.
|
||||||
|
##
|
||||||
|
## This checks ASCII characters only.
|
||||||
|
## Returns true if all characters in `s` are upper case
|
||||||
|
## and there is at least one character in `s`.
|
||||||
|
if s.len() == 0:
|
||||||
|
return false
|
||||||
|
|
||||||
|
result = true
|
||||||
|
for c in s:
|
||||||
|
result = c.isUpper() and result
|
||||||
|
|
||||||
proc toLower*(c: char): char {.noSideEffect, procvar,
|
proc toLower*(c: char): char {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuToLowerChar".} =
|
rtl, extern: "nsuToLowerChar".} =
|
||||||
## Converts `c` into lower case.
|
## Converts `c` into lower case.
|
||||||
|
|
@ -1526,3 +1652,55 @@ when isMainModule:
|
||||||
doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
|
doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
|
||||||
|
|
||||||
doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar"
|
doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar"
|
||||||
|
|
||||||
|
doAssert isAlpha('r')
|
||||||
|
doAssert isAlpha('A')
|
||||||
|
doAssert(not isAlpha('$'))
|
||||||
|
|
||||||
|
doAssert isAlpha("Rasp")
|
||||||
|
doAssert isAlpha("Args")
|
||||||
|
doAssert(not isAlpha("$Tomato"))
|
||||||
|
|
||||||
|
doAssert isAlphaNumeric('3')
|
||||||
|
doAssert isAlphaNumeric('R')
|
||||||
|
doAssert(not isAlphaNumeric('!'))
|
||||||
|
|
||||||
|
doAssert isAlphaNumeric("34ABc")
|
||||||
|
doAssert isAlphaNumeric("Rad")
|
||||||
|
doAssert isAlphaNumeric("1234")
|
||||||
|
doAssert(not isAlphaNumeric("@nose"))
|
||||||
|
|
||||||
|
doAssert isDigit('3')
|
||||||
|
doAssert(not isDigit('a'))
|
||||||
|
doAssert(not isDigit('%'))
|
||||||
|
|
||||||
|
doAssert isDigit("12533")
|
||||||
|
doAssert(not isDigit("12.33"))
|
||||||
|
doAssert(not isDigit("A45b"))
|
||||||
|
|
||||||
|
doAssert isSpace('\t')
|
||||||
|
doAssert isSpace('\l')
|
||||||
|
doAssert(not isSpace('A'))
|
||||||
|
|
||||||
|
doAssert isSpace("\t\l \v\r\f")
|
||||||
|
doAssert isSpace(" ")
|
||||||
|
doAssert(not isSpace("ABc \td"))
|
||||||
|
|
||||||
|
doAssert isLower('a')
|
||||||
|
doAssert isLower('z')
|
||||||
|
doAssert(not isLower('A'))
|
||||||
|
doAssert(not isLower('5'))
|
||||||
|
doAssert(not isLower('&'))
|
||||||
|
|
||||||
|
doAssert isLower("abcd")
|
||||||
|
doAssert(not isLower("abCD"))
|
||||||
|
doAssert(not isLower("33aa"))
|
||||||
|
|
||||||
|
doAssert isUpper('A')
|
||||||
|
doAssert(not isUpper('b'))
|
||||||
|
doAssert(not isUpper('5'))
|
||||||
|
doAssert(not isUpper('%'))
|
||||||
|
|
||||||
|
doAssert isUpper("ABC")
|
||||||
|
doAssert(not isUpper("AAcc"))
|
||||||
|
doAssert(not isUpper("A#$"))
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,8 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
|
||||||
try:
|
try:
|
||||||
when declared(testSetupIMPLFlag): testSetupIMPL()
|
when declared(testSetupIMPLFlag): testSetupIMPL()
|
||||||
body
|
body
|
||||||
|
when declared(testTeardownIMPLFlag):
|
||||||
|
defer: testTeardownIMPL()
|
||||||
|
|
||||||
except:
|
except:
|
||||||
when not defined(js):
|
when not defined(js):
|
||||||
|
|
@ -158,7 +160,6 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
|
||||||
fail()
|
fail()
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
when declared(testTeardownIMPLFlag): testTeardownIMPL()
|
|
||||||
testDone name, testStatusIMPL
|
testDone name, testStatusIMPL
|
||||||
|
|
||||||
proc checkpoint*(msg: string) =
|
proc checkpoint*(msg: string) =
|
||||||
|
|
|
||||||
|
|
@ -139,11 +139,16 @@ proc delete*(n: XmlNode, i: Natural) {.noSideEffect.} =
|
||||||
assert n.k == xnElement
|
assert n.k == xnElement
|
||||||
n.s.delete(i)
|
n.s.delete(i)
|
||||||
|
|
||||||
proc mget* (n: var XmlNode, i: int): var XmlNode {.inline.} =
|
proc `[]`* (n: var XmlNode, i: int): var XmlNode {.inline.} =
|
||||||
## returns the `i`'th child of `n` so that it can be modified
|
## returns the `i`'th child of `n` so that it can be modified
|
||||||
assert n.k == xnElement
|
assert n.k == xnElement
|
||||||
result = n.s[i]
|
result = n.s[i]
|
||||||
|
|
||||||
|
proc mget*(n: var XmlNode, i: int): var XmlNode {.inline, deprecated.} =
|
||||||
|
## returns the `i`'th child of `n` so that it can be modified. Use ```[]```
|
||||||
|
## instead.
|
||||||
|
n[i]
|
||||||
|
|
||||||
iterator items*(n: XmlNode): XmlNode {.inline.} =
|
iterator items*(n: XmlNode): XmlNode {.inline.} =
|
||||||
## iterates over any child of `n`.
|
## iterates over any child of `n`.
|
||||||
assert n.k == xnElement
|
assert n.k == xnElement
|
||||||
|
|
@ -152,7 +157,7 @@ iterator items*(n: XmlNode): XmlNode {.inline.} =
|
||||||
iterator mitems*(n: var XmlNode): var XmlNode {.inline.} =
|
iterator mitems*(n: var XmlNode): var XmlNode {.inline.} =
|
||||||
## iterates over any child of `n`.
|
## iterates over any child of `n`.
|
||||||
assert n.k == xnElement
|
assert n.k == xnElement
|
||||||
for i in 0 .. n.len-1: yield mget(n, i)
|
for i in 0 .. n.len-1: yield n[i]
|
||||||
|
|
||||||
proc attrs*(n: XmlNode): XmlAttributes {.inline.} =
|
proc attrs*(n: XmlNode): XmlAttributes {.inline.} =
|
||||||
## gets the attributes belonging to `n`.
|
## gets the attributes belonging to `n`.
|
||||||
|
|
@ -337,7 +342,7 @@ proc attr*(n: XmlNode, name: string): string =
|
||||||
## Returns "" on failure.
|
## Returns "" on failure.
|
||||||
assert n.kind == xnElement
|
assert n.kind == xnElement
|
||||||
if n.attrs == nil: return ""
|
if n.attrs == nil: return ""
|
||||||
return n.attrs[name]
|
return n.attrs.getOrDefault(name)
|
||||||
|
|
||||||
proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode]) =
|
proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode]) =
|
||||||
## Iterates over all the children of `n` returning those matching `tag`.
|
## Iterates over all the children of `n` returning those matching `tag`.
|
||||||
|
|
|
||||||
|
|
@ -1260,6 +1260,15 @@ const
|
||||||
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
|
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
|
||||||
taintMode = compileOption("taintmode")
|
taintMode = compileOption("taintmode")
|
||||||
|
|
||||||
|
when defined(boehmgc):
|
||||||
|
when defined(windows):
|
||||||
|
const boehmLib = "boehmgc.dll"
|
||||||
|
elif defined(macosx):
|
||||||
|
const boehmLib = "libgc.dylib"
|
||||||
|
else:
|
||||||
|
const boehmLib = "libgc.so.1"
|
||||||
|
{.pragma: boehmGC, noconv, dynlib: boehmLib.}
|
||||||
|
|
||||||
when taintMode:
|
when taintMode:
|
||||||
type TaintedString* = distinct string ## a distinct string type that
|
type TaintedString* = distinct string ## a distinct string type that
|
||||||
## is `tainted`:idx:. It is an alias for
|
## is `tainted`:idx:. It is an alias for
|
||||||
|
|
@ -2160,53 +2169,6 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
|
||||||
result = s[L]
|
result = s[L]
|
||||||
setLen(s, L)
|
setLen(s, L)
|
||||||
|
|
||||||
proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] {.
|
|
||||||
deprecated.} =
|
|
||||||
## The well-known ``map`` operation from functional programming. Applies
|
|
||||||
## `op` to every item in `data` and returns the result as a sequence.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.9:** Use the ``map`` proc instead.
|
|
||||||
newSeq(result, data.len)
|
|
||||||
for i in 0..data.len-1: result[i] = op(data[i])
|
|
||||||
|
|
||||||
proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) {.
|
|
||||||
deprecated.} =
|
|
||||||
## The well-known ``map`` operation from functional programming. Applies
|
|
||||||
## `op` to every item in `data` modifying it directly.
|
|
||||||
##
|
|
||||||
## **Deprecated since version 0.9:** Use the ``map`` proc instead.
|
|
||||||
for i in 0..data.len-1: op(data[i])
|
|
||||||
|
|
||||||
proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] =
|
|
||||||
## Returns a new sequence with the results of `op` applied to every item in
|
|
||||||
## `data`.
|
|
||||||
##
|
|
||||||
## Since the input is not modified you can use this version of ``map`` to
|
|
||||||
## transform the type of the elements in the input sequence. Example:
|
|
||||||
##
|
|
||||||
## .. code-block:: nim
|
|
||||||
## let
|
|
||||||
## a = @[1, 2, 3, 4]
|
|
||||||
## b = map(a, proc(x: int): string = $x)
|
|
||||||
## assert b == @["1", "2", "3", "4"]
|
|
||||||
newSeq(result, data.len)
|
|
||||||
for i in 0..data.len-1: result[i] = op(data[i])
|
|
||||||
|
|
||||||
proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) =
|
|
||||||
## Applies `op` to every item in `data` modifying it directly.
|
|
||||||
##
|
|
||||||
## Note that this version of ``map`` requires your input and output types to
|
|
||||||
## be the same, since they are modified in-place. Example:
|
|
||||||
##
|
|
||||||
## .. code-block:: nim
|
|
||||||
## var a = @["1", "2", "3", "4"]
|
|
||||||
## echo repr(a)
|
|
||||||
## # --> ["1", "2", "3", "4"]
|
|
||||||
## map(a, proc(x: var string) = x &= "42")
|
|
||||||
## echo repr(a)
|
|
||||||
## # --> ["142", "242", "342", "442"]
|
|
||||||
for i in 0..data.len-1: op(data[i])
|
|
||||||
|
|
||||||
iterator fields*[T: tuple|object](x: T): RootObj {.
|
iterator fields*[T: tuple|object](x: T): RootObj {.
|
||||||
magic: "Fields", noSideEffect.}
|
magic: "Fields", noSideEffect.}
|
||||||
## iterates over every field of `x`. Warning: This really transforms
|
## iterates over every field of `x`. Warning: This really transforms
|
||||||
|
|
|
||||||
|
|
@ -51,3 +51,8 @@ when defined(nimlocks):
|
||||||
{.pragma: benign, gcsafe, locks: 0.}
|
{.pragma: benign, gcsafe, locks: 0.}
|
||||||
else:
|
else:
|
||||||
{.pragma: benign, gcsafe.}
|
{.pragma: benign, gcsafe.}
|
||||||
|
|
||||||
|
when defined(nimTableGet):
|
||||||
|
{.pragma: deprecatedGet, deprecated.}
|
||||||
|
else:
|
||||||
|
{.pragma: deprecatedGet.}
|
||||||
|
|
|
||||||
|
|
@ -66,41 +66,34 @@ proc raiseOutOfMem() {.noinline.} =
|
||||||
quit(1)
|
quit(1)
|
||||||
|
|
||||||
when defined(boehmgc):
|
when defined(boehmgc):
|
||||||
when defined(windows):
|
proc boehmGCinit {.importc: "GC_init", boehmGC.}
|
||||||
const boehmLib = "boehmgc.dll"
|
proc boehmGC_disable {.importc: "GC_disable", boehmGC.}
|
||||||
elif defined(macosx):
|
proc boehmGC_enable {.importc: "GC_enable", boehmGC.}
|
||||||
const boehmLib = "libgc.dylib"
|
|
||||||
else:
|
|
||||||
const boehmLib = "libgc.so.1"
|
|
||||||
|
|
||||||
proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
|
|
||||||
proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
|
|
||||||
proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
|
|
||||||
proc boehmGCincremental {.
|
proc boehmGCincremental {.
|
||||||
importc: "GC_enable_incremental", dynlib: boehmLib.}
|
importc: "GC_enable_incremental", boehmGC.}
|
||||||
proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
|
proc boehmGCfullCollect {.importc: "GC_gcollect", boehmGC.}
|
||||||
proc boehmAlloc(size: int): pointer {.
|
proc boehmAlloc(size: int): pointer {.importc: "GC_malloc", boehmGC.}
|
||||||
importc: "GC_malloc", dynlib: boehmLib.}
|
|
||||||
proc boehmAllocAtomic(size: int): pointer {.
|
proc boehmAllocAtomic(size: int): pointer {.
|
||||||
importc: "GC_malloc_atomic", dynlib: boehmLib.}
|
importc: "GC_malloc_atomic", boehmGC.}
|
||||||
proc boehmRealloc(p: pointer, size: int): pointer {.
|
proc boehmRealloc(p: pointer, size: int): pointer {.
|
||||||
importc: "GC_realloc", dynlib: boehmLib.}
|
importc: "GC_realloc", boehmGC.}
|
||||||
proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
|
proc boehmDealloc(p: pointer) {.importc: "GC_free", boehmGC.}
|
||||||
|
when hasThreadSupport:
|
||||||
|
proc boehmGC_allow_register_threads {.
|
||||||
|
importc: "GC_allow_register_threads", boehmGC.}
|
||||||
|
|
||||||
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
|
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", boehmGC.}
|
||||||
## Return the number of bytes in the heap. Excludes collector private
|
## Return the number of bytes in the heap. Excludes collector private
|
||||||
## data structures. Includes empty blocks and fragmentation loss.
|
## data structures. Includes empty blocks and fragmentation loss.
|
||||||
## Includes some pages that were allocated but never written.
|
## Includes some pages that were allocated but never written.
|
||||||
|
|
||||||
proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", dynlib: boehmLib.}
|
proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", boehmGC.}
|
||||||
## Return a lower bound on the number of free bytes in the heap.
|
## Return a lower bound on the number of free bytes in the heap.
|
||||||
|
|
||||||
proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc",
|
proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc", boehmGC.}
|
||||||
dynlib: boehmLib.}
|
|
||||||
## Return the number of bytes allocated since the last collection.
|
## Return the number of bytes allocated since the last collection.
|
||||||
|
|
||||||
proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes",
|
proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes", boehmGC.}
|
||||||
dynlib: boehmLib.}
|
|
||||||
## Return the total number of bytes allocated in this process.
|
## Return the total number of bytes allocated in this process.
|
||||||
## Never decreases.
|
## Never decreases.
|
||||||
|
|
||||||
|
|
@ -157,7 +150,9 @@ when defined(boehmgc):
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc setStackBottom(theStackBottom: pointer) = discard
|
||||||
|
|
||||||
proc initGC() =
|
proc initGC() =
|
||||||
when defined(macosx): boehmGCinit()
|
boehmGCinit()
|
||||||
|
when hasThreadSupport:
|
||||||
|
boehmGC_allow_register_threads()
|
||||||
|
|
||||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||||
if ntfNoRefs in typ.flags: result = allocAtomic(size)
|
if ntfNoRefs in typ.flags: result = allocAtomic(size)
|
||||||
|
|
@ -204,9 +199,6 @@ elif defined(gogc):
|
||||||
else:
|
else:
|
||||||
const goLib = "libgo.so"
|
const goLib = "libgo.so"
|
||||||
|
|
||||||
proc `div`[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
|
|
||||||
proc `-`[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.}
|
|
||||||
|
|
||||||
proc roundup(x, v: int): int {.inline.} =
|
proc roundup(x, v: int): int {.inline.} =
|
||||||
result = (x + (v-1)) and not (v-1)
|
result = (x + (v-1)) and not (v-1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -304,22 +304,53 @@ type
|
||||||
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc):
|
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc):
|
||||||
proc deallocOsPages()
|
proc deallocOsPages()
|
||||||
|
|
||||||
template threadProcWrapperBody(closure: expr) {.immediate.} =
|
when defined(boehmgc):
|
||||||
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
|
type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}
|
||||||
var t = cast[ptr Thread[TArg]](closure)
|
proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer)
|
||||||
when useStackMaskHack:
|
{.importc: "GC_call_with_stack_base", boehmGC.}
|
||||||
var tls: ThreadLocalStorage
|
proc boehmGC_register_my_thread(sb: pointer)
|
||||||
when not defined(boehmgc) and not defined(gogc) and not defined(nogc) and not hasSharedHeap:
|
{.importc: "GC_register_my_thread", boehmGC.}
|
||||||
# init the GC for this thread:
|
proc boehmGC_unregister_my_thread()
|
||||||
setStackBottom(addr(t))
|
{.importc: "GC_unregister_my_thread", boehmGC.}
|
||||||
|
|
||||||
|
proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} =
|
||||||
|
boehmGC_register_my_thread(sb)
|
||||||
|
let thrd = cast[ptr Thread[TArg]](thrd)
|
||||||
|
when TArg is void:
|
||||||
|
thrd.dataFn()
|
||||||
|
else:
|
||||||
|
thrd.dataFn(thrd.data)
|
||||||
|
boehmGC_unregister_my_thread()
|
||||||
|
else:
|
||||||
|
proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) =
|
||||||
|
when TArg is void:
|
||||||
|
thrd.dataFn()
|
||||||
|
else:
|
||||||
|
thrd.dataFn(thrd.data)
|
||||||
|
|
||||||
|
proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
|
||||||
|
when defined(boehmgc):
|
||||||
|
boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd)
|
||||||
|
elif not defined(nogc) and not defined(gogc):
|
||||||
|
var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall.} =
|
||||||
|
threadProcWrapDispatch[TArg]
|
||||||
|
when not hasSharedHeap:
|
||||||
|
# init the GC for refc/markandsweep
|
||||||
|
setStackBottom(addr(p))
|
||||||
initGC()
|
initGC()
|
||||||
when declared(registerThread):
|
when declared(registerThread):
|
||||||
t.stackBottom = addr(t)
|
thrd.stackBottom = addr(thrd)
|
||||||
registerThread(t)
|
registerThread(thrd)
|
||||||
when TArg is void: t.dataFn()
|
p(thrd)
|
||||||
else: t.dataFn(t.data)
|
when declared(registerThread): unregisterThread(thrd)
|
||||||
when declared(registerThread): unregisterThread(t)
|
|
||||||
when declared(deallocOsPages): deallocOsPages()
|
when declared(deallocOsPages): deallocOsPages()
|
||||||
|
else:
|
||||||
|
threadProcWrapDispatch(thrd)
|
||||||
|
|
||||||
|
template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||||
|
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
|
||||||
|
var thrd = cast[ptr Thread[TArg]](closure)
|
||||||
|
threadProcWrapStackFrame(thrd)
|
||||||
# Since an unhandled exception terminates the whole process (!), there is
|
# Since an unhandled exception terminates the whole process (!), there is
|
||||||
# no need for a ``try finally`` here, nor would it be correct: The current
|
# no need for a ``try finally`` here, nor would it be correct: The current
|
||||||
# exception is tried to be re-raised by the code-gen after the ``finally``!
|
# exception is tried to be re-raised by the code-gen after the ``finally``!
|
||||||
|
|
@ -327,7 +358,7 @@ template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||||
# page!
|
# page!
|
||||||
|
|
||||||
# mark as not running anymore:
|
# mark as not running anymore:
|
||||||
t.dataFn = nil
|
thrd.dataFn = nil
|
||||||
|
|
||||||
{.push stack_trace:off.}
|
{.push stack_trace:off.}
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
|
||||||
15
readme.md
15
readme.md
|
|
@ -81,20 +81,27 @@ All rights reserved.
|
||||||
|
|
||||||
| | Linux | Windows | Mac |
|
| | Linux | Windows | Mac |
|
||||||
| ------ | ----- | ------- | --- |
|
| ------ | ----- | ------- | --- |
|
||||||
| x86 | ![linux-x86][linux-x86-img] | ![windows-x86][windows-x86-img] | ![mac-x86][mac-x86-img] |
|
| x86 | [![linux-x86][linux-x86-img]][linux-x86] | [![windows-x86][windows-x86-img]][windows-x86] |
|
||||||
| x86_64 | ![linux-x86_64][linux-x86_64-img] | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] |
|
| x86_64 | [![linux-x86_64][linux-x86_64-img]][linux-x86_64] | [![windows-x86_64][windows-x86_64-img]][windows-x86_64] | [![mac-x86_64][mac-x86_64-img]][mac-x86_64] |
|
||||||
| arm | ![linux-armv5][linux-arm5-img]<br/> ![linux-armv6][linux-arm6-img]<br/> ![linux-armv7][linux-arm7-img] | | |
|
| arm | [![linux-armv5][linux-arm5-img]][linux-arm5]<br/> [![linux-armv6][linux-arm6-img]][linux-arm6]<br/> [![linux-armv7][linux-arm7-img]][linux-arm7]
|
||||||
|
|
||||||
|
[linux-x86]: http://buildbot.nim-lang.org/builders/linux-x32-builder
|
||||||
[linux-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder
|
[linux-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder
|
||||||
|
[linux-x86_64]: http://buildbot.nim-lang.org/builders/linux-x64-builder
|
||||||
[linux-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder
|
[linux-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder
|
||||||
|
[linux-arm5]: http://buildbot.nim-lang.org/builders/linux-arm5-builder
|
||||||
[linux-arm5-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder
|
[linux-arm5-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder
|
||||||
|
[linux-arm6]: http://buildbot.nim-lang.org/builders/linux-arm6-builder
|
||||||
[linux-arm6-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder
|
[linux-arm6-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder
|
||||||
|
[linux-arm7]: http://buildbot.nim-lang.org/builders/linux-arm7-builder
|
||||||
[linux-arm7-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder
|
[linux-arm7-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder
|
||||||
|
|
||||||
|
[windows-x86]: http://buildbot.nim-lang.org/builders/windows-x32-builder
|
||||||
[windows-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder
|
[windows-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder
|
||||||
|
[windows-x86_64]: http://buildbot.nim-lang.org/builders/windows-x64-builder
|
||||||
[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder
|
[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder
|
||||||
|
|
||||||
[mac-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder
|
[mac-x86_64]: http://buildbot.nim-lang.org/builders/mac-x64-builder
|
||||||
[mac-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder
|
[mac-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder
|
||||||
|
|
||||||
[waterfall]: http://buildbot.nim-lang.org/waterfall
|
[waterfall]: http://buildbot.nim-lang.org/waterfall
|
||||||
|
|
|
||||||
|
|
@ -24,4 +24,3 @@ var
|
||||||
"D": action4}.toTable
|
"D": action4}.toTable
|
||||||
|
|
||||||
actionTable["C"]("arg")
|
actionTable["C"]("arg")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import json, tables
|
import json, tables, sequtils
|
||||||
|
|
||||||
proc run(json_params: TTable) =
|
proc run(json_params: TTable) =
|
||||||
let json_elems = json_params["files"].elems
|
let json_elems = json_params["files"].elems
|
||||||
|
|
|
||||||
11
tests/collections/tapply.nim
Normal file
11
tests/collections/tapply.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
discard """
|
||||||
|
output: '''true'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sequtils
|
||||||
|
|
||||||
|
var x = @[1, 2, 3]
|
||||||
|
x.apply(proc(x: var int) = x = x+10)
|
||||||
|
x.apply(proc(x: int): int = x+100)
|
||||||
|
x.applyIt(it+5000)
|
||||||
|
echo x == @[5111, 5112, 5113]
|
||||||
33
tests/collections/tmapit.nim
Normal file
33
tests/collections/tmapit.nim
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
discard """
|
||||||
|
output: '''true
|
||||||
|
true'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sequtils
|
||||||
|
|
||||||
|
var x = @[1, 2, 3]
|
||||||
|
# This mapIt call will run with preallocation because ``len`` is available.
|
||||||
|
var y = x.mapIt($(it+10))
|
||||||
|
echo y == @["11", "12", "13"]
|
||||||
|
|
||||||
|
type structureWithoutLen = object
|
||||||
|
a: array[5, int]
|
||||||
|
|
||||||
|
iterator items(s: structureWithoutLen): int {.inline.} =
|
||||||
|
yield s.a[0]
|
||||||
|
yield s.a[1]
|
||||||
|
yield s.a[2]
|
||||||
|
yield s.a[3]
|
||||||
|
yield s.a[4]
|
||||||
|
|
||||||
|
var st: structureWithoutLen
|
||||||
|
st.a[0] = 0
|
||||||
|
st.a[1] = 1
|
||||||
|
st.a[2] = 2
|
||||||
|
st.a[3] = 3
|
||||||
|
st.a[4] = 4
|
||||||
|
|
||||||
|
# this will run without preallocating the result
|
||||||
|
# since ``len`` is not available
|
||||||
|
var r = st.mapIt($(it+10))
|
||||||
|
echo r == @["10", "11", "12", "13", "14"]
|
||||||
|
|
@ -60,8 +60,12 @@ block tableTest2:
|
||||||
t["123"] = 1.5 # test overwriting
|
t["123"] = 1.5 # test overwriting
|
||||||
|
|
||||||
assert t["123"] == 1.5
|
assert t["123"] == 1.5
|
||||||
assert t["111"] == 0.0 # deleted
|
try:
|
||||||
|
echo t["111"] # deleted
|
||||||
|
except KeyError:
|
||||||
|
discard
|
||||||
assert(not hasKey(t, "111"))
|
assert(not hasKey(t, "111"))
|
||||||
|
|
||||||
assert "123" in t
|
assert "123" in t
|
||||||
assert("111" notin t)
|
assert("111" notin t)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,10 @@ block tableTest2:
|
||||||
t["123"] = 1.5 # test overwriting
|
t["123"] = 1.5 # test overwriting
|
||||||
|
|
||||||
assert t["123"] == 1.5
|
assert t["123"] == 1.5
|
||||||
assert t["111"] == 0.0 # deleted
|
try:
|
||||||
assert "123" in t
|
echo t["111"] # deleted
|
||||||
|
except KeyError:
|
||||||
|
discard
|
||||||
assert(not hasKey(t, "111"))
|
assert(not hasKey(t, "111"))
|
||||||
assert "111" notin t
|
assert "111" notin t
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ discard """
|
||||||
3'''
|
3'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sequtils
|
||||||
# https://github.com/Araq/Nim/issues/797
|
# https://github.com/Araq/Nim/issues/797
|
||||||
proc foo[T](s:T):string = $s
|
proc foo[T](s:T):string = $s
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import future
|
import future, sequtils
|
||||||
|
|
||||||
let x = map(@[1, 2, 3], x => x+10)
|
let x = map(@[1, 2, 3], x => x+10)
|
||||||
assert x == @[11, 12, 13]
|
assert x == @[11, 12, 13]
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ proc on*(emitter: var EventEmitter, event: string,
|
||||||
if not hasKey(emitter.events, event):
|
if not hasKey(emitter.events, event):
|
||||||
var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]
|
var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]
|
||||||
add(emitter.events, event, list) #if not, add it.
|
add(emitter.events, event, list) #if not, add it.
|
||||||
append(emitter.events.mget(event), fn)
|
append(emitter.events[event], fn)
|
||||||
|
|
||||||
proc initEmitter(emitter: var EventEmitter) =
|
proc initEmitter(emitter: var EventEmitter) =
|
||||||
emitter.events = initTable[string,
|
emitter.events = initTable[string,
|
||||||
|
|
@ -30,4 +30,3 @@ var
|
||||||
initEmitter(ee)
|
initEmitter(ee)
|
||||||
ee.on("print", proc(e: EventArgs) = echo("pie"))
|
ee.on("print", proc(e: EventArgs) = echo("pie"))
|
||||||
ee.emit("print", args)
|
ee.emit("print", args)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ mode = ScriptMode.Whatif
|
||||||
|
|
||||||
exec "gcc -v"
|
exec "gcc -v"
|
||||||
|
|
||||||
|
# test that ospaths actually compiles:
|
||||||
|
import ospaths
|
||||||
|
|
||||||
--forceBuild
|
--forceBuild
|
||||||
|
|
||||||
task listDirs, "lists every subdirectory":
|
task listDirs, "lists every subdirectory":
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ yay'''
|
||||||
|
|
||||||
# Test overloading of procs when used as function pointers
|
# Test overloading of procs when used as function pointers
|
||||||
|
|
||||||
import strutils
|
import strutils, sequtils
|
||||||
|
|
||||||
proc parseInt(x: float): int {.noSideEffect.} = discard
|
proc parseInt(x: float): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: bool): int {.noSideEffect.} = discard
|
proc parseInt(x: bool): int {.noSideEffect.} = discard
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ discard """
|
||||||
77'''
|
77'''
|
||||||
"""
|
"""
|
||||||
#import math
|
#import math
|
||||||
|
import sequtils
|
||||||
|
|
||||||
proc optarg(x:int, y:int = 0):int = x + 3 * y
|
proc optarg(x:int, y:int = 0):int = x + 3 * y
|
||||||
proc singlearg(x:int):int = 20*x
|
proc singlearg(x:int):int = 20*x
|
||||||
|
|
|
||||||
141
tests/stdlib/tmget.nim
Normal file
141
tests/stdlib/tmget.nim
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
discard """
|
||||||
|
output: '''Can't access 6
|
||||||
|
10
|
||||||
|
11
|
||||||
|
Can't access 6
|
||||||
|
10
|
||||||
|
11
|
||||||
|
Can't access 6
|
||||||
|
10
|
||||||
|
11
|
||||||
|
Can't access 6
|
||||||
|
10
|
||||||
|
11
|
||||||
|
Can't access 6
|
||||||
|
10
|
||||||
|
11
|
||||||
|
Can't access 6
|
||||||
|
10
|
||||||
|
11
|
||||||
|
Can't access 6
|
||||||
|
5
|
||||||
|
Can't access 6
|
||||||
|
10
|
||||||
|
11
|
||||||
|
Can't access 6
|
||||||
|
10
|
||||||
|
11'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tables
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = initTable[int, int]()
|
||||||
|
x[5] = 10
|
||||||
|
try:
|
||||||
|
echo x[6]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x[5]
|
||||||
|
x[5] += 1
|
||||||
|
var c = x[5]
|
||||||
|
echo c
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = newTable[int, int]()
|
||||||
|
x[5] = 10
|
||||||
|
try:
|
||||||
|
echo x[6]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x[5]
|
||||||
|
x[5] += 1
|
||||||
|
var c = x[5]
|
||||||
|
echo c
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = initOrderedTable[int, int]()
|
||||||
|
x[5] = 10
|
||||||
|
try:
|
||||||
|
echo x[6]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x[5]
|
||||||
|
x[5] += 1
|
||||||
|
var c = x[5]
|
||||||
|
echo c
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = newOrderedTable[int, int]()
|
||||||
|
x[5] = 10
|
||||||
|
try:
|
||||||
|
echo x[6]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x[5]
|
||||||
|
x[5] += 1
|
||||||
|
var c = x[5]
|
||||||
|
echo c
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = initCountTable[int]()
|
||||||
|
x[5] = 10
|
||||||
|
try:
|
||||||
|
echo x[6]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x[5]
|
||||||
|
x[5] += 1
|
||||||
|
var c = x[5]
|
||||||
|
echo c
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = newCountTable[int]()
|
||||||
|
x[5] = 10
|
||||||
|
try:
|
||||||
|
echo x[6]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x[5]
|
||||||
|
x[5] += 1
|
||||||
|
var c = x[5]
|
||||||
|
echo c
|
||||||
|
|
||||||
|
import sets
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = initSet[int]()
|
||||||
|
x.incl 5
|
||||||
|
try:
|
||||||
|
echo x[6]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x[5]
|
||||||
|
|
||||||
|
import critbits
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: CritBitTree[int]
|
||||||
|
x["5"] = 10
|
||||||
|
try:
|
||||||
|
echo x["6"]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x["5"]
|
||||||
|
x["5"] += 1
|
||||||
|
var c = x["5"]
|
||||||
|
echo c
|
||||||
|
|
||||||
|
import strtabs
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = newStringTable()
|
||||||
|
x["5"] = "10"
|
||||||
|
try:
|
||||||
|
echo x["6"]
|
||||||
|
except KeyError:
|
||||||
|
echo "Can't access 6"
|
||||||
|
echo x["5"]
|
||||||
|
x["5"][1] = '1'
|
||||||
|
var c = x["5"]
|
||||||
|
echo c
|
||||||
|
|
@ -132,5 +132,5 @@ block:
|
||||||
</Students>""")
|
</Students>""")
|
||||||
for x in d.mitems:
|
for x in d.mitems:
|
||||||
x = <>Student(Name=x.attrs["Name"] & "foo")
|
x = <>Student(Name=x.attrs["Name"] & "foo")
|
||||||
d.mget(1).attrs["Name"] = "bar"
|
d[1].attrs["Name"] = "bar"
|
||||||
echo d
|
echo d
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import unittest
|
import unittest, sequtils
|
||||||
|
|
||||||
|
|
||||||
proc doThings(spuds: var int): int =
|
proc doThings(spuds: var int): int =
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,6 @@ when ATTEMPT == 0:
|
||||||
# bug #1543
|
# bug #1543
|
||||||
import sequtils
|
import sequtils
|
||||||
|
|
||||||
(var i = @[""];i).mapIt(it)
|
(var i = @[""];i).applyIt(it)
|
||||||
# now works:
|
# now works:
|
||||||
echo "##", i[0], "##"
|
echo "##", i[0], "##"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import strutils, db_sqlite, os, osproc
|
import strutils, db_sqlite, os, osproc
|
||||||
|
|
||||||
var db: TDbConn
|
var db: DbConn
|
||||||
|
|
||||||
proc createDb() =
|
proc createDb() =
|
||||||
db.exec(sql"""
|
db.exec(sql"""
|
||||||
|
|
@ -61,7 +61,7 @@ var
|
||||||
|
|
||||||
proc `()`(cmd: string{lit}): string = cmd.execProcess.string.strip
|
proc `()`(cmd: string{lit}): string = cmd.execProcess.string.strip
|
||||||
|
|
||||||
proc getMachine*(db: TDbConn): MachineId =
|
proc getMachine*(db: DbConn): MachineId =
|
||||||
var name = "hostname"()
|
var name = "hostname"()
|
||||||
if name.len == 0:
|
if name.len == 0:
|
||||||
name = when defined(posix): getenv"HOSTNAME".string
|
name = when defined(posix): getenv"HOSTNAME".string
|
||||||
|
|
@ -76,7 +76,7 @@ proc getMachine*(db: TDbConn): MachineId =
|
||||||
result = db.insertId(sql"insert into Machine(name, os, cpu) values (?,?,?)",
|
result = db.insertId(sql"insert into Machine(name, os, cpu) values (?,?,?)",
|
||||||
name, system.hostOS, system.hostCPU).MachineId
|
name, system.hostOS, system.hostCPU).MachineId
|
||||||
|
|
||||||
proc getCommit(db: TDbConn): CommitId =
|
proc getCommit(db: DbConn): CommitId =
|
||||||
const commLen = "commit ".len
|
const commLen = "commit ".len
|
||||||
let hash = "git log -n 1"()[commLen..commLen+10]
|
let hash = "git log -n 1"()[commLen..commLen+10]
|
||||||
let branch = "git symbolic-ref --short HEAD"()
|
let branch = "git symbolic-ref --short HEAD"()
|
||||||
|
|
|
||||||
|
|
@ -119,12 +119,21 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
|
||||||
testSpec r, makeTest("tests/gc" / filename, options &
|
testSpec r, makeTest("tests/gc" / filename, options &
|
||||||
" -d:release -d:useRealtimeGC", cat, actionRun)
|
" -d:release -d:useRealtimeGC", cat, actionRun)
|
||||||
|
|
||||||
template test(filename: expr): stmt =
|
template testWithoutBoehm(filename: expr): stmt =
|
||||||
testWithoutMs filename
|
testWithoutMs filename
|
||||||
testSpec r, makeTest("tests/gc" / filename, options &
|
testSpec r, makeTest("tests/gc" / filename, options &
|
||||||
" --gc:markAndSweep", cat, actionRun)
|
" --gc:markAndSweep", cat, actionRun)
|
||||||
testSpec r, makeTest("tests/gc" / filename, options &
|
testSpec r, makeTest("tests/gc" / filename, options &
|
||||||
" -d:release --gc:markAndSweep", cat, actionRun)
|
" -d:release --gc:markAndSweep", cat, actionRun)
|
||||||
|
template test(filename: expr): stmt =
|
||||||
|
testWithoutBoehm filename
|
||||||
|
when not defined(windows):
|
||||||
|
# AR: cannot find any boehm.dll on the net, right now, so disabled
|
||||||
|
# for windows:
|
||||||
|
testSpec r, makeTest("tests/gc" / filename, options &
|
||||||
|
" --gc:boehm", cat, actionRun)
|
||||||
|
testSpec r, makeTest("tests/gc" / filename, options &
|
||||||
|
" -d:release --gc:boehm", cat, actionRun)
|
||||||
|
|
||||||
test "gcemscripten"
|
test "gcemscripten"
|
||||||
test "growobjcrash"
|
test "growobjcrash"
|
||||||
|
|
@ -136,9 +145,9 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
|
||||||
test "gcleak4"
|
test "gcleak4"
|
||||||
# Disabled because it works and takes too long to run:
|
# Disabled because it works and takes too long to run:
|
||||||
#test "gcleak5"
|
#test "gcleak5"
|
||||||
test "weakrefs"
|
testWithoutBoehm "weakrefs"
|
||||||
test "cycleleak"
|
test "cycleleak"
|
||||||
test "closureleak"
|
testWithoutBoehm "closureleak"
|
||||||
testWithoutMs "refarrayleak"
|
testWithoutMs "refarrayleak"
|
||||||
|
|
||||||
test "stackrefleak"
|
test "stackrefleak"
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ div.tabContent.hide { display: none; }
|
||||||
proc td(s: string): string =
|
proc td(s: string): string =
|
||||||
result = "<td>" & s.substr(0, 200).xmlEncode & "</td>"
|
result = "<td>" & s.substr(0, 200).xmlEncode & "</td>"
|
||||||
|
|
||||||
proc getCommit(db: TDbConn, c: int): string =
|
proc getCommit(db: DbConn, c: int): string =
|
||||||
var commit = c
|
var commit = c
|
||||||
for thisCommit in db.rows(sql"select id from [Commit] order by id desc"):
|
for thisCommit in db.rows(sql"select id from [Commit] order by id desc"):
|
||||||
if commit == 0: result = thisCommit[0]
|
if commit == 0: result = thisCommit[0]
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ proc callCompiler(cmdTemplate, filename, options: string,
|
||||||
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
|
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
|
||||||
"options", options, "file", filename.quoteShell])
|
"options", options, "file", filename.quoteShell])
|
||||||
var p = startProcess(command=c[0], args=c[1.. ^1],
|
var p = startProcess(command=c[0], args=c[1.. ^1],
|
||||||
options={poStdErrToStdOut, poUseShell})
|
options={poStdErrToStdOut, poUsePath})
|
||||||
let outp = p.outputStream
|
let outp = p.outputStream
|
||||||
var suc = ""
|
var suc = ""
|
||||||
var err = ""
|
var err = ""
|
||||||
|
|
@ -215,7 +215,7 @@ proc generatedFile(path, name: string, target: TTarget): string =
|
||||||
|
|
||||||
proc codegenCheck(test: TTest, check: string, given: var TSpec) =
|
proc codegenCheck(test: TTest, check: string, given: var TSpec) =
|
||||||
try:
|
try:
|
||||||
let (path, name, ext2) = test.name.splitFile
|
let (path, name, _) = test.name.splitFile
|
||||||
let genFile = generatedFile(path, name, test.target)
|
let genFile = generatedFile(path, name, test.target)
|
||||||
let contents = readFile(genFile).string
|
let contents = readFile(genFile).string
|
||||||
if check[0] == '\\':
|
if check[0] == '\\':
|
||||||
|
|
@ -307,7 +307,7 @@ proc testSpec(r: var TResults, test: TTest) =
|
||||||
let isJsTarget = test.target == targetJS
|
let isJsTarget = test.target == targetJS
|
||||||
var exeFile: string
|
var exeFile: string
|
||||||
if isJsTarget:
|
if isJsTarget:
|
||||||
let (dir, file, ext) = splitFile(tname)
|
let (dir, file, _) = splitFile(tname)
|
||||||
exeFile = dir / "nimcache" / file & ".js" # *TODO* hardcoded "nimcache"
|
exeFile = dir / "nimcache" / file & ".js" # *TODO* hardcoded "nimcache"
|
||||||
else:
|
else:
|
||||||
exeFile = changeFileExt(tname, ExeExt)
|
exeFile = changeFileExt(tname, ExeExt)
|
||||||
|
|
@ -352,7 +352,7 @@ proc testSpec(r: var TResults, test: TTest) =
|
||||||
|
|
||||||
proc testNoSpec(r: var TResults, test: TTest) =
|
proc testNoSpec(r: var TResults, test: TTest) =
|
||||||
# does not extract the spec because the file is not supposed to have any
|
# does not extract the spec because the file is not supposed to have any
|
||||||
let tname = test.name.addFileExt(".nim")
|
#let tname = test.name.addFileExt(".nim")
|
||||||
inc(r.total)
|
inc(r.total)
|
||||||
let given = callCompiler(cmdTemplate, test.name, test.options, test.target)
|
let given = callCompiler(cmdTemplate, test.name, test.options, test.target)
|
||||||
r.addResult(test, "", given.msg, given.err)
|
r.addResult(test, "", given.msg, given.err)
|
||||||
|
|
@ -368,7 +368,7 @@ proc testC(r: var TResults, test: TTest) =
|
||||||
r.addResult(test, "", given.msg, given.err)
|
r.addResult(test, "", given.msg, given.err)
|
||||||
elif test.action == actionRun:
|
elif test.action == actionRun:
|
||||||
let exeFile = changeFileExt(test.name, ExeExt)
|
let exeFile = changeFileExt(test.name, ExeExt)
|
||||||
var (buf, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUseShell})
|
var (_, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUsePath})
|
||||||
if exitCode != 0: given.err = reExitCodesDiffer
|
if exitCode != 0: given.err = reExitCodesDiffer
|
||||||
if given.err == reSuccess: inc(r.passed)
|
if given.err == reSuccess: inc(r.passed)
|
||||||
|
|
||||||
|
|
|
||||||
24
web/news.txt
24
web/news.txt
|
|
@ -8,7 +8,11 @@ News
|
||||||
|
|
||||||
Changes affecting backwards compatibility
|
Changes affecting backwards compatibility
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
- ``tables.[]``, ``strtabs.[]``, ``critbits.[]`` **now raise**
|
||||||
|
the ``KeyError`` **exception when the key does not exist**! Use the
|
||||||
|
new ``getOrDefault`` instead to get the old behaviour. Compile all your
|
||||||
|
code with ``-d:nimTableGet`` to get a listing of where your code
|
||||||
|
uses ``[]``!
|
||||||
- The ``rawsockets`` module has been renamed to ``nativesockets`` to avoid
|
- The ``rawsockets`` module has been renamed to ``nativesockets`` to avoid
|
||||||
confusion with TCP/IP raw sockets, so ``newNativeSocket`` should be used
|
confusion with TCP/IP raw sockets, so ``newNativeSocket`` should be used
|
||||||
instead of ``newRawSocket``.
|
instead of ``newRawSocket``.
|
||||||
|
|
@ -68,10 +72,10 @@ News
|
||||||
* ``libeay32.dll``: Split into ``libeay32.dll`` and ``libeay64.dll``.
|
* ``libeay32.dll``: Split into ``libeay32.dll`` and ``libeay64.dll``.
|
||||||
|
|
||||||
Compile with ``-d:nimOldDLLs`` to make the stdlib use the old DLL names.
|
Compile with ``-d:nimOldDLLs`` to make the stdlib use the old DLL names.
|
||||||
- Nim VM now treats objects as nkObjConstr nodes, and not nkPar nodes as it
|
- Nim VM now treats objects as ``nkObjConstr`` nodes, and not ``nkPar`` nodes
|
||||||
was previously. Macros that generate nkPar nodes when object is expected are
|
as it was previously. Macros that generate ``nkPar`` nodes when object is
|
||||||
likely to break. Macros that expect nkPar nodes to which objects are passed
|
expected are likely to break. Macros that expect ``nkPar`` nodes to which
|
||||||
are likely to break as well.
|
objects are passed are likely to break as well.
|
||||||
- Base methods now need to be annotated with the ``base`` pragma. This makes
|
- Base methods now need to be annotated with the ``base`` pragma. This makes
|
||||||
multi methods less error-prone to use with the effect system.
|
multi methods less error-prone to use with the effect system.
|
||||||
- Nim's parser directive ``#!`` is now ``#?`` in order to produce no conflicts
|
- Nim's parser directive ``#!`` is now ``#?`` in order to produce no conflicts
|
||||||
|
|
@ -86,8 +90,14 @@ News
|
||||||
|
|
||||||
echo f(0, "abc")
|
echo f(0, "abc")
|
||||||
- The ``ftpclient`` module is now deprecated in favour of the
|
- The ``ftpclient`` module is now deprecated in favour of the
|
||||||
``asyncdispatch`` module.
|
``asyncftpclient`` module.
|
||||||
|
- In sequtils.nim renamed ``repeat`` function to ``cycle`` (concatenating
|
||||||
|
a sequence by itself the given times), and also introduced ``repeat``,
|
||||||
|
which repeats an element the given times.
|
||||||
|
- The function ``map`` is moved to sequtils.nim. The inplace ``map`` version
|
||||||
|
is renamed to ``apply``.
|
||||||
|
- The template ``mapIt`` now doesn't require the result's type parameter.
|
||||||
|
Also the inplace ``mapIt`` is renamed to ``apply``.
|
||||||
|
|
||||||
Library Additions
|
Library Additions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
|
||||||
doc: "nimfix.txt;nimsuggest.txt;nep1.txt;nims.txt"
|
doc: "nimfix.txt;nimsuggest.txt;nep1.txt;nims.txt"
|
||||||
pdf: "manual.txt;lib;tut1;tut2;nimc;niminst;gc"
|
pdf: "manual.txt;lib;tut1;tut2;nimc;niminst;gc"
|
||||||
srcdoc2: "system.nim;system/nimscript;pure/ospaths"
|
srcdoc2: "system.nim;system/nimscript;pure/ospaths"
|
||||||
srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
|
srcdoc2: "core/macros;pure/marshal;core/typeinfo"
|
||||||
srcdoc2: "impure/re;pure/sockets;pure/typetraits"
|
srcdoc2: "impure/re;pure/typetraits"
|
||||||
srcdoc2: "pure/concurrency/threadpool.nim;pure/concurrency/cpuinfo.nim"
|
srcdoc2: "pure/concurrency/threadpool.nim;pure/concurrency/cpuinfo.nim"
|
||||||
srcdoc: "system/threads.nim;system/channels.nim;js/dom"
|
srcdoc: "system/threads.nim;system/channels.nim;js/dom"
|
||||||
srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm"
|
srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm"
|
||||||
|
|
@ -52,12 +52,13 @@ srcdoc2: "pure/json;pure/base64;pure/scgi"
|
||||||
srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
|
srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
|
||||||
srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings"
|
srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings"
|
||||||
srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
|
srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
|
||||||
srcdoc2: "pure/ftpclient;pure/memfiles;pure/subexes;pure/collections/critbits"
|
srcdoc2: "pure/memfiles;pure/subexes;pure/collections/critbits"
|
||||||
srcdoc2: "pure/asyncio;pure/actors;core/locks;pure/oids;pure/endians;pure/uri"
|
srcdoc2: "deprecated/pure/asyncio;deprecated/pure/actors;core/locks;pure/oids;pure/endians;pure/uri"
|
||||||
srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
|
srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
|
||||||
srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
|
srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
|
||||||
srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
|
srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
|
||||||
srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
|
srcdoc2: "deprecated/pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
|
||||||
|
srcdoc2: "deprecated/pure/ftpclient"
|
||||||
srcdoc2: "pure/asyncfile"
|
srcdoc2: "pure/asyncfile"
|
||||||
srcdoc2: "pure/md5;pure/rationals"
|
srcdoc2: "pure/md5;pure/rationals"
|
||||||
srcdoc2: "posix/posix"
|
srcdoc2: "posix/posix"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue