Browse Source
* Remove obsolete TextInputMethodClient.ShowInputPanel method * Merge Move and Move private in KeyboardNavigationHandler * Change Inline.TextDecorations type to AttachedProperty * Change TextSearch.GetText/SetText parameter to Interactive * Remove Design.SetPreviewWith overload * Replace JSWebWorkerClone with JSWebWorker * Remove StringTokenizer * Update API suppressions * Add reflection comment to RenderWorkerpull/20561/head
committed by
GitHub
11 changed files with 134 additions and 474 deletions
@ -1,245 +0,0 @@ |
|||||
using System; |
|
||||
using System.Diagnostics.CodeAnalysis; |
|
||||
using System.Globalization; |
|
||||
using static System.Char; |
|
||||
|
|
||||
namespace Avalonia.Utilities |
|
||||
{ |
|
||||
// TODO12: Remove this struct in 12.0 (breaking change)
|
|
||||
|
|
||||
[Obsolete("This type has been superseded by SpanStringTokenizer.")] |
|
||||
#if !BUILDTASK
|
|
||||
public |
|
||||
#endif
|
|
||||
record struct StringTokenizer : IDisposable |
|
||||
{ |
|
||||
private const char DefaultSeparatorChar = ','; |
|
||||
|
|
||||
private readonly string _s; |
|
||||
private readonly int _length; |
|
||||
private readonly char _separator; |
|
||||
private readonly string? _exceptionMessage; |
|
||||
private readonly IFormatProvider _formatProvider; |
|
||||
private int _index; |
|
||||
private int _tokenIndex; |
|
||||
private int _tokenLength; |
|
||||
|
|
||||
public StringTokenizer(string s, IFormatProvider formatProvider, string? exceptionMessage = null) |
|
||||
: this(s, GetSeparatorFromFormatProvider(formatProvider), exceptionMessage) |
|
||||
{ |
|
||||
_formatProvider = formatProvider; |
|
||||
} |
|
||||
|
|
||||
public StringTokenizer(string s, char separator = DefaultSeparatorChar, string? exceptionMessage = null) |
|
||||
{ |
|
||||
_s = s ?? throw new ArgumentNullException(nameof(s)); |
|
||||
_length = s?.Length ?? 0; |
|
||||
_separator = separator; |
|
||||
_exceptionMessage = exceptionMessage; |
|
||||
_formatProvider = CultureInfo.InvariantCulture; |
|
||||
_index = 0; |
|
||||
_tokenIndex = -1; |
|
||||
_tokenLength = 0; |
|
||||
|
|
||||
while (_index < _length && IsWhiteSpace(_s, _index)) |
|
||||
{ |
|
||||
_index++; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public string? CurrentToken => _tokenIndex < 0 ? null : _s.Substring(_tokenIndex, _tokenLength); |
|
||||
|
|
||||
public ReadOnlySpan<char> CurrentTokenSpan => _tokenIndex < 0 ? ReadOnlySpan<char>.Empty : _s.AsSpan().Slice(_tokenIndex, _tokenLength); |
|
||||
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
if (_index != _length) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public bool TryReadInt32(out Int32 result, char? separator = null) |
|
||||
{ |
|
||||
if (TryReadSpan(out var stringResult, separator) && |
|
||||
SpanHelpers.TryParseInt(stringResult, NumberStyles.Integer, _formatProvider, out result)) |
|
||||
{ |
|
||||
return true; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
result = default; |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public int ReadInt32(char? separator = null) |
|
||||
{ |
|
||||
if (!TryReadInt32(out var result, separator)) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
public bool TryReadDouble(out double result, char? separator = null) |
|
||||
{ |
|
||||
if (TryReadSpan(out var stringResult, separator) && |
|
||||
SpanHelpers.TryParseDouble(stringResult, NumberStyles.Float, _formatProvider, out result)) |
|
||||
{ |
|
||||
return true; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
result = default; |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public double ReadDouble(char? separator = null) |
|
||||
{ |
|
||||
if (!TryReadDouble(out var result, separator)) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
public bool TryReadString([NotNull] out string result, char? separator = null) |
|
||||
{ |
|
||||
var success = TryReadToken(separator ?? _separator); |
|
||||
result = CurrentTokenSpan.ToString(); |
|
||||
return success; |
|
||||
} |
|
||||
|
|
||||
public string ReadString(char? separator = null) |
|
||||
{ |
|
||||
if (!TryReadString(out var result, separator)) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
public bool TryReadSpan(out ReadOnlySpan<char> result, char? separator = null) |
|
||||
{ |
|
||||
var success = TryReadToken(separator ?? _separator); |
|
||||
result = CurrentTokenSpan; |
|
||||
return success; |
|
||||
} |
|
||||
|
|
||||
public ReadOnlySpan<char> ReadSpan(char? separator = null) |
|
||||
{ |
|
||||
if (!TryReadSpan(out var result, separator)) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
private bool TryReadToken(char separator) |
|
||||
{ |
|
||||
_tokenIndex = -1; |
|
||||
|
|
||||
if (_index >= _length) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
var c = _s[_index]; |
|
||||
|
|
||||
var index = _index; |
|
||||
var length = 0; |
|
||||
|
|
||||
while (_index < _length) |
|
||||
{ |
|
||||
c = _s[_index]; |
|
||||
|
|
||||
if (IsWhiteSpace(c) || c == separator) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
_index++; |
|
||||
length++; |
|
||||
} |
|
||||
|
|
||||
SkipToNextToken(separator); |
|
||||
|
|
||||
_tokenIndex = index; |
|
||||
_tokenLength = length; |
|
||||
|
|
||||
if (_tokenLength < 1) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
private void SkipToNextToken(char separator) |
|
||||
{ |
|
||||
if (_index < _length) |
|
||||
{ |
|
||||
var c = _s[_index]; |
|
||||
|
|
||||
if (c != separator && !IsWhiteSpace(c)) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
|
|
||||
var length = 0; |
|
||||
|
|
||||
while (_index < _length) |
|
||||
{ |
|
||||
c = _s[_index]; |
|
||||
|
|
||||
if (c == separator) |
|
||||
{ |
|
||||
length++; |
|
||||
_index++; |
|
||||
|
|
||||
if (length > 1) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
if (!IsWhiteSpace(c)) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
_index++; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (length > 0 && _index >= _length) |
|
||||
{ |
|
||||
throw GetFormatException(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private FormatException GetFormatException() => |
|
||||
_exceptionMessage != null ? new FormatException(_exceptionMessage) : new FormatException(); |
|
||||
|
|
||||
private static char GetSeparatorFromFormatProvider(IFormatProvider provider) |
|
||||
{ |
|
||||
var c = DefaultSeparatorChar; |
|
||||
|
|
||||
var formatInfo = NumberFormatInfo.GetInstance(provider); |
|
||||
if (formatInfo.NumberDecimalSeparator.Length > 0 && c == formatInfo.NumberDecimalSeparator[0]) |
|
||||
{ |
|
||||
c = ';'; |
|
||||
} |
|
||||
|
|
||||
return c; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,81 +0,0 @@ |
|||||
using System; |
|
||||
using Avalonia.Utilities; |
|
||||
using Xunit; |
|
||||
|
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
|
||||
|
|
||||
namespace Avalonia.Base.UnitTests.Utilities |
|
||||
{ |
|
||||
public class StringTokenizerTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public void ReadInt32_Reads_Values() |
|
||||
{ |
|
||||
var target = new StringTokenizer("123,456"); |
|
||||
|
|
||||
Assert.Equal(123, target.ReadInt32()); |
|
||||
Assert.Equal(456, target.ReadInt32()); |
|
||||
Assert.Throws<FormatException>(() => target.ReadInt32()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void ReadDouble_Reads_Values() |
|
||||
{ |
|
||||
var target = new StringTokenizer("12.3,45.6"); |
|
||||
|
|
||||
Assert.Equal(12.3, target.ReadDouble()); |
|
||||
Assert.Equal(45.6, target.ReadDouble()); |
|
||||
Assert.Throws<FormatException>(() => target.ReadDouble()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void TryReadInt32_Reads_Values() |
|
||||
{ |
|
||||
var target = new StringTokenizer("123,456"); |
|
||||
|
|
||||
Assert.True(target.TryReadInt32(out var value)); |
|
||||
Assert.Equal(123, value); |
|
||||
Assert.True(target.TryReadInt32(out value)); |
|
||||
Assert.Equal(456, value); |
|
||||
Assert.False(target.TryReadInt32(out value)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void TryReadInt32_Doesnt_Throw() |
|
||||
{ |
|
||||
var target = new StringTokenizer("abc"); |
|
||||
|
|
||||
Assert.False(target.TryReadInt32(out var value)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void TryReadDouble_Reads_Values() |
|
||||
{ |
|
||||
var target = new StringTokenizer("12.3,45.6"); |
|
||||
|
|
||||
Assert.True(target.TryReadDouble(out var value)); |
|
||||
Assert.Equal(12.3, value); |
|
||||
Assert.True(target.TryReadDouble(out value)); |
|
||||
Assert.Equal(45.6, value); |
|
||||
Assert.False(target.TryReadDouble(out value)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void TryReadDouble_Doesnt_Throw() |
|
||||
{ |
|
||||
var target = new StringTokenizer("abc"); |
|
||||
|
|
||||
Assert.False(target.TryReadDouble(out var value)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void ReadSpan_And_ReadString_Reads_Same() |
|
||||
{ |
|
||||
var target1 = new StringTokenizer("abc,def"); |
|
||||
var target2 = new StringTokenizer("abc,def"); |
|
||||
|
|
||||
Assert.Equal(target1.ReadString(), target2.ReadSpan().ToString()); |
|
||||
Assert.True(target1.ReadSpan().SequenceEqual(target2.ReadString())); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue