diff --git a/Avalonia.sln b/Avalonia.sln index d1c5026e58..e43bfe242e 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -150,7 +150,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\SharpDX.props = build\SharpDX.props build\SkiaSharp.props = build\SkiaSharp.props build\Splat.props = build\Splat.props - build\Sprache.props = build\Sprache.props + build\System.Memory.props = build\System.Memory.props build\XUnit.props = build\XUnit.props EndProjectSection EndProject diff --git a/build/Sprache.props b/build/Sprache.props deleted file mode 100644 index 8ea84de163..0000000000 --- a/build/Sprache.props +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/build/System.Memory.props b/build/System.Memory.props index f3253f8882..df7956af84 100644 --- a/build/System.Memory.props +++ b/build/System.Memory.props @@ -1,5 +1,8 @@ - + + + + diff --git a/build/readme.md b/build/readme.md index aed508a508..3575f0ab94 100644 --- a/build/readme.md +++ b/build/readme.md @@ -16,7 +16,6 @@ - ``` diff --git a/packages.cake b/packages.cake index 51d9c48159..7ebe8d4694 100644 --- a/packages.cake +++ b/packages.cake @@ -110,7 +110,6 @@ public class Packages var SerilogVersion = packageVersions["Serilog"].FirstOrDefault().Item1; var SerilogSinksDebugVersion = packageVersions["Serilog.Sinks.Debug"].FirstOrDefault().Item1; var SerilogSinksTraceVersion = packageVersions["Serilog.Sinks.Trace"].FirstOrDefault().Item1; - var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1; var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1; var ReactiveUIVersion = packageVersions["reactiveui"].FirstOrDefault().Item1; var SystemValueTupleVersion = packageVersions["System.ValueTuple"].FirstOrDefault().Item1; @@ -121,10 +120,10 @@ public class Packages var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1; var SharpDXDirect3D9Version = packageVersions["SharpDX.Direct3D9"].FirstOrDefault().Item1; var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1; + var SystemMemoryVersion = packageVersions["System.Memory"].FirstOrDefault().Item1; var SystemComponentModelAnnotationsVersion = packageVersions["System.ComponentModel.Annotations"].FirstOrDefault().Item1; context.Information("Package: Serilog, version: {0}", SerilogVersion); - context.Information("Package: Sprache, version: {0}", SpracheVersion); context.Information("Package: System.Reactive, version: {0}", SystemReactiveVersion); context.Information("Package: reactiveui, version: {0}", ReactiveUIVersion); context.Information("Package: System.ValueTuple, version: {0}", SystemValueTupleVersion); @@ -135,6 +134,7 @@ public class Packages context.Information("Package: SharpDX.Direct3D11, version: {0}", SharpDXDirect3D11Version); context.Information("Package: SharpDX.Direct3D9, version: {0}", SharpDXDirect3D9Version); context.Information("Package: SharpDX.DXGI, version: {0}", SharpDXDXGIVersion); + context.Information("Package: System.Memory, version: {0}", SystemMemoryVersion); var nugetPackagesDir = System.Environment.GetEnvironmentVariable("NUGET_HOME") ?? System.IO.Path.Combine(System.Environment.GetEnvironmentVariable("USERPROFILE") ?? System.Environment.GetEnvironmentVariable("HOME"), ".nuget"); @@ -253,9 +253,9 @@ public class Packages new NuSpecDependency() { Id = "Serilog", Version = SerilogVersion }, new NuSpecDependency() { Id = "Serilog.Sinks.Debug", Version = SerilogSinksDebugVersion }, new NuSpecDependency() { Id = "Serilog.Sinks.Trace", Version = SerilogSinksTraceVersion }, - new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion }, new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion }, new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", Version = parameters.Version }, + new NuSpecDependency() { Id = "System.Memory", Version = SystemMemoryVersion }, new NuSpecDependency() { Id = "System.ComponentModel.Annotations", Version = SystemComponentModelAnnotationsVersion }, //.NET Core new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp2.0", Version = "4.3.0" }, @@ -264,9 +264,9 @@ public class Packages new NuSpecDependency() { Id = "Serilog", TargetFramework = "netcoreapp2.0", Version = SerilogVersion }, new NuSpecDependency() { Id = "Serilog.Sinks.Debug", TargetFramework = "netcoreapp2.0", Version = SerilogSinksDebugVersion }, new NuSpecDependency() { Id = "Serilog.Sinks.Trace", TargetFramework = "netcoreapp2.0", Version = SerilogSinksTraceVersion }, - new NuSpecDependency() { Id = "Sprache", TargetFramework = "netcoreapp2.0", Version = SpracheVersion }, new NuSpecDependency() { Id = "System.Reactive", TargetFramework = "netcoreapp2.0", Version = SystemReactiveVersion }, new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", TargetFramework = "netcoreapp2.0", Version = parameters.Version }, + new NuSpecDependency() { Id = "System.Memory", TargetFramework = "netcoreapp2.0", Version = SystemMemoryVersion }, } .Deps(new string[]{null, "netcoreapp2.0"}, "System.ValueTuple", "System.ComponentModel.TypeConverter", "System.ComponentModel.Primitives", diff --git a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj index a60fd242e4..368bc19abf 100644 --- a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj +++ b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj @@ -174,6 +174,5 @@ ControlCatalog - - \ No newline at end of file + diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj index 359adaa1f0..06008ef02e 100644 --- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj +++ b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj @@ -150,6 +150,6 @@ - + \ No newline at end of file diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 26397a6f32..bc068857ff 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -8,4 +8,5 @@ - \ No newline at end of file + + diff --git a/src/Avalonia.Base/Data/Core/ExpressionParseException.cs b/src/Avalonia.Base/Data/Core/ExpressionParseException.cs index 1845b1b52a..195c9b7660 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionParseException.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionParseException.cs @@ -17,6 +17,7 @@ namespace Avalonia.Data.Core /// /// The column position of the error. /// The exception message. + /// The exception that caused the parsing failure. public ExpressionParseException(int column, string message, Exception innerException = null) : base(message, innerException) { diff --git a/src/Avalonia.Base/Utilities/CharacterReader.cs b/src/Avalonia.Base/Utilities/CharacterReader.cs index 0910d5b969..55be8db043 100644 --- a/src/Avalonia.Base/Utilities/CharacterReader.cs +++ b/src/Avalonia.Base/Utilities/CharacterReader.cs @@ -2,30 +2,37 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.Globalization; +using System.Text; namespace Avalonia.Utilities { - public class CharacterReader + public ref struct CharacterReader { - private readonly string _s; - private int _i; + private ReadOnlySpan _s; - public CharacterReader(string s) + public CharacterReader(ReadOnlySpan s) + :this() { _s = s; } - public bool End => _i == _s.Length; - public char Peek => _s[_i]; - public int Position => _i; - public char Take() => _s[_i++]; + public bool End => _s.IsEmpty; + public char Peek => _s[0]; + public int Position { get; private set; } + public char Take() + { + Position++; + char taken = _s[0]; + _s = _s.Slice(1); + return taken; + } public void SkipWhitespace() { - while (!End && char.IsWhiteSpace(Peek)) - { - Take(); - } + var trimmed = _s.TrimStart(); + Position += _s.Length - trimmed.Length; + _s = trimmed; } public bool TakeIf(char c) @@ -40,5 +47,39 @@ namespace Avalonia.Utilities return false; } } + + public bool TakeIf(Func condition) + { + if (condition(Peek)) + { + Take(); + return true; + } + return false; + } + + public ReadOnlySpan TakeUntil(char c) + { + int len; + for (len = 0; len < _s.Length && _s[len] != c; len++) + { + } + var span = _s.Slice(0, len); + _s = _s.Slice(len); + Position += len; + return span; + } + + public ReadOnlySpan TakeWhile(Func condition) + { + int len; + for (len = 0; len < _s.Length && condition(_s[len]); len++) + { + } + var span = _s.Slice(0, len); + _s = _s.Slice(len); + Position += len; + return span; + } } } diff --git a/src/Avalonia.Base/Utilities/IdentifierParser.cs b/src/Avalonia.Base/Utilities/IdentifierParser.cs index 14b8affbdd..0a2e8e1e1b 100644 --- a/src/Avalonia.Base/Utilities/IdentifierParser.cs +++ b/src/Avalonia.Base/Utilities/IdentifierParser.cs @@ -1,6 +1,8 @@ -// Copyright (c) The Avalonia Project. All rights reserved. +// Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; +using System.Collections.Generic; using System.Globalization; using System.Text; @@ -8,22 +10,15 @@ namespace Avalonia.Utilities { public static class IdentifierParser { - public static string Parse(CharacterReader r) + public static ReadOnlySpan ParseIdentifier(this ref CharacterReader r) { if (IsValidIdentifierStart(r.Peek)) { - var result = new StringBuilder(); - - while (!r.End && IsValidIdentifierChar(r.Peek)) - { - result.Append(r.Take()); - } - - return result.ToString(); + return r.TakeWhile(IsValidIdentifierChar); } else { - return null; + return ReadOnlySpan.Empty; } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs index 627a646bcf..8a0ba64582 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs @@ -26,8 +26,7 @@ namespace Avalonia.Markup.Xaml.Converters { var registry = AvaloniaPropertyRegistry.Instance; var parser = new PropertyParser(); - var reader = new CharacterReader((string)value); - var (ns, owner, propertyName) = parser.Parse(reader); + var (ns, owner, propertyName) = parser.Parse(new CharacterReader(((string)value).AsSpan())); var ownerType = TryResolveOwnerByName(context, ns, owner); var targetType = context.GetFirstAmbientValue()?.TargetType ?? context.GetFirstAmbientValue