//----------------------------------------------------------------------- // ----------------------------------------------------------------------- // 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 _allParameters; private readonly Dictionary _derivedLengthSources; private ManagedCommandPlan( IReadOnlyList publicParameters, Dictionary allParameters, Dictionary derivedLengthSources ) { PublicParameters = publicParameters; _allParameters = allParameters; _derivedLengthSources = derivedLengthSources; } public IReadOnlyList PublicParameters { get; } public IReadOnlyDictionary DerivedLengthSources => _derivedLengthSources; public static ManagedCommandPlan Create( GlCommand command ) { Dictionary 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 derivedLengths = new(StringComparer.Ordinal); foreach (GlParam scalar in command.Parameters.Where(p => p.PointerLevel == 0)) { List 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 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]; } }