Class StreamDemand
head N bounds the PULL (decision 10, rule B) - use this, never
re-derive which heads gate a loop or how the gate is folded into a loop condition.
Every head in a segment stops the pull once it has its N items. A segment runs from the nearest
upstream stage that must see everything (sort, tail, join, and group/split/async, which are lowered as
drains) - or the source - down to the next such stage. A must-drain stage always consumes its whole input;
a head after it limits only what it emits, so it gates the drain's EMISSION loop, never the drain.
The gate is ordinary IR: each loop condition becomes c1 < l1 AND (c2 < l2 AND ... hasNext()) as
nested short-circuit LOGICAL_AND blocks, the counters FIRST, so hasNext()/next() are never
called once any head is satisfied. That ordering is backend Contract 12: no back end may hoist, prefetch or
speculatively call hasNext() - on an unbounded or infinite source it blocks or never ends.
-
Field Summary
Fields inherited from class AbstractStreamStageGenerator
generators, listBufferCalls, symbolTypeOrException, valuePromoterFields inherited from class AbstractGenerator
constantCopyOnAccessLoader, debugInfoCreator, instructionBuilder, MAX_MESSAGE_LENGTH, stackContext, synthesisedCallMetaData, typeNameOrException -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription(package private) StringappendBoundedCondition(List<IRInstr> conditionEvaluation, List<IRInstr> leftInstructions, String leftResult, String leftPrimitive, List<IRInstr> rightInstructions, String rightResult, String scopeId, DebugInfo debugInfo) Append a short-circuitLEFT AND RIGHTBoolean condition toconditionEvaluationand return the combined Boolean result variable.(package private) StringappendDemandCondition(List<IRInstr> conditionEvaluation, List<StageState> bounds, List<IRInstr> rightInstructions, String rightResult, String scopeId, DebugInfo debugInfo) Append the demand-bounded conditionc1 < l1 AND (... AND right)toconditionEvaluationand return its Boolean result.(package private) StringappendDemandOverPrimitive(List<IRInstr> condition, List<StageState> heads, List<IRInstr> primitiveInstructions, String primitiveResult, String scopeId, DebugInfo debugInfo) Gate a loop whose continuation is a runtime helper's PRIMITIVEhasNext-style call (Ek9Group.hasNextGroup,Ek9Async.hasNext): with no heads the condition is unchanged; otherwise the primitive is lifted to a Boolean (Boolean._of) so it can be the right operand of the demand AND.(package private) FreshBooleanOperandcontinueCondition(List<StageState> heads, String scopeId, DebugInfo debugInfo) The demand condition of a loop whose own continuation is not ahasNext()- aforrange, whose range test the back end evaluates itself.(package private) static booleanendsDemandSegment(int opType) True for a stage that is lowered as a drain (or emits only after its loop): aheaddownstream of it cannot bound what flows into it, so the demand segment ends there.(package private) static List<StageState> heads(List<EK9Parser.StreamPartContext> stages, List<StageState> stageStates) THE heads that bound the pull of a loop overstages: everyheadbefore the first stage that ends the demand segment, in pipeline order.(package private) static List<StageState> headsCappingAsync(List<EK9Parser.StreamPartContext> postAsyncStages, List<StageState> postAsyncStates) THE heads that cap anasync(decision 15 d): those reached from the async through stages that pass EVERY item on -map,call,teeand anotherhead- in pipeline order.(package private) static intsegmentEnd(List<EK9Parser.StreamPartContext> stages) The index of the first stage that ends the demand segment, or -1 when every stage streams.Methods inherited from class AbstractStreamStageGenerator
addManagedCall, concrete, emitStageFunctionOperand, evaluateExpressionOperand, extractPrimitive, gate, generateCounterDelta, generateTerminalPipe, publishAndContinue, rebind, streamFunctionCall
-
Constructor Details
-
StreamDemand
StreamDemand(IRGenerationContext stackContext, GeneratorSet generators)
-
-
Method Details
-
endsDemandSegment
static boolean endsDemandSegment(int opType) True for a stage that is lowered as a drain (or emits only after its loop): aheaddownstream of it cannot bound what flows into it, so the demand segment ends there. THE rule isStreamStages.endsDemandSegment(int), shared with the front end's boundedness checks. -
segmentEnd
The index of the first stage that ends the demand segment, or -1 when every stage streams. The stages before it are the ones aheadamong them can stop pulling for - which is also how far a multi-sourcecat a, bpulls each source in turn before it must gather (decision 15 b). -
heads
static List<StageState> heads(List<EK9Parser.StreamPartContext> stages, List<StageState> stageStates) THE heads that bound the pull of a loop overstages: everyheadbefore the first stage that ends the demand segment, in pipeline order. Empty when there is none (the loop is a plainhasNext()). -
headsCappingAsync
static List<StageState> headsCappingAsync(List<EK9Parser.StreamPartContext> postAsyncStages, List<StageState> postAsyncStates) THE heads that cap anasync(decision 15 d): those reached from the async through stages that pass EVERY item on -map,call,teeand anotherhead- in pipeline order. Every task started then yields an item such a head counts, so a head N needs only N tasks and the async starts no more than that: the caller bounds what is SUBMITTED by these limits. A stage that can drop an item (filter, reject, uniq, skip, flatten - an element may flatten to nothing) or must see everything stops the scan; past it, which tasks yield usable items is unknown, so the window stays.postAsyncStages/postAsyncStatesstart at the stage straight after the async. -
appendDemandCondition
String appendDemandCondition(List<IRInstr> conditionEvaluation, List<StageState> bounds, List<IRInstr> rightInstructions, String rightResult, String scopeId, DebugInfo debugInfo) Append the demand-bounded conditionc1 < l1 AND (... AND right)toconditionEvaluationand return its Boolean result. With no bounds,rightis appended unchanged (byte-identical to an ungated loop).boundsare counter/limit pairs: the heads, or the async window's in-flight bound. -
continueCondition
The demand condition of a loop whose own continuation is not ahasNext()- aforrange, whose range test the back end evaluates itself. Returns the heads alone (c1 < l1 AND ...) in their own scope-free instruction list, or null when no head bounds the loop. -
appendDemandOverPrimitive
String appendDemandOverPrimitive(List<IRInstr> condition, List<StageState> heads, List<IRInstr> primitiveInstructions, String primitiveResult, String scopeId, DebugInfo debugInfo) Gate a loop whose continuation is a runtime helper's PRIMITIVEhasNext-style call (Ek9Group.hasNextGroup,Ek9Async.hasNext): with no heads the condition is unchanged; otherwise the primitive is lifted to a Boolean (Boolean._of) so it can be the right operand of the demand AND. Returns the {primitive} to branch on, appending everything tocondition. -
appendBoundedCondition
String appendBoundedCondition(List<IRInstr> conditionEvaluation, List<IRInstr> leftInstructions, String leftResult, String leftPrimitive, List<IRInstr> rightInstructions, String rightResult, String scopeId, DebugInfo debugInfo) Append a short-circuitLEFT AND RIGHTBoolean condition toconditionEvaluationand return the combined Boolean result variable. RIGHT is evaluated ONLY when LEFT's primitive is true (LOGICAL_AND_BLOCK short-circuit). This is the generic two-operand AND-block; callers build LEFT (the short-circuit decision: head'scounter < limit, the window'sinFlight < W, etc.) and pass its result+primitive, plus the RIGHT operand's instructions+result (e.g. the managed hasNext()). MirrorsGuardedConditionEvaluator's guard-into-condition fold.
-