Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed: FormatItem.AsSpan() #304

Merged
merged 1 commit into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 17 additions & 20 deletions src/SmartFormat.Tests/TestUtils/ConvertibleDecimal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,27 @@

namespace SmartFormat.Tests.TestUtils;

class ConvertibleDecimal : IConvertible
public class ConvertibleDecimal : IConvertible
{
private readonly decimal _value;

public TypeCode GetTypeCode() => TypeCode.Decimal;
public decimal ToDecimal(IFormatProvider provider) => _value;

public bool ToBoolean(IFormatProvider provider) => throw new NotImplementedException();
public byte ToByte(IFormatProvider provider) => throw new NotImplementedException();
public char ToChar(IFormatProvider provider) => throw new NotImplementedException();
public DateTime ToDateTime(IFormatProvider provider) => throw new NotImplementedException();
public double ToDouble(IFormatProvider provider) => throw new NotImplementedException();
public short ToInt16(IFormatProvider provider) => throw new NotImplementedException();
public int ToInt32(IFormatProvider provider) => throw new NotImplementedException();
public long ToInt64(IFormatProvider provider) => throw new NotImplementedException();
public sbyte ToSByte(IFormatProvider provider) => throw new NotImplementedException();
public float ToSingle(IFormatProvider provider) => throw new NotImplementedException();
public string ToString(IFormatProvider provider) => throw new NotImplementedException();
public object ToType(Type conversionType, IFormatProvider provider) => throw new NotImplementedException();
public ushort ToUInt16(IFormatProvider provider) => throw new NotImplementedException();
public uint ToUInt32(IFormatProvider provider) => throw new NotImplementedException();
public ulong ToUInt64(IFormatProvider provider) => throw new NotImplementedException();

public decimal ToDecimal(IFormatProvider? provider) => _value;
public bool ToBoolean(IFormatProvider? provider) => throw new NotImplementedException();
public byte ToByte(IFormatProvider? provider) => throw new NotImplementedException();
public char ToChar(IFormatProvider? provider) => throw new NotImplementedException();
public DateTime ToDateTime(IFormatProvider? provider) => throw new NotImplementedException();
public double ToDouble(IFormatProvider? provider) => throw new NotImplementedException();
public short ToInt16(IFormatProvider? provider) => throw new NotImplementedException();
public int ToInt32(IFormatProvider? provider) => throw new NotImplementedException();
public long ToInt64(IFormatProvider? provider) => throw new NotImplementedException();
public sbyte ToSByte(IFormatProvider? provider) => throw new NotImplementedException();
public float ToSingle(IFormatProvider? provider) => throw new NotImplementedException();
public string ToString(IFormatProvider? provider) => throw new NotImplementedException();
public object ToType(Type conversionType, IFormatProvider? provider) => throw new NotImplementedException();
public ushort ToUInt16(IFormatProvider? provider) => throw new NotImplementedException();
public uint ToUInt32(IFormatProvider? provider) => throw new NotImplementedException();
public ulong ToUInt64(IFormatProvider? provider) => throw new NotImplementedException();
public override string ToString() => $"Convertible({_value})";

public ConvertibleDecimal(decimal v) => _value = v;
}
5 changes: 5 additions & 0 deletions src/SmartFormat/Core/Parsing/Format.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,15 @@ public void ReturnToPool()
ParentPlaceholder = null;
HasNested = false;

#pragma warning disable S3267 // Don't use LINQ in favor of less GC
// Return and clear FormatItems we own
foreach (var item in Items)
{
if (ReferenceEquals(this, item.ParentFormatItem))
ReturnFormatItemToPool(item);
}
#pragma warning restore S3267 // Restore: Loops should be simplified with "LINQ" expressions

Items.Clear();

// Return and clear the list of SplitLists
Expand Down Expand Up @@ -237,6 +240,7 @@ public int IndexOf(char search)
public int IndexOf(char search, int start)
{
start = StartIndex + start;
#pragma warning disable S3267 // Don't use LINQ in favor of less GC
foreach (var item in Items)
{
if (item.EndIndex < start || item is not LiteralText literalItem) continue;
Expand All @@ -246,6 +250,7 @@ public int IndexOf(char search, int start)
literalItem.BaseString.IndexOf(search, start, literalItem.EndIndex - start);
if (literalIndex != -1) return literalIndex - StartIndex;
}
#pragma warning restore S3267 // Restore: Loops should be simplified with "LINQ" expressions

return -1;
}
Expand Down
4 changes: 2 additions & 2 deletions src/SmartFormat/Core/Parsing/FormatItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,6 @@ public virtual void Clear()
/// </summary>
/// <returns>The <see cref="ReadOnlySpan{T}"/> representation of this <see cref="FormatItem"/></returns>
public virtual ReadOnlySpan<char> AsSpan() => EndIndex <= StartIndex
? BaseString.AsSpan(StartIndex)
? ReadOnlySpan<char>.Empty
: BaseString.AsSpan(StartIndex, Length);
}
}
2 changes: 2 additions & 0 deletions src/SmartFormat/Core/Sources/Source.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ private bool HasNullableOperator(ISelectorInfo selectorInfo)
{
if (_smartSettings != null && selectorInfo.Placeholder != null)
{
#pragma warning disable S3267 // Don't use LINQ in favor of less GC
foreach (var s in selectorInfo.Placeholder.Selectors)
{
if (s.OperatorLength > 1 && s.BaseString[s.OperatorStartIndex] == _smartSettings.Parser.NullableOperator)
return true;
}
#pragma warning restore S3267 // Restore: Loops should be simplified with "LINQ" expressions
}
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/SmartFormat/Extensions/DefaultFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public bool TryEvaluateFormat(IFormattingInfo formattingInfo)
var current = formattingInfo.CurrentValue;

// If the format has nested placeholders, we process those first
// instead of formatting the item.
// instead of formatting the item. Like with "{2:list:{:{FirstName}}|, }"
if (format is {HasNested: true})
{
formattingInfo.FormatAsChild(format, current);
Expand Down
2 changes: 2 additions & 0 deletions src/SmartFormat/Extensions/ListFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,13 @@ private bool HasNullableOperator(IFormattingInfo formattingInfo)
{
if (formattingInfo.Placeholder != null)
{
#pragma warning disable S3267 // Don't use LINQ in favor of less GC
foreach (var s in formattingInfo.Placeholder.Selectors)
{
if (s.OperatorLength > 0 && s.BaseString[s.OperatorStartIndex] == _smartSettings.Parser.NullableOperator)
return true;
}
#pragma warning restore S3267 // Restore: Loops should be simplified with "LINQ" expressions
}
return false;
}
Expand Down
15 changes: 12 additions & 3 deletions src/SmartFormat/SmartFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,6 @@ public void Format(FormattingInfo formattingInfo)
var childFormattingInfo = formattingInfo.CreateChild(placeholder);
try
{
// Note: If there is no selector (like {:0.00}),
// FormattingInfo.CurrentValue is left unchanged
EvaluateSelectors(childFormattingInfo);
}
catch (Exception ex)
Expand Down Expand Up @@ -529,6 +527,16 @@ private void CheckForExtensions()
"No formatter extensions are available. Please add at least one formatter extension, such as the DefaultFormatter.");
}

/// <summary>
/// Evaluates all <see cref="Selector"/>s of a <see cref="Placeholder"/>.
/// </summary>
/// <remarks>
/// Note: If there is no selector (like {:0.00}), <see cref="FormattingInfo.CurrentValue"/> is left unchanged.
/// <br/>
/// Child formats <b>inside <see cref="Placeholder"/>s</b> are evaluated in <see cref="DefaultFormatter"/>.
/// Example: "{ChildOne.ChildTwo.ChildThree: {Four}}" where "{Four}" is a child placeholder.
/// </remarks>
/// <param name="formattingInfo"></param>
private void EvaluateSelectors(FormattingInfo formattingInfo)
{
if (formattingInfo.Placeholder is null) return;
Expand All @@ -553,7 +561,8 @@ private void EvaluateSelectors(FormattingInfo formattingInfo)
if (firstSelector)
{
firstSelector = false;
// Handle "nested scopes" by traversing the stack:
// Handle "nested scopes" like "{ChildOne.ChildTwo.ChildThree: {Four}}
// by traversing the stack:
var parentFormattingInfo = formattingInfo;
while (!handled && parentFormattingInfo.Parent != null)
{
Expand Down