Files
stgsharp/test/StgSharp.GenerateGL/CodeGen/ManagedParameterPlanner.cs
T

139 lines
5.3 KiB
C#

//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="ManagedParameterPlanner"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
namespace GenerateGL.CodeGen
{
internal enum ManagedParameterKind
{
Value,
RawPointer,
ReadOnlySpan,
Span,
Out
}
internal sealed record ManagedParameterPlan(
GlParam Source,
string PublicType,
ManagedParameterKind Kind,
string? ElementType
)
{
public bool IsSpan => Kind is ManagedParameterKind.ReadOnlySpan or
ManagedParameterKind.Span;
}
internal sealed class ManagedCommandPlan
{
private readonly Dictionary<string, ManagedParameterPlan> _allParameters;
private readonly Dictionary<string, string> _derivedLengthSources;
private ManagedCommandPlan(
IReadOnlyList<ManagedParameterPlan> publicParameters,
Dictionary<string, ManagedParameterPlan> allParameters,
Dictionary<string, string> derivedLengthSources
)
{
PublicParameters = publicParameters;
_allParameters = allParameters;
_derivedLengthSources = derivedLengthSources;
}
public IReadOnlyList<ManagedParameterPlan> PublicParameters { get; }
public IReadOnlyDictionary<string, string> DerivedLengthSources =>
_derivedLengthSources;
public static ManagedCommandPlan Create(
GlCommand command
)
{
Dictionary<string, ManagedParameterPlan> all = new(StringComparer.Ordinal);
foreach (GlParam parameter in command.Parameters)
{
ManagedParameterPlan plan;
if (CsTypeMapper.TryMapPointerElement(parameter, out string elementType) &&
(parameter.IsConst || !string.IsNullOrWhiteSpace(parameter.Length) ||
command.Name.StartsWith("glGet", StringComparison.Ordinal)))
{
if (!parameter.IsConst && parameter.Length == "1")
{
plan = new ManagedParameterPlan(
parameter, $"out {elementType}", ManagedParameterKind.Out,
elementType);
} else
{
ManagedParameterKind kind = parameter.IsConst
? ManagedParameterKind.ReadOnlySpan
: ManagedParameterKind.Span;
string container = parameter.IsConst ? "ReadOnlySpan" : "Span";
plan = new ManagedParameterPlan(
parameter, $"{container}<{elementType}>", kind, elementType);
}
} else
{
string mapped = CsTypeMapper.MapParameter(parameter);
ManagedParameterKind kind = parameter.PointerLevel == 0
? ManagedParameterKind.Value
: ManagedParameterKind.RawPointer;
plan = new ManagedParameterPlan(parameter, mapped, kind, null);
}
all.Add(parameter.Name, plan);
}
Dictionary<string, string> derivedLengths = new(StringComparer.Ordinal);
foreach (GlParam scalar in command.Parameters.Where(p => p.PointerLevel == 0))
{
List<ManagedParameterPlan> spans = command.Parameters
.Select(p => all[p.Name])
.Where(p => p.IsSpan &&
string.Equals(p.Source.Length, scalar.Name,
StringComparison.Ordinal))
.ToList();
if (spans.Count == 0) {
continue;
}
bool lengthAlsoControlsRawPointer = command.Parameters
.Select(p => all[p.Name]).Any(p =>
p.Kind == ManagedParameterKind.RawPointer &&
string.Equals(p.Source.Length, scalar.Name, StringComparison.Ordinal));
if (lengthAlsoControlsRawPointer) {
continue;
}
string scalarType = all[scalar.Name].PublicType;
if (scalarType is not ("int" or "uint" or "nint" or "nuint")) {
continue;
}
derivedLengths.Add(scalar.Name, spans[0].Source.Name);
}
IReadOnlyList<ManagedParameterPlan> publicParameters = command.Parameters
.Where(p => !derivedLengths.ContainsKey(p.Name))
.Select(p => all[p.Name])
.ToArray();
return new ManagedCommandPlan(publicParameters, all, derivedLengths);
}
public ManagedParameterPlan GetParameter(
string name
) => _allParameters[name];
}
}