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