Editor/Services/ArchBuildMemo.cs
using System;
using System.Collections.Generic;
namespace Sunless.Architecture;
// Per-build cache opened AFTER connections resolve; a generator must not mutate the plan.
public sealed class ArchBuildMemo : IDisposable {
public static ArchBuildMemo Current { get; private set; }
readonly ArchBuildMemo held;
readonly ArchPlan plan;
ArchBuildMemo( ArchPlan plan ) {
this.plan = plan;
held = Current;
Current = this;
}
public static IDisposable Begin( ArchPlan plan ) => new ArchBuildMemo( plan );
public void Dispose() => Current = held;
public Dictionary<int, float> Lifts { get; } = new();
public Dictionary<int, List<ArchCarveVolume>> Volumes { get; } = new();
public Dictionary<(int Affector, int Host), IReadOnlySet<int>> Reaches { get; } = new();
public Dictionary<int, ArchSiteAssembly> Holders { get; } = new();
Dictionary<int, ArchLayerRecord> records;
// Every Applies call used to linear-scan the whole record list, once per operation per host.
public Dictionary<int, ArchLayerRecord> Records {
get {
if ( records is not null ) {
return records;
}
records = new Dictionary<int, ArchLayerRecord>();
foreach ( var record in plan?.Layers ?? new List<ArchLayerRecord>() ) {
records[record.ItemId] = record;
}
return records;
}
}
// Held if a build is open, resolved plainly if not - so no caller needs to know whether one is.
public static TValue Held<TKey, TValue>( Func<ArchBuildMemo, Dictionary<TKey, TValue>> table, TKey key, Func<TValue> resolve ) {
if ( Current is not { } memo ) {
return resolve();
}
var into = table( memo );
if ( into.TryGetValue( key, out var found ) ) {
return found;
}
return into[key] = resolve();
}
}