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 makeInstance(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; for (port : element.ports()) if (port.isOutput() && port.cable != null) { var otherPort = port.cable.from; if (otherPort != null) invalidateNode(otherPort.element()); } } void invalidateNode(G22NetworkElement element) { var value = valuesByBlueprint.get(element); if (value.dirty()) ret; // Node already dirty value.dirty(true); invalidateDependentNodes(element); } }