mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
bring back id table algorithm instead of std table [backport:2.2] (#24930)
refs #24929, partially reverts #23403
Instead of using `Table[ItemId, T]`, the old algorithm is brought back
into `TIdTable[T]` to prevent a performance regression. The inheritance
removal from #23403 still holds, only `ItemId`s are stored.
(cherry picked from commit 82553384d1)
This commit is contained in:
@@ -796,6 +796,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
|
||||
@@ -940,9 +949,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.
|
||||
@@ -1269,6 +1280,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)
|
||||
@@ -1607,6 +1623,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)
|
||||
@@ -2135,14 +2161,8 @@ proc isTrue*(n: PNode): bool =
|
||||
n.kind == nkIntLit and n.intVal != 0
|
||||
|
||||
type
|
||||
TypeMapping* = Table[ItemId, PType]
|
||||
SymMapping* = Table[ItemId, PSym]
|
||||
TypeMapping* = TIdTable[PType]
|
||||
SymMapping* = TIdTable[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]()
|
||||
|
||||
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]()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import std/[tables]
|
||||
import ast
|
||||
import ast, astalgo
|
||||
|
||||
type
|
||||
LayeredIdTableObj* {.acyclic.} = object
|
||||
@@ -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:
|
||||
@@ -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
|
||||
|
||||
@@ -909,15 +909,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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -258,7 +258,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user