Skip to content

Commit

Permalink
emit opcodes instead of using expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
malstraem committed Dec 19, 2024
1 parent 5eb81b7 commit 24341d6
Show file tree
Hide file tree
Showing 17 changed files with 51 additions and 38 deletions.
8 changes: 4 additions & 4 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

<PackageVersion Include="Docfx.App" Version="2.78.2" />

<PackageVersion Include="Avalonia" Version="11.2.2" />
<PackageVersion Include="Avalonia.Desktop" Version="11.2.2" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.2" />
<PackageVersion Include="Avalonia.Fonts.Inter" Version="11.2.2" />
<PackageVersion Include="Avalonia" Version="11.2.3" />
<PackageVersion Include="Avalonia.Desktop" Version="11.2.3" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.3" />
<PackageVersion Include="Avalonia.Fonts.Inter" Version="11.2.3" />

<PackageVersion Include="Semi.Avalonia" Version="11.2.1.2" />
<PackageVersion Include="Irihi.Ursa" Version="1.6.2" />
Expand Down
2 changes: 1 addition & 1 deletion source/library/Parser424.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class Parser424
/// <summary>
/// Storage for entity builds. Covers bare types and compositions.
/// </summary>
internal readonly Dictionary<Section, Dictionary<Type, Queue<Build>>> builds = [];
protected internal readonly Dictionary<Section, Dictionary<Type, Queue<Build>>> builds = [];

private void Process(IEnumerable<string> strings, Queue<string> skipped)
{
Expand Down
23 changes: 23 additions & 0 deletions source/library/building/Assignment{TRecord}.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Reflection;
using System.Reflection.Emit;
using System.Text.RegularExpressions;

using Arinc424.Diagnostics;
Expand All @@ -17,4 +18,26 @@ internal abstract class Assignment<TRecord>(PropertyInfo property) where TRecord
internal NullabilityInfo? NullabilityInfo { get; } = property.PropertyType.IsClass ? new NullabilityInfoContext().Create(property) : null;

internal abstract void Assign(TRecord record, ReadOnlySpan<char> @string, Queue<Diagnostic> diagnostics);

protected static Action<TRecord, TType> GetCompiledSetter<TType>(PropertyInfo property, bool isValueNullable)
{
var method = new DynamicMethod(Guid.NewGuid().ToString(), null, [typeof(TRecord), typeof(TType)]);

var gen = method.GetILGenerator();

gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);

if (isValueNullable)
{
var con = property.PropertyType.GetConstructor([typeof(TType)]);
gen.Emit(OpCodes.Newobj, con);
}

gen.EmitCall(OpCodes.Callvirt, property.GetSetMethod()!, null);

gen.Emit(OpCodes.Ret);

return method.CreateDelegate<Action<TRecord, TType>>();
}
}
6 changes: 2 additions & 4 deletions source/library/building/BuildInfo{TRecord}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ private static IndexAssignment<TRecord> GetIndexAssignment(PropertyInfo property

private static RangeAssignment<TRecord> GetRangeAssignment(PropertyInfo property, Supplement supplement, Range range)
{
var (type, isValueNullable) = property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)
? (property.PropertyType.GetGenericArguments().First(), true)
: (property.PropertyType, false);
var type = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;

// prefer decode attached to the property
if (!property.TryAttribute<TRecord, DecodeAttribute>(supplement, out var decode))
Expand All @@ -39,7 +37,7 @@ private static RangeAssignment<TRecord> GetRangeAssignment(PropertyInfo property

: (RangeAssignment<TRecord>)
Activator.CreateInstance(typeof(DecodeAssignment<,>)
.MakeGenericType(typeof(TRecord), type), property, range, decode, isValueNullable)!
.MakeGenericType(typeof(TRecord), type), property, range, decode)!

: new StringAssignment<TRecord>(property, range);
}
Expand Down
2 changes: 1 addition & 1 deletion source/library/building/IndexAssignment{TRecord}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal override void Assign(TRecord record, ReadOnlySpan<char> @string, Queue<
internal sealed class CharAssignment<TRecord>(PropertyInfo property, int index)
: IndexAssignment<TRecord>(property, index) where TRecord : Record424
{
private readonly Action<TRecord, char> set = property.GetSetMethod()!.CreateDelegate<Action<TRecord, char>>();
private readonly Action<TRecord, char> set = GetCompiledSetter<char>(property, Nullable.GetUnderlyingType(property.PropertyType) is not null);

internal override void Assign(TRecord record, ReadOnlySpan<char> @string, Queue<Diagnostic> _) => set(record, @string[index]);
}
22 changes: 2 additions & 20 deletions source/library/building/RangeAssignment{TRecord}.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
using System.Linq.Expressions;
using System.Reflection;

using Arinc424.Diagnostics;
Expand All @@ -10,33 +9,16 @@ namespace Arinc424.Building;
internal abstract class RangeAssignment<TRecord>(PropertyInfo property, Range range) : Assignment<TRecord>(property) where TRecord : Record424
{
protected readonly Range range = range;

[Obsolete("todo: replace with emit op codes")]
protected static Action<TRecord, TType> GetCompiledSetter<TType>(PropertyInfo property, bool isValueNullable)
{
var record = Expression.Parameter(typeof(TRecord));

var value = Expression.Parameter(typeof(TType), property.Name);

var setter = Expression.Property(record, property.Name);

Expression rightExpression = value;

if (isValueNullable)
rightExpression = Expression.New(property.PropertyType.GetConstructor([typeof(TType)])!, value);

return Expression.Lambda<Action<TRecord, TType>>(Expression.Assign(setter, rightExpression), record, value).Compile();
}
}

internal sealed class DecodeAssignment<TRecord, TType>(PropertyInfo property, Range range, DecodeAttribute<TType> decode, bool isValueNullable)
internal sealed class DecodeAssignment<TRecord, TType>(PropertyInfo property, Range range, DecodeAttribute<TType> decode)
: RangeAssignment<TRecord>(property, range)
where TType : notnull
where TRecord : Record424
{
private readonly DecodeAttribute<TType> decode = decode;

private readonly Action<TRecord, TType> set = GetCompiledSetter<TType>(property, isValueNullable);
private readonly Action<TRecord, TType> set = GetCompiledSetter<TType>(property, Nullable.GetUnderlyingType(property.PropertyType) is not null);

internal override void Assign(TRecord record, ReadOnlySpan<char> @string, Queue<Diagnostic> diagnostics)
{
Expand Down
3 changes: 3 additions & 0 deletions source/library/records/Fix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

namespace Arinc424;

/// <summary>
/// Base fix with an identifier used as a navigation point.
/// </summary>
public abstract class Fix : Geo, IIdentity
{
/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion source/library/records/IMultiple.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ internal interface IMultiple
/// <c>Multiple Code(MULTI CD)</c> character.
/// </summary>
/// <remarks>See section 5.130.</remarks>
char Multiplier { get; set; }
char? Multiplier { get; set; }
}
2 changes: 1 addition & 1 deletion source/library/records/airspace/ControlledVolume.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Arinc424.Airspace;
/// <summary>
/// <c>Controlled Airspace</c> primary record sequence.
/// </summary>
/// <remarks>See section 4.1.25.1.</remarks>
/// <remarks>Used by <see cref="ControlledSpace"/> like subsequence.</remarks>
[Pipeline<Sequence<ControlledVolume, BoundaryPoint>>]

[DebuggerDisplay($"{nameof(Class)} - {{{nameof(Class)},nq}}, {nameof(Type)} - {{{nameof(Type)}}}")]
Expand Down
4 changes: 4 additions & 0 deletions source/library/records/airspace/FlightRegion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace Arinc424.Airspace;

/// <summary>
/// Multiple <c>FIR/UIR</c> primary record sequences.
/// </summary>
/// <remarks>See section 4.1.17.1.</remarks>
[Section('U', 'F'), Identifier(7, 10)]

[Pipeline<IdentityWrap<FlightRegion, RegionVolume>>]
Expand Down
2 changes: 1 addition & 1 deletion source/library/records/airspace/RegionVolume.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Arinc424.Airspace;
/// <summary>
/// <c>FIR/UIR</c> primary record sequence.
/// </summary>
/// <remarks>See section 4.1.17.1.</remarks>
/// <remarks>Used by <see cref="FlightRegion"/> like subsequence.</remarks>
[Continuous(20), Pipeline<Sequence<RegionVolume, RegionPoint>>]

[DebuggerDisplay($"{{{nameof(Type)},nq}}")]
Expand Down
2 changes: 1 addition & 1 deletion source/library/records/airspace/RestrictiveVolume.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Arinc424.Airspace;
/// <summary>
/// <c>Restrictive Airspace</c> primary record sequence.
/// </summary>
/// <remarks>See section 4.1.18.1.</remarks>
/// <remarks>Used by <see cref="RestrictiveSpace"/> like subsequence.</remarks>
[Pipeline<Sequence<RestrictiveVolume, BoundaryPoint>>]

[DebuggerDisplay($"{{{nameof(Type)},nq}}")]
Expand Down
3 changes: 3 additions & 0 deletions source/library/records/airspace/Space{TVolume}.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace Arinc424.Airspace;

/// <summary>
/// Base space properties.
/// </summary>
[Continuous(25)]
public abstract class Space<TVolume> : Record424<TVolume>, IIcao, INamed where TVolume : Volume
{
Expand Down
2 changes: 1 addition & 1 deletion source/library/records/airspace/Volume.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Arinc424.Airspace;
public abstract class Volume : Record424<BoundaryPoint>, IMultiple
{
[Character(20)]
public char Multiplier { get; set; }
public char? Multiplier { get; set; }

/// <inheritdoc cref="Arinc424.LevelType"/>
[Character(26)]
Expand Down
2 changes: 1 addition & 1 deletion source/library/records/procedures/ApproachSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Arinc424.Procedures;
/// <summary>
/// <c>Airport and Heliport Approach</c> primary record sequence.
/// </summary>
/// <remarks>See section 4.1.9.1 and 4.2.3.1.</remarks>
/// <remarks>Used by <see cref="Approach"/> like subsequence.</remarks>
[Pipeline<Sequence<ApproachSequence, ApproachPoint>>]
public class ApproachSequence : ProcedureSequence<ApproachPoint>
{
Expand Down
2 changes: 1 addition & 1 deletion source/library/records/procedures/ArrivalSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Arinc424.Procedures;
/// <summary>
/// <c>Airport and Heliport STAR</c> primary record sequence.
/// </summary>
/// <remarks>See section 4.1.9.1 and 4.2.3.1.</remarks>
/// <remarks>Used by <see cref="Arrival"/> like subsequence.</remarks>
[Pipeline<Sequence<ArrivalSequence, ArrivalPoint>>]
public class ArrivalSequence : ProcedureSequence<ArrivalPoint>
{
Expand Down
2 changes: 1 addition & 1 deletion source/library/records/procedures/DepartureSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Arinc424.Procedures;
/// <summary>
/// <c>Airport and Heliport SID</c> primary record sequence.
/// </summary>
/// <remarks>See section 4.1.9.1 and 4.2.3.1.</remarks>
/// <remarks>Used by <see cref="Departure"/> like subsequence.</remarks>
[Pipeline<Sequence<DepartureSequence, DeparturePoint>>]
public class DepartureSequence : ProcedureSequence<DeparturePoint>
{
Expand Down

0 comments on commit 24341d6

Please sign in to comment.