From 10664b74fdf99f46380cc816718b7ac75b1c53a3 Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Vieira Date: Sat, 30 Dec 2023 21:45:31 -0300 Subject: [PATCH] draft --- .../Reader/FixedLengthReaderBuilder.cs | 4 +- RecordParser/Parsers/FixedLengthReader.cs | 10 ++- RecordParser/Visitors/MemoryVisitor.cs | 78 +++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 RecordParser/Visitors/MemoryVisitor.cs diff --git a/RecordParser/Builders/Reader/FixedLengthReaderBuilder.cs b/RecordParser/Builders/Reader/FixedLengthReaderBuilder.cs index 1a4514f..67bcf27 100644 --- a/RecordParser/Builders/Reader/FixedLengthReaderBuilder.cs +++ b/RecordParser/Builders/Reader/FixedLengthReaderBuilder.cs @@ -98,7 +98,9 @@ public IFixedLengthReader Build(CultureInfo cultureInfo = null, Func facto func = CultureInfoVisitor.ReplaceCulture(func, cultureInfo); - return new FixedLengthReader(func.Compile()); + var memory = new SpanReplacerVisitor().Modify(func); + + return new FixedLengthReader(func.Compile(true), memory.Compile(true)); } } } diff --git a/RecordParser/Parsers/FixedLengthReader.cs b/RecordParser/Parsers/FixedLengthReader.cs index d67e549..d428c01 100644 --- a/RecordParser/Parsers/FixedLengthReader.cs +++ b/RecordParser/Parsers/FixedLengthReader.cs @@ -5,16 +5,24 @@ namespace RecordParser.Parsers public interface IFixedLengthReader { T Parse(ReadOnlySpan line); + T Parse(ReadOnlyMemory line); bool TryParse(ReadOnlySpan line, out T result); } internal class FixedLengthReader : IFixedLengthReader { private readonly FuncSpanT parser; + private readonly Func, T> parser2; - internal FixedLengthReader(FuncSpanT parser) + internal FixedLengthReader(FuncSpanT parser, Func, T> parser2) { this.parser = parser; + this.parser2 = parser2; + } + + public T Parse(ReadOnlyMemory line) + { + return parser2(line); } public T Parse(ReadOnlySpan line) diff --git a/RecordParser/Visitors/MemoryVisitor.cs b/RecordParser/Visitors/MemoryVisitor.cs new file mode 100644 index 0000000..2989fb0 --- /dev/null +++ b/RecordParser/Visitors/MemoryVisitor.cs @@ -0,0 +1,78 @@ +using System; +using System.Linq; +using System.Linq.Expressions; + +namespace RecordParser.Visitors +{ + internal class SpanReplacerVisitor : ExpressionVisitor + { + private readonly static ParameterExpression memory = Expression.Parameter(typeof(ReadOnlyMemory), "memory"); + private readonly static MemberExpression span = Expression.Property(memory, "Span"); + + + + public Expression, T>> Modify(Expression> ex) + { + if (ex is null) return null; + + var body = Visit(ex.Body); + + body = new StaticMethodVisitor().Visit(body); + + var lamb = Expression.Lambda, T>>(body, memory); + + return lamb; + } + + + + protected override Expression VisitParameter(ParameterExpression node) + { + if (node.Type == typeof(ReadOnlySpan)) + return span; + + return base.VisitParameter(node); + } + + class StaticMethodVisitor : ExpressionVisitor + { + public static string ToString(ReadOnlySpan span) => span.ToString(); + public static ReadOnlySpan Trim(ReadOnlySpan span) => span.Trim(); + public static ReadOnlySpan Slice1(ReadOnlySpan span, int start) => span.Slice(start); + public static ReadOnlySpan Slice2(ReadOnlySpan span, int start, int count) => span.Slice(start, count); + + protected override Expression VisitMethodCall(MethodCallExpression node) + { + if (node.Object?.Type == typeof(ReadOnlySpan)) + { + var args = node.Arguments.Prepend(node.Object).ToArray(); + + if (node.Method.Name == "Slice") + { + Delegate f = node.Arguments.Count == 1 + ? StaticMethodVisitor.Slice1 + : StaticMethodVisitor.Slice2; + + return Expression.Call(f.Method, args); + } + + if (node.Method.Name == "ToString") + { + var f = StaticMethodVisitor.ToString; + + return Expression.Call(f.Method, args); + } + + if (node.Method.Name == "Trim") + { + var f = StaticMethodVisitor.Trim; + + return Expression.Call(f.Method, args); + } + } + + return base.VisitMethodCall(node); + } + } + } +}