mirror of
https://github.com/nim-lang/Nim.git
synced 2026-05-01 03:24: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]
|
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
|
TNodePair* = object
|
||||||
h*: Hash # because it is expensive to compute!
|
h*: Hash # because it is expensive to compute!
|
||||||
key*: PNode
|
key*: PNode
|
||||||
@@ -940,9 +949,11 @@ proc getPIdent*(a: PNode): PIdent {.inline.} =
|
|||||||
const
|
const
|
||||||
moduleShift = when defined(cpu32): 20 else: 24
|
moduleShift = when defined(cpu32): 20 else: 24
|
||||||
|
|
||||||
template id*(a: PType | PSym): int =
|
template toId*(a: ItemId): int =
|
||||||
let x = a
|
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
|
type
|
||||||
IdGenerator* = ref object # unfortunately, we really need the 'shared mutable' aspect here.
|
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)
|
setLen(dest.data, src.data.len)
|
||||||
for i in 0..high(src.data): dest.data[i] = src.data[i]
|
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) =
|
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||||
dest.counter = src.counter
|
dest.counter = src.counter
|
||||||
setLen(dest.data, src.data.len)
|
setLen(dest.data, src.data.len)
|
||||||
@@ -1607,6 +1623,16 @@ proc initStrTable*(): TStrTable =
|
|||||||
result = TStrTable(counter: 0)
|
result = TStrTable(counter: 0)
|
||||||
newSeq(result.data, StartSize)
|
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 =
|
proc initObjectSet*(): TObjectSet =
|
||||||
result = TObjectSet(counter: 0)
|
result = TObjectSet(counter: 0)
|
||||||
newSeq(result.data, StartSize)
|
newSeq(result.data, StartSize)
|
||||||
@@ -2135,14 +2161,8 @@ proc isTrue*(n: PNode): bool =
|
|||||||
n.kind == nkIntLit and n.intVal != 0
|
n.kind == nkIntLit and n.intVal != 0
|
||||||
|
|
||||||
type
|
type
|
||||||
TypeMapping* = Table[ItemId, PType]
|
TypeMapping* = TIdTable[PType]
|
||||||
SymMapping* = Table[ItemId, PSym]
|
SymMapping* = TIdTable[PSym]
|
||||||
|
|
||||||
template idTableGet*(tab: typed; key: PSym | PType): untyped = tab.getOrDefault(key.itemId)
|
template initSymMapping*(): SymMapping = initIdTable[PSym]()
|
||||||
template idTablePut*(tab: typed; key, val: PSym | PType) = tab[key.itemId] = val
|
template initTypeMapping*(): TypeMapping = initIdTable[PType]()
|
||||||
|
|
||||||
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()
|
|
||||||
|
|||||||
@@ -713,6 +713,70 @@ iterator items*(tab: TStrTable): PSym =
|
|||||||
yield s
|
yield s
|
||||||
s = nextIter(it, tab)
|
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) =
|
proc initIITable(x: var TIITable) =
|
||||||
x.counter = 0
|
x.counter = 0
|
||||||
newSeq(x.data, StartSize)
|
newSeq(x.data, StartSize)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import std/[tables]
|
import std/[tables]
|
||||||
import ast
|
import ast, astalgo
|
||||||
|
|
||||||
type
|
type
|
||||||
LayeredIdTableObj* {.acyclic.} = object
|
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,
|
## copies only the type bindings of the current layer, but not any parent layers,
|
||||||
## useful for write-only bindings
|
## useful for write-only bindings
|
||||||
result = LayeredIdTable(topLayer: pt.topLayer, nextLayer: pt.nextLayer, previousLen: pt.previousLen)
|
result = LayeredIdTable(topLayer: pt.topLayer, nextLayer: pt.nextLayer, previousLen: pt.previousLen)
|
||||||
|
#copyIdTable(result.topLayer, pt.topLayer)
|
||||||
|
|
||||||
proc currentLen*(pt: LayeredIdTable): int =
|
proc currentLen*(pt: LayeredIdTable): int =
|
||||||
## the sum of the cached total binding count of the parents and
|
## the sum of the cached total binding count of the parents and
|
||||||
## the current binding count, just used to track if bindings were added
|
## 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 =
|
proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable =
|
||||||
result = LayeredIdTable(topLayer: initTable[ItemId, PType](), previousLen: pt.currentLen)
|
result = LayeredIdTable(topLayer: initTypeMapping(), previousLen: pt.currentLen)
|
||||||
when useRef:
|
when useRef:
|
||||||
result.nextLayer = pt
|
result.nextLayer = pt
|
||||||
else:
|
else:
|
||||||
@@ -56,7 +57,7 @@ proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} =
|
|||||||
iterator pairs*(pt: LayeredIdTable): (ItemId, PType) =
|
iterator pairs*(pt: LayeredIdTable): (ItemId, PType) =
|
||||||
var tm = pt
|
var tm = pt
|
||||||
while true:
|
while true:
|
||||||
for (k, v) in pairs(tm.topLayer):
|
for (k, v) in idTablePairs(tm.topLayer):
|
||||||
yield (k, v)
|
yield (k, v)
|
||||||
if tm.nextLayer == nil:
|
if tm.nextLayer == nil:
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -909,15 +909,15 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
|||||||
if c.inGenericContext > 0 and c.matchedConcept == nil:
|
if c.inGenericContext > 0 and c.matchedConcept == nil:
|
||||||
result = semGenericStmt(c, n)
|
result = semGenericStmt(c, n)
|
||||||
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
result.typ() = makeTypeFromExpr(c, result.copyTree)
|
||||||
|
elif efNoUndeclared in flags:
|
||||||
|
result = nil
|
||||||
elif efExplain notin flags:
|
elif efExplain notin flags:
|
||||||
# repeat the overload resolution,
|
# repeat the overload resolution,
|
||||||
# this time enabling all the diagnostic output (this should fail again)
|
# this time enabling all the diagnostic output (this should fail again)
|
||||||
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
|
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
|
||||||
elif efNoUndeclared notin flags:
|
|
||||||
result = nil
|
|
||||||
notFoundError(c, n, errors)
|
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
|
notFoundError(c, n, errors)
|
||||||
|
|
||||||
proc explicitGenericInstError(c: PContext; n: PNode): PNode =
|
proc explicitGenericInstError(c: PContext; n: PNode): PNode =
|
||||||
localError(c.config, getCallLineInfo(n), errCannotInstantiateX % renderTree(n))
|
localError(c.config, getCallLineInfo(n), errCannotInstantiateX % renderTree(n))
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ when defined(nimPreviewSlimSystem):
|
|||||||
import
|
import
|
||||||
options, ast, msgs, idents, renderer,
|
options, ast, msgs, idents, renderer,
|
||||||
magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable,
|
magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable,
|
||||||
types, lowerings, trees, parampatterns
|
types, lowerings, trees, parampatterns, astalgo
|
||||||
|
|
||||||
import ic / ic
|
import ic / ic
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ type
|
|||||||
breakInLoop*: bool # whether we are in a loop without block
|
breakInLoop*: bool # whether we are in a loop without block
|
||||||
next*: PProcCon # used for stacking procedure contexts
|
next*: PProcCon # used for stacking procedure contexts
|
||||||
mappingExists*: bool
|
mappingExists*: bool
|
||||||
mapping*: Table[ItemId, PSym]
|
mapping*: SymMapping
|
||||||
caseContext*: seq[tuple[n: PNode, idx: int]]
|
caseContext*: seq[tuple[n: PNode, idx: int]]
|
||||||
localBindStmts*: seq[PNode]
|
localBindStmts*: seq[PNode]
|
||||||
|
|
||||||
@@ -258,7 +258,7 @@ proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
|
|||||||
|
|
||||||
proc put*(p: PProcCon; key, val: PSym) =
|
proc put*(p: PProcCon; key, val: PSym) =
|
||||||
if not p.mappingExists:
|
if not p.mappingExists:
|
||||||
p.mapping = initTable[ItemId, PSym]()
|
p.mapping = initSymMapping()
|
||||||
p.mappingExists = true
|
p.mappingExists = true
|
||||||
#echo "put into table ", key.info
|
#echo "put into table ", key.info
|
||||||
p.mapping[key.itemId] = val
|
p.mapping[key.itemId] = val
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ type
|
|||||||
TReplTypeVars* = object
|
TReplTypeVars* = object
|
||||||
c*: PContext
|
c*: PContext
|
||||||
typeMap*: LayeredIdTable # map PType to PType
|
typeMap*: LayeredIdTable # map PType to PType
|
||||||
symMap*: SymMapping # map PSym to PSym
|
symMap*: SymMapping # map PSym to PSym
|
||||||
localCache*: TypeMapping # local cache for remembering already replaced
|
localCache*: TypeMapping # local cache for remembering already replaced
|
||||||
# types during instantiation of meta types
|
# types during instantiation of meta types
|
||||||
# (they are not stored in the global cache)
|
# (they are not stored in the global cache)
|
||||||
info*: TLineInfo
|
info*: TLineInfo
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import closureiters, lambdalifting
|
|||||||
|
|
||||||
type
|
type
|
||||||
PTransCon = ref object # part of TContext; stackable
|
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
|
owner: PSym # current owner
|
||||||
forStmt: PNode # current for stmt
|
forStmt: PNode # current for stmt
|
||||||
forLoopBody: PNode # transformed for loop body
|
forLoopBody: PNode # transformed for loop body
|
||||||
@@ -78,7 +78,7 @@ proc newTransNode(kind: TNodeKind, n: PNode,
|
|||||||
|
|
||||||
proc newTransCon(owner: PSym): PTransCon =
|
proc newTransCon(owner: PSym): PTransCon =
|
||||||
assert owner != nil
|
assert owner != nil
|
||||||
result = PTransCon(mapping: initTable[ItemId, PNode](), owner: owner)
|
result = PTransCon(mapping: initIdTable[PNode](), owner: owner)
|
||||||
|
|
||||||
proc pushTransCon(c: PTransf, t: PTransCon) =
|
proc pushTransCon(c: PTransf, t: PTransCon) =
|
||||||
t.next = c.transCon
|
t.next = c.transCon
|
||||||
|
|||||||
Reference in New Issue
Block a user