mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-17 18:17:11 +00:00
use cbuilder for seq type generation (#24202)
`addSimpleStruct` is just so the compiler doesn't use so much extra computation on analyzing the `typ` parameter for `addStruct`, which doesn't change anything for `seq` types. We could probably still get away with using `addStruct` instead, or making `addStruct` accept `nil` as the `typ` argument but this would be even more computation. There were a lot of hidden issues with `addStruct` being a template & template argument substitution, so most of the behavior is moved into `startStruct`/`finishStruct` procs. This is turning out to be a lot of code for just a couple of changed lines, we might have to split `cbuilder` into multiple modules.
This commit is contained in:
@@ -5,14 +5,19 @@ type
|
||||
template newBuilder(s: string): Builder =
|
||||
s
|
||||
|
||||
proc addField(obj: var Builder; name, typ: Snippet) =
|
||||
proc addField(obj: var Builder; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
|
||||
obj.add('\t')
|
||||
obj.add(typ)
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
if isFlexArray:
|
||||
obj.add("[SEQ_DECL_SIZE]")
|
||||
if initializer.len != 0:
|
||||
obj.add(initializer)
|
||||
obj.add(";\n")
|
||||
|
||||
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool; initializer: Snippet) =
|
||||
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
|
||||
## for fields based on an `skField` symbol
|
||||
obj.add('\t')
|
||||
if field.alignment > 0:
|
||||
obj.add("NIM_ALIGN(")
|
||||
@@ -32,6 +37,13 @@ proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bo
|
||||
obj.add(initializer)
|
||||
obj.add(";\n")
|
||||
|
||||
type
|
||||
BaseClassKind = enum
|
||||
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
|
||||
StructBuilderInfo = object
|
||||
baseKind: BaseClassKind
|
||||
preFieldsLen: int
|
||||
|
||||
proc structOrUnion(t: PType): Snippet =
|
||||
let t = t.skipTypes({tyAlias, tySink})
|
||||
if tfUnion in t.flags: "union"
|
||||
@@ -40,47 +52,80 @@ proc structOrUnion(t: PType): Snippet =
|
||||
proc ptrType(t: Snippet): Snippet =
|
||||
t & "*"
|
||||
|
||||
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: string; body: typed) =
|
||||
if tfPacked in typ.flags:
|
||||
if hasAttribute in CC[m.config.cCompiler].props:
|
||||
obj.add(structOrUnion(typ))
|
||||
obj.add(" __attribute__((__packed__))")
|
||||
else:
|
||||
obj.add("#pragma pack(push, 1)\n")
|
||||
obj.add(structOrUnion(typ))
|
||||
else:
|
||||
obj.add(structOrUnion(typ))
|
||||
obj.add(" ")
|
||||
proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet): StructBuilderInfo =
|
||||
result = StructBuilderInfo(baseKind: bcNone)
|
||||
obj.add("struct ")
|
||||
obj.add(name)
|
||||
type BaseClassKind = enum
|
||||
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
|
||||
var baseKind = bcNone
|
||||
if typ.kind == tyObject:
|
||||
if typ.baseClass == nil:
|
||||
if lacksMTypeField(typ):
|
||||
baseKind = bcNone
|
||||
elif optTinyRtti in m.config.globalOptions:
|
||||
baseKind = bcNoneTinyRtti
|
||||
else:
|
||||
baseKind = bcNoneRtti
|
||||
elif m.compileToCpp:
|
||||
baseKind = bcCppInherit
|
||||
if baseType.len != 0:
|
||||
if m.compileToCpp:
|
||||
result.baseKind = bcCppInherit
|
||||
else:
|
||||
baseKind = bcSupField
|
||||
if baseKind == bcCppInherit:
|
||||
result.baseKind = bcSupField
|
||||
if result.baseKind == bcCppInherit:
|
||||
obj.add(" : public ")
|
||||
obj.add(baseType)
|
||||
obj.add(" ")
|
||||
obj.add("{\n")
|
||||
let currLen = obj.len
|
||||
case baseKind
|
||||
result.preFieldsLen = obj.len
|
||||
if result.baseKind == bcSupField:
|
||||
obj.addField(name = "Sup", typ = baseType)
|
||||
|
||||
proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
|
||||
if info.baseKind == bcNone and info.preFieldsLen == obj.len:
|
||||
# no fields were added, add dummy field
|
||||
obj.addField(name = "dummy", typ = "char")
|
||||
obj.add("};\n")
|
||||
|
||||
template addSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet; body: typed) =
|
||||
## for independent structs, not directly based on a Nim type
|
||||
let info = startSimpleStruct(obj, m, name, baseType)
|
||||
body
|
||||
finishSimpleStruct(obj, m, info)
|
||||
|
||||
proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType: Snippet): StructBuilderInfo =
|
||||
result = StructBuilderInfo(baseKind: bcNone)
|
||||
if tfPacked in t.flags:
|
||||
if hasAttribute in CC[m.config.cCompiler].props:
|
||||
obj.add(structOrUnion(t))
|
||||
obj.add(" __attribute__((__packed__))")
|
||||
else:
|
||||
obj.add("#pragma pack(push, 1)\n")
|
||||
obj.add(structOrUnion(t))
|
||||
else:
|
||||
obj.add(structOrUnion(t))
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
if t.kind == tyObject:
|
||||
if t.baseClass == nil:
|
||||
if lacksMTypeField(t):
|
||||
result.baseKind = bcNone
|
||||
elif optTinyRtti in m.config.globalOptions:
|
||||
result.baseKind = bcNoneTinyRtti
|
||||
else:
|
||||
result.baseKind = bcNoneRtti
|
||||
elif m.compileToCpp:
|
||||
result.baseKind = bcCppInherit
|
||||
else:
|
||||
result.baseKind = bcSupField
|
||||
elif baseType.len != 0:
|
||||
if m.compileToCpp:
|
||||
result.baseKind = bcCppInherit
|
||||
else:
|
||||
result.baseKind = bcSupField
|
||||
if result.baseKind == bcCppInherit:
|
||||
obj.add(" : public ")
|
||||
obj.add(baseType)
|
||||
obj.add(" ")
|
||||
obj.add("{\n")
|
||||
result.preFieldsLen = obj.len
|
||||
case result.baseKind
|
||||
of bcNone:
|
||||
# rest of the options add a field or don't need it due to inheritance,
|
||||
# we need to add the dummy field for uncheckedarray ahead of time
|
||||
# so that it remains trailing
|
||||
if typ.itemId notin m.g.graph.memberProcsPerType and
|
||||
typ.n != nil and typ.n.len == 1 and typ.n[0].kind == nkSym and
|
||||
typ.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
|
||||
if t.itemId notin m.g.graph.memberProcsPerType and
|
||||
t.n != nil and t.n.len == 1 and t.n[0].kind == nkSym and
|
||||
t.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
|
||||
# only consists of flexible array field, add *initial* dummy field
|
||||
obj.addField(name = "dummy", typ = "char")
|
||||
of bcCppInherit: discard
|
||||
@@ -90,13 +135,21 @@ template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseT
|
||||
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
|
||||
of bcSupField:
|
||||
obj.addField(name = "Sup", typ = baseType)
|
||||
body
|
||||
if baseKind == bcNone and currLen == obj.len and typ.itemId notin m.g.graph.memberProcsPerType:
|
||||
|
||||
proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
|
||||
if info.baseKind == bcNone and info.preFieldsLen == obj.len and
|
||||
t.itemId notin m.g.graph.memberProcsPerType:
|
||||
# no fields were added, add dummy field
|
||||
obj.addField(name = "dummy", typ = "char")
|
||||
obj.add("};\n")
|
||||
if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
||||
result.add("#pragma pack(pop)\n")
|
||||
if tfPacked in t.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
||||
obj.add("#pragma pack(pop)\n")
|
||||
|
||||
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: Snippet; body: typed) =
|
||||
## for structs built directly from a Nim type
|
||||
let info = startStruct(obj, m, typ, name, baseType)
|
||||
body
|
||||
finishStruct(obj, m, typ, info)
|
||||
|
||||
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
|
||||
## adds a field with a `struct { ... }` type, building it according to `body`
|
||||
|
||||
@@ -967,18 +967,14 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
|
||||
m.typeCache[sig] = result & seqStar(m)
|
||||
if not isImportedType(t):
|
||||
if skipTypes(t.elementType, typedescInst).kind != tyEmpty:
|
||||
const
|
||||
cppSeq = "struct $2 : #TGenericSeq {$n"
|
||||
cSeq = "struct $2 {$n" &
|
||||
" #TGenericSeq Sup;$n"
|
||||
if m.compileToCpp:
|
||||
appcg(m, m.s[cfsSeqTypes],
|
||||
cppSeq & " $1 data[SEQ_DECL_SIZE];$n" &
|
||||
"};$n", [getTypeDescAux(m, t.elementType, check, kind), result])
|
||||
else:
|
||||
appcg(m, m.s[cfsSeqTypes],
|
||||
cSeq & " $1 data[SEQ_DECL_SIZE];$n" &
|
||||
"};$n", [getTypeDescAux(m, t.elementType, check, kind), result])
|
||||
var struct = newBuilder("")
|
||||
let baseType = cgsymValue(m, "TGenericSeq")
|
||||
struct.addSimpleStruct(m, name = result, baseType = baseType):
|
||||
struct.addField(
|
||||
name = "data",
|
||||
typ = getTypeDescAux(m, t.elementType, check, kind),
|
||||
isFlexArray = true)
|
||||
m.s[cfsSeqTypes].add struct
|
||||
else:
|
||||
result = rope("TGenericSeq")
|
||||
result.add(seqStar(m))
|
||||
|
||||
Reference in New Issue
Block a user