Skip to content

Commit 0f88a64

Browse files
authored
Merge pull request #2888 from GaijinEntertainment/bbatkin/linq-fold-pattern-table-prd3
linq_fold: PR D3 — full GroupBySourceAdapter melt (closes masterplan refactor)
2 parents 574b031 + 093a2da commit 0f88a64

2 files changed

Lines changed: 26 additions & 128 deletions

File tree

daslib/linq_fold.das

Lines changed: 21 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,7 @@ def private finalize_emission_stmts(top : Expression?; srcName : string; at : Li
16731673

16741674
// The per-element bind name emit fns peel where/select/key/value lambdas against. Drives build_decs_inner_for_pruned's
16751675
// pattern matching, so the decs side MUST use `decs_tup`. DecsJoin carries the per-pair result-lam bind name in its payload.
1676+
[macro_function]
16761677
def private adapter_bind_name(adapter : SourceAdapter; at : LineInfo) : string {
16771678
return (adapter as DecsJoin).resBindName if (adapter is DecsJoin)
16781679
return qn("decs_tup", at) if (adapter is Decs)
@@ -4156,88 +4157,6 @@ def private expr_uses_var(var e : Expression?; name : string) : bool {
41564157

41574158
// ── group_by core (shared between array and decs sources) ──────────────────────
41584159

4159-
// Source-loop adapter: dispatches the per-source-shape divergence (initial bind name + element type, per-element source loop emission, final invoke wrap). Used by plan_group_by_core to unify the ~350 LOC shared recognizer/splice machinery between plan_group_by (array source via for(it in src)) and plan_decs_group_by (decs bridge via for_each_archetype + inner multi-iter for + tupBind).
4160-
struct private GroupBySourceAdapter {
4161-
// The bind name the upstream segment walk and reducer recognition see as "the element" (srcItName for array, tupName for decs — both alias the post-iterator-bind variable).
4162-
initialBindName : string
4163-
// The element type at that bind point (peel_each-derived from `top._type.firstType` for array, `bridge.elementType` for decs).
4164-
initialElemType : TypeDeclPtr
4165-
// Prefix for all hoisted names ("" for array → tab/dummy/k/uk/…; "decs_" for decs → decs_tab/decs_dummy/…). Lets the same core function generate distinct-but-recognizable names per source.
4166-
namePrefix : string
4167-
// Discriminator for the three emit modes below (isDecsJoin > isDecs > array fallthrough).
4168-
isDecs : bool
4169-
isDecsJoin : bool
4170-
// Array side: the source expression bound by finalize_emission_stmts into srcName.
4171-
arrayTop : Expression?
4172-
arraySrcName : string
4173-
// Decs side: bridge metadata used by build_decs_tup_bind / build_decs_inner_for + the outer for_each_archetype call.
4174-
decsBridge : DecsBridgeShape?
4175-
// Decs-join side (Theme 3 — audit probe C3): hashB collect + srcA probe + per-pair result-lam bind feeds plan_group_by_core's bucket update directly. initialBindName aliases the result-lam output (one bind per (a,b) pair).
4176-
decsJoinBridgeA : DecsBridgeShape?
4177-
decsJoinBridgeB : DecsBridgeShape?
4178-
decsJoinKeyaLam : Expression?
4179-
decsJoinKeybLam : Expression?
4180-
decsJoinResultLam : Expression?
4181-
decsJoinKeyType : TypeDeclPtr
4182-
decsJoinTupBType : TypeDeclPtr
4183-
decsJoinResultType : TypeDeclPtr
4184-
}
4185-
4186-
// decs-join → Decs(null, …) is safe at finalize: adapter_wrap_invoke's Decs branch reads only the variant tag.
4187-
[macro_function]
4188-
def private to_source_adapter(adapter : GroupBySourceAdapter) : SourceAdapter {
4189-
return SourceAdapter(Decs = (adapter.decsBridge, adapter.initialBindName)) if (adapter.isDecs || adapter.isDecsJoin)
4190-
return SourceAdapter(Array = (adapter.arrayTop, adapter.arraySrcName))
4191-
}
4192-
4193-
[macro_function]
4194-
def private adapter_emit_source_loop(adapter : GroupBySourceAdapter; var body : Expression?; at : LineInfo) : Expression? {
4195-
// decs-join (Theme 3 C3) hashes srcB, walks srcA, binds result-lam output once per pair — GroupBy-specific.
4196-
if (adapter.isDecsJoin) {
4197-
let jhashName = qn("{adapter.namePrefix}jhash", at)
4198-
let arrName = qn("{adapter.namePrefix}jarr", at)
4199-
let tupAName = qn("{adapter.namePrefix}jta", at)
4200-
let tupBName = qn("{adapter.namePrefix}jtb", at)
4201-
let resName = adapter.initialBindName
4202-
var keyaBody = peel_lambda_rename_var(adapter.decsJoinKeyaLam, tupAName)
4203-
var keybBody = peel_lambda_rename_var(adapter.decsJoinKeybLam, tupBName)
4204-
var resultBody = peel_lambda_rename_2vars(adapter.decsJoinResultLam, tupAName, tupBName)
4205-
if (keyaBody == null || keybBody == null || resultBody == null) return null
4206-
var tupBindA = build_decs_tup_bind(adapter.decsJoinBridgeA, tupAName, at)
4207-
var tupBindB = build_decs_tup_bind(adapter.decsJoinBridgeB, tupBName, at)
4208-
if (tupBindA == null || tupBindB == null) return null
4209-
var collectBody <- qmacro_block_to_array() {
4210-
// nolint:PERF006 per-key bucket size unknown ahead of time
4211-
$i(jhashName)[$e(keybBody)] |> push_clone($i(tupBName))
4212-
}
4213-
var collectInner = build_decs_inner_for(adapter.decsJoinBridgeB, tupBindB, stmts_to_expr(collectBody), at)
4214-
var probeBody <- qmacro_block_to_array() {
4215-
get($i(jhashName), $e(keyaBody), $(var $i(arrName) : array<$t(adapter.decsJoinTupBType)>) {
4216-
for ($i(tupBName) in $i(arrName)) {
4217-
let $i(resName) : $t(adapter.decsJoinResultType) = $e(resultBody)
4218-
$e(body)
4219-
}
4220-
})
4221-
}
4222-
var probeInner = build_decs_inner_for(adapter.decsJoinBridgeA, tupBindA, stmts_to_expr(probeBody), at)
4223-
return qmacro_block() {
4224-
var $i(jhashName) : table<$t(adapter.decsJoinKeyType); array<$t(adapter.decsJoinTupBType)>>
4225-
for_each_archetype($e(adapter.decsJoinBridgeB.reqHashExpr), $e(adapter.decsJoinBridgeB.erqExpr), $($i(adapter.decsJoinBridgeB.archName) : Archetype) {
4226-
$e(collectInner)
4227-
})
4228-
for_each_archetype($e(adapter.decsJoinBridgeA.reqHashExpr), $e(adapter.decsJoinBridgeA.erqExpr), $($i(adapter.decsJoinBridgeA.archName) : Archetype) {
4229-
$e(probeInner)
4230-
})
4231-
}
4232-
}
4233-
return adapter_wrap_source_loop(to_source_adapter(adapter), body, at)
4234-
}
4235-
4236-
[macro_function]
4237-
def private adapter_finalize_emission(adapter : GroupBySourceAdapter; var stmts : array<Expression?>; retType : TypeDeclPtr; at : LineInfo) : Expression? {
4238-
return adapter_wrap_invoke(to_source_adapter(adapter), stmts, retType, false, at)
4239-
}
4240-
42414160
[macro_function]
42424161
def private plan_group_by_core(var calls : array<tuple<ExprCall?; LinqCall?>>;
42434162
var keyBlock : Expression?;
@@ -4249,9 +4168,9 @@ def private plan_group_by_core(var calls : array<tuple<ExprCall?; LinqCall?>>;
42494168
var orderKey : Expression?;
42504169
exprIsIterator : bool;
42514170
at : LineInfo;
4252-
var adapter : GroupBySourceAdapter) : Expression? {
4253-
// Shared group_by splice machinery. Caller pops terminator/select/having/group_by_lazy + extracts keyBlock + sets up the source adapter; this function does the rest (upstream chain walk, reducer recognition, state-table hoisting, tab?[uk]??dummy splice, output emission, source-loop wrap, terminator emission, final invoke wrap).
4254-
let prefix = adapter.namePrefix
4171+
var adapter : SourceAdapter) : Expression? {
4172+
// Prefix keeps hoisted names per-source distinct ("" array / "decs_" decs / "djoin_" decs-join).
4173+
let prefix = (adapter is Array) ? "" : ((adapter is DecsJoin) ? "djoin_" : "decs_")
42554174
let tabName = qn("{prefix}tab", at)
42564175
let kName = qn("{prefix}k", at)
42574176
let ukName = qn("{prefix}uk", at)
@@ -4268,8 +4187,8 @@ def private plan_group_by_core(var calls : array<tuple<ExprCall?; LinqCall?>>;
42684187
var currentBinds : array<Expression?>
42694188
var currentWhere : Expression?
42704189
var projection : Expression?
4271-
var lastBindName = adapter.initialBindName
4272-
var elemType = strip_const_ref(clone_type(adapter.initialElemType))
4190+
var lastBindName = adapter_bind_name(adapter, at)
4191+
var elemType = strip_const_ref(adapter_element_type(adapter))
42734192
var totalBindCount = 0
42744193
for (i in 0 .. (calls |> length)) {
42754194
let opName = calls[i]._1.name
@@ -4451,7 +4370,7 @@ def private plan_group_by_core(var calls : array<tuple<ExprCall?; LinqCall?>>;
44514370
idx --
44524371
}
44534372
// Adapter-specific source loop emission (for(it in src) for array, for_each_archetype + inner for for decs).
4454-
stmts |> push(adapter_emit_source_loop(adapter, body, at))
4373+
stmts |> push(adapter_wrap_source_loop(adapter, body, at))
44554374
// Compute output tuple + bufElemType — needed by to_array always, and by count when trailingWherePred is present (predicate is bound against the constructed output).
44564375
let needOutput = terminatorName != "count" || trailingWherePred != null
44574376
var outputExpr : Expression?
@@ -4602,7 +4521,7 @@ def private plan_group_by_core(var calls : array<tuple<ExprCall?; LinqCall?>>;
46024521
}
46034522
stmts |> push(buffer_return(bufName, exprIsIterator))
46044523
}
4605-
return adapter_finalize_emission(adapter, stmts, retType, at)
4524+
return adapter_wrap_invoke(adapter, stmts, retType, false, at)
46064525
}
46074526

46084527
// Shared array/decs/decs-join group_by emitter. Reconstructs head calls (mirrors emit_loop_or_count_lane_decs),
@@ -4640,7 +4559,7 @@ def private emit_group_by(var c : Captures; var ctx : EmitCtx; at : LineInfo) :
46404559
var lc & = unsafe(linqCalls?[nm] ?? default<LinqCall>)
46414560
headCalls |> push((call, unsafe(addr(lc))))
46424561
}
4643-
var adapter : GroupBySourceAdapter
4562+
var adapter : SourceAdapter
46444563
if (ctx.src is Decs) {
46454564
var bridge = (ctx.src as Decs)._0
46464565
if (c.single |> key_exists("upstream_join")) {
@@ -4657,47 +4576,23 @@ def private emit_group_by(var c : Captures; var ctx : EmitCtx; at : LineInfo) :
46574576
if (!is_primitive_join_key_type(keyType)) return null
46584577
var resultType = strip_const_ref(clone_type(resultLam._type.firstType))
46594578
var tupBType = strip_const_ref(clone_type(bridgeB.elementType))
4660-
adapter = GroupBySourceAdapter(
4661-
initialBindName := qn("djoin_jres", at),
4662-
initialElemType = strip_const_ref(clone_type(resultLam._type.firstType)),
4663-
namePrefix := "djoin_",
4664-
isDecs = false,
4665-
isDecsJoin = true,
4666-
arrayTop = null,
4667-
arraySrcName := "",
4668-
decsBridge = null,
4669-
decsJoinBridgeA = bridge,
4670-
decsJoinBridgeB = bridgeB,
4671-
decsJoinKeyaLam = keyaLam,
4672-
decsJoinKeybLam = keybLam,
4673-
decsJoinResultLam = resultLam,
4674-
decsJoinKeyType = keyType,
4675-
decsJoinTupBType = tupBType,
4676-
decsJoinResultType = resultType
4677-
)
4579+
adapter = SourceAdapter(DecsJoin = DecsJoinShape(
4580+
bridgeA = bridge,
4581+
bridgeB = bridgeB,
4582+
keyaLam = keyaLam,
4583+
keybLam = keybLam,
4584+
resultLam = resultLam,
4585+
keyType = keyType,
4586+
tupBType = tupBType,
4587+
resultType = resultType,
4588+
resBindName = qn("djoin_jres", at)))
46784589
} else {
4679-
adapter = GroupBySourceAdapter(
4680-
initialBindName := qn("decs_tup", at),
4681-
initialElemType = strip_const_ref(clone_type(bridge.elementType)),
4682-
namePrefix := "decs_",
4683-
isDecs = true,
4684-
arrayTop = null,
4685-
arraySrcName := "",
4686-
decsBridge = bridge
4687-
)
4590+
adapter = SourceAdapter(Decs = (bridge, qn("decs_tup", at)))
46884591
}
46894592
} else {
46904593
var top = (ctx.src as Array)._0
46914594
if (top._type == null) return null
4692-
adapter = GroupBySourceAdapter(
4693-
initialBindName := qn("it", at),
4694-
initialElemType = strip_const_ref(clone_type(top._type.firstType)),
4695-
namePrefix := "",
4696-
isDecs = false,
4697-
arrayTop = top,
4698-
arraySrcName := qn("source", at),
4699-
decsBridge = null
4700-
)
4595+
adapter = SourceAdapter(Array = (top, qn("source", at)))
47014596
}
47024597
return plan_group_by_core(headCalls, keyBlock, groupProjCall, havingCall, trailingWhereCall,
47034598
terminatorName, orderName, orderKey, ctx.expr_is_iterator, at, adapter)

0 commit comments

Comments
 (0)