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

SepWriter.Col: Replace StringBuilder with ArrayPool array and DefaultInterpolatedStringHandler #216

Merged
merged 18 commits into from
Jan 12, 2025
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
6 changes: 0 additions & 6 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
7.0.x
8.0.x
- name: Setup .NET (global.json)
uses: actions/setup-dotnet@v4
Expand Down Expand Up @@ -78,7 +77,6 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
configuration: [Debug, Release]

runs-on: ${{ matrix.os }}

Expand All @@ -88,16 +86,13 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
7.0.x
8.0.x
- name: Setup .NET (global.json)
uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build -c ${{ matrix.configuration }} --no-restore
- name: Test Parsers
shell: pwsh
run: ./test-parsers.ps1
Expand All @@ -116,7 +111,6 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
7.0.x
8.0.x
- name: Setup .NET (global.json)
uses: actions/setup-dotnet@v4
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2130,8 +2130,12 @@ namespace nietras.SeparatedValues
public void Set(System.IFormatProvider? provider, [System.Runtime.CompilerServices.InterpolatedStringHandlerArgument(new string?[]?[] {
"",
"provider"})] ref nietras.SeparatedValues.SepWriter.Col.FormatInterpolatedStringHandler handler) { }
[System.Obsolete(("Types with embedded references are not supported in this version of your compiler" +
"."), true)]
[System.Runtime.CompilerServices.CompilerFeatureRequired("RefStructs")]
[System.Runtime.CompilerServices.InterpolatedStringHandler]
public readonly struct FormatInterpolatedStringHandler
[System.Runtime.CompilerServices.IsByRefLike]
public struct FormatInterpolatedStringHandler
{
public FormatInterpolatedStringHandler(int literalLength, int formattedCount, nietras.SeparatedValues.SepWriter.Col col) { }
public FormatInterpolatedStringHandler(int literalLength, int formattedCount, nietras.SeparatedValues.SepWriter.Col col, System.IFormatProvider? provider) { }
Expand Down
9 changes: 6 additions & 3 deletions src/Sep.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
Expand All @@ -22,16 +23,16 @@
{
var config = (Debugger.IsAttached ? new DebugInProcessConfig() : DefaultConfig.Instance)
.WithSummaryStyle(SummaryStyle.Default.WithMaxParameterColumnWidth(200))
.AddColumn(MBPerSecFromCharsLength())
//.AddColumn(MBPerSecFromCharsLength())
;
//BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly()).Run(args, config);
BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly()).Run(args, config);
//BenchmarkRunner.Run(typeof(SepReaderBench), config, args);
//BenchmarkRunner.Run(typeof(SepWriterBench), config, args);
//BenchmarkRunner.Run(typeof(SepReaderWriterBench), config, args);
//BenchmarkRunner.Run(typeof(SepEndToEndBench), config, args);
//BenchmarkRunner.Run(typeof(SepHashBench), config, args);
//BenchmarkRunner.Run(typeof(SepParseSeparatorsMaskBench), config, args);
BenchmarkRunner.Run(typeof(SepParserBench), config, args);
//BenchmarkRunner.Run(typeof(SepParserBench), config, args);
//BenchmarkRunner.Run(typeof(StopwatchBench), config, args);
}
else
Expand All @@ -46,8 +47,10 @@
}
}

#pragma warning disable CS8321 // Local function is declared but never used
static IColumn MBPerSecFromCharsLength() => new BytesStatisticColumn("MB/s",
BytesFromCharsLength, BytesStatisticColumn.FormatMBPerSec);
#pragma warning restore CS8321 // Local function is declared but never used

static long BytesFromCharsLength(IReadOnlyList<ParameterInstance> parameters)
{
Expand Down
12 changes: 11 additions & 1 deletion src/Sep.Benchmarks/SepWriterBench.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class SepWriterBench
[IterationSetup]
public void Setup()
{
_writer = Sep.Writer().ToText(256 * 1024 * 1024);
_writer = Sep.Writer(o => o with { WriteHeader = false }).ToText(256 * 1024 * 1024);
}

[IterationCleanup]
Expand All @@ -36,4 +36,14 @@ public void SetByColName()
writeRow["C"].Set("cccccccccccccccccccccccc");
writeRow["D"].Set("ddddddddddddddddddddddddddddddd");
}

[Benchmark]
public void SetByColIndex()
{
using var writeRow = _writer!.NewRow();
writeRow[0].Set("aaaaaaaaaaaaaaaaaaa");
writeRow[1].Set("bbbbbbbbbbbbbbbbbbbbbb");
writeRow[2].Set("cccccccccccccccccccccccc");
writeRow[3].Set("ddddddddddddddddddddddddddddddd");
}
}
21 changes: 21 additions & 0 deletions src/Sep.Test/Internals/InterpolatedStringHandlerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ namespace nietras.SeparatedValues.Test.Internals;
[TestClass]
public class InterpolatedStringHandlerTest
{
#if NET8_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_pos")]
static extern ref int Position(ref DefaultInterpolatedStringHandler handler);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_arrayToReturnToPool")]
static extern ref char[]? ArrayToReturnToPool(ref DefaultInterpolatedStringHandler handler);

[TestMethod]
public void InterpolatedStringHandlerTest_DefaultInterpolatedStringHandler_Accessor()
{
var buffer = new char[16];
var handler = new DefaultInterpolatedStringHandler(literalLength: 10, formattedCount: 2, provider: null, buffer);
ref var position = ref Position(ref handler);
position = 2;
handler.AppendFormatted(42);
var text = handler.ToStringAndClear();
Assert.IsNotNull(text);
}
#endif

[TestMethod]
public void InterpolatedStringHandlerTest_Log()
{
Expand Down
45 changes: 45 additions & 0 deletions src/Sep.Test/SepWriterColTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class SepWriterColTest
const string ColName = "A";
const int ColValue = 123456;
const string ColText = "123456";
static readonly string ColTextLong = new('a', 2048);

static readonly string NL = Environment.NewLine;

Expand All @@ -31,12 +32,24 @@ public void SepWriterColTest_Set_String()
Run(col => col.Set(ColText));
}

[TestMethod]
public void SepWriterColTest_Set_String_Long()
{
Run(col => col.Set(ColTextLong), ColTextLong);
}

[TestMethod]
public void SepWriterColTest_Set_Span()
{
Run(col => col.Set(ColText.AsSpan()));
}

[TestMethod]
public void SepWriterColTest_Set_Span_Long()
{
Run(col => col.Set(ColTextLong.AsSpan()), ColTextLong);
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString()
{
Expand All @@ -61,6 +74,18 @@ public void SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsParam()
Run(col => col.Set(CultureInfo.GetCultureInfo("da-DK"), $"{ColValue:F2}"), ColText + ",00");
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsConfig_Null()
{
Run(col => col.Set($"{ColValue:F2}"), ColText + ".00", null);
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_F2_CultureInfoAsParam_Null()
{
Run(col => col.Set(provider: null, $"{ColValue:F2}"), ColText + ".00");
}

[TestMethod]
public void SepWriterColTest_Set_InterpolatedString_AppendLiteral()
{
Expand Down Expand Up @@ -111,6 +136,26 @@ public void SepWriterColTest_Format()
Run(col => col.Format(ColValue));
}

[TestMethod]
public void SepWriterColTest_Format_Long()
{
var f = new LongSpanFormattable();
Run(col => col.Format(f), f.Text);
}

public class LongSpanFormattable : ISpanFormattable
{
public string Text { get; } = ColTextLong;

public string ToString(string? format, IFormatProvider? formatProvider) => Text;

public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
{
charsWritten = Text.Length;
return Text.TryCopyTo(destination);
}
}

// No escaping needed
[DataRow("", "")]
[DataRow(" ", " ")]
Expand Down
Loading
Loading