Skip to content

bring back id table algorithm instead of std table [backport:2.2] #24930

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,15 @@ type

TPairSeq* = seq[TPair]

TIdPair*[T] = object
key*: ItemId
val*: T

TIdPairSeq*[T] = seq[TIdPair[T]]
TIdTable*[T] = object
counter*: int
data*: TIdPairSeq[T]

TNodePair* = object
h*: Hash # because it is expensive to compute!
key*: PNode
Expand Down Expand Up @@ -939,9 +948,11 @@ proc getPIdent*(a: PNode): PIdent {.inline.} =
const
moduleShift = when defined(cpu32): 20 else: 24

template id*(a: PType | PSym): int =
template toId*(a: ItemId): int =
let x = a
(x.itemId.module.int shl moduleShift) + x.itemId.item.int
(x.module.int shl moduleShift) + x.item.int

template id*(a: PType | PSym): int = toId(a.itemId)

type
IdGenerator* = ref object # unfortunately, we really need the 'shared mutable' aspect here.
Expand Down Expand Up @@ -1268,6 +1279,11 @@ proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
setLen(dest.data, src.data.len)
for i in 0..high(src.data): dest.data[i] = src.data[i]

proc copyIdTable*[T](dest: var TIdTable[T], src: TIdTable[T]) =
dest.counter = src.counter
newSeq(dest.data, src.data.len)
for i in 0..high(src.data): dest.data[i] = src.data[i]

proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
dest.counter = src.counter
setLen(dest.data, src.data.len)
Expand Down Expand Up @@ -1606,6 +1622,16 @@ proc initStrTable*(): TStrTable =
result = TStrTable(counter: 0)
newSeq(result.data, StartSize)

proc initIdTable*[T](): TIdTable[T] =
result = TIdTable[T](counter: 0)
newSeq(result.data, StartSize)

proc resetIdTable*[T](x: var TIdTable[T]) =
x.counter = 0
# clear and set to old initial size:
setLen(x.data, 0)
setLen(x.data, StartSize)

proc initObjectSet*(): TObjectSet =
result = TObjectSet(counter: 0)
newSeq(result.data, StartSize)
Expand Down Expand Up @@ -2134,14 +2160,8 @@ proc isTrue*(n: PNode): bool =
n.kind == nkIntLit and n.intVal != 0

type
TypeMapping* = Table[ItemId, PType]
SymMapping* = Table[ItemId, PSym]

template idTableGet*(tab: typed; key: PSym | PType): untyped = tab.getOrDefault(key.itemId)
template idTablePut*(tab: typed; key, val: PSym | PType) = tab[key.itemId] = val

template initSymMapping*(): Table[ItemId, PSym] = initTable[ItemId, PSym]()
template initTypeMapping*(): Table[ItemId, PType] = initTable[ItemId, PType]()
TypeMapping* = TIdTable[PType]
SymMapping* = TIdTable[PSym]

template resetIdTable*(tab: Table[ItemId, PSym]) = tab.clear()
template resetIdTable*(tab: Table[ItemId, PType]) = tab.clear()
template initSymMapping*(): SymMapping = initIdTable[PSym]()
template initTypeMapping*(): TypeMapping = initIdTable[PType]()
64 changes: 64 additions & 0 deletions compiler/astalgo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,70 @@ iterator items*(tab: TStrTable): PSym =
yield s
s = nextIter(it, tab)

proc isNil(x: ItemId): bool {.inline.} =
x.module == 0 and x.item == 0

proc hasEmptySlot[T](data: TIdPairSeq[T]): bool =
for h in 0..high(data):
if isNil(data[h].key):
return true
result = false

proc idTableRawGet[T](t: TIdTable[T], key: int): int =
var h: Hash
h = key and high(t.data) # start with real hash value
while not isNil(t.data[h].key):
if toId(t.data[h].key) == key:
return h
h = nextTry(h, high(t.data))
result = - 1

proc getOrDefault*[T](t: TIdTable[T], key: ItemId): T =
var index = idTableRawGet(t, toId(key))
if index >= 0: result = t.data[index].val
else: result = default(T)

template idTableGet*[T](t: TIdTable[T], key: PType | PSym): T =
getOrDefault(t, key.itemId)

proc idTableRawInsert[T](data: var TIdPairSeq[T], key: ItemId, val: T) =
var h: Hash
let keyId = toId(key)
h = keyId and high(data)
while not isNil(data[h].key):
assert(toId(data[h].key) != keyId)
h = nextTry(h, high(data))
assert(isNil(data[h].key))
data[h].key = key
data[h].val = val

proc `[]=`*[T](t: var TIdTable[T], key: ItemId, val: T) =
var
index: int
n: TIdPairSeq[T]
index = idTableRawGet(t, toId(key))
if index >= 0:
assert(not isNil(t.data[index].key))
t.data[index].val = val
else:
if mustRehash(t.data.len, t.counter):
newSeq(n, t.data.len * GrowthFactor)
for i in 0..high(t.data):
if not isNil(t.data[i].key):
idTableRawInsert(n, t.data[i].key, t.data[i].val)
assert(hasEmptySlot(n))
swap(t.data, n)
idTableRawInsert(t.data, key, val)
inc(t.counter)

template idTablePut*[T](t: var TIdTable[T], key: PType | PSym, val: T) =
t[key.itemId] = val

iterator idTablePairs*[T](t: TIdTable[T]): tuple[key: ItemId, val: T] =
for i in 0..high(t.data):
if not isNil(t.data[i].key):
yield (t.data[i].key, t.data[i].val)

proc initIITable(x: var TIITable) =
x.counter = 0
newSeq(x.data, StartSize)
Expand Down
9 changes: 5 additions & 4 deletions compiler/layeredtable.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import std/[tables]
import ast
import ast, astalgo

type
LayeredIdTableObj* {.acyclic.} = object
Expand Down Expand Up @@ -28,14 +28,15 @@ proc shallowCopy*(pt: LayeredIdTable): LayeredIdTable {.inline.} =
## copies only the type bindings of the current layer, but not any parent layers,
## useful for write-only bindings
result = LayeredIdTable(topLayer: pt.topLayer, nextLayer: pt.nextLayer, previousLen: pt.previousLen)
#copyIdTable(result.topLayer, pt.topLayer)

proc currentLen*(pt: LayeredIdTable): int =
## the sum of the cached total binding count of the parents and
## the current binding count, just used to track if bindings were added
pt.previousLen + pt.topLayer.len
pt.previousLen + pt.topLayer.counter

proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable =
result = LayeredIdTable(topLayer: initTable[ItemId, PType](), previousLen: pt.currentLen)
result = LayeredIdTable(topLayer: initTypeMapping(), previousLen: pt.currentLen)
when useRef:
result.nextLayer = pt
else:
Expand All @@ -56,7 +57,7 @@ proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} =
iterator pairs*(pt: LayeredIdTable): (ItemId, PType) =
var tm = pt
while true:
for (k, v) in pairs(tm.topLayer):
for (k, v) in idTablePairs(tm.topLayer):
yield (k, v)
if tm.nextLayer == nil:
break
Expand Down
6 changes: 3 additions & 3 deletions compiler/semcall.nim
Original file line number Diff line number Diff line change
Expand Up @@ -907,15 +907,15 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
if c.inGenericContext > 0 and c.matchedConcept == nil:
result = semGenericStmt(c, n)
result.typ() = makeTypeFromExpr(c, result.copyTree)
elif efNoUndeclared in flags:
result = nil
elif efExplain notin flags:
# repeat the overload resolution,
# this time enabling all the diagnostic output (this should fail again)
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
elif efNoUndeclared notin flags:
result = nil
notFoundError(c, n, errors)
else:
result = nil
notFoundError(c, n, errors)

proc explicitGenericInstError(c: PContext; n: PNode): PNode =
localError(c.config, getCallLineInfo(n), errCannotInstantiateX % renderTree(n))
Expand Down
6 changes: 3 additions & 3 deletions compiler/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ when defined(nimPreviewSlimSystem):
import
options, ast, msgs, idents, renderer,
magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable,
types, lowerings, trees, parampatterns
types, lowerings, trees, parampatterns, astalgo

import ic / ic

Expand All @@ -42,7 +42,7 @@ type
breakInLoop*: bool # whether we are in a loop without block
next*: PProcCon # used for stacking procedure contexts
mappingExists*: bool
mapping*: Table[ItemId, PSym]
mapping*: SymMapping
caseContext*: seq[tuple[n: PNode, idx: int]]
localBindStmts*: seq[PNode]

Expand Down Expand Up @@ -260,7 +260,7 @@ proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next

proc put*(p: PProcCon; key, val: PSym) =
if not p.mappingExists:
p.mapping = initTable[ItemId, PSym]()
p.mapping = initSymMapping()
p.mappingExists = true
#echo "put into table ", key.info
p.mapping[key.itemId] = val
Expand Down
4 changes: 2 additions & 2 deletions compiler/semtypinst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ type
TReplTypeVars* = object
c*: PContext
typeMap*: LayeredIdTable # map PType to PType
symMap*: SymMapping # map PSym to PSym
localCache*: TypeMapping # local cache for remembering already replaced
symMap*: SymMapping # map PSym to PSym
localCache*: TypeMapping # local cache for remembering already replaced
# types during instantiation of meta types
# (they are not stored in the global cache)
info*: TLineInfo
Expand Down
4 changes: 2 additions & 2 deletions compiler/transf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import closureiters, lambdalifting

type
PTransCon = ref object # part of TContext; stackable
mapping: Table[ItemId, PNode] # mapping from symbols to nodes
mapping: TIdTable[PNode] # mapping from symbols to nodes
owner: PSym # current owner
forStmt: PNode # current for stmt
forLoopBody: PNode # transformed for loop body
Expand Down Expand Up @@ -78,7 +78,7 @@ proc newTransNode(kind: TNodeKind, n: PNode,

proc newTransCon(owner: PSym): PTransCon =
assert owner != nil
result = PTransCon(mapping: initTable[ItemId, PNode](), owner: owner)
result = PTransCon(mapping: initIdTable[PNode](), owner: owner)

proc pushTransCon(c: PTransf, t: PTransCon) =
t.next = c.transCon
Expand Down