diff options
author | Araq <rumpf_a@web.de> | 2011-06-14 01:36:49 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-06-14 01:36:49 +0200 |
commit | ade67f1abcc29402b489e9f5940036276878fb18 (patch) | |
tree | c21aeca55a0b9137bf4479dcf67726b367ea1859 | |
parent | ca637c019c13f552d0f44a18d3f3afe4b8a88832 (diff) | |
download | Nim-ade67f1abcc29402b489e9f5940036276878fb18.tar.gz |
intsets are now a proper module and part of the stdlib
-rwxr-xr-x | compiler/ast.nim | 144 | ||||
-rwxr-xr-x | compiler/astalgo.nim | 21 | ||||
-rwxr-xr-x | compiler/ccgstmts.nim | 2 | ||||
-rwxr-xr-x | compiler/ccgtypes.nim | 10 | ||||
-rwxr-xr-x | compiler/cgen.nim | 24 | ||||
-rwxr-xr-x | compiler/cgmeth.nim | 11 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 7 | ||||
-rwxr-xr-x | compiler/importer.nim | 8 | ||||
-rwxr-xr-x | compiler/lookups.nim | 16 | ||||
-rwxr-xr-x | compiler/rodwrite.nim | 6 | ||||
-rwxr-xr-x | compiler/sem.nim | 2 | ||||
-rwxr-xr-x | compiler/semdata.nim | 7 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 5 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 9 | ||||
-rwxr-xr-x | compiler/semtempl.nim | 7 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 25 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 14 | ||||
-rwxr-xr-x | compiler/transf.nim | 8 | ||||
-rwxr-xr-x | compiler/types.nim | 55 | ||||
-rwxr-xr-x | doc/lib.txt | 7 | ||||
-rw-r--r-- | lib/pure/collections/intsets.nim | 177 | ||||
-rwxr-xr-x | lib/system/cntbits.nim | 12 | ||||
-rwxr-xr-x | todo.txt | 2 | ||||
-rwxr-xr-x | web/news.txt | 1 | ||||
-rwxr-xr-x | web/nimrod.ini | 3 |
25 files changed, 297 insertions, 286 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 808fb683d..ae8680c6b 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,7 +10,7 @@ # abstract syntax tree + symbol table import - msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists + msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, intsets const ImportTablePos* = 0 @@ -620,39 +620,6 @@ proc leValue*(a, b: PNode): bool # a <= b? a, b are literals 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 debugIds* = false @@ -663,7 +630,7 @@ var usedIds: TIntSet proc registerID(id: PIdObj) = 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)) proc getID(): int = @@ -1036,109 +1003,4 @@ proc getStrOrChar*(a: PNode): string = internalError(a.info, "getStrOrChar") result = "" -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 - # 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) +if debugIDs: usedIds = InitIntSet() diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index fa01dabbf..08b502af7 100755 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -12,7 +12,7 @@ # the data structures here are used in various places of the compiler. import - ast, hashes, strutils, options, msgs, ropes, idents, rodutils + ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils proc hashNode*(p: PObject): THash 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 = if n == nil: result = toRope("null") - elif IntSetContainsOrIncl(marker, n.id): + elif ContainsOrIncl(marker, n.id): result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope( strutils.toHex(cast[TAddress](n), sizeof(n) * 2))]) else: @@ -284,7 +284,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, maxRecDepth: int): PRope = if n == nil: result = toRope("null") - elif intSetContainsOrIncl(marker, n.id): + elif ContainsOrIncl(marker, n.id): result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope( strutils.toHex(cast[TAddress](n), sizeof(n) * 2))]) else: @@ -346,18 +346,15 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, appf(result, "$n$1}", [spaces(indent)]) proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = treeToYamlAux(n, marker, indent, maxRecDepth) proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = typeToYamlAux(n, marker, indent, maxRecDepth) proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = symToYamlAux(n, marker, indent, maxRecDepth) proc debugType(n: PType): PRope = @@ -612,15 +609,15 @@ proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, var start = h result = tab.data[h] while result != nil: - if result.Name.id == ti.name.id and - not IntSetContains(excluding, result.id): break + if result.Name.id == ti.name.id and not Contains(excluding, result.id): + break h = nextTry(h, high(tab.data)) if h == start: result = nil break result = tab.data[h] 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, excluding: TIntSet): PSym = diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index d45035989..8a05c68a4 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -709,7 +709,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType, assert t.kind == tyObject discard genTypeInfo(p.module, t) 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", discriminatorTableDecl(p.module, t, field)) appcg(p, cpsStmts, diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 84e1850ad..26c0242f5 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -387,7 +387,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = if t.sym != nil: useHeader(m, t.sym) result = getTypePre(m, t) if result != nil: return - if IntSetContainsOrIncl(check, t.id): + if ContainsOrIncl(check, t.id): InternalError("cannot generate C type for: " & typeToString(typ)) # 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 @@ -490,8 +490,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = result = nil proc getTypeDesc(m: BModule, typ: PType): PRope = - var check: TIntSet - IntSetInit(check) + var check = initIntSet() result = getTypeDescAux(m, typ, check) proc getTypeDesc(m: BModule, magic: string): PRope = @@ -511,10 +510,9 @@ proc finishTypeDescriptions(m: BModule) = proc genProcHeader(m: BModule, prc: PSym): PRope = var rettype, params: PRope - check: TIntSet # using static is needed for inline procs if (prc.typ.callConv == ccInline): result = toRope"static " - IntSetInit(check) + var check = initIntSet() fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown) genProcParams(m, prc.typ, rettype, params, check) appf(result, "$1($2, $3)$4", @@ -736,7 +734,7 @@ proc genTypeInfo(m: BModule, typ: PType): PRope = else: dataGenerated = true result = ropef("NTI$1", [toRope(id)]) - if not IntSetContainsOrIncl(m.typeInfoMarker, id): + if not ContainsOrIncl(m.typeInfoMarker, id): # declare type information structures: discard cgsym(m, "TNimType") discard cgsym(m, "TNimNode") diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e549f1101..449814d01 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -12,7 +12,7 @@ import ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, - options, + options, intsets, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, rodutils @@ -690,12 +690,12 @@ proc genProcPrototype(m: BModule, sym: PSym) = if lfNoDecl in sym.loc.Flags: return if lfDynamicLib in sym.loc.Flags: 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", "@$2 = linkonce global $1 zeroinitializer$n", [getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)]) 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)]) 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. # This also means that a check with ``gGeneratedSyms`` is wrong, we need # 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: - if not IntSetContainsOrIncl(gGeneratedSyms, prc.id): + if not ContainsOrIncl(gGeneratedSyms, prc.id): SymInDynamicLib(findPendingModule(m, prc), prc) elif not (sfImportc in prc.flags): - if not IntSetContainsOrIncl(gGeneratedSyms, prc.id): + if not ContainsOrIncl(gGeneratedSyms, prc.id): genProcAux(findPendingModule(m, prc), prc) proc genProc(m: BModule, prc: PSym) = @@ -726,7 +726,7 @@ proc genVarPrototype(m: BModule, sym: PSym) = useHeader(m, sym) fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap) if (lfNoDecl in sym.loc.Flags) or - intSetContainsOrIncl(m.declaredThings, sym.id): + ContainsOrIncl(m.declaredThings, sym.id): return if sym.owner.id != m.module.id: # else we already have the symbol generated! @@ -748,7 +748,7 @@ proc genConstPrototype(m: BModule, sym: PSym) = if sym.loc.k == locNone: fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown) if (lfNoDecl in sym.loc.Flags) or - intSetContainsOrIncl(m.declaredThings, sym.id): + ContainsOrIncl(m.declaredThings, sym.id): return if sym.owner.id != m.module.id: # 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 = new(result) InitLinkedList(result.headerFiles) - intSetInit(result.declaredThings) - intSetInit(result.declaredProtos) + result.declaredThings = initIntSet() + result.declaredProtos = initIntSet() result.cfilename = filename result.filename = filename initIdTable(result.typeCache) initIdTable(result.forwTypeCache) result.module = module - intSetInit(result.typeInfoMarker) + result.typeInfoMarker = initIntSet() result.initProc = newProc(nil, result) result.initProc.options = gOptions initNodeTable(result.dataCache) @@ -1037,4 +1037,4 @@ proc cgenPass(): TPass = result.close = myClose InitIiTable(gToTypeInfoId) -IntSetInit(gGeneratedSyms) +gGeneratedSyms = initIntSet() diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index dff844489..dd1ab944e 100755 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -10,7 +10,7 @@ ## This module implements code generation for multi methods. 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 = var dest = skipTypes(d, abstractPtrs) @@ -95,7 +95,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool = proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int = result = 0 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 bb = skipTypes(b.typ.sons[col], skipPtrs) var d = inheritanceDiff(aa, bb) @@ -132,7 +132,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym = var curr = methods[meth] # generate condition: var cond: PNode = nil for col in countup(1, paramLen - 1): - if IntSetContains(relevantCols, col): + if Contains(relevantCols, col): var isn = newNodeIT(nkCall, base.info, getSysType(tyBool)) addSon(isn, newSymNode(iss)) 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 proc generateMethodDispatchers*(): PNode = - var relevantCols: TIntSet result = newNode(nkStmtList) for bucket in countup(0, len(gMethods) - 1): - IntSetInit(relevantCols) + var relevantCols = initIntSet() 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) addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols))) diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index dc87d1924..592a24043 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -14,7 +14,8 @@ import ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, 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 # implementation @@ -67,7 +68,7 @@ type proc newGlobals(): PGlobals = new(result) - IntSetInit(result.typeInfoGenerated) + result.typeInfoGenerated = initIntSet() proc initCompRes(r: var TCompRes) = r.com = nil @@ -228,7 +229,7 @@ proc genTypeInfo(p: var TProc, typ: PType): PRope = var t = typ if t.kind == tyGenericInst: t = lastSon(t) 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 of tyDistinct: result = genTypeInfo(p, typ.sons[0]) diff --git a/compiler/importer.nim b/compiler/importer.nim index 06eebcb4e..6267cb68d 100755 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -10,8 +10,8 @@ # This module implements the symbol importing mechanism. import - strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups, semdata, - passes + intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups, + semdata, passes proc evalImport*(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 not (s.kind in OverloadableSyms): # s and check need to be qualified: - IntSetIncl(c.AmbiguousSymbols, copy.id) - IntSetIncl(c.AmbiguousSymbols, check.id) + Incl(c.AmbiguousSymbols, copy.id) + Incl(c.AmbiguousSymbols, check.id) StrTableAdd(c.tab.stack[importTablePos], copy) if s.kind == skType: var etyp = s.typ diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 0aaff6bc5..d72ec1555 100755 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -10,7 +10,8 @@ # This module implements lookup helpers. 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 = case n.kind @@ -115,7 +116,7 @@ proc lookUp*(c: PContext, n: PNode): PSym = result = SymtabGet(c.Tab, ident) if result == nil: GlobalError(n.info, errUndeclaredIdentifier, ident.s) else: InternalError(n.info, "lookUp") - if IntSetContains(c.AmbiguousSymbols, result.id): + if Contains(c.AmbiguousSymbols, result.id): LocalError(n.info, errUseQualifier, result.name.s) 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: GlobalError(n.info, errUndeclaredIdentifier, ident.s) elif checkAmbiguity in flags and result != nil and - IntSetContains(c.AmbiguousSymbols, result.id): + Contains(c.AmbiguousSymbols, result.id): LocalError(n.info, errUseQualifier, ident.s) of nkSym: result = n.sym - if checkAmbiguity in flags and IntSetContains(c.AmbiguousSymbols, - result.id): + if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id): LocalError(n.info, errUseQualifier, n.sym.name.s) of nkDotExpr: result = nil @@ -197,8 +197,8 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.mode = oimSymChoice result = n.sons[0].sym o.stackPtr = 1 - IntSetInit(o.inSymChoice) - IntSetIncl(o.inSymChoice, result.id) + o.inSymChoice = initIntSet() + Incl(o.inSymChoice, result.id) else: nil 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: if o.stackPtr < sonsLen(n): result = n.sons[o.stackPtr].sym - IntSetIncl(o.inSymChoice, result.id) + Incl(o.inSymChoice, result.id) inc(o.stackPtr) else: # try 'local' symbols too for Koenig's lookup: diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index ea427dce9..66cf7bd2c 100755 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -12,8 +12,8 @@ # writing of rod files is split into two different modules. import - os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, - ropes, idents, crc, rodread, passes, importer + intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform, + condsyms, ropes, idents, crc, rodread, passes, importer proc rodwritePass*(): TPass # implementation @@ -446,4 +446,4 @@ proc rodwritePass(): TPass = result.close = myClose result.process = process -IntSetInit(debugWritten) +debugWritten= initIntSet() diff --git a/compiler/sem.nim b/compiler/sem.nim index 533f93601..a22452b39 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -14,7 +14,7 @@ import wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, magicsys, parser, nversion, nimsets, semdata, evals, semfold, importer, procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest, - semthreads + semthreads, intsets proc semPass*(): TPass # implementation diff --git a/compiler/semdata.nim b/compiler/semdata.nim index a1a641ba4..7e40cd0a6 100755 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -10,7 +10,8 @@ # This module contains the data structures for the semantic checking phase. 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, magicsys, nversion, nimsets, parser, times, passes, rodread @@ -118,7 +119,7 @@ proc newOptionEntry(): POptionEntry = proc newContext(module: PSym, nimfile: string): PContext = new(result) InitSymTab(result.tab) - IntSetInit(result.AmbiguousSymbols) + result.AmbiguousSymbols = initIntset() initLinkedList(result.optionStack) initLinkedList(result.libs) append(result.optionStack, newOptionEntry()) @@ -127,7 +128,7 @@ proc newContext(module: PSym, nimfile: string): PContext = result.threadEntries = newNode(nkStmtList) result.converters = @[] result.filename = nimfile - IntSetInit(result.includedFiles) + result.includedFiles = initIntSet() initStrTable(result.userPragmas) proc addConverter(c: PContext, conv: PSym) = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 342d07cbf..dac72c2f0 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -888,11 +888,10 @@ proc checkPar(n: PNode): TParKind = return paNone proc semTupleFieldsConstr(c: PContext, n: PNode): PNode = - var ids: TIntSet result = newNodeI(nkPar, n.info) var typ = newTypeS(tyTuple, c) typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs - IntSetInit(ids) + var ids = initIntSet() for i in countup(0, sonsLen(n) - 1): if (n.sons[i].kind != nkExprColonExpr) or not (n.sons[i].sons[0].kind in {nkSym, nkIdent}): @@ -900,7 +899,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): PNode = var id: PIdent if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident 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) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1]) var f = newSymS(skField, n.sons[i].sons[0], c) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0c4ccef40..f074a00cd 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -476,11 +476,10 @@ proc semRaise(c: PContext, n: PNode): PNode = localError(n.info, errExprCannotBeRaised) proc semTry(c: PContext, n: PNode): PNode = - var check: TIntSet result = n checkMinSonsLen(n, 2) n.sons[0] = semStmtScope(c, n.sons[0]) - IntSetInit(check) + var check = initIntSet() for i in countup(1, sonsLen(n) - 1): var a = n.sons[i] checkMinSonsLen(a, 1) @@ -493,7 +492,7 @@ proc semTry(c: PContext, n: PNode): PNode = GlobalError(a.sons[j].info, errExprCannotBeRaised) a.sons[j] = newNodeI(nkType, a.sons[j].info) a.sons[j].typ = typ - if IntSetContainsOrIncl(check, typ.id): + if ContainsOrIncl(check, typ.id): localError(a.sons[j].info, errExceptionAlreadyHandled) elif a.kind != nkFinally: illFormedAst(n) @@ -820,10 +819,10 @@ proc evalInclude(c: PContext, n: PNode): PNode = for i in countup(0, sonsLen(n) - 1): var f = getModuleFile(n.sons[i]) var fileIndex = includeFilename(f) - if IntSetContainsOrIncl(c.includedFiles, fileIndex): + if ContainsOrIncl(c.includedFiles, fileIndex): GlobalError(n.info, errRecursiveDependencyX, f) addSon(result, semStmt(c, gIncludeFile(f))) - IntSetExcl(c.includedFiles, fileIndex) + Excl(c.includedFiles, fileIndex) proc SemStmt(c: PContext, n: PNode): PNode = const # must be last statements in a block: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 7782c7b42..dee703d30 100755 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -117,7 +117,7 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool, var s: PSym case n.kind 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) if (s != nil): result = newSymNode(s) @@ -125,7 +125,7 @@ proc resolveTemplateParams(c: PContext, n: PNode, withinBind: bool, else: result = n else: - IntSetIncl(toBind, n.ident.id) + Incl(toBind, n.ident.id) result = symChoice(c, n, lookup(c, n)) of nkEmpty, nkSym..nkNilLit: # atom result = n @@ -160,7 +160,6 @@ proc transformToExpr(n: PNode): PNode = proc semTemplateDef(c: PContext, n: PNode): PNode = var s: PSym - toBind: TIntSet if c.p.owner.kind == skModule: s = semIdentVis(c, skTemplate, n.sons[0], {sfStar}) incl(s.flags, sfGlobal) @@ -189,7 +188,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = s.typ.sons[0] = newTypeS(tyStmt, c) s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0]) addParams(c, s.typ.n) # resolve parameters: - IntSetInit(toBind) + var toBind = initIntSet() n.sons[codePos] = resolveTemplateParams(c, n.sons[codePos], false, toBind) if not (s.typ.sons[0].kind in {tyStmt, tyTypeDesc}): n.sons[codePos] = transformToExpr(n.sons[codePos]) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 91a00de11..ca46ea0e0 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -192,10 +192,9 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = proc semTuple(c: PContext, n: PNode, prev: PType): PType = var typ: PType - check: TIntSet result = newOrPrevType(tyTuple, prev, c) result.n = newNodeI(nkRecList, n.info) - IntSetInit(check) + var check = initIntSet() var counter = 0 for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] @@ -212,7 +211,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = field.typ = typ field.position = counter inc(counter) - if IntSetContainsOrIncl(check, field.name.id): + if ContainsOrIncl(check, field.name.id): GlobalError(a.sons[j].info, errAttemptToRedefine, field.name.s) addSon(result.n, newSymNode(field)) 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.flags = f.flags + ({sfImportc, sfExportc} * rectype.flags) inc(pos) - if IntSetContainsOrIncl(check, f.name.id): + if ContainsOrIncl(check, f.name.id): localError(n.sons[i].info, errAttemptToRedefine, f.name.s) if a.kind == nkEmpty: addSon(father, 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): addInheritedFieldsAux(c, check, pos, n.sons[i]) of nkSym: - IntSetIncl(check, n.sym.name.id) + Incl(check, n.sym.name.id) inc(pos) else: InternalError(n.info, "addInheritedFieldsAux()") @@ -437,8 +436,7 @@ proc skipGenericInvokation(t: PType): PType {.inline.} = result = lastSon(result) proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = - var check: TIntSet - IntSetInit(check) + var check = initIntSet() var pos = 0 var base: PType = nil # 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 = result = t if t == nil: return - if IntSetContainsOrIncl(cl, t.id): return + if ContainsOrIncl(cl, t.id): return case t.kind of tyGenericBody: #debug(t) @@ -470,7 +468,7 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode, if t.sons[i].kind != tyGenericParam: InternalError("addTypeVarsOfGenericBody") # 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) s.position = sonsLen(genericParams) if s.typ == nil or s.typ.kind != tyGenericParam: @@ -501,16 +499,17 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, var def, res: PNode typ: PType - check, cl: TIntSet + cl: TIntSet checkMinSonsLen(n, 1) result = newOrPrevType(tyProc, prev, c) result.callConv = lastOptionEntry(c).defaultCC 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 res = newNodeI(nkType, n.info) addSon(result.n, res) - IntSetInit(check) + var check = initIntSet() var counter = 0 for i in countup(1, sonsLen(n) - 1): var a = n.sons[i] @@ -539,7 +538,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, arg.position = counter inc(counter) 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) addSon(result.n, newSymNode(arg)) addSon(result, typ) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 5b397167a..c9ab27123 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -11,7 +11,7 @@ # the call to overloaded procs, generic procs and operators. import - ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, + intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, magicsys type @@ -608,7 +608,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate, # no error message! m.state = csNoMatch return - if IntSetContainsOrIncl(marker, formal.position): + if ContainsOrIncl(marker, formal.position): # already in namedParams: LocalError(n.sons[a].info, errCannotBindXTwice, formal.name.s) m.state = csNoMatch @@ -653,7 +653,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate, if m.callee.n.sons[f].kind != nkSym: InternalError(n.sons[a].info, "matches") formal = m.callee.n.sons[f].sym - if IntSetContainsOrIncl(marker, formal.position): + if ContainsOrIncl(marker, formal.position): # already in namedParams: LocalError(n.sons[a].info, errCannotBindXTwice, formal.name.s) 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) = # for 'suggest' support: - var marker: TIntSet - IntSetInit(marker) + var marker = initIntSet() matchesAux(c, n, m, marker) proc matches*(c: PContext, n: PNode, m: var TCandidate) = - var marker: TIntSet - IntSetInit(marker) + var marker = initIntSet() matchesAux(c, n, m, marker) if m.state == csNoMatch: return # check that every formal parameter got a value: var f = 1 while f < sonsLen(m.callee.n): 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.typ.kind == tyOpenArray: var container = newNodeI(nkBracket, n.info) diff --git a/compiler/transf.nim b/compiler/transf.nim index 9e38822c7..15deb266d 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -17,7 +17,7 @@ # * introduces method dispatchers 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 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 skTemp, skForVar, skParam: found = true else: nil - if found and (owner.id != s.owner.id) and - not IntSetContainsOrIncl(marked, s.id): + if found and (owner.id != s.owner.id) and not ContainsOrIncl(marked, s.id): incl(s.flags, sfInClosure) addSon(container, copyNode(n)) # DON'T make a copy of the symbol! of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: @@ -555,9 +554,8 @@ proc indirectAccess(a, b: PSym): PNode = result.typ = y.typ proc transformLambda(c: PTransf, n: PNode): PNode = - var marked: TIntSet + var marked = initIntSet() result = n - IntSetInit(marked) if (n.sons[namePos].kind != nkSym): InternalError(n.info, "transformLambda") var s = n.sons[namePos].sym var closure = newNodeI(nkRecList, n.sons[codePos].info) diff --git a/compiler/types.nim b/compiler/types.nim index 953366deb..8769993f2 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -10,7 +10,7 @@ # this module contains routines for accessing and iterating over types import - ast, astalgo, trees, msgs, strutils, platform + intsets, ast, astalgo, trees, msgs, strutils, platform proc firstOrd*(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 result = iter(t, closure) if result: return - if not IntSetContainsOrIncl(marker, t.id): + if not ContainsOrIncl(marker, t.id): case t.kind of tyGenericInst, tyGenericBody: 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) proc IterOverType(t: PType, iter: TTypeIter, closure: PObject): bool = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = iterOverTypeAux(marker, t, iter, closure) proc searchTypeForAux(t: PType, predicate: TTypePredicate, @@ -263,7 +262,7 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var TIntSet): # iterates over VALUE types! result = false if t == nil: return - if IntSetContainsOrIncl(marker, t.id): return + if ContainsOrIncl(marker, t.id): return result = Predicate(t) if result: return case t.kind @@ -280,8 +279,7 @@ proc searchTypeForAux(t: PType, predicate: TTypePredicate, marker: var TIntSet): nil proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = searchTypeForAux(t, predicate, marker) proc isObjectPredicate(t: PType): bool = @@ -322,8 +320,7 @@ proc analyseObjectWithTypeFieldAux(t: PType, marker: var TIntSet): TTypeFieldRes nil proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = analyseObjectWithTypeFieldAux(t, marker) 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 case t.kind 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): result = canFormAcycleAux(marker, t.sons[i], startId) if result: return @@ -376,8 +373,7 @@ proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool = nil proc canFormAcycle(typ: PType): bool = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = canFormAcycleAux(marker, typ, typ.id) proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, @@ -400,7 +396,7 @@ proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, result = nil if t == nil: return result = iter(t, closure) - if not IntSetContainsOrIncl(marker, t.id): + if not ContainsOrIncl(marker, t.id): for i in countup(0, sonsLen(t) - 1): result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure) 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) proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = mutateTypeAux(marker, t, iter, closure) proc rangeToStr(n: PNode): string = @@ -591,17 +586,14 @@ proc equalParam(a, b: PSym): TParamsEquality = result = paramsNotEqual proc equalParams(a, b: PNode): TParamsEquality = - var - length: int - m, n: PSym result = paramsEqual - length = sonsLen(a) + var length = sonsLen(a) if length != sonsLen(b): result = paramsNotEqual else: for i in countup(1, length - 1): - m = a.sons[i].sym - n = b.sons[i].sym + var m = a.sons[i].sym + var n = b.sons[i].sym assert((m.kind == skParam) and (n.kind == skParam)) case equalParam(m, n) 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; # however, both types may not have any field names (t.n may be nil) which # complicates the matter a bit. - var x, y: PSym if sonsLen(a) == sonsLen(b): result = true for i in countup(0, sonsLen(a) - 1): @@ -658,8 +649,8 @@ proc sameTuple(a, b: PType, DistinctOf: bool): bool = # check field names: if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple") if b.n.sons[i].kind != nkSym: InternalError(b.n.info, "sameTuple") - x = a.n.sons[i].sym - y = b.n.sons[i].sym + var x = a.n.sons[i].sym + var y = b.n.sons[i].sym result = x.name.id == y.name.id if not result: break else: @@ -758,17 +749,16 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool = if not result: return proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = - var t, t2: PType 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 - if typ == nil: - return # if we have already checked the type, return true, because we stop the - # evaluation if something is wrong: - if IntSetContainsOrIncl(marker, typ.id): return - t = skipTypes(typ, abstractInst) + if typ == nil: return + if ContainsOrIncl(marker, typ.id): return + var t = skipTypes(typ, abstractInst) case t.kind of tyVar: - t2 = skipTypes(t.sons[0], abstractInst) + var t2 = skipTypes(t.sons[0], abstractInst) case t2.kind of tyVar: 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) proc typeAllowed(t: PType, kind: TSymKind): bool = - var marker: TIntSet - IntSetInit(marker) + var marker = InitIntSet() result = typeAllowedAux(marker, t, kind) proc align(address, alignment: biggestInt): biggestInt = diff --git a/doc/lib.txt b/doc/lib.txt index 23dd93aea..6effabe0b 100755 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -42,6 +42,9 @@ Core Contains procs for serialization and deseralization of arbitrary Nimrod data structures. +* `typeinfo <typeinfo.html>`_ + Provides (unsafe) access to Nimrod's run time type information. + Collections and algorithms -------------------------- @@ -53,7 +56,9 @@ Collections and algorithms * `lists <lists.html>`_ Nimrod linked list support. Contains singly and doubly linked lists and circular lists ("rings"). - +* `intsets <intsets.html>`_ + Efficient implementation of a set of ints as a sparse bit set. + String handling --------------- diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim new file mode 100644 index 000000000..bbe6a674b --- /dev/null +++ b/lib/pure/collections/intsets.nim @@ -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 + + diff --git a/lib/system/cntbits.nim b/lib/system/cntbits.nim deleted file mode 100755 index 281b96dd0..000000000 --- a/lib/system/cntbits.nim +++ /dev/null @@ -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. -# - - - - diff --git a/todo.txt b/todo.txt index 5ab4d3be6..873cf8bf9 100755 --- a/todo.txt +++ b/todo.txt @@ -78,7 +78,7 @@ Low priority Library ------- -- specialized bit sets; specialized string sets +- radix tree for strings; maybe suffix tree - locale support - conversion between character sets - bignums diff --git a/web/news.txt b/web/news.txt index f048ae541..d9b0ef6b2 100755 --- a/web/news.txt +++ b/web/news.txt @@ -51,6 +51,7 @@ Additions - Added ``lists`` module which contains generic linked lists. - Added ``sets`` module which contains generic hash sets. - Added ``tables`` module which contains generic hash tables. +- Added ``intsets`` module which contains a specialized int set data type. - Added ``scgi`` module. - Added ``smtp`` module. - Added ``re.findAll``, ``pegs.findAll``. diff --git a/web/nimrod.ini b/web/nimrod.ini index a7bee7492..e9562eb3a 100755 --- a/web/nimrod.ini +++ b/web/nimrod.ini @@ -24,7 +24,7 @@ file: ticker doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview" doc: "tools;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: "system.nim;system/threads.nim;pure/os;pure/strutils;pure/math" 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: "impure/rdstdin;wrappers/zmq" 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/sqlite3;wrappers/postgres;wrappers/tinyc" |