transient srecord noeq G22NetworkInstance(G22Network network) { new Map valuesByIdentifier; new Map valuesByBlueprint; event dirtyStatesChanged; sclass Value { settable O object; // the actual value calculated by the node settable Timestamp calculatedWhen; // when the value was calculated settable bool dirty; // does this node need recalculation? O get() { ret object; } toString { ret classNameWithIdentity(this) + ": " + object; } } void calculateNode(G22Utils g22utils, G22NetworkElement e) { if (e == null) ret; Value value = valuesByBlueprint.get(e); O instance = e.makeInstance(g22utils, this); print("Calculated: " + instance); value.object(instance).calculatedWhen(tsNow()); if (value.dirty()) { value.dirty(false); dirtyStatesChanged(); } invalidateDependentNodes(e); } void init(G22Utils g22utils) { // make empty Value object for each node for (e : network.elements) { new Value value; value.dirty(true); dirtyStatesChanged(); valuesByBlueprint.put(e, value); //print("Put value in map: " + e + " => " + value); mapPut(valuesByIdentifier, e.identifier(), value); } } O getObjectForBlueprint(G22NetworkElement element) { var value = valuesByBlueprint.get(element); O object = value!; printVars("getObjectForBlueprint", +element, +value, +object); ret object; } void invalidateDependentNodes(G22NetworkElement element) { if (element == null) ret; print("invalidateDependentNodes", element); for (e : element.downstreamNodes()) invalidateNode(e); } // a node is calculable if its upstream nodes (the inputs // it needs) are clean bool isCalculable(G22NetworkElement element) { ret all(element.upstreamNodes(), e -> !isDirty(e)); } bool isDirty(G22NetworkElement element) { ret valuesByBlueprint.get(e).dirty(); } void invalidateNode(G22NetworkElement element) { print("invalidateNode", element); var value = valuesByBlueprint.get(element); if (value.dirty()) ret; // Node already dirty value.dirty(true); dirtyStatesChanged(); invalidateDependentNodes(element); } // select any calculable node and calculate it G22NetworkElement calculateOneNode(G22Utils g22utils) { var calculableElements = filter( e -> isDirty(e) && isCalculable(e), keys(valuesByBlueprint)); var e = random(calculableElements); calculateNode(g22utils, e); ret e; } }