|
// <auto-generated/>
#nullable enable
using System;
using System.Collections.Generic;
using Microsoft.Diagnostics.DataContractReader.Contracts;
namespace Microsoft.Diagnostics.DataContractReader.Generated;
/// <summary>
/// An ordered set of type layouts resolved from multiple type info sources.
/// Field lookups iterate sources in priority order (native cdac descriptor
/// first, then managed type metadata), trying each candidate field name
/// per source. Sources are resolved lazily.
/// </summary>
internal readonly struct LayoutSet
{
private readonly LazyLayout[] _layouts;
public LayoutSet(LazyLayout[] layouts)
{
_layouts = layouts;
}
public ulong InstanceSize
{
get
{
foreach (LazyLayout layout in _layouts)
{
if (layout.Get()?.Size is uint s)
return s;
}
throw new InvalidOperationException("No layout source has a known instance size.");
}
}
public bool TrySelect(TargetPointer address, out Target.TypeInfo type, out TargetPointer baseAddr, out string name, params ReadOnlySpan<string> names)
{
foreach (LazyLayout layout in _layouts)
{
if (layout.Get() is not Target.TypeInfo ti)
continue;
foreach (string candidate in names)
{
if (ti.Fields.ContainsKey(candidate))
{
type = ti; baseAddr = address; name = candidate; return true;
}
}
}
type = default!; baseAddr = default; name = default!;
return false;
}
public void Select(TargetPointer address, out Target.TypeInfo type, out TargetPointer baseAddr, out string name, params ReadOnlySpan<string> names)
{
if (!TrySelect(address, out type, out baseAddr, out name, names))
{
throw new InvalidOperationException(FormatMissing(names));
}
}
private static string FormatMissing(ReadOnlySpan<string> names)
=> $"Field not found in any layout (names=[{string.Join(",", names.ToArray())}]).";
public static LayoutSet Resolve(Target target, string[] names)
{
List<LazyLayout> layouts = new(2);
foreach (string name in names)
{
if (target.TryGetTypeInfo(name, out Target.TypeInfo n))
{
layouts.Add(new LazyLayout(n));
break;
}
}
if (target.Contracts.TryGetContract(out IManagedTypeSource mts))
{
layouts.Add(new LazyLayout(() =>
{
foreach (string name in names)
{
if (mts.TryGetTypeInfo(name, out Target.TypeInfo m))
return m;
}
return null;
}));
}
return new LayoutSet(layouts.ToArray());
}
}
/// <summary>
/// Memoized lazy holder for a single <see cref="Target.TypeInfo"/> source.
/// Constructed either with a pre-resolved value (for cheap sources) or with
/// a factory invoked on first access (for expensive sources).
/// </summary>
internal sealed class LazyLayout
{
private Func<Target.TypeInfo?>? _factory;
private Target.TypeInfo? _value;
public LazyLayout(Target.TypeInfo value)
{
_value = value;
}
public LazyLayout(Func<Target.TypeInfo?> factory)
{
_factory = factory;
}
public Target.TypeInfo? Get()
{
if (_factory is not null)
{
_value = _factory();
_factory = null;
}
return _value;
}
} |