intsets are now a proper module and part of the stdlib

This commit is contained in:
Araq 2011-06-14 01:36:49 +02:00
commit ade67f1abc
25 changed files with 297 additions and 286 deletions

View file

@ -10,7 +10,7 @@
# abstract syntax tree + symbol table # abstract syntax tree + symbol table
import import
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, intsets
const const
ImportTablePos* = 0 ImportTablePos* = 0
@ -620,39 +620,6 @@ proc leValue*(a, b: PNode): bool
# a <= b? a, b are literals # a <= b? a, b are literals
proc ValueToString*(a: PNode): string proc ValueToString*(a: PNode): string
# ------------- efficient integer sets -------------------------------------
type
TBitScalar* = int
const
InitIntSetSize* = 8 # must be a power of two!
TrunkShift* = 9
BitsPerTrunk* = 1 shl TrunkShift # needs to be a power of 2 and
# divisible by 64
TrunkMask* = BitsPerTrunk - 1
IntsPerTrunk* = BitsPerTrunk div (sizeof(TBitScalar) * 8)
IntShift* = 5 + ord(sizeof(TBitScalar) == 8) # 5 or 6, depending on int width
IntMask* = 1 shl IntShift - 1
type
PTrunk* = ref TTrunk
TTrunk*{.final.} = object
next*: PTrunk # all nodes are connected with this pointer
key*: int # start address at bit 0
bits*: array[0..IntsPerTrunk - 1, TBitScalar] # a bit vector
TTrunkSeq* = seq[PTrunk]
TIntSet*{.final.} = object
counter*, max*: int
head*: PTrunk
data*: TTrunkSeq
proc IntSetContains*(s: TIntSet, key: int): bool
proc IntSetIncl*(s: var TIntSet, key: int)
proc IntSetExcl*(s: var TIntSet, key: int)
proc IntSetInit*(s: var TIntSet)
proc IntSetContainsOrIncl*(s: var TIntSet, key: int): bool
const const
debugIds* = false debugIds* = false
@ -663,7 +630,7 @@ var usedIds: TIntSet
proc registerID(id: PIdObj) = proc registerID(id: PIdObj) =
if debugIDs: if debugIDs:
if (id.id == - 1) or IntSetContainsOrIncl(usedIds, id.id): if (id.id == - 1) or ContainsOrIncl(usedIds, id.id):
InternalError("ID already used: " & $(id.id)) InternalError("ID already used: " & $(id.id))
proc getID(): int = proc getID(): int =
@ -1036,109 +1003,4 @@ proc getStrOrChar*(a: PNode): string =
internalError(a.info, "getStrOrChar") internalError(a.info, "getStrOrChar")
result = "" result = ""
proc mustRehash(length, counter: int): bool {.inline.} = if debugIDs: usedIds = InitIntSet()
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
result = ((5 * h) + 1) and maxHash
# For any initial h in range(maxHash), repeating that maxHash times
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc IntSetInit(s: var TIntSet) =
newSeq(s.data, InitIntSetSize)
s.max = InitIntSetSize - 1
s.counter = 0
s.head = nil
proc IntSetGet(t: TIntSet, key: int): PTrunk =
var h = key and t.max
while t.data[h] != nil:
if t.data[h].key == key:
return t.data[h]
h = nextTry(h, t.max)
result = nil
proc IntSetRawInsert(t: TIntSet, data: var TTrunkSeq, desc: PTrunk) =
var h = desc.key and t.max
while data[h] != nil:
assert(data[h] != desc)
h = nextTry(h, t.max)
assert(data[h] == nil)
data[h] = desc
proc IntSetEnlarge(t: var TIntSet) =
var
n: TTrunkSeq
oldMax: int
oldMax = t.max
t.max = ((t.max + 1) * 2) - 1
newSeq(n, t.max + 1)
for i in countup(0, oldmax):
if t.data[i] != nil: IntSetRawInsert(t, n, t.data[i])
swap(t.data, n)
proc IntSetPut(t: var TIntSet, key: int): PTrunk =
var h = key and t.max
while t.data[h] != nil:
if t.data[h].key == key:
return t.data[h]
h = nextTry(h, t.max)
if mustRehash(t.max + 1, t.counter): IntSetEnlarge(t)
inc(t.counter)
h = key and t.max
while t.data[h] != nil: h = nextTry(h, t.max)
assert(t.data[h] == nil)
new(result)
result.next = t.head
result.key = key
t.head = result
t.data[h] = result
proc IntSetContains(s: TIntSet, key: int): bool =
var
u: TBitScalar
t: PTrunk
t = IntSetGet(s, `shr`(key, TrunkShift))
if t != nil:
u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
else:
result = false
proc IntSetIncl(s: var TIntSet, key: int) =
var
u: TBitScalar
t: PTrunk
t = IntSetPut(s, `shr`(key, TrunkShift))
u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask)
proc IntSetExcl(s: var TIntSet, key: int) =
var
u: TBitScalar
t: PTrunk
t = IntSetGet(s, `shr`(key, TrunkShift))
if t != nil:
u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
not `shl`(1, u and IntMask)
proc IntSetContainsOrIncl(s: var TIntSet, key: int): bool =
var
u: TBitScalar
t: PTrunk
t = IntSetGet(s, `shr`(key, TrunkShift))
if t != nil:
u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
if not result:
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask)
else:
IntSetIncl(s, key)
result = false
if debugIDs: IntSetInit(usedIds)

View file

@ -12,7 +12,7 @@
# the data structures here are used in various places of the compiler. # the data structures here are used in various places of the compiler.
import import
ast, hashes, strutils, options, msgs, ropes, idents, rodutils ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
proc hashNode*(p: PObject): THash proc hashNode*(p: PObject): THash
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
@ -263,7 +263,7 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
elif IntSetContainsOrIncl(marker, n.id): elif ContainsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope( result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))]) strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
else: else:
@ -284,7 +284,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
elif intSetContainsOrIncl(marker, n.id): elif ContainsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope( result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))]) strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
else: else:
@ -346,18 +346,15 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
appf(result, "$n$1}", [spaces(indent)]) appf(result, "$n$1}", [spaces(indent)])
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope = proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = treeToYamlAux(n, marker, indent, maxRecDepth) result = treeToYamlAux(n, marker, indent, maxRecDepth)
proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope = proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = typeToYamlAux(n, marker, indent, maxRecDepth) result = typeToYamlAux(n, marker, indent, maxRecDepth)
proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope = proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = symToYamlAux(n, marker, indent, maxRecDepth) result = symToYamlAux(n, marker, indent, maxRecDepth)
proc debugType(n: PType): PRope = proc debugType(n: PType): PRope =
@ -612,15 +609,15 @@ proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
var start = h var start = h
result = tab.data[h] result = tab.data[h]
while result != nil: while result != nil:
if result.Name.id == ti.name.id and if result.Name.id == ti.name.id and not Contains(excluding, result.id):
not IntSetContains(excluding, result.id): break break
h = nextTry(h, high(tab.data)) h = nextTry(h, high(tab.data))
if h == start: if h == start:
result = nil result = nil
break break
result = tab.data[h] result = tab.data[h]
ti.h = nextTry(h, high(tab.data)) ti.h = nextTry(h, high(tab.data))
if result != nil and IntSetContains(excluding, result.id): result = nil if result != nil and Contains(excluding, result.id): result = nil
proc FirstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent, proc FirstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
excluding: TIntSet): PSym = excluding: TIntSet): PSym =

View file

@ -709,7 +709,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
assert t.kind == tyObject assert t.kind == tyObject
discard genTypeInfo(p.module, t) discard genTypeInfo(p.module, t)
var L = lengthOrd(field.typ) var L = lengthOrd(field.typ)
if not IntSetContainsOrIncl(p.module.declaredThings, field.id): if not ContainsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1", appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field)) discriminatorTableDecl(p.module, t, field))
appcg(p, cpsStmts, appcg(p, cpsStmts,

View file

@ -387,7 +387,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
if t.sym != nil: useHeader(m, t.sym) if t.sym != nil: useHeader(m, t.sym)
result = getTypePre(m, t) result = getTypePre(m, t)
if result != nil: return if result != nil: return
if IntSetContainsOrIncl(check, t.id): if ContainsOrIncl(check, t.id):
InternalError("cannot generate C type for: " & typeToString(typ)) InternalError("cannot generate C type for: " & typeToString(typ))
# XXX: this BUG is hard to fix -> we need to introduce helper structs, # XXX: this BUG is hard to fix -> we need to introduce helper structs,
# but determining when this needs to be done is hard. We should split # but determining when this needs to be done is hard. We should split
@ -490,8 +490,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
result = nil result = nil
proc getTypeDesc(m: BModule, typ: PType): PRope = proc getTypeDesc(m: BModule, typ: PType): PRope =
var check: TIntSet var check = initIntSet()
IntSetInit(check)
result = getTypeDescAux(m, typ, check) result = getTypeDescAux(m, typ, check)
proc getTypeDesc(m: BModule, magic: string): PRope = proc getTypeDesc(m: BModule, magic: string): PRope =
@ -511,10 +510,9 @@ proc finishTypeDescriptions(m: BModule) =
proc genProcHeader(m: BModule, prc: PSym): PRope = proc genProcHeader(m: BModule, prc: PSym): PRope =
var var
rettype, params: PRope rettype, params: PRope
check: TIntSet
# using static is needed for inline procs # using static is needed for inline procs
if (prc.typ.callConv == ccInline): result = toRope"static " if (prc.typ.callConv == ccInline): result = toRope"static "
IntSetInit(check) var check = initIntSet()
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown) fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown)
genProcParams(m, prc.typ, rettype, params, check) genProcParams(m, prc.typ, rettype, params, check)
appf(result, "$1($2, $3)$4", appf(result, "$1($2, $3)$4",
@ -736,7 +734,7 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
else: else:
dataGenerated = true dataGenerated = true
result = ropef("NTI$1", [toRope(id)]) result = ropef("NTI$1", [toRope(id)])
if not IntSetContainsOrIncl(m.typeInfoMarker, id): if not ContainsOrIncl(m.typeInfoMarker, id):
# declare type information structures: # declare type information structures:
discard cgsym(m, "TNimType") discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")

View file

@ -12,7 +12,7 @@
import import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
options, options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
rodutils rodutils
@ -690,12 +690,12 @@ proc genProcPrototype(m: BModule, sym: PSym) =
if lfNoDecl in sym.loc.Flags: return if lfNoDecl in sym.loc.Flags: return
if lfDynamicLib in sym.loc.Flags: if lfDynamicLib in sym.loc.Flags:
if sym.owner.id != m.module.id and if sym.owner.id != m.module.id and
not intSetContainsOrIncl(m.declaredThings, sym.id): not ContainsOrIncl(m.declaredThings, sym.id):
appff(m.s[cfsVars], "extern $1 $2;$n", appff(m.s[cfsVars], "extern $1 $2;$n",
"@$2 = linkonce global $1 zeroinitializer$n", "@$2 = linkonce global $1 zeroinitializer$n",
[getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)]) [getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)])
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect) if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
elif not IntSetContainsOrIncl(m.declaredProtos, sym.id): elif not ContainsOrIncl(m.declaredProtos, sym.id):
appf(m.s[cfsProcHeaders], "$1;$n", [genProcHeader(m, sym)]) appf(m.s[cfsProcHeaders], "$1;$n", [genProcHeader(m, sym)])
proc genProcNoForward(m: BModule, prc: PSym) = proc genProcNoForward(m: BModule, prc: PSym) =
@ -707,12 +707,12 @@ proc genProcNoForward(m: BModule, prc: PSym) =
# We add inline procs to the calling module to enable C based inlining. # We add inline procs to the calling module to enable C based inlining.
# This also means that a check with ``gGeneratedSyms`` is wrong, we need # This also means that a check with ``gGeneratedSyms`` is wrong, we need
# a check for ``m.declaredThings``. # a check for ``m.declaredThings``.
if not intSetContainsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc) if not ContainsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
elif lfDynamicLib in prc.loc.flags: elif lfDynamicLib in prc.loc.flags:
if not IntSetContainsOrIncl(gGeneratedSyms, prc.id): if not ContainsOrIncl(gGeneratedSyms, prc.id):
SymInDynamicLib(findPendingModule(m, prc), prc) SymInDynamicLib(findPendingModule(m, prc), prc)
elif not (sfImportc in prc.flags): elif not (sfImportc in prc.flags):
if not IntSetContainsOrIncl(gGeneratedSyms, prc.id): if not ContainsOrIncl(gGeneratedSyms, prc.id):
genProcAux(findPendingModule(m, prc), prc) genProcAux(findPendingModule(m, prc), prc)
proc genProc(m: BModule, prc: PSym) = proc genProc(m: BModule, prc: PSym) =
@ -726,7 +726,7 @@ proc genVarPrototype(m: BModule, sym: PSym) =
useHeader(m, sym) useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap) fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
if (lfNoDecl in sym.loc.Flags) or if (lfNoDecl in sym.loc.Flags) or
intSetContainsOrIncl(m.declaredThings, sym.id): ContainsOrIncl(m.declaredThings, sym.id):
return return
if sym.owner.id != m.module.id: if sym.owner.id != m.module.id:
# else we already have the symbol generated! # else we already have the symbol generated!
@ -748,7 +748,7 @@ proc genConstPrototype(m: BModule, sym: PSym) =
if sym.loc.k == locNone: if sym.loc.k == locNone:
fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown) fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown)
if (lfNoDecl in sym.loc.Flags) or if (lfNoDecl in sym.loc.Flags) or
intSetContainsOrIncl(m.declaredThings, sym.id): ContainsOrIncl(m.declaredThings, sym.id):
return return
if sym.owner.id != m.module.id: if sym.owner.id != m.module.id:
# else we already have the symbol generated! # else we already have the symbol generated!
@ -903,14 +903,14 @@ proc genModule(m: BModule, cfilenoext: string): PRope =
proc rawNewModule(module: PSym, filename: string): BModule = proc rawNewModule(module: PSym, filename: string): BModule =
new(result) new(result)
InitLinkedList(result.headerFiles) InitLinkedList(result.headerFiles)
intSetInit(result.declaredThings) result.declaredThings = initIntSet()
intSetInit(result.declaredProtos) result.declaredProtos = initIntSet()
result.cfilename = filename result.cfilename = filename
result.filename = filename result.filename = filename
initIdTable(result.typeCache) initIdTable(result.typeCache)
initIdTable(result.forwTypeCache) initIdTable(result.forwTypeCache)
result.module = module result.module = module
intSetInit(result.typeInfoMarker) result.typeInfoMarker = initIntSet()
result.initProc = newProc(nil, result) result.initProc = newProc(nil, result)
result.initProc.options = gOptions result.initProc.options = gOptions
initNodeTable(result.dataCache) initNodeTable(result.dataCache)
@ -1037,4 +1037,4 @@ proc cgenPass(): TPass =
result.close = myClose result.close = myClose
InitIiTable(gToTypeInfoId) InitIiTable(gToTypeInfoId)
IntSetInit(gGeneratedSyms) gGeneratedSyms = initIntSet()

View file

@ -10,7 +10,7 @@
## This module implements code generation for multi methods. ## This module implements code generation for multi methods.
import import
options, ast, astalgo, msgs, idents, renderer, types, magicsys intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys
proc genConv(n: PNode, d: PType, downcast: bool): PNode = proc genConv(n: PNode, d: PType, downcast: bool): PNode =
var dest = skipTypes(d, abstractPtrs) var dest = skipTypes(d, abstractPtrs)
@ -95,7 +95,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int = proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
result = 0 result = 0
for col in countup(1, sonsLen(a.typ) - 1): for col in countup(1, sonsLen(a.typ) - 1):
if intSetContains(relevantCols, col): if Contains(relevantCols, col):
var aa = skipTypes(a.typ.sons[col], skipPtrs) var aa = skipTypes(a.typ.sons[col], skipPtrs)
var bb = skipTypes(b.typ.sons[col], skipPtrs) var bb = skipTypes(b.typ.sons[col], skipPtrs)
var d = inheritanceDiff(aa, bb) var d = inheritanceDiff(aa, bb)
@ -132,7 +132,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
var curr = methods[meth] # generate condition: var curr = methods[meth] # generate condition:
var cond: PNode = nil var cond: PNode = nil
for col in countup(1, paramLen - 1): for col in countup(1, paramLen - 1):
if IntSetContains(relevantCols, col): if Contains(relevantCols, col):
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool)) var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
addSon(isn, newSymNode(iss)) addSon(isn, newSymNode(iss))
addSon(isn, newSymNode(base.typ.n.sons[col].sym)) addSon(isn, newSymNode(base.typ.n.sons[col].sym))
@ -169,12 +169,11 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
result.ast.sons[codePos] = disp result.ast.sons[codePos] = disp
proc generateMethodDispatchers*(): PNode = proc generateMethodDispatchers*(): PNode =
var relevantCols: TIntSet
result = newNode(nkStmtList) result = newNode(nkStmtList)
for bucket in countup(0, len(gMethods) - 1): for bucket in countup(0, len(gMethods) - 1):
IntSetInit(relevantCols) var relevantCols = initIntSet()
for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1): for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1):
if relevantCol(gMethods[bucket], col): IntSetIncl(relevantCols, col) if relevantCol(gMethods[bucket], col): Incl(relevantCols, col)
sortBucket(gMethods[bucket], relevantCols) sortBucket(gMethods[bucket], relevantCols)
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols))) addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)))

View file

@ -14,7 +14,8 @@
import import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os, options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
intsets
proc ecmasgenPass*(): TPass proc ecmasgenPass*(): TPass
# implementation # implementation
@ -67,7 +68,7 @@ type
proc newGlobals(): PGlobals = proc newGlobals(): PGlobals =
new(result) new(result)
IntSetInit(result.typeInfoGenerated) result.typeInfoGenerated = initIntSet()
proc initCompRes(r: var TCompRes) = proc initCompRes(r: var TCompRes) =
r.com = nil r.com = nil
@ -228,7 +229,7 @@ proc genTypeInfo(p: var TProc, typ: PType): PRope =
var t = typ var t = typ
if t.kind == tyGenericInst: t = lastSon(t) if t.kind == tyGenericInst: t = lastSon(t)
result = ropef("NTI$1", [toRope(t.id)]) result = ropef("NTI$1", [toRope(t.id)])
if IntSetContainsOrIncl(p.globals.TypeInfoGenerated, t.id): return if ContainsOrIncl(p.globals.TypeInfoGenerated, t.id): return
case t.kind case t.kind
of tyDistinct: of tyDistinct:
result = genTypeInfo(p, typ.sons[0]) result = genTypeInfo(p, typ.sons[0])

View file

@ -10,8 +10,8 @@
# This module implements the symbol importing mechanism. # This module implements the symbol importing mechanism.
import import
strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups, semdata, intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
passes semdata, passes
proc evalImport*(c: PContext, n: PNode): PNode proc evalImport*(c: PContext, n: PNode): PNode
proc evalFrom*(c: PContext, n: PNode): PNode proc evalFrom*(c: PContext, n: PNode): PNode
@ -45,8 +45,8 @@ proc rawImportSymbol(c: PContext, s: PSym) =
if (check != nil) and (check.id != copy.id): if (check != nil) and (check.id != copy.id):
if not (s.kind in OverloadableSyms): if not (s.kind in OverloadableSyms):
# s and check need to be qualified: # s and check need to be qualified:
IntSetIncl(c.AmbiguousSymbols, copy.id) Incl(c.AmbiguousSymbols, copy.id)
IntSetIncl(c.AmbiguousSymbols, check.id) Incl(c.AmbiguousSymbols, check.id)
StrTableAdd(c.tab.stack[importTablePos], copy) StrTableAdd(c.tab.stack[importTablePos], copy)
if s.kind == skType: if s.kind == skType:
var etyp = s.typ var etyp = s.typ

View file

@ -10,7 +10,8 @@
# This module implements lookup helpers. # This module implements lookup helpers.
import import
ast, astalgo, idents, semdata, types, msgs, options, rodread, renderer intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
renderer
proc considerAcc*(n: PNode): PIdent = proc considerAcc*(n: PNode): PIdent =
case n.kind case n.kind
@ -115,7 +116,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
result = SymtabGet(c.Tab, ident) result = SymtabGet(c.Tab, ident)
if result == nil: GlobalError(n.info, errUndeclaredIdentifier, ident.s) if result == nil: GlobalError(n.info, errUndeclaredIdentifier, ident.s)
else: InternalError(n.info, "lookUp") else: InternalError(n.info, "lookUp")
if IntSetContains(c.AmbiguousSymbols, result.id): if Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, result.name.s) LocalError(n.info, errUseQualifier, result.name.s)
if result.kind == skStub: loadStub(result) if result.kind == skStub: loadStub(result)
@ -131,12 +132,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
if result == nil and checkUndeclared in flags: if result == nil and checkUndeclared in flags:
GlobalError(n.info, errUndeclaredIdentifier, ident.s) GlobalError(n.info, errUndeclaredIdentifier, ident.s)
elif checkAmbiguity in flags and result != nil and elif checkAmbiguity in flags and result != nil and
IntSetContains(c.AmbiguousSymbols, result.id): Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, ident.s) LocalError(n.info, errUseQualifier, ident.s)
of nkSym: of nkSym:
result = n.sym result = n.sym
if checkAmbiguity in flags and IntSetContains(c.AmbiguousSymbols, if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id):
result.id):
LocalError(n.info, errUseQualifier, n.sym.name.s) LocalError(n.info, errUseQualifier, n.sym.name.s)
of nkDotExpr: of nkDotExpr:
result = nil result = nil
@ -197,8 +197,8 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.mode = oimSymChoice o.mode = oimSymChoice
result = n.sons[0].sym result = n.sons[0].sym
o.stackPtr = 1 o.stackPtr = 1
IntSetInit(o.inSymChoice) o.inSymChoice = initIntSet()
IntSetIncl(o.inSymChoice, result.id) Incl(o.inSymChoice, result.id)
else: nil else: nil
if result != nil and result.kind == skStub: loadStub(result) if result != nil and result.kind == skStub: loadStub(result)
@ -223,7 +223,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
of oimSymChoice: of oimSymChoice:
if o.stackPtr < sonsLen(n): if o.stackPtr < sonsLen(n):
result = n.sons[o.stackPtr].sym result = n.sons[o.stackPtr].sym
IntSetIncl(o.inSymChoice, result.id) Incl(o.inSymChoice, result.id)
inc(o.stackPtr) inc(o.stackPtr)
else: else:
# try 'local' symbols too for Koenig's lookup: # try 'local' symbols too for Koenig's lookup:

View file

@ -12,8 +12,8 @@
# writing of rod files is split into two different modules. # writing of rod files is split into two different modules.
import import
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
ropes, idents, crc, rodread, passes, importer condsyms, ropes, idents, crc, rodread, passes, importer
proc rodwritePass*(): TPass proc rodwritePass*(): TPass
# implementation # implementation
@ -446,4 +446,4 @@ proc rodwritePass(): TPass =
result.close = myClose result.close = myClose
result.process = process result.process = process
IntSetInit(debugWritten) debugWritten= initIntSet()

View file

@ -14,7 +14,7 @@ import
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
magicsys, parser, nversion, nimsets, semdata, evals, semfold, importer, magicsys, parser, nversion, nimsets, semdata, evals, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest, procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest,
semthreads semthreads, intsets
proc semPass*(): TPass proc semPass*(): TPass
# implementation # implementation

View file

@ -10,7 +10,8 @@
# This module contains the data structures for the semantic checking phase. # This module contains the data structures for the semantic checking phase.
import import
strutils, lists, options, lexer, ast, astalgo, trees, treetab, wordrecg, strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
wordrecg,
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
magicsys, nversion, nimsets, parser, times, passes, rodread magicsys, nversion, nimsets, parser, times, passes, rodread
@ -118,7 +119,7 @@ proc newOptionEntry(): POptionEntry =
proc newContext(module: PSym, nimfile: string): PContext = proc newContext(module: PSym, nimfile: string): PContext =
new(result) new(result)
InitSymTab(result.tab) InitSymTab(result.tab)
IntSetInit(result.AmbiguousSymbols) result.AmbiguousSymbols = initIntset()
initLinkedList(result.optionStack) initLinkedList(result.optionStack)
initLinkedList(result.libs) initLinkedList(result.libs)
append(result.optionStack, newOptionEntry()) append(result.optionStack, newOptionEntry())
@ -127,7 +128,7 @@ proc newContext(module: PSym, nimfile: string): PContext =
result.threadEntries = newNode(nkStmtList) result.threadEntries = newNode(nkStmtList)
result.converters = @[] result.converters = @[]
result.filename = nimfile result.filename = nimfile
IntSetInit(result.includedFiles) result.includedFiles = initIntSet()
initStrTable(result.userPragmas) initStrTable(result.userPragmas)
proc addConverter(c: PContext, conv: PSym) = proc addConverter(c: PContext, conv: PSym) =

View file

@ -888,11 +888,10 @@ proc checkPar(n: PNode): TParKind =
return paNone return paNone
proc semTupleFieldsConstr(c: PContext, n: PNode): PNode = proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
var ids: TIntSet
result = newNodeI(nkPar, n.info) result = newNodeI(nkPar, n.info)
var typ = newTypeS(tyTuple, c) var typ = newTypeS(tyTuple, c)
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
IntSetInit(ids) var ids = initIntSet()
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if (n.sons[i].kind != nkExprColonExpr) or if (n.sons[i].kind != nkExprColonExpr) or
not (n.sons[i].sons[0].kind in {nkSym, nkIdent}): not (n.sons[i].sons[0].kind in {nkSym, nkIdent}):
@ -900,7 +899,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
var id: PIdent var id: PIdent
if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident
else: id = n.sons[i].sons[0].sym.name else: id = n.sons[i].sons[0].sym.name
if IntSetContainsOrIncl(ids, id.id): if ContainsOrIncl(ids, id.id):
localError(n.sons[i].info, errFieldInitTwice, id.s) localError(n.sons[i].info, errFieldInitTwice, id.s)
n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1]) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
var f = newSymS(skField, n.sons[i].sons[0], c) var f = newSymS(skField, n.sons[i].sons[0], c)

View file

@ -476,11 +476,10 @@ proc semRaise(c: PContext, n: PNode): PNode =
localError(n.info, errExprCannotBeRaised) localError(n.info, errExprCannotBeRaised)
proc semTry(c: PContext, n: PNode): PNode = proc semTry(c: PContext, n: PNode): PNode =
var check: TIntSet
result = n result = n
checkMinSonsLen(n, 2) checkMinSonsLen(n, 2)
n.sons[0] = semStmtScope(c, n.sons[0]) n.sons[0] = semStmtScope(c, n.sons[0])
IntSetInit(check) var check = initIntSet()
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
checkMinSonsLen(a, 1) checkMinSonsLen(a, 1)
@ -493,7 +492,7 @@ proc semTry(c: PContext, n: PNode): PNode =
GlobalError(a.sons[j].info, errExprCannotBeRaised) GlobalError(a.sons[j].info, errExprCannotBeRaised)
a.sons[j] = newNodeI(nkType, a.sons[j].info) a.sons[j] = newNodeI(nkType, a.sons[j].info)
a.sons[j].typ = typ a.sons[j].typ = typ
if IntSetContainsOrIncl(check, typ.id): if ContainsOrIncl(check, typ.id):
localError(a.sons[j].info, errExceptionAlreadyHandled) localError(a.sons[j].info, errExceptionAlreadyHandled)
elif a.kind != nkFinally: elif a.kind != nkFinally:
illFormedAst(n) illFormedAst(n)
@ -820,10 +819,10 @@ proc evalInclude(c: PContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var f = getModuleFile(n.sons[i]) var f = getModuleFile(n.sons[i])
var fileIndex = includeFilename(f) var fileIndex = includeFilename(f)
if IntSetContainsOrIncl(c.includedFiles, fileIndex): if ContainsOrIncl(c.includedFiles, fileIndex):
GlobalError(n.info, errRecursiveDependencyX, f) GlobalError(n.info, errRecursiveDependencyX, f)
addSon(result, semStmt(c, gIncludeFile(f))) addSon(result, semStmt(c, gIncludeFile(f)))
IntSetExcl(c.includedFiles, fileIndex) Excl(c.includedFiles, fileIndex)
proc SemStmt(c: PContext, n: PNode): PNode = proc SemStmt(c: PContext, n: PNode): PNode =
const # must be last statements in a block: const # must be last statements in a block:

View file

@ -117,7 +117,7 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
var s: PSym var s: PSym
case n.kind case n.kind
of nkIdent: of nkIdent:
if not withinBind and not IntSetContains(toBind, n.ident.id): if not withinBind and not Contains(toBind, n.ident.id):
s = SymTabLocalGet(c.Tab, n.ident) s = SymTabLocalGet(c.Tab, n.ident)
if (s != nil): if (s != nil):
result = newSymNode(s) result = newSymNode(s)
@ -125,7 +125,7 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool,
else: else:
result = n result = n
else: else:
IntSetIncl(toBind, n.ident.id) Incl(toBind, n.ident.id)
result = symChoice(c, n, lookup(c, n)) result = symChoice(c, n, lookup(c, n))
of nkEmpty, nkSym..nkNilLit: # atom of nkEmpty, nkSym..nkNilLit: # atom
result = n result = n
@ -160,7 +160,6 @@ proc transformToExpr(n: PNode): PNode =
proc semTemplateDef(c: PContext, n: PNode): PNode = proc semTemplateDef(c: PContext, n: PNode): PNode =
var var
s: PSym s: PSym
toBind: TIntSet
if c.p.owner.kind == skModule: if c.p.owner.kind == skModule:
s = semIdentVis(c, skTemplate, n.sons[0], {sfStar}) s = semIdentVis(c, skTemplate, n.sons[0], {sfStar})
incl(s.flags, sfGlobal) incl(s.flags, sfGlobal)
@ -189,7 +188,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
s.typ.sons[0] = newTypeS(tyStmt, c) s.typ.sons[0] = newTypeS(tyStmt, c)
s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0]) s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
addParams(c, s.typ.n) # resolve parameters: addParams(c, s.typ.n) # resolve parameters:
IntSetInit(toBind) var toBind = initIntSet()
n.sons[codePos] = resolveTemplateParams(c, n.sons[codePos], false, toBind) n.sons[codePos] = resolveTemplateParams(c, n.sons[codePos], false, toBind)
if not (s.typ.sons[0].kind in {tyStmt, tyTypeDesc}): if not (s.typ.sons[0].kind in {tyStmt, tyTypeDesc}):
n.sons[codePos] = transformToExpr(n.sons[codePos]) n.sons[codePos] = transformToExpr(n.sons[codePos])

View file

@ -192,10 +192,9 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
proc semTuple(c: PContext, n: PNode, prev: PType): PType = proc semTuple(c: PContext, n: PNode, prev: PType): PType =
var var
typ: PType typ: PType
check: TIntSet
result = newOrPrevType(tyTuple, prev, c) result = newOrPrevType(tyTuple, prev, c)
result.n = newNodeI(nkRecList, n.info) result.n = newNodeI(nkRecList, n.info)
IntSetInit(check) var check = initIntSet()
var counter = 0 var counter = 0
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
@ -212,7 +211,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
field.typ = typ field.typ = typ
field.position = counter field.position = counter
inc(counter) inc(counter)
if IntSetContainsOrIncl(check, field.name.id): if ContainsOrIncl(check, field.name.id):
GlobalError(a.sons[j].info, errAttemptToRedefine, field.name.s) GlobalError(a.sons[j].info, errAttemptToRedefine, field.name.s)
addSon(result.n, newSymNode(field)) addSon(result.n, newSymNode(field))
addSon(result, typ) addSon(result, typ)
@ -396,7 +395,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
f.loc.r = toRope(f.name.s) f.loc.r = toRope(f.name.s)
f.flags = f.flags + ({sfImportc, sfExportc} * rectype.flags) f.flags = f.flags + ({sfImportc, sfExportc} * rectype.flags)
inc(pos) inc(pos)
if IntSetContainsOrIncl(check, f.name.id): if ContainsOrIncl(check, f.name.id):
localError(n.sons[i].info, errAttemptToRedefine, f.name.s) localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
if a.kind == nkEmpty: addSon(father, newSymNode(f)) if a.kind == nkEmpty: addSon(father, newSymNode(f))
else: addSon(a, newSymNode(f)) else: addSon(a, newSymNode(f))
@ -419,7 +418,7 @@ proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int,
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
addInheritedFieldsAux(c, check, pos, n.sons[i]) addInheritedFieldsAux(c, check, pos, n.sons[i])
of nkSym: of nkSym:
IntSetIncl(check, n.sym.name.id) Incl(check, n.sym.name.id)
inc(pos) inc(pos)
else: InternalError(n.info, "addInheritedFieldsAux()") else: InternalError(n.info, "addInheritedFieldsAux()")
@ -437,8 +436,7 @@ proc skipGenericInvokation(t: PType): PType {.inline.} =
result = lastSon(result) result = lastSon(result)
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
var check: TIntSet var check = initIntSet()
IntSetInit(check)
var pos = 0 var pos = 0
var base: PType = nil var base: PType = nil
# n.sons[0] contains the pragmas (if any). We process these later... # n.sons[0] contains the pragmas (if any). We process these later...
@ -460,7 +458,7 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
cl: var TIntSet): PType = cl: var TIntSet): PType =
result = t result = t
if t == nil: return if t == nil: return
if IntSetContainsOrIncl(cl, t.id): return if ContainsOrIncl(cl, t.id): return
case t.kind case t.kind
of tyGenericBody: of tyGenericBody:
#debug(t) #debug(t)
@ -470,7 +468,7 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
if t.sons[i].kind != tyGenericParam: if t.sons[i].kind != tyGenericParam:
InternalError("addTypeVarsOfGenericBody") InternalError("addTypeVarsOfGenericBody")
# do not declare ``TKey`` twice: # do not declare ``TKey`` twice:
#if not IntSetContainsOrIncl(cl, t.sons[i].sym.ident.id): #if not ContainsOrIncl(cl, t.sons[i].sym.ident.id):
var s = copySym(t.sons[i].sym) var s = copySym(t.sons[i].sym)
s.position = sonsLen(genericParams) s.position = sonsLen(genericParams)
if s.typ == nil or s.typ.kind != tyGenericParam: if s.typ == nil or s.typ.kind != tyGenericParam:
@ -501,16 +499,17 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
var var
def, res: PNode def, res: PNode
typ: PType typ: PType
check, cl: TIntSet cl: TIntSet
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
result = newOrPrevType(tyProc, prev, c) result = newOrPrevType(tyProc, prev, c)
result.callConv = lastOptionEntry(c).defaultCC result.callConv = lastOptionEntry(c).defaultCC
result.n = newNodeI(nkFormalParams, n.info) result.n = newNodeI(nkFormalParams, n.info)
if (genericParams != nil) and (sonsLen(genericParams) == 0): IntSetInit(cl) if (genericParams != nil) and (sonsLen(genericParams) == 0):
cl = initIntSet()
addSon(result, nil) # return type addSon(result, nil) # return type
res = newNodeI(nkType, n.info) res = newNodeI(nkType, n.info)
addSon(result.n, res) addSon(result.n, res)
IntSetInit(check) var check = initIntSet()
var counter = 0 var counter = 0
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
@ -539,7 +538,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
arg.position = counter arg.position = counter
inc(counter) inc(counter)
if def.kind != nkEmpty: arg.ast = copyTree(def) if def.kind != nkEmpty: arg.ast = copyTree(def)
if IntSetContainsOrIncl(check, arg.name.id): if ContainsOrIncl(check, arg.name.id):
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s) LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
addSon(result.n, newSymNode(arg)) addSon(result.n, newSymNode(arg))
addSon(result, typ) addSon(result, typ)

View file

@ -11,7 +11,7 @@
# the call to overloaded procs, generic procs and operators. # the call to overloaded procs, generic procs and operators.
import import
ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
magicsys magicsys
type type
@ -608,7 +608,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
# no error message! # no error message!
m.state = csNoMatch m.state = csNoMatch
return return
if IntSetContainsOrIncl(marker, formal.position): if ContainsOrIncl(marker, formal.position):
# already in namedParams: # already in namedParams:
LocalError(n.sons[a].info, errCannotBindXTwice, formal.name.s) LocalError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
m.state = csNoMatch m.state = csNoMatch
@ -653,7 +653,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
if m.callee.n.sons[f].kind != nkSym: if m.callee.n.sons[f].kind != nkSym:
InternalError(n.sons[a].info, "matches") InternalError(n.sons[a].info, "matches")
formal = m.callee.n.sons[f].sym formal = m.callee.n.sons[f].sym
if IntSetContainsOrIncl(marker, formal.position): if ContainsOrIncl(marker, formal.position):
# already in namedParams: # already in namedParams:
LocalError(n.sons[a].info, errCannotBindXTwice, formal.name.s) LocalError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
m.state = csNoMatch m.state = csNoMatch
@ -677,20 +677,18 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
proc partialMatch*(c: PContext, n: PNode, m: var TCandidate) = proc partialMatch*(c: PContext, n: PNode, m: var TCandidate) =
# for 'suggest' support: # for 'suggest' support:
var marker: TIntSet var marker = initIntSet()
IntSetInit(marker)
matchesAux(c, n, m, marker) matchesAux(c, n, m, marker)
proc matches*(c: PContext, n: PNode, m: var TCandidate) = proc matches*(c: PContext, n: PNode, m: var TCandidate) =
var marker: TIntSet var marker = initIntSet()
IntSetInit(marker)
matchesAux(c, n, m, marker) matchesAux(c, n, m, marker)
if m.state == csNoMatch: return if m.state == csNoMatch: return
# check that every formal parameter got a value: # check that every formal parameter got a value:
var f = 1 var f = 1
while f < sonsLen(m.callee.n): while f < sonsLen(m.callee.n):
var formal = m.callee.n.sons[f].sym var formal = m.callee.n.sons[f].sym
if not IntSetContainsOrIncl(marker, formal.position): if not ContainsOrIncl(marker, formal.position):
if formal.ast == nil: if formal.ast == nil:
if formal.typ.kind == tyOpenArray: if formal.typ.kind == tyOpenArray:
var container = newNodeI(nkBracket, n.info) var container = newNodeI(nkBracket, n.info)

View file

@ -17,7 +17,7 @@
# * introduces method dispatchers # * introduces method dispatchers
import import
strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, passes, semfold, magicsys, cgmeth idents, renderer, types, passes, semfold, magicsys, cgmeth
const const
@ -528,8 +528,7 @@ proc gatherVars(c: PTransf, n: PNode, marked: var TIntSet, owner: PSym,
of skVar: found = not (sfGlobal in s.flags) of skVar: found = not (sfGlobal in s.flags)
of skTemp, skForVar, skParam: found = true of skTemp, skForVar, skParam: found = true
else: nil else: nil
if found and (owner.id != s.owner.id) and if found and (owner.id != s.owner.id) and not ContainsOrIncl(marked, s.id):
not IntSetContainsOrIncl(marked, s.id):
incl(s.flags, sfInClosure) incl(s.flags, sfInClosure)
addSon(container, copyNode(n)) # DON'T make a copy of the symbol! addSon(container, copyNode(n)) # DON'T make a copy of the symbol!
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
@ -555,9 +554,8 @@ proc indirectAccess(a, b: PSym): PNode =
result.typ = y.typ result.typ = y.typ
proc transformLambda(c: PTransf, n: PNode): PNode = proc transformLambda(c: PTransf, n: PNode): PNode =
var marked: TIntSet var marked = initIntSet()
result = n result = n
IntSetInit(marked)
if (n.sons[namePos].kind != nkSym): InternalError(n.info, "transformLambda") if (n.sons[namePos].kind != nkSym): InternalError(n.info, "transformLambda")
var s = n.sons[namePos].sym var s = n.sons[namePos].sym
var closure = newNodeI(nkRecList, n.sons[codePos].info) var closure = newNodeI(nkRecList, n.sons[codePos].info)

View file

@ -10,7 +10,7 @@
# this module contains routines for accessing and iterating over types # this module contains routines for accessing and iterating over types
import import
ast, astalgo, trees, msgs, strutils, platform intsets, ast, astalgo, trees, msgs, strutils, platform
proc firstOrd*(t: PType): biggestInt proc firstOrd*(t: PType): biggestInt
proc lastOrd*(t: PType): biggestInt proc lastOrd*(t: PType): biggestInt
@ -219,7 +219,7 @@ proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter,
if t == nil: return if t == nil: return
result = iter(t, closure) result = iter(t, closure)
if result: return if result: return
if not IntSetContainsOrIncl(marker, t.id): if not ContainsOrIncl(marker, t.id):
case t.kind case t.kind
of tyGenericInst, tyGenericBody: of tyGenericInst, tyGenericBody:
result = iterOverTypeAux(marker, lastSon(t), iter, closure) result = iterOverTypeAux(marker, lastSon(t), iter, closure)
@ -230,8 +230,7 @@ proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter,
if t.n != nil: result = iterOverNode(marker, t.n, iter, closure) if t.n != nil: result = iterOverNode(marker, t.n, iter, closure)
proc IterOverType(t: PType, iter: TTypeIter, closure: PObject): bool = proc IterOverType(t: PType, iter: TTypeIter, closure: PObject): bool =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = iterOverTypeAux(marker, t, iter, closure) result = iterOverTypeAux(marker, t, iter, closure)
proc searchTypeForAux(t: PType, predicate: TTypePredicate, proc searchTypeForAux(t: PType, predicate: TTypePredicate,
@ -263,7 +262,7 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var TIntSet):
# iterates over VALUE types! # iterates over VALUE types!
result = false result = false
if t == nil: return if t == nil: return
if IntSetContainsOrIncl(marker, t.id): return if ContainsOrIncl(marker, t.id): return
result = Predicate(t) result = Predicate(t)
if result: return if result: return
case t.kind case t.kind
@ -280,8 +279,7 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var TIntSet):
nil nil
proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = proc searchTypeFor(t: PType, predicate: TTypePredicate): bool =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = searchTypeForAux(t, predicate, marker) result = searchTypeForAux(t, predicate, marker)
proc isObjectPredicate(t: PType): bool = proc isObjectPredicate(t: PType): bool =
@ -322,8 +320,7 @@ proc analyseObjectWithTypeFieldAux(t: PType, marker: var TIntSet): TTypeFieldRes
nil nil
proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = analyseObjectWithTypeFieldAux(t, marker) result = analyseObjectWithTypeFieldAux(t, marker)
proc isGBCRef(t: PType): bool = proc isGBCRef(t: PType): bool =
@ -365,7 +362,7 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool =
if tfAcyclic in t.flags: return if tfAcyclic in t.flags: return
case t.kind case t.kind
of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray: of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray:
if not IntSetContainsOrIncl(marker, t.id): if not ContainsOrIncl(marker, t.id):
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
result = canFormAcycleAux(marker, t.sons[i], startId) result = canFormAcycleAux(marker, t.sons[i], startId)
if result: return if result: return
@ -376,8 +373,7 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool =
nil nil
proc canFormAcycle(typ: PType): bool = proc canFormAcycle(typ: PType): bool =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = canFormAcycleAux(marker, typ, typ.id) result = canFormAcycleAux(marker, typ, typ.id)
proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator,
@ -400,7 +396,7 @@ proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator,
result = nil result = nil
if t == nil: return if t == nil: return
result = iter(t, closure) result = iter(t, closure)
if not IntSetContainsOrIncl(marker, t.id): if not ContainsOrIncl(marker, t.id):
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure) result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure)
if (result.sons[i] == nil) and (result.kind == tyGenericInst): if (result.sons[i] == nil) and (result.kind == tyGenericInst):
@ -409,8 +405,7 @@ proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator,
assert(result != nil) assert(result != nil)
proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType = proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = mutateTypeAux(marker, t, iter, closure) result = mutateTypeAux(marker, t, iter, closure)
proc rangeToStr(n: PNode): string = proc rangeToStr(n: PNode): string =
@ -591,17 +586,14 @@ proc equalParam(a, b: PSym): TParamsEquality =
result = paramsNotEqual result = paramsNotEqual
proc equalParams(a, b: PNode): TParamsEquality = proc equalParams(a, b: PNode): TParamsEquality =
var
length: int
m, n: PSym
result = paramsEqual result = paramsEqual
length = sonsLen(a) var length = sonsLen(a)
if length != sonsLen(b): if length != sonsLen(b):
result = paramsNotEqual result = paramsNotEqual
else: else:
for i in countup(1, length - 1): for i in countup(1, length - 1):
m = a.sons[i].sym var m = a.sons[i].sym
n = b.sons[i].sym var n = b.sons[i].sym
assert((m.kind == skParam) and (n.kind == skParam)) assert((m.kind == skParam) and (n.kind == skParam))
case equalParam(m, n) case equalParam(m, n)
of paramsNotEqual: of paramsNotEqual:
@ -646,7 +638,6 @@ proc sameTuple(a, b: PType, DistinctOf: bool): bool =
# two tuples are equivalent iff the names, types and positions are the same; # two tuples are equivalent iff the names, types and positions are the same;
# however, both types may not have any field names (t.n may be nil) which # however, both types may not have any field names (t.n may be nil) which
# complicates the matter a bit. # complicates the matter a bit.
var x, y: PSym
if sonsLen(a) == sonsLen(b): if sonsLen(a) == sonsLen(b):
result = true result = true
for i in countup(0, sonsLen(a) - 1): for i in countup(0, sonsLen(a) - 1):
@ -658,8 +649,8 @@ proc sameTuple(a, b: PType, DistinctOf: bool): bool =
# check field names: # check field names:
if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple") if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple")
if b.n.sons[i].kind != nkSym: InternalError(b.n.info, "sameTuple") if b.n.sons[i].kind != nkSym: InternalError(b.n.info, "sameTuple")
x = a.n.sons[i].sym var x = a.n.sons[i].sym
y = b.n.sons[i].sym var y = b.n.sons[i].sym
result = x.name.id == y.name.id result = x.name.id == y.name.id
if not result: break if not result: break
else: else:
@ -758,17 +749,16 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
if not result: return if not result: return
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
var t, t2: PType
assert(kind in {skVar, skConst, skParam}) assert(kind in {skVar, skConst, skParam})
# if we have already checked the type, return true, because we stop the
# evaluation if something is wrong:
result = true result = true
if typ == nil: if typ == nil: return
return # if we have already checked the type, return true, because we stop the if ContainsOrIncl(marker, typ.id): return
# evaluation if something is wrong: var t = skipTypes(typ, abstractInst)
if IntSetContainsOrIncl(marker, typ.id): return
t = skipTypes(typ, abstractInst)
case t.kind case t.kind
of tyVar: of tyVar:
t2 = skipTypes(t.sons[0], abstractInst) var t2 = skipTypes(t.sons[0], abstractInst)
case t2.kind case t2.kind
of tyVar: of tyVar:
result = false # ``var var`` is always an invalid type: result = false # ``var var`` is always an invalid type:
@ -815,8 +805,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
if t.n != nil: result = typeAllowedNode(marker, t.n, skVar) if t.n != nil: result = typeAllowedNode(marker, t.n, skVar)
proc typeAllowed(t: PType, kind: TSymKind): bool = proc typeAllowed(t: PType, kind: TSymKind): bool =
var marker: TIntSet var marker = InitIntSet()
IntSetInit(marker)
result = typeAllowedAux(marker, t, kind) result = typeAllowedAux(marker, t, kind)
proc align(address, alignment: biggestInt): biggestInt = proc align(address, alignment: biggestInt): biggestInt =

View file

@ -42,6 +42,9 @@ Core
Contains procs for serialization and deseralization of arbitrary Nimrod Contains procs for serialization and deseralization of arbitrary Nimrod
data structures. data structures.
* `typeinfo <typeinfo.html>`_
Provides (unsafe) access to Nimrod's run time type information.
Collections and algorithms Collections and algorithms
-------------------------- --------------------------
@ -53,7 +56,9 @@ Collections and algorithms
* `lists <lists.html>`_ * `lists <lists.html>`_
Nimrod linked list support. Contains singly and doubly linked lists and Nimrod linked list support. Contains singly and doubly linked lists and
circular lists ("rings"). circular lists ("rings").
* `intsets <intsets.html>`_
Efficient implementation of a set of ints as a sparse bit set.
String handling String handling
--------------- ---------------

View file

@ -0,0 +1,177 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## The ``intsets`` module implements an efficient int set implemented as a
## sparse bit set.
## **Note**: Since Nimrod does not allow the assignment operator to be
## overloaded, ``=`` for int sets performs some rather meaningless shallow
## copy.
import
os, hashes, math
type
TBitScalar = int
const
InitIntSetSize = 8 # must be a power of two!
TrunkShift = 9
BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
# divisible by 64
TrunkMask = BitsPerTrunk - 1
IntsPerTrunk = BitsPerTrunk div (sizeof(TBitScalar) * 8)
IntShift = 5 + ord(sizeof(TBitScalar) == 8) # 5 or 6, depending on int width
IntMask = 1 shl IntShift - 1
type
PTrunk = ref TTrunk
TTrunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0
bits: array[0..IntsPerTrunk - 1, TBitScalar] # a bit vector
TTrunkSeq = seq[PTrunk]
TIntSet* {.final.} = object ## an efficient set of 'int' implemented as a
## sparse bit set
counter, max: int
head: PTrunk
data: TTrunkSeq
proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc IntSetGet(t: TIntSet, key: int): PTrunk =
var h = key and t.max
while t.data[h] != nil:
if t.data[h].key == key:
return t.data[h]
h = nextTry(h, t.max)
result = nil
proc IntSetRawInsert(t: TIntSet, data: var TTrunkSeq, desc: PTrunk) =
var h = desc.key and t.max
while data[h] != nil:
assert(data[h] != desc)
h = nextTry(h, t.max)
assert(data[h] == nil)
data[h] = desc
proc IntSetEnlarge(t: var TIntSet) =
var n: TTrunkSeq
var oldMax = t.max
t.max = ((t.max + 1) * 2) - 1
newSeq(n, t.max + 1)
for i in countup(0, oldmax):
if t.data[i] != nil: IntSetRawInsert(t, n, t.data[i])
swap(t.data, n)
proc IntSetPut(t: var TIntSet, key: int): PTrunk =
var h = key and t.max
while t.data[h] != nil:
if t.data[h].key == key:
return t.data[h]
h = nextTry(h, t.max)
if mustRehash(t.max + 1, t.counter): IntSetEnlarge(t)
inc(t.counter)
h = key and t.max
while t.data[h] != nil: h = nextTry(h, t.max)
assert(t.data[h] == nil)
new(result)
result.next = t.head
result.key = key
t.head = result
t.data[h] = result
proc contains*(s: TIntSet, key: int): bool =
## returns true iff `key` is in `s`.
var t = IntSetGet(s, `shr`(key, TrunkShift))
if t != nil:
var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
else:
result = false
proc incl*(s: var TIntSet, key: int) =
## includes an element `key` in `s`.
var t = IntSetPut(s, `shr`(key, TrunkShift))
var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask)
proc excl*(s: var TIntSet, key: int) =
## excludes `key` from the set `s`.
var t = IntSetGet(s, `shr`(key, TrunkShift))
if t != nil:
var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
not `shl`(1, u and IntMask)
proc containsOrIncl*(s: var TIntSet, key: int): bool =
## returns true if `s` contains `key`, otherwise `key` is included in `s`
## and false is returned.
var t = IntSetGet(s, `shr`(key, TrunkShift))
if t != nil:
var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
if not result:
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask)
else:
incl(s, key)
result = false
proc initIntSet*: TIntSet =
## creates a new int set that is empty.
newSeq(result.data, InitIntSetSize)
result.max = InitIntSetSize-1
result.counter = 0
result.head = nil
template dollarImpl(): stmt =
result = "{"
for key in items(s):
if result.len > 1: result.add(", ")
result.add($key)
result.add("}")
proc `$`*(s: TIntSet): string =
## The `$` operator for int sets.
dollarImpl()
iterator items*(s: TIntSet): int {.inline.} =
## iterates over any included element of `s`.
var r = s.head
while r != nil:
var i = 0
while i <= high(r.bits):
var w = r.bits[i]
# taking a copy of r.bits[i] here is correct, because
# modifying operations are not allowed during traversation
var j = 0
while w != 0: # test all remaining bits for zero
if (w and 1) != 0: # the bit is set!
yield (r.key shl TrunkShift) or (i shl IntShift +% j)
inc(j)
w = w shr 1
inc(i)
r = r.next
when isMainModule:
var x = initIntSet()
x.incl(1)
x.incl(2)
x.incl(7)
x.incl(1056)
for e in items(x): echo e

View file

@ -1,12 +0,0 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2006 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#

View file

@ -78,7 +78,7 @@ Low priority
Library Library
------- -------
- specialized bit sets; specialized string sets - radix tree for strings; maybe suffix tree
- locale support - locale support
- conversion between character sets - conversion between character sets
- bignums - bignums

View file

@ -51,6 +51,7 @@ Additions
- Added ``lists`` module which contains generic linked lists. - Added ``lists`` module which contains generic linked lists.
- Added ``sets`` module which contains generic hash sets. - Added ``sets`` module which contains generic hash sets.
- Added ``tables`` module which contains generic hash tables. - Added ``tables`` module which contains generic hash tables.
- Added ``intsets`` module which contains a specialized int set data type.
- Added ``scgi`` module. - Added ``scgi`` module.
- Added ``smtp`` module. - Added ``smtp`` module.
- Added ``re.findAll``, ``pegs.findAll``. - Added ``re.findAll``, ``pegs.findAll``.

View file

@ -24,7 +24,7 @@ file: ticker
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview" doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview"
doc: "tools;c2nim;niminst" doc: "tools;c2nim;niminst"
pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst" pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst"
srcdoc: "core/macros;core/marshal" srcdoc: "core/macros;core/marshal;core/typeinfo"
srcdoc: "impure/graphics;pure/sockets" srcdoc: "impure/graphics;pure/sockets"
srcdoc: "system.nim;system/threads.nim;pure/os;pure/strutils;pure/math" srcdoc: "system.nim;system/threads.nim;pure/os;pure/strutils;pure/math"
srcdoc: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib" srcdoc: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib"
@ -39,6 +39,7 @@ srcdoc: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors"
srcdoc: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics" srcdoc: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics"
srcdoc: "impure/rdstdin;wrappers/zmq" srcdoc: "impure/rdstdin;wrappers/zmq"
srcdoc: "pure/collections/tables;pure/collections/sets;pure/collections/lists" srcdoc: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
srcdoc: "pure/collections/intsets"
webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup" webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup"
webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc" webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"