public NodeStateTable <ImmutableArray <TInput> > UpdateStateTable(DriverStateTable.Builder builder, NodeStateTable <ImmutableArray <TInput> > previousTable, CancellationToken cancellationToken) { // grab the source inputs var sourceTable = builder.GetLatestStateTableForNode(_sourceNode); // Semantics of a batch transform: // Batches will always exist (a batch of the empty table is still []) // There is only ever one input, the batch of the upstream table // - Output is cached when upstream is all cached // - Added when the previous table was empty // - Modified otherwise var source = sourceTable.Batch(); // update the table var newTable = previousTable.ToBuilder(); if (!sourceTable.IsCached || !newTable.TryUseCachedEntries()) { if (!newTable.TryModifyEntry(source, _comparer)) { newTable.AddEntry(source, EntryState.Added); } } return(newTable.ToImmutableAndFree()); }
public NodeStateTable <T> UpdateStateTable(DriverStateTable.Builder graphState, NodeStateTable <T> previousTable, CancellationToken cancellationToken) { var inputItems = _getInput(graphState); // create a mutable hashset of the new items we can check against HashSet <T> itemsSet = new HashSet <T>(_comparer); foreach (var item in inputItems) { var added = itemsSet.Add(item); Debug.Assert(added); } var builder = previousTable.ToBuilder(); // for each item in the previous table, check if its still in the new items int itemIndex = 0; foreach ((var oldItem, _) in previousTable) { if (itemsSet.Remove(oldItem)) { // we're iterating the table, so know that it has entries var usedCache = builder.TryUseCachedEntries(); Debug.Assert(usedCache); } else if (inputItems.Length == previousTable.Count) { // When the number of items matches the previous iteration, we use a heuristic to mark the input as modified // This allows us to correctly 'replace' items even when they aren't actually the same. In the case that the // item really isn't modified, but a new item, we still function correctly as we mostly treat them the same, // but will perform an extra comparison that is omitted in the pure 'added' case. var modified = builder.TryModifyEntry(inputItems[itemIndex], _comparer); Debug.Assert(modified); itemsSet.Remove(inputItems[itemIndex]); } else { builder.RemoveEntries(); } itemIndex++; } // any remaining new items are added foreach (var newItem in itemsSet) { builder.AddEntry(newItem, EntryState.Added); } return(builder.ToImmutableAndFree()); }
public NodeStateTable <TOutput> UpdateStateTable(DriverStateTable.Builder graphState, NodeStateTable <TOutput> previousTable, CancellationToken cancellationToken) { var sourceTable = graphState.GetLatestStateTableForNode(_source); if (sourceTable.IsCached) { return(previousTable); } var nodeTable = previousTable.ToBuilder(); foreach (var entry in sourceTable) { if (entry.state == EntryState.Removed) { nodeTable.RemoveEntries(); } else if (entry.state != EntryState.Cached || !nodeTable.TryUseCachedEntries()) { // we don't currently handle modified any differently than added at the output // we just run the action and mark the new source as added. In theory we could compare // the diagnostics and sources produced and compare them, to see if they are any different // than before. var sourcesBuilder = ArrayBuilder <GeneratedSourceText> .GetInstance(); var diagnostics = DiagnosticBag.GetInstance(); SourceProductionContext context = new SourceProductionContext(sourcesBuilder, diagnostics, cancellationToken); try { _action(context, entry.item); nodeTable.AddEntry((sourcesBuilder.ToImmutable(), diagnostics.ToReadOnly()), EntryState.Added); } finally { sourcesBuilder.Free(); diagnostics.Free(); } } } return(nodeTable.ToImmutableAndFree()); }
public NodeStateTable <T> UpdateStateTable(DriverStateTable.Builder graphState, NodeStateTable <T> previousTable, CancellationToken cancellationToken) { var inputItems = _getInput(graphState); // create a mutable hashset of the new items we can check against HashSet <T> itemsSet = new HashSet <T>(_comparer); foreach (var item in inputItems) { var added = itemsSet.Add(item); Debug.Assert(added); } var builder = previousTable.ToBuilder(); // for each item in the previous table, check if its still in the new items foreach ((var oldItem, _) in previousTable) { if (itemsSet.Remove(oldItem)) { // we're iterating the table, so know that it has entries var usedCache = builder.TryUseCachedEntries(); Debug.Assert(usedCache); } else { builder.RemoveEntries(); } } // any remaining new items are added foreach (var newItem in itemsSet) { builder.AddEntry(newItem, EntryState.Added); } return(builder.ToImmutableAndFree()); }
public NodeStateTable <TOutput> UpdateStateTable(DriverStateTable.Builder builder, NodeStateTable <TOutput> previousTable, CancellationToken cancellationToken) { // grab the source inputs var sourceTable = builder.GetLatestStateTableForNode(_sourceNode); if (sourceTable.IsCached) { return(previousTable); } // Semantics of a transform: // Element-wise comparison of upstream table // - Cached or Removed: no transform, just use previous values // - Added: perform transform and add // - Modified: perform transform and do element wise comparison with previous results var newTable = previousTable.ToBuilder(); foreach (var entry in sourceTable) { if (entry.state == EntryState.Removed) { newTable.RemoveEntries(); } else if (entry.state != EntryState.Cached || !newTable.TryUseCachedEntries()) { // generate the new entries var newOutputs = _func(entry.item, cancellationToken); if (entry.state != EntryState.Modified || !newTable.TryModifyEntries(newOutputs, _comparer)) { newTable.AddEntries(newOutputs, EntryState.Added); } } } return(newTable.ToImmutableAndFree()); }
public NodeStateTable <T> .Builder CreateTableBuilder <T>( NodeStateTable <T> previousTable, string?stepName, IEqualityComparer <T>?equalityComparer, int?tableCapacity = null) { return(previousTable.ToBuilder(stepName, DriverState.TrackIncrementalSteps, equalityComparer, tableCapacity)); }
public NodeStateTable <T> .Builder CreateTableBuilder <T>(NodeStateTable <T> previousTable, string?stepName) { return(previousTable.ToBuilder(stepName, DriverState.TrackIncrementalSteps)); }